From 1b70baa17340b78a62f479dfd6483bae772895e6 Mon Sep 17 00:00:00 2001 From: kdayday Date: Fri, 18 Oct 2024 17:32:22 -0600 Subject: [PATCH 01/40] Add explanation --- docs/src/docs_best_practices/explanation.md | 35 +++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 docs/src/docs_best_practices/explanation.md diff --git a/docs/src/docs_best_practices/explanation.md b/docs/src/docs_best_practices/explanation.md new file mode 100644 index 000000000..f79943606 --- /dev/null +++ b/docs/src/docs_best_practices/explanation.md @@ -0,0 +1,35 @@ +# Explanation + +## History and Motivation + +During the first phase of Sienna's (previously SIIP's) development, Sienna used a 3-part +documentation organization, based on the expected needs of different user personas: + + - **Modeler**: Users that want to use existing functionality + - **Model Developer**: Users that want to develop custom structs, components, models, and/or workflows + - **Code Base Developers**: Users that want to add new core functionalities or fix bugs in the core capabilities + +However, as Sienna's user base has expanded, it has become apparent that this previous +organization is no longer serving. As of 2024, a new effort is underway to clean up and +re-organize the Sienna documentation according to the 4-part [Diataxis](https://diataxis.fr/) +framework, a well-established, systematic approach to technical documentation split up into +[Tutorials](https://diataxis.fr/tutorials/), +[How-to guides](https://diataxis.fr/how-to-guides/), +[Reference](https://diataxis.fr/reference/), and +[Explanation](https://diataxis.fr/explanation/). + +In addition, the current documentation has multiple quality issues, including misformatted +text, broken reference links, and documentation that has been written but is not visible to +users in the API ("missing docstrings"). While the [style guide](@ref style_guide) +has been available, the guide focuses primarily on the style of code itself, without +providing clear guidelines and best practices for other parts of the documentation besides +docstrings. In addition, the first stage of Sienna's development coincided with the initial +development of the [`Documenter.jl`](https://documenter.juliadocs.org/stable/) package. +Early versions of Sienna's packages were documented requiring `Documenter.jl` v0.27, and in +the meantime, `Documenter.jl` has released its v1.0 and onwards, which contain much +more rigorous checks for documentation quality. Sienna's packages have not kept up with +these improvements. + +We aim to remedy these issues through a concerted clean up and re-organization effort, +compliance with `Documenter.jl` >v1.0's quality control checks, and clear best practice +guidelines that can be applied as a regular part of future pull request reviews. From 37f2e2207a443c30e88f36a9afd21fe89890ef4a Mon Sep 17 00:00:00 2001 From: kdayday Date: Fri, 18 Oct 2024 17:32:58 -0600 Subject: [PATCH 02/40] Add howto compile --- .../src/docs_best_practices/how-to/compile.md | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 docs/src/docs_best_practices/how-to/compile.md diff --git a/docs/src/docs_best_practices/how-to/compile.md b/docs/src/docs_best_practices/how-to/compile.md new file mode 100644 index 000000000..13e99d762 --- /dev/null +++ b/docs/src/docs_best_practices/how-to/compile.md @@ -0,0 +1,60 @@ +# Compile and View Documentation Locally + +## Step 0a: Update Docs Environment (First Time) +The first time you compile documentation for a package, make sure the `docs/` environment +(i.e., `docs/Manifest.toml`, not the main `Manifest.toml` in the root of the repository) +is pointing to your local version of the package, so it compiles your local changes: + +```julia +julia --project=docs +using Pkg +Pkg.develop(path = "..") +``` + +## Step 0b: Auto-Generate Structs (If Needed) +Most documentation changes are made directly to markdown (.md) files, but if you changed one +of Sienna's .json descriptor files, you must first +[follow the instructions here](@ref "Auto-Generation of Component Structs") to auto-generate +the structs from the .json to have your changes propagated into the markdown files used for +documentation. + +**Example**: You updated `PowerSystems.jl`' +[`power_system_structs.json`](https://github.com/NREL-Sienna/PowerSystems.jl/blob/main/src/descriptors/power_system_structs.json) +file. + +From a terminal at the root of the repository (i.e., `PowerSystems.jl`), run: +```julia +julia --project=. +using InfrastructureSystems +InfrastructureSystems.generate_structs( + "./src/descriptors/power_system_structs.json", + "./src/models/generated", +) +``` + +## Step 1: Run the Formatter +To automatically format the documentation to conform with the [style guide](@ref style_guide), +run in a terminal at the root of the repository: +``` +julia scripts/formatter/formatter_code.jl +``` + +Resolve any errors and re-run until error-free. See how to [Troubleshoot Common Errors](@ref) +for help. + +## Step 2: Compile + +To compile, run in a terminal at the root of the repository: +``` +julia --project=docs docs/make.jl +``` + +Resolve any errors and re-run until error-free. See how to [Troubleshoot Common Errors](@ref) +for help. + +## Step 3: View +Click on the newly-created `index.html` file (e.g., +`SomeSiennaPackage/docs/build/index.html`) to view your locally compiled documentation in a +browser. + +Visually verify formatting and that code blocks compile as expected. From 57dfa1f633fa2f784e176e01ad7a4e08101d8514 Mon Sep 17 00:00:00 2001 From: kdayday Date: Fri, 18 Oct 2024 17:39:15 -0600 Subject: [PATCH 03/40] Add how to view on github --- docs/src/docs_best_practices/how-to/view_github.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 docs/src/docs_best_practices/how-to/view_github.md diff --git a/docs/src/docs_best_practices/how-to/view_github.md b/docs/src/docs_best_practices/how-to/view_github.md new file mode 100644 index 000000000..d8f53f3a0 --- /dev/null +++ b/docs/src/docs_best_practices/how-to/view_github.md @@ -0,0 +1,6 @@ +# View Draft Documentation on Github + +1. Create a pull request on Github. +2. Verify the Documentation/build check was successful (takes a few minutes). +2. Preview it in a browser following this url format: + > https://nrel-sienna.github.io/.jl/previews/PR/ \ No newline at end of file From 0583c1cef46fd791e830f2dd669632e22afa3cd7 Mon Sep 17 00:00:00 2001 From: kdayday Date: Fri, 18 Oct 2024 17:44:45 -0600 Subject: [PATCH 04/40] Add docs troubleshoot draft --- .../how-to/troubleshoot.md | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 docs/src/docs_best_practices/how-to/troubleshoot.md diff --git a/docs/src/docs_best_practices/how-to/troubleshoot.md b/docs/src/docs_best_practices/how-to/troubleshoot.md new file mode 100644 index 000000000..d954f8117 --- /dev/null +++ b/docs/src/docs_best_practices/how-to/troubleshoot.md @@ -0,0 +1,24 @@ +# Troubleshoot Common Errors + +## ` Error: ## docstrings not included in the manual` + +TODO + +## `Error: duplicate docs found` + +> **Example**: `Error: duplicate docs found for 'PowerSimulations.SimulationProblemResults' in src\reference\PowerSimulations.md` + +**Problem**: The same `.jl` file has been found more than once by `Documenter.jl`, which matches +based on the end of a file path. + +1. Determine which file the function is located in + > **Example**: `simulation_problem_results.jl` for `PowerSimulations.SimulationProblemResults` +2. Check whether that file is listed more than once in an `@autodocs` `Pages` list in the API + markdown file (e.g., `PowerSimulations.md` or `public.md`). Remove duplicates. +3. Also check for other files with the same partial ending in the `@autodocs` `Pages` lists. + Specify more of that file path to distinguish it. + > **Example**: Change `Pages = ["problem_results.jl"]` to `Pages = ["operation/problem_results.jl"]` + +## `Parsing error for input` from `JuliaFormatter` + +TODO \ No newline at end of file From 70850aa78a0f69551e22f62811dc7a0f7b002aea Mon Sep 17 00:00:00 2001 From: kdayday Date: Fri, 18 Oct 2024 17:45:09 -0600 Subject: [PATCH 05/40] Add new pages to make --- docs/make.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/make.jl b/docs/make.jl index db7d61b0a..3cc460fbc 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -17,6 +17,13 @@ pages = OrderedDict( "dev_guide/logging.md", ], "Style Guide" => "style.md", + "Documentation Best Practices" => Any[ + "How to..." => Any[ + "Compile and View Documentation Locally" => "docs_best_practices/how-to/compile.md", + "View Draft Documentation on Github" => "docs_best_practices/how-to/view_github.md", + "Troubleshoot Common Errors" => "docs_best_practices/how-to/troubleshoot.md",], + "Explanation" => "docs_best_practices/explanation.md" + ], "API" => "InfrastructureSystems.md" ) From 4beb783094fef7b11626856d3974aa94748cf02c Mon Sep 17 00:00:00 2001 From: kdayday Date: Tue, 22 Oct 2024 13:32:45 -0600 Subject: [PATCH 06/40] Add useful links --- docs/make.jl | 3 ++- docs/src/docs_best_practices/reference/useful_links.md | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 docs/src/docs_best_practices/reference/useful_links.md diff --git a/docs/make.jl b/docs/make.jl index 3cc460fbc..f0b601176 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -22,7 +22,8 @@ pages = OrderedDict( "Compile and View Documentation Locally" => "docs_best_practices/how-to/compile.md", "View Draft Documentation on Github" => "docs_best_practices/how-to/view_github.md", "Troubleshoot Common Errors" => "docs_best_practices/how-to/troubleshoot.md",], - "Explanation" => "docs_best_practices/explanation.md" + "Explanation" => "docs_best_practices/explanation.md", + "Reference" => Any["docs_best_practices/reference/useful_links.md"], ], "API" => "InfrastructureSystems.md" ) diff --git a/docs/src/docs_best_practices/reference/useful_links.md b/docs/src/docs_best_practices/reference/useful_links.md new file mode 100644 index 000000000..d772fd86d --- /dev/null +++ b/docs/src/docs_best_practices/reference/useful_links.md @@ -0,0 +1,10 @@ +# Useful Links + +- [Diataxis](https://diataxis.fr/): Reference for the new + documentation framework Sienna is striving to follow (not specific to Julia) +- [`Documenter.jl`](https://documenter.juliadocs.org/stable/): Julia's documentation + package, the [Syntax](https://documenter.juliadocs.org/stable/man/syntax/) and + [Showcase](https://documenter.juliadocs.org/stable/showcase/) pages are + especially useful +- [`Sienna-Template` Git repository](https://github.com/NREL-Sienna/Sienna-Template): A + template for new Sienna packages that includes the required documentation framework. From 5a190357eafc652b818a7546e813e04beafb1e83 Mon Sep 17 00:00:00 2001 From: kdayday Date: Wed, 23 Oct 2024 14:26:39 -0600 Subject: [PATCH 07/40] Add how-to write a tutorial and draft requirements checklist --- docs/make.jl | 6 +- .../how-to/write_a_tutorial.md | 104 ++++++++++++++++++ .../reference/requirements_checklist.md | 40 +++++++ 3 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 docs/src/docs_best_practices/how-to/write_a_tutorial.md create mode 100644 docs/src/docs_best_practices/reference/requirements_checklist.md diff --git a/docs/make.jl b/docs/make.jl index f0b601176..0900571f3 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -18,12 +18,14 @@ pages = OrderedDict( ], "Style Guide" => "style.md", "Documentation Best Practices" => Any[ + "Explanation" => "docs_best_practices/explanation.md", "How to..." => Any[ + "Write a Tutorial" => "docs_best_practices/how-to/write_a_tutorial.md", "Compile and View Documentation Locally" => "docs_best_practices/how-to/compile.md", "View Draft Documentation on Github" => "docs_best_practices/how-to/view_github.md", "Troubleshoot Common Errors" => "docs_best_practices/how-to/troubleshoot.md",], - "Explanation" => "docs_best_practices/explanation.md", - "Reference" => Any["docs_best_practices/reference/useful_links.md"], + "Reference" => Any["docs_best_practices/reference/requirements_checklist.md", + "docs_best_practices/reference/useful_links.md",], ], "API" => "InfrastructureSystems.md" ) diff --git a/docs/src/docs_best_practices/how-to/write_a_tutorial.md b/docs/src/docs_best_practices/how-to/write_a_tutorial.md new file mode 100644 index 000000000..1f76c9544 --- /dev/null +++ b/docs/src/docs_best_practices/how-to/write_a_tutorial.md @@ -0,0 +1,104 @@ +# Write a Tutorial + +Tutorials are learning experiences to give our users confidence and experience in using +Sienna. + +## Prepare + +- If you have not read [Diataxis](https://diataxis.fr/), first read it in its entirety. +- If you have read it, skim the pages on [Tutorials](https://diataxis.fr/tutorials/) and + the [difference between a tutorial and how-to guide](https://diataxis.fr/tutorials-how-to/) + to refresh your memory and refer back throughout the process. +- Look at an example: `PowerSystems.jl`'s + [Working with Time Series](https://nrel-sienna.github.io/PowerSystems.jl/stable/tutorials/working_with_time_series/) + + +## Follow the Do's and Don't's + +The [Diataxis Tutorials](https://diataxis.fr/tutorials/) page should be your main reference +as you write, but in addition, use these functional and aesthetic guidelines to +ensure we follow Diataxis and avoid common pitfalls from previous versions of Sienna +documentation: + +```@contents +Pages = ["write_a_tutorial.md"] +Depth = 3:3 +``` + +### Give it a story + +The tutorial should have a logical flow, rather than be a series of disconnected code +demonstrations. +!!! tip "Do" + Use either named + [`@example`](https://documenter.juliadocs.org/stable/man/syntax/#reference-at-example) + or named + [`@repl`](https://documenter.juliadocs.org/stable/man/syntax/#@repl-block) blocks to + ensure all code compiles in order in the same environment and ensuring each step builds + on the previous steps in your story: + ````markdown + ```@example my_tutorial + + ``` + ```` +!!! warning "Don't" + Use a series of `julia` markdown blocks. These won't be compiled, failing the + intention of a tutorial and introducing high likelihood of errors as syntax changes. + ````markdown + ```julia + + ``` + ```` + +### Make it reproducible +A user should be able to copy and paste every code block in the tutorial in order and get +the exact results seen on the documentation page. +!!! tip "Do" + Display all code, starting from `import SomeSiennaPackage` +!!! warning "Don't" + Use `#hide` or + [`@setup`](https://documenter.juliadocs.org/stable/man/syntax/#reference-at-setup) + blocks. + +### Make it realistic and relatable +!!! tip "Do" + Take the time to define some realistic example data. +!!! warning "Don't" + Use `zero()` or `one()` for all example data. + +### Make it effortless to read +!!! tip "Do" + Split code examples into ideally 1 (to 3) lines ONLY, with a short preface + to explain what each line is doing, even if it's obvious to you. +!!! warning "Don't" + Use blocks of example code and/or return statements that go over 1 screen + length in the compiled .html. They are very hard to follow and allow a user to tune out + or give up. + +### Only show relevant log and return statements +!!! tip "Do" + [Configure the logger](@ref "Logging") or load/build a `System` that returns very + few log statements. Use semi-colons at line ends to hide return statements if need be. +!!! warning "Don't" + Show extensive or confusing log or return statements that bog down a reader with + information that isn't directly relevant to what you're trying to teach. + +### Remove other types of documentation +Particularly when editting existing material, watch out for material that should be +moved elsewhere according to Diataxis principles, especially details and examples +that should live in the docstrings. +!!! tip "Do" + Preface each call to a new function with a hyperlink to that function's + docstring so the user can find more detail +!!! warning "Don't" + Include details about different keyword argument functions or versions of + a function in the tutorial itself. Some repetition is OK, but details and examples + live in the docstrings. + +### Look at the compiled .html! +!!! tip "Do" + - [Compile](@ref "Compile and View Documentation Locally") the tutorial regularly and + look at it + - Check all code examples gave the expected results without erroring + - Check for length of the code examples and iteratively adjust to make it easy + to read diff --git a/docs/src/docs_best_practices/reference/requirements_checklist.md b/docs/src/docs_best_practices/reference/requirements_checklist.md new file mode 100644 index 000000000..f03ae7ea6 --- /dev/null +++ b/docs/src/docs_best_practices/reference/requirements_checklist.md @@ -0,0 +1,40 @@ +# Requirements Checklist + +## Code and Environment Requirements + +The [`Sienna-Template`](https://github.com/NREL-Sienna/Sienna-Template) Git repo has the +required environments and formatting and documentation code. New Sienna packages should +start from this template. + +Existing Sienna packages will need to be updated with these requirements, but these will +only need to be addressed once: + +1. `docs/` environment must use [`Documenter.jl`](https://documenter.juliadocs.org/stable/) + v1.0 or greater + - That is, previous `compat` requirements of `Documenter = "0.27"` must be removed. +1. `docs/make.jl` file must call + [`Documenter.makedocs`](https://documenter.juliadocs.org/stable/lib/public/#Documenter.makedocs) + *without* the `warnonly` `kwarg` (i.e., all errors caught by `makedocs` must be resolved before + merging). [See an example here](https://github.com/NREL-Sienna/InfrastructureSystems.jl/blob/768438a40c46767560891ec493cf87ed232a2b2b/docs/make.jl#L47). +1. The `scripts/formatter/formatter_code.jl` must be updated to format the markdown .md files in the + `docs/` folder, calling `format`() with the `kwarg` `format_markdown = true`. See + [these](https://github.com/NREL-Sienna/InfrastructureSystems.jl/blob/768438a40c46767560891ec493cf87ed232a2b2b/scripts/formatter/formatter_code.jl#L13) + [three](https://github.com/NREL-Sienna/InfrastructureSystems.jl/blob/768438a40c46767560891ec493cf87ed232a2b2b/scripts/formatter/formatter_code.jl#L8) + [links](https://github.com/NREL-Sienna/InfrastructureSystems.jl/blob/768438a40c46767560891ec493cf87ed232a2b2b/scripts/formatter/formatter_code.jl#L23) + for examples of the updated lines. + +## Diataxis Requirements + +1. Top-level documentation organization follows the [Diataxis](https://diataxis.fr/) + framework (plus a welcome page/section) + + +!!! todo + + +## Pull Request Requirements + +1. [Compile](@ref "Compile and View Documentation Locally") the documentation and look at + it! + +!!! todo \ No newline at end of file From dcc6edc9e910e9ded9fc66234e218e49499ad2b3 Mon Sep 17 00:00:00 2001 From: kdayday Date: Wed, 23 Oct 2024 14:27:05 -0600 Subject: [PATCH 08/40] Update explanation --- docs/src/docs_best_practices/explanation.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/src/docs_best_practices/explanation.md b/docs/src/docs_best_practices/explanation.md index f79943606..7ea632f4e 100644 --- a/docs/src/docs_best_practices/explanation.md +++ b/docs/src/docs_best_practices/explanation.md @@ -30,6 +30,14 @@ the meantime, `Documenter.jl` has released its v1.0 and onwards, which contain m more rigorous checks for documentation quality. Sienna's packages have not kept up with these improvements. -We aim to remedy these issues through a concerted clean up and re-organization effort, -compliance with `Documenter.jl` >v1.0's quality control checks, and clear best practice -guidelines that can be applied as a regular part of future pull request reviews. +## Purpose of the Documentation Best Practices + +We aim to remedy the historical issues above through a concerted clean up and +re-organization effort and compliance with `Documenter.jl` >v1.0's quality control checks, +following these best practice guidelines. These guidelines are not intended to reiterate +[Diataxis](https://diataxis.fr/), beyond regularly reminding contributers to refer to them +-- and contributers should read the [Diataxis](https://diataxis.fr/) website in its entirety +before getting started. Instead, the best practices are intended to bridge the gap where +there are Julia- or Sienna-specific recommendations, either to consistently implement the +Diataxis framework or to highlight common documentation issues throughout the Sienna +packages that need to be addressed as part of our concerted clean-up effort. From 24ffbdb7f3554e5a51d61425965ce79a03d4bb9a Mon Sep 17 00:00:00 2001 From: kdayday Date: Wed, 23 Oct 2024 14:29:02 -0600 Subject: [PATCH 09/40] Tweak how-to tutorial --- .../docs_best_practices/how-to/write_a_tutorial.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/src/docs_best_practices/how-to/write_a_tutorial.md b/docs/src/docs_best_practices/how-to/write_a_tutorial.md index 1f76c9544..d4a933a75 100644 --- a/docs/src/docs_best_practices/how-to/write_a_tutorial.md +++ b/docs/src/docs_best_practices/how-to/write_a_tutorial.md @@ -60,12 +60,6 @@ the exact results seen on the documentation page. [`@setup`](https://documenter.juliadocs.org/stable/man/syntax/#reference-at-setup) blocks. -### Make it realistic and relatable -!!! tip "Do" - Take the time to define some realistic example data. -!!! warning "Don't" - Use `zero()` or `one()` for all example data. - ### Make it effortless to read !!! tip "Do" Split code examples into ideally 1 (to 3) lines ONLY, with a short preface @@ -75,6 +69,12 @@ the exact results seen on the documentation page. length in the compiled .html. They are very hard to follow and allow a user to tune out or give up. +### Make it realistic and relatable +!!! tip "Do" + Take the time to define some realistic example data. +!!! warning "Don't" + Use `zero()` or `one()` for all example data. + ### Only show relevant log and return statements !!! tip "Do" [Configure the logger](@ref "Logging") or load/build a `System` that returns very From 12002c815cc2c330b4e936e1123a1984ccb24187 Mon Sep 17 00:00:00 2001 From: kdayday Date: Wed, 23 Oct 2024 15:04:43 -0600 Subject: [PATCH 10/40] Add general formatting how-to --- docs/make.jl | 1 + .../how-to/general_formatting.md | 52 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 docs/src/docs_best_practices/how-to/general_formatting.md diff --git a/docs/make.jl b/docs/make.jl index 0900571f3..496e6d02d 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -20,6 +20,7 @@ pages = OrderedDict( "Documentation Best Practices" => Any[ "Explanation" => "docs_best_practices/explanation.md", "How to..." => Any[ + "Clean Up General Formatting" => "docs_best_practices/how-to/general_formatting.md", "Write a Tutorial" => "docs_best_practices/how-to/write_a_tutorial.md", "Compile and View Documentation Locally" => "docs_best_practices/how-to/compile.md", "View Draft Documentation on Github" => "docs_best_practices/how-to/view_github.md", diff --git a/docs/src/docs_best_practices/how-to/general_formatting.md b/docs/src/docs_best_practices/how-to/general_formatting.md new file mode 100644 index 000000000..783e9179f --- /dev/null +++ b/docs/src/docs_best_practices/how-to/general_formatting.md @@ -0,0 +1,52 @@ +# Clean Up General Formatting + +These recommendations are to make navigating our documentation effortless for users, while +addressing common markdown formatting issues in the existing Sienna documentation: + +## Format in back-ticks + +All package names, types, functions, methods, and parameters, etc. should formatted in +back-ticks: +!!! tip "Do" + ``` + `max_active_power` + ``` + compiles as `max_active_power` +!!! warning "Don't" + ``` + max_active_power + ``` + compiles as max_active_power + +## Put hyperlinks everywhere +All types, function, and methods should have hyperlinks to the correct docstring, accounting +for multiple methods of the same name due to Julia's multiple dispatch. +[`Documenter.jl`](https://documenter.juliadocs.org/stable/) will link to the first +occurrance in documentation. If that's not the one you're referring to, copy the entire +signature with types into the hyperlink reference. +!!! tip "Do" + ``` + [`get_time_series_values`](@ref) + ``` + Or + ``` + [`get_time_series_values` from a `ForecastCache`](@ref get_time_series_values( + owner::TimeSeriesOwners, + forecast::Forecast, + start_time::Dates.DateTime; + len::Union{Nothing, Int} = nothing, + ignore_scaling_factors = false, + )) + ``` +!!! warning "Don't" + - ``` `get_time_series_values` ``` + - ```get_time_series_values``` + +## Add links to other Sienna packages + +All other Sienna package names should have documentation (not Git repo) hyperlinks: +!!! tip "Do" + ``` [`PowerSystems.jl`](https://nrel-sienna.github.io/PowerSystems.jl/stable/) ``` +!!! warning "Don't" + - ``` `PowerSystems.jl` ``` + - ``` [`PowerSystems.jl`](https://github.com/NREL-Sienna/PowerSystems.jl)``` From e5e5b51954372fd03997a2365eb908da136cb640 Mon Sep 17 00:00:00 2001 From: kdayday Date: Thu, 24 Oct 2024 12:09:04 -0600 Subject: [PATCH 11/40] Fix logging link --- docs/src/dev_guide/logging.md | 2 +- docs/src/docs_best_practices/how-to/write_a_tutorial.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/dev_guide/logging.md b/docs/src/dev_guide/logging.md index 9ff909f09..d71d52f96 100644 --- a/docs/src/dev_guide/logging.md +++ b/docs/src/dev_guide/logging.md @@ -1,4 +1,4 @@ -# Logging +# [Logging](@id log) `InfrastructureSystems.jl` provides a `MultiLogger` object that allows customized logging to console and file. Refer to the [logging diff --git a/docs/src/docs_best_practices/how-to/write_a_tutorial.md b/docs/src/docs_best_practices/how-to/write_a_tutorial.md index d4a933a75..c0a022688 100644 --- a/docs/src/docs_best_practices/how-to/write_a_tutorial.md +++ b/docs/src/docs_best_practices/how-to/write_a_tutorial.md @@ -77,7 +77,7 @@ the exact results seen on the documentation page. ### Only show relevant log and return statements !!! tip "Do" - [Configure the logger](@ref "Logging") or load/build a `System` that returns very + [Configure the logger](@ref log) or load/build a `System` that returns very few log statements. Use semi-colons at line ends to hide return statements if need be. !!! warning "Don't" Show extensive or confusing log or return statements that bog down a reader with From ed5cda2ae2eb9dc97829d8688239488b3322fabe Mon Sep 17 00:00:00 2001 From: kdayday Date: Thu, 24 Oct 2024 13:19:24 -0600 Subject: [PATCH 12/40] Format explanation --- docs/src/docs_best_practices/explanation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/docs_best_practices/explanation.md b/docs/src/docs_best_practices/explanation.md index 7ea632f4e..2c3b2949c 100644 --- a/docs/src/docs_best_practices/explanation.md +++ b/docs/src/docs_best_practices/explanation.md @@ -28,7 +28,7 @@ development of the [`Documenter.jl`](https://documenter.juliadocs.org/stable/) p Early versions of Sienna's packages were documented requiring `Documenter.jl` v0.27, and in the meantime, `Documenter.jl` has released its v1.0 and onwards, which contain much more rigorous checks for documentation quality. Sienna's packages have not kept up with -these improvements. +these improvements. ## Purpose of the Documentation Best Practices @@ -40,4 +40,4 @@ following these best practice guidelines. These guidelines are not intended to r before getting started. Instead, the best practices are intended to bridge the gap where there are Julia- or Sienna-specific recommendations, either to consistently implement the Diataxis framework or to highlight common documentation issues throughout the Sienna -packages that need to be addressed as part of our concerted clean-up effort. +packages that need to be addressed as part of our concerted clean-up effort. From 484a8568c2cc2906f1bc23676db1f20b45d7144a Mon Sep 17 00:00:00 2001 From: kdayday Date: Thu, 24 Oct 2024 14:48:02 -0600 Subject: [PATCH 13/40] Add missing docstrings from Optimization and Simulation submodules and enforce strict compilation --- docs/make.jl | 1 - docs/src/InfrastructureSystems.md | 4 ++- src/Optimization/Optimization.jl | 7 +++++ .../optimization_problem_results.jl | 30 +++++++------------ src/Simulation/Simulation.jl | 7 +++++ 5 files changed, 27 insertions(+), 22 deletions(-) diff --git a/docs/make.jl b/docs/make.jl index 496e6d02d..da546ce91 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -62,7 +62,6 @@ makedocs( size_threshold = nothing), sitename = "InfrastructureSystems.jl", pages = Any[p for p in pages], - warnonly = Documenter.except(), ) diff --git a/docs/src/InfrastructureSystems.md b/docs/src/InfrastructureSystems.md index 1d3236ed9..72c07bdc1 100644 --- a/docs/src/InfrastructureSystems.md +++ b/docs/src/InfrastructureSystems.md @@ -1,5 +1,7 @@ # [InfrastructureSystems API Reference](@id API_ref) ```@autodocs -Modules = [InfrastructureSystems] +Modules = [InfrastructureSystems, + InfrastructureSystems.Simulation, + InfrastructureSystems.Optimization] ``` diff --git a/src/Optimization/Optimization.jl b/src/Optimization/Optimization.jl index 0f26cb08c..05739454b 100644 --- a/src/Optimization/Optimization.jl +++ b/src/Optimization/Optimization.jl @@ -28,6 +28,13 @@ import ..InfrastructureSystems: convert_for_path, InvalidValue +using DocStringExtensions + +@template (FUNCTIONS, METHODS) = """ + $(TYPEDSIGNATURES) + $(DOCSTRING) + """ + export OptimizationProblemResults export OptimizationProblemResultsExport export OptimizerStats diff --git a/src/Optimization/optimization_problem_results.jl b/src/Optimization/optimization_problem_results.jl index d2cef4540..2b52489f1 100644 --- a/src/Optimization/optimization_problem_results.jl +++ b/src/Optimization/optimization_problem_results.jl @@ -320,8 +320,7 @@ end """ Return the values for the requested variable key for a problem. -Accepts a vector of keys for the return of the values. If the time stamps and keys are -loaded using the [`load_results!`](@ref) function it will read from memory. +Accepts a vector of keys for the return of the values. # Arguments @@ -349,8 +348,7 @@ end """ Return the values for the requested variable keys for a problem. -Accepts a vector of keys for the return of the values. If the time stamps and keys are -loaded using the [`load_results!`](@ref) function it will read from memory. +Accepts a vector of keys for the return of the values. # Arguments @@ -394,8 +392,7 @@ end """ Return the values for the requested dual key for a problem. -Accepts a vector of keys for the return of the values. If the time stamps and keys are -loaded using the [`load_results!`](@ref) function it will read from memory. +Accepts a vector of keys for the return of the values. # Arguments @@ -423,8 +420,7 @@ end """ Return the values for the requested dual keys for a problem. -Accepts a vector of keys for the return of the values. If the time stamps and keys are -loaded using the [`load_results!`](@ref) function it will read from memory. +Accepts a vector of keys for the return of the values. # Arguments @@ -467,8 +463,7 @@ end """ Return the values for the requested parameter key for a problem. -Accepts a vector of keys for the return of the values. If the time stamps and keys are -loaded using the [`load_results!`](@ref) function it will read from memory. +Accepts a vector of keys for the return of the values. # Arguments @@ -496,8 +491,7 @@ end """ Return the values for the requested parameter keys for a problem. -Accepts a vector of keys for the return of the values. If the time stamps and keys are -loaded using the [`load_results!`](@ref) function it will read from memory. +Accepts a vector of keys for the return of the values. # Arguments @@ -541,8 +535,7 @@ end """ Return the values for the requested aux_variable key for a problem. -Accepts a vector of keys for the return of the values. If the time stamps and keys are -loaded using the [`load_results!`](@ref) function it will read from memory. +Accepts a vector of keys for the return of the values. # Arguments @@ -570,8 +563,7 @@ end """ Return the values for the requested aux_variable keys for a problem. -Accepts a vector of keys for the return of the values. If the time stamps and keys are -loaded using the [`load_results!`](@ref) function it will read from memory. +Accepts a vector of keys for the return of the values. # Arguments @@ -615,8 +607,7 @@ end """ Return the values for the requested expression key for a problem. -Accepts a vector of keys for the return of the values. If the time stamps and keys are -loaded using the [`load_results!`](@ref) function it will read from memory. +Accepts a vector of keys for the return of the values. # Arguments @@ -644,8 +635,7 @@ end """ Return the values for the requested expression keys for a problem. -Accepts a vector of keys for the return of the values. If the time stamps and keys are -loaded using the [`load_results!`](@ref) function it will read from memory. +Accepts a vector of keys for the return of the values. # Arguments diff --git a/src/Simulation/Simulation.jl b/src/Simulation/Simulation.jl index 6a3cc3bb7..ccfe0cbf5 100644 --- a/src/Simulation/Simulation.jl +++ b/src/Simulation/Simulation.jl @@ -11,4 +11,11 @@ import ..InfrastructureSystems: include("enums.jl") +using DocStringExtensions + +@template (FUNCTIONS, METHODS) = """ + $(TYPEDSIGNATURES) + $(DOCSTRING) + """ + end From 5fad70f05affe964724eebc3afc38cce1d954241 Mon Sep 17 00:00:00 2001 From: kdayday Date: Sat, 2 Nov 2024 11:49:38 -0600 Subject: [PATCH 14/40] import to using --- docs/src/docs_best_practices/how-to/write_a_tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/docs_best_practices/how-to/write_a_tutorial.md b/docs/src/docs_best_practices/how-to/write_a_tutorial.md index c0a022688..cdaa56932 100644 --- a/docs/src/docs_best_practices/how-to/write_a_tutorial.md +++ b/docs/src/docs_best_practices/how-to/write_a_tutorial.md @@ -54,7 +54,7 @@ demonstrations. A user should be able to copy and paste every code block in the tutorial in order and get the exact results seen on the documentation page. !!! tip "Do" - Display all code, starting from `import SomeSiennaPackage` + Display all code, starting from `using SomeSiennaPackage` !!! warning "Don't" Use `#hide` or [`@setup`](https://documenter.juliadocs.org/stable/man/syntax/#reference-at-setup) From fafda01e93e3cb7abd96e93da380fe0809c2e2ae Mon Sep 17 00:00:00 2001 From: kdayday Date: Sat, 2 Nov 2024 11:50:31 -0600 Subject: [PATCH 15/40] list format --- docs/src/docs_best_practices/explanation.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/src/docs_best_practices/explanation.md b/docs/src/docs_best_practices/explanation.md index 2c3b2949c..d6a4ea734 100644 --- a/docs/src/docs_best_practices/explanation.md +++ b/docs/src/docs_best_practices/explanation.md @@ -12,11 +12,12 @@ documentation organization, based on the expected needs of different user person However, as Sienna's user base has expanded, it has become apparent that this previous organization is no longer serving. As of 2024, a new effort is underway to clean up and re-organize the Sienna documentation according to the 4-part [Diataxis](https://diataxis.fr/) -framework, a well-established, systematic approach to technical documentation split up into -[Tutorials](https://diataxis.fr/tutorials/), -[How-to guides](https://diataxis.fr/how-to-guides/), -[Reference](https://diataxis.fr/reference/), and -[Explanation](https://diataxis.fr/explanation/). +framework, a well-established, systematic approach to technical documentation split up into: + + - [Tutorials](https://diataxis.fr/tutorials/) + - [How-to guides](https://diataxis.fr/how-to-guides/) + - [Reference](https://diataxis.fr/reference/) + - [Explanation](https://diataxis.fr/explanation/) In addition, the current documentation has multiple quality issues, including misformatted text, broken reference links, and documentation that has been written but is not visible to From efc5f598311f0b5388c549a4a2f1949e09cf181d Mon Sep 17 00:00:00 2001 From: kdayday Date: Mon, 4 Nov 2024 08:03:55 -0700 Subject: [PATCH 16/40] Add DocumenterInterLinks and update Project.toml --- docs/Project.toml | 2 ++ docs/make.jl | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/docs/Project.toml b/docs/Project.toml index 3de9e340e..9ac5d4bf0 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -2,8 +2,10 @@ CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +DocumenterInterLinks = "d12716ef-a0f6-4df4-a9f1-a5a34e75c656" InfrastructureSystems = "2cd47ed4-ca9b-11e9-27f2-ab636a7671f1" Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" [compat] InfrastructureSystems = "2" +Documenter = "1" diff --git a/docs/make.jl b/docs/make.jl index da546ce91..a3155ab1e 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,6 +1,12 @@ using Documenter, InfrastructureSystems import DataStructures: OrderedDict using Literate +using DocumenterInterLinks + +links = InterLinks( + "Documenter" => "https://documenter.juliadocs.org/stable/", + "Julia" => "https://docs.julialang.org/en/v1/", +) if haskey(ENV, "GITHUB_ACTIONS") ENV["JULIA_DEBUG"] = "Documenter" @@ -62,6 +68,7 @@ makedocs( size_threshold = nothing), sitename = "InfrastructureSystems.jl", pages = Any[p for p in pages], + plugins = [links], ) From 2e7ed2700df7367778840aaadb51772087130b6e Mon Sep 17 00:00:00 2001 From: kdayday Date: Tue, 5 Nov 2024 14:51:53 -0700 Subject: [PATCH 17/40] Partial draft how to write docstrings --- docs/make.jl | 1 + .../how-to/troubleshoot.md | 5 +- .../how-to/write_docstrings_org_api.md | 91 +++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 docs/src/docs_best_practices/how-to/write_docstrings_org_api.md diff --git a/docs/make.jl b/docs/make.jl index a3155ab1e..d9e317f2d 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -28,6 +28,7 @@ pages = OrderedDict( "How to..." => Any[ "Clean Up General Formatting" => "docs_best_practices/how-to/general_formatting.md", "Write a Tutorial" => "docs_best_practices/how-to/write_a_tutorial.md", + "Write Docstrings and Organize the APIs" => "docs_best_practices/how-to/write_docstrings_org_api.md", "Compile and View Documentation Locally" => "docs_best_practices/how-to/compile.md", "View Draft Documentation on Github" => "docs_best_practices/how-to/view_github.md", "Troubleshoot Common Errors" => "docs_best_practices/how-to/troubleshoot.md",], diff --git a/docs/src/docs_best_practices/how-to/troubleshoot.md b/docs/src/docs_best_practices/how-to/troubleshoot.md index d954f8117..fbc80ae48 100644 --- a/docs/src/docs_best_practices/how-to/troubleshoot.md +++ b/docs/src/docs_best_practices/how-to/troubleshoot.md @@ -1,9 +1,12 @@ # Troubleshoot Common Errors -## ` Error: ## docstrings not included in the manual` +## [`Error: ## docstrings not included in the manual`](@id miss_doc) TODO +1. Are these docstrings from `InfrastructureSystems.jl`? Follow how-to + [selectively export docstrings from `InfrastructureSystems.jl`](@ref docs_from_is) + ## `Error: duplicate docs found` > **Example**: `Error: duplicate docs found for 'PowerSimulations.SimulationProblemResults' in src\reference\PowerSimulations.md` diff --git a/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md b/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md new file mode 100644 index 000000000..1fe7098cf --- /dev/null +++ b/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md @@ -0,0 +1,91 @@ +# Write Docstrings and Organize the APIs + +Docstrings for all structs, methods, and functions belong in the public or internal APIs, +organized under the [Reference](https://diataxis.fr/reference/) section in Diataxis organization. +Refer to this page particularly while editing existing Sienna docstrings and APIs for +guidance on common problems in our existing documentation. + +## Prepare + +- If you have not read [Diataxis](https://diataxis.fr/), first read it in its entirety. +- Refer back to the Diataxis [Reference](https://diataxis.fr/reference/) section while + working. +- Read and follow Julia's guidance on [Writing Documentation](@extref), + which mainly applies to docstrings +- Read the sections on `Documenter.jl`'s [`@docs` block](@extref) and + [`@autodocs` block](@extref), and follow the guidance below on using `@autodocs` + wherever possible + +## Follow the Do's and Don't's + +Julia and `Documenter.jl`'s guidance above should be your main reference, but in addition, +follow these do's and don't to avoid common pitfalls from previous versions of Sienna +documentation: + +```@contents +Pages = ["write_docstrings_org_api.md"] +Depth = 3:3 +``` + +Do: checj all dock strings have a function signature. (is there a more correct name for that?), Plus an additional arguments list if needed. +Don’t: leave strings That just have a description to remain unaddressed + +Do: use auto docs typed signatures to automatically compile arguments lists +Don’t: copy and paste arguments lists into the doc string, which opens opportunity for out of date errors from changes in the future + +### + +Do: if you want to make a dock string visible outside of the API (e.g., in a tutorial), use non-canonical reference +Do: migrate all formulation library, and model libraries into the public API + +## + +Do: use auto docs to automatically find all dock strings in a file +Don’t: manually list out the struts or methods within a topic, because that introduces more work whenever we make a change. Consider re-organizing code if need be, so all related functions are in the same file. + +### [Selectively Export Docstrings from `InfrastructureSystems.jl`](@id docs_from_isz) + +If you are working in another Sienna package (e.g., `SomeSiennaPackage.jl`) that imports and +exports code from `InfrastructureSystems.jl`: + +!!! tip "Do" + List the files containing necessary `InfrastructureSystems.jl` structs and methods in + `SomeSiennaPackage.jl`'s API, then explicitly filter by what `SomeSiennaPackage.jl` exports: + + ````markdown + ```@autodocs + Modules = [InfrastructureSystems] + Pages = ["production_variable_cost_curve.jl", # examples + "cost_aliases.jl", + ] + Order = [:type, :function] + Filter = t -> nameof(t) in names(SomeSiennaPackage) + ``` + ```` + +!!! warning "Don't" + List `InfrastructureSystems` as one of the `modules` in [`Documenter.makedocs`](@extref). + `Documenter.jl` will + look to map **all** `InfrastructureSystems.jl` docstrings into the API, resulting in + hundreds of [missing docstring](@ref miss_doc) errors: + + ```julia + makedocs( + modules = [SomeSiennaPackage, InfrastructureSystems], + format = Documenter.HTML( + prettyurls = haskey(ENV, "GITHUB_ACTIONS"), + size_threshold = nothing), + sitename = "SomeSiennaPackage.jl", + pages = Any[p for p in pages], + ) + ``` + + +### Remove other types of documentation + + +### Look at the compiled .html! +!!! tip "Do" + - [Compile](@ref "Compile and View Documentation Locally") the tutorial regularly and + look at it + - Check method signatures and argument lists are formatted correctly From 0cbbf9cb32b27a58c88e02c58cbc88c23ff22542 Mon Sep 17 00:00:00 2001 From: kdayday Date: Wed, 11 Dec 2024 15:25:35 -0700 Subject: [PATCH 18/40] typo --- docs/src/docs_best_practices/how-to/write_docstrings_org_api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md b/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md index 1fe7098cf..60e0e5840 100644 --- a/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md +++ b/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md @@ -43,7 +43,7 @@ Do: migrate all formulation library, and model libraries into the public API Do: use auto docs to automatically find all dock strings in a file Don’t: manually list out the struts or methods within a topic, because that introduces more work whenever we make a change. Consider re-organizing code if need be, so all related functions are in the same file. -### [Selectively Export Docstrings from `InfrastructureSystems.jl`](@id docs_from_isz) +### [Selectively Export Docstrings from `InfrastructureSystems.jl`](@id docs_from_is) If you are working in another Sienna package (e.g., `SomeSiennaPackage.jl`) that imports and exports code from `InfrastructureSystems.jl`: From 4bbfa9c3a22b0e7e8745aaf8a7d799942334e02e Mon Sep 17 00:00:00 2001 From: kdayday Date: Wed, 11 Dec 2024 15:26:15 -0700 Subject: [PATCH 19/40] Fix how to cmpile logic --- docs/src/docs_best_practices/how-to/compile.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/src/docs_best_practices/how-to/compile.md b/docs/src/docs_best_practices/how-to/compile.md index 13e99d762..1b7bd3bb2 100644 --- a/docs/src/docs_best_practices/how-to/compile.md +++ b/docs/src/docs_best_practices/how-to/compile.md @@ -32,7 +32,7 @@ InfrastructureSystems.generate_structs( ) ``` -## Step 1: Run the Formatter +## Step 0c: Run the Formatter (Before Submitting a Pull Request) To automatically format the documentation to conform with the [style guide](@ref style_guide), run in a terminal at the root of the repository: ``` @@ -42,7 +42,10 @@ julia scripts/formatter/formatter_code.jl Resolve any errors and re-run until error-free. See how to [Troubleshoot Common Errors](@ref) for help. -## Step 2: Compile +This is not a necessary step to compile, but needs to be done at least once to pass pull +request checks. + +## Step 1: Compile To compile, run in a terminal at the root of the repository: ``` @@ -52,7 +55,7 @@ julia --project=docs docs/make.jl Resolve any errors and re-run until error-free. See how to [Troubleshoot Common Errors](@ref) for help. -## Step 3: View +## Step 2: View Click on the newly-created `index.html` file (e.g., `SomeSiennaPackage/docs/build/index.html`) to view your locally compiled documentation in a browser. From f43af58557c1bd87aa29ab6fe403182d6833fe43 Mon Sep 17 00:00:00 2001 From: kdayday Date: Fri, 13 Dec 2024 09:16:45 -0700 Subject: [PATCH 20/40] Formatting updates --- .../how-to/general_formatting.md | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/docs/src/docs_best_practices/how-to/general_formatting.md b/docs/src/docs_best_practices/how-to/general_formatting.md index 783e9179f..899c24251 100644 --- a/docs/src/docs_best_practices/how-to/general_formatting.md +++ b/docs/src/docs_best_practices/how-to/general_formatting.md @@ -39,8 +39,13 @@ signature with types into the hyperlink reference. )) ``` !!! warning "Don't" - - ``` `get_time_series_values` ``` - - ```get_time_series_values``` + ``` + `get_time_series_values` + ``` + Or + ``` + get_time_series_values + ``` ## Add links to other Sienna packages @@ -48,5 +53,14 @@ All other Sienna package names should have documentation (not Git repo) hyperlin !!! tip "Do" ``` [`PowerSystems.jl`](https://nrel-sienna.github.io/PowerSystems.jl/stable/) ``` !!! warning "Don't" - - ``` `PowerSystems.jl` ``` - - ``` [`PowerSystems.jl`](https://github.com/NREL-Sienna/PowerSystems.jl)``` + ``` + `PowerSystems.jl` + ``` + Or + ``` + PSY + ``` + Or + ``` + [`PowerSystems.jl`](https://github.com/NREL-Sienna/PowerSystems.jl) + ``` From 7459a0038df5060a18867b0de8b0fd4b27cf1f86 Mon Sep 17 00:00:00 2001 From: kdayday Date: Fri, 13 Dec 2024 09:17:28 -0700 Subject: [PATCH 21/40] Update organize apis and add example pics --- docs/make.jl | 2 +- docs/src/assets/comp_after.png | Bin 0 -> 94349 bytes docs/src/assets/comp_before.png | Bin 0 -> 20761 bytes .../how-to/write_docstrings_org_api.md | 87 +++++++++++++++--- 4 files changed, 73 insertions(+), 16 deletions(-) create mode 100644 docs/src/assets/comp_after.png create mode 100644 docs/src/assets/comp_before.png diff --git a/docs/make.jl b/docs/make.jl index d9e317f2d..928c003b8 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -28,7 +28,7 @@ pages = OrderedDict( "How to..." => Any[ "Clean Up General Formatting" => "docs_best_practices/how-to/general_formatting.md", "Write a Tutorial" => "docs_best_practices/how-to/write_a_tutorial.md", - "Write Docstrings and Organize the APIs" => "docs_best_practices/how-to/write_docstrings_org_api.md", + "Organize APIs and Write Docstrings" => "docs_best_practices/how-to/write_docstrings_org_api.md", "Compile and View Documentation Locally" => "docs_best_practices/how-to/compile.md", "View Draft Documentation on Github" => "docs_best_practices/how-to/view_github.md", "Troubleshoot Common Errors" => "docs_best_practices/how-to/troubleshoot.md",], diff --git a/docs/src/assets/comp_after.png b/docs/src/assets/comp_after.png new file mode 100644 index 0000000000000000000000000000000000000000..6430c2928eea6521fc4d1d008c84c8b9442513e5 GIT binary patch literal 94349 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 literal 0 HcmV?d00001 diff --git a/docs/src/assets/comp_before.png b/docs/src/assets/comp_before.png new file mode 100644 index 0000000000000000000000000000000000000000..d18f52cc9c48cffa351c58d6b6ca9fda59a48432 GIT binary patch literal 20761 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 Uh)>L|-Lis424?!j*Bv7M1;}Bpb^rhX literal 0 HcmV?d00001 diff --git a/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md b/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md index 60e0e5840..32c364607 100644 --- a/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md +++ b/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md @@ -1,8 +1,8 @@ -# Write Docstrings and Organize the APIs +# Organize APIs and Write Docstrings Docstrings for all structs, methods, and functions belong in the public or internal APIs, organized under the [Reference](https://diataxis.fr/reference/) section in Diataxis organization. -Refer to this page particularly while editing existing Sienna docstrings and APIs for +Refer to this page particularly while editing Sienna docstrings and APIs for guidance on common problems in our existing documentation. ## Prepare @@ -27,21 +27,51 @@ Pages = ["write_docstrings_org_api.md"] Depth = 3:3 ``` -Do: checj all dock strings have a function signature. (is there a more correct name for that?), Plus an additional arguments list if needed. -Don’t: leave strings That just have a description to remain unaddressed +### Ensure All Docstrings Are Located in the APIs -Do: use auto docs typed signatures to automatically compile arguments lists -Don’t: copy and paste arguments lists into the doc string, which opens opportunity for out of date errors from changes in the future +!!! tip "Do" + Include a Public API for exported structs, functions, and methods, and an Internals API + for private functions. See + [`PowerSystems.jl`](https://nrel-sienna.github.io/PowerSystems.jl/stable/) + for an example with a Public API organized with `@autodocs` ([see next](@ref use_autodocs)) + or [`SiennaTemplate.jl`](https://github.com/NREL-Sienna/SiennaTemplate.jl) for a basic + template when starting a new package. + +!!! tip "Do" + Migrate all existing Formulation Libraries and Model Libraries into the Public API. -### +!!! tip "Do" + If you want to make a docstring visible outside of the API (e.g., in a tutorial), use + a [non-canonical reference](@extref noncanonical-block). -Do: if you want to make a dock string visible outside of the API (e.g., in a tutorial), use non-canonical reference -Do: migrate all formulation library, and model libraries into the public API +### [Automate Updating the Docstrings in the API with `@autodocs`](@id use_autodocs) -## +!!! tip "Do" + Use [`@autodocs` block](@extref)s in the Public API to automatically find all + docstrings in a file. Example: + ````markdown + ## Variables + ```@autodocs + Modules = [SomeSiennaPackage] + Pages = ["variables.jl"] + Public = true + Private = false + ``` + ```` -Do: use auto docs to automatically find all dock strings in a file -Don’t: manually list out the struts or methods within a topic, because that introduces more work whenever we make a change. Consider re-organizing code if need be, so all related functions are in the same file. +!!! warning "Don't" + Manually list out the struts or methods on a topic in a [`@docs` block](@extref), + because that introduces more work whenever we add something new or make a change. + Example: + ````markdown + ## Variables + ```@docs + variable1 + variable2 + ``` + ```` + Consider re-organizing code if need be, so all related functions are in the same file(s) + (e.g., `variables.jl`). ### [Selectively Export Docstrings from `InfrastructureSystems.jl`](@id docs_from_is) @@ -50,7 +80,8 @@ exports code from `InfrastructureSystems.jl`: !!! tip "Do" List the files containing necessary `InfrastructureSystems.jl` structs and methods in - `SomeSiennaPackage.jl`'s API, then explicitly filter by what `SomeSiennaPackage.jl` exports: + `SomeSiennaPackage.jl`'s Public API, then explicitly filter by what + `SomeSiennaPackage.jl` exports. Example: ````markdown ```@autodocs @@ -67,7 +98,7 @@ exports code from `InfrastructureSystems.jl`: List `InfrastructureSystems` as one of the `modules` in [`Documenter.makedocs`](@extref). `Documenter.jl` will look to map **all** `InfrastructureSystems.jl` docstrings into the API, resulting in - hundreds of [missing docstring](@ref miss_doc) errors: + hundreds of [missing docstring](@ref miss_doc) errors. Example: ```julia makedocs( @@ -80,9 +111,35 @@ exports code from `InfrastructureSystems.jl`: ) ``` +### Ensure All Docstrings Have a Function Signature and Arguments List + +!!! tip "Do" + Check all docstrings have a function signature and detailed arguments list + *visible in the API when you compile it*. Example: + + ![A docstring with function signature and args list](../../assets/comp_after.png) + +!!! warning "Don't" + Leave docstrings that just have a description unaddressed. Example: + + ![A single line docstring](../../assets/comp_before.png) + + + +### Automate Updating Docstring Arguments Lists + +# TODO EXAMPLES + +!!! tip "Do" + Use autodocs typed signatures to automatically compile arguments lists + +!!! warning "Don't" + Copy and paste arguments lists into the docstring, which opens opportunity for + out-of-date errors from changes in the future. -### Remove other types of documentation +### Extract Docstring Information from Other Types of Documentation +# TODO HERE ### Look at the compiled .html! !!! tip "Do" From fb96e6d7363e6d9e620527bb70fa5527d539c7aa Mon Sep 17 00:00:00 2001 From: kdayday Date: Fri, 13 Dec 2024 14:41:15 -0700 Subject: [PATCH 22/40] Complete how-to docstrings --- .../how-to/write_docstrings_org_api.md | 88 ++++++++++++++++--- 1 file changed, 74 insertions(+), 14 deletions(-) diff --git a/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md b/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md index 32c364607..ac5da4eba 100644 --- a/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md +++ b/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md @@ -27,6 +27,12 @@ Pages = ["write_docstrings_org_api.md"] Depth = 3:3 ``` +### Look at the compiled .html! +!!! tip "Do" + - [Compile](@ref "Compile and View Documentation Locally") regularly and + look at the APIs + - Check method signatures and argument lists are formatted correctly + ### Ensure All Docstrings Are Located in the APIs !!! tip "Do" @@ -44,7 +50,7 @@ Depth = 3:3 If you want to make a docstring visible outside of the API (e.g., in a tutorial), use a [non-canonical reference](@extref noncanonical-block). -### [Automate Updating the Docstrings in the API with `@autodocs`](@id use_autodocs) +### [Automate Adding Docstrings in the Public API with `@autodocs`](@id use_autodocs) !!! tip "Do" Use [`@autodocs` block](@extref)s in the Public API to automatically find all @@ -114,7 +120,7 @@ exports code from `InfrastructureSystems.jl`: ### Ensure All Docstrings Have a Function Signature and Arguments List !!! tip "Do" - Check all docstrings have a function signature and detailed arguments list + Check all exported docstrings have a function signature and detailed arguments list *visible in the API when you compile it*. Example: ![A docstring with function signature and args list](../../assets/comp_after.png) @@ -124,25 +130,79 @@ exports code from `InfrastructureSystems.jl`: ![A single line docstring](../../assets/comp_before.png) - - ### Automate Updating Docstring Arguments Lists - -# TODO EXAMPLES +This is not commonly done in Sienna yet, but a goal is to improve our use of +[`DocStringExtensions.jl`](https://docstringextensions.juliadocs.org/stable) for automation: !!! tip "Do" - Use autodocs typed signatures to automatically compile arguments lists + Use + [`DocStringExtensions.TYPEDFIELDS`](https://docstringextensions.juliadocs.org/stable/#DocStringExtensions.TYPEDFIELDS) + to automatically compile arguments lists. Example: + ````markdown + """ + SomeSiennaStruct(arg1, arg2) + + # Arguments + $(TYPEDFIELDS) + + This is the docstring line. + """ + struct SomeSiennaStruct <: OperationalCost + "Documentation for argument 1" + arg1::ProductionVariableCostCurve + "Documentation for argument 2" + arg2::Float64 + end + ```` !!! warning "Don't" Copy and paste arguments lists into the docstring, which opens opportunity for - out-of-date errors from changes in the future. + out-of-date errors when arguments are added or regorded. Example: + ````markdown + """ + SomeSiennaStruct(arg1, arg2) + + This is the docstring line. + + # Arguments + - `arg2::Float64`: Documentation for argument 2 + - `arg1::ProductionVariableCostCurve`: Documentation for argument 1 + """ + struct SomeSiennaStruct <: OperationalCost + arg1::ProductionVariableCostCurve + arg2::Float64 + end + ```` -### Extract Docstring Information from Other Types of Documentation +### Add `See also` Links to Functions with the Same Name + +!!! tip "Do" + To help users navigate Julia's multiple dispatch, add `See also` to other versions of + the function with the same name, using the guidance on + [adding a specific hyperlink](@ref hyperlinks). + Example: + ``` + See also + [`get_time_series_array` by name from storage](@ref get_time_series_array( + ::Type{T}, + owner::TimeSeriesOwners, + name::AbstractString; + start_time::Union{Nothing, Dates.DateTime} = nothing, + len::Union{Nothing, Int} = nothing, + ignore_scaling_factors = false, + features..., + ) where {T <: TimeSeriesData}), + [`get_time_series_array` from a `StaticTimeSeriesCache`](@ref get_time_series_array( + owner::TimeSeriesOwners, + time_series::StaticTimeSeries, + start_time::Union{Nothing, Dates.DateTime} = nothing; + len::Union{Nothing, Int} = nothing, + ignore_scaling_factors = false, + )) + ``` -# TODO HERE +### Follow the Guidelines on Cleaning Up General Formatting -### Look at the compiled .html! !!! tip "Do" - - [Compile](@ref "Compile and View Documentation Locally") the tutorial regularly and - look at it - - Check method signatures and argument lists are formatted correctly + Follow How-to [Clean Up General Formatting](@ref), especially by adding + hyperlinks to other Sienna structs that appear within an arguments list. From 42f16b46488f9978e9dbddea0df834177d943502 Mon Sep 17 00:00:00 2001 From: kdayday Date: Fri, 13 Dec 2024 14:42:30 -0700 Subject: [PATCH 23/40] Add id --- docs/src/docs_best_practices/how-to/general_formatting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/docs_best_practices/how-to/general_formatting.md b/docs/src/docs_best_practices/how-to/general_formatting.md index 899c24251..bd8f93059 100644 --- a/docs/src/docs_best_practices/how-to/general_formatting.md +++ b/docs/src/docs_best_practices/how-to/general_formatting.md @@ -18,7 +18,7 @@ back-ticks: ``` compiles as max_active_power -## Put hyperlinks everywhere +## [Put hyperlinks everywhere](@id hyperlinks) All types, function, and methods should have hyperlinks to the correct docstring, accounting for multiple methods of the same name due to Julia's multiple dispatch. [`Documenter.jl`](https://documenter.juliadocs.org/stable/) will link to the first From c2905cb66ff556a4d933d6b4a47edbf32258cde3 Mon Sep 17 00:00:00 2001 From: kdayday Date: Fri, 13 Dec 2024 16:30:06 -0700 Subject: [PATCH 24/40] Finish how-to trouble-shoot --- docs/make.jl | 1 + .../how-to/troubleshoot.md | 41 +++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/docs/make.jl b/docs/make.jl index 928c003b8..11975dc2f 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -6,6 +6,7 @@ using DocumenterInterLinks links = InterLinks( "Documenter" => "https://documenter.juliadocs.org/stable/", "Julia" => "https://docs.julialang.org/en/v1/", + "JuliaFormatter" => "https://domluna.github.io/JuliaFormatter.jl/stable/", ) if haskey(ENV, "GITHUB_ACTIONS") diff --git a/docs/src/docs_best_practices/how-to/troubleshoot.md b/docs/src/docs_best_practices/how-to/troubleshoot.md index fbc80ae48..ac12d27f1 100644 --- a/docs/src/docs_best_practices/how-to/troubleshoot.md +++ b/docs/src/docs_best_practices/how-to/troubleshoot.md @@ -2,10 +2,22 @@ ## [`Error: ## docstrings not included in the manual`](@id miss_doc) -TODO - +**Problem**: Docstrings have been written, but have not been properly mapped to either a +public or internal API. There may be multiple issues: + +1. Verify there is an Internal API file to catch doctrings for structs/functions that are + not exported. + [Example here](https://github.com/NREL-Sienna/SiennaTemplate.jl/blob/main/docs/src/reference/internal.md) +1. Identify the `*.jl` file for one of your missing docstrings. Are other docstrings in that file + visible in the API? + - If yes, check whether those other docstrings are listed in the API in a `@docs` block and + [switch to `@autodocs`](@ref use_autodocs) with the `*.jl` file as one of its `Pages` + instead. + - If no, add a new [`@autodocs` block](@extref) in the Public API with that `*.jl` file + as one of its `Pages`. + - Iterate through the missing docstrings to find other missing `*.jl` files. 1. Are these docstrings from `InfrastructureSystems.jl`? Follow how-to - [selectively export docstrings from `InfrastructureSystems.jl`](@ref docs_from_is) + [selectively export docstrings from `InfrastructureSystems.jl`](@ref docs_from_is). ## `Error: duplicate docs found` @@ -24,4 +36,25 @@ based on the end of a file path. ## `Parsing error for input` from `JuliaFormatter` -TODO \ No newline at end of file +**Problem**: `JuliaFormatter` 1.0 typically errors on a single bracket in +the markdown, with an uninformative error message. Example: +```julia +] add PowerSystems +``` + +Workarounds: +- Avoid the single bracket with alternatives: +```julia +using Pkg; Pkg.add(["PowerSystems"]) +``` +- If you can't avoid it: + 1. Remove the text with single bracket temporarily + 2. Run the formatter once to format the rest of the file + 3. Add the text back in + 4. Add the `ignore` keyword argument with the file name to + [`JuliaFormatter.format`](@extref `JuliaFormatter.format-Tuple{Any}`) in `scripts/formatter/formatter_code.jl` + to skip the file in the future: +```julia +ignore = ["problem-file.md"], +``` +You might need to iterate through multiple files. \ No newline at end of file From e0c0da481802699adaa392157e0665641a064b70 Mon Sep 17 00:00:00 2001 From: kdayday Date: Fri, 13 Dec 2024 20:46:20 -0700 Subject: [PATCH 25/40] Add how-to write how-to --- docs/make.jl | 5 +- .../how-to/write_a_how-to.md | 72 +++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 docs/src/docs_best_practices/how-to/write_a_how-to.md diff --git a/docs/make.jl b/docs/make.jl index 11975dc2f..b9365a0eb 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -29,10 +29,11 @@ pages = OrderedDict( "How to..." => Any[ "Clean Up General Formatting" => "docs_best_practices/how-to/general_formatting.md", "Write a Tutorial" => "docs_best_practices/how-to/write_a_tutorial.md", + "Write a How-To Guide" => "docs_best_practices/how-to/write_a_how-to.md", "Organize APIs and Write Docstrings" => "docs_best_practices/how-to/write_docstrings_org_api.md", + "Troubleshoot Common Errors" => "docs_best_practices/how-to/troubleshoot.md", "Compile and View Documentation Locally" => "docs_best_practices/how-to/compile.md", - "View Draft Documentation on Github" => "docs_best_practices/how-to/view_github.md", - "Troubleshoot Common Errors" => "docs_best_practices/how-to/troubleshoot.md",], + "View Draft Documentation on Github" => "docs_best_practices/how-to/view_github.md",], "Reference" => Any["docs_best_practices/reference/requirements_checklist.md", "docs_best_practices/reference/useful_links.md",], ], diff --git a/docs/src/docs_best_practices/how-to/write_a_how-to.md b/docs/src/docs_best_practices/how-to/write_a_how-to.md new file mode 100644 index 000000000..1bab02988 --- /dev/null +++ b/docs/src/docs_best_practices/how-to/write_a_how-to.md @@ -0,0 +1,72 @@ +# Write a How-to Guide + +A How-To guides a user trying to accomplish a certain task in their work, or address a +problem or series of linked problems. + +## Prepare + +- If you have not read [Diataxis](https://diataxis.fr/), first read it in its entirety. +- If you have read it, skim the pages on [How-to guides](https://diataxis.fr/how-to-guides/) and + the [difference between a tutorial and how-to guide](https://diataxis.fr/tutorials-how-to/) + to refresh your memory and refer back throughout the process. +- Look at an example: this page, how to [Compile and View Documentation Locally](@ref), and + how to [Troubleshoot Common Errors](@ref) are all examples. + +## Follow the Do's and Don't's + +The [Diataxis How-to's](https://diataxis.fr/how-to-guides/) page should be your main reference +as you write, but in addition, use these guidelines to +ensure we follow Diataxis and avoid common pitfalls from previous versions of Sienna +documentation: + +```@contents +Pages = ["write_a_how-to.md"] +Depth = 3:3 +``` + +### Omit the Unnecessary +!!! tip "Do" + Jump the user right to a logical starting point in the code using `#hide` or + [`@setup`](https://documenter.juliadocs.org/stable/man/syntax/#reference-at-setup) + blocks. +!!! tip "Do" + [Configure the logger](@ref log) or load/build a `System` that returns very + few log statements. Use semi-colons at line ends to hide return statements if need be. + +### Make it effortless to read +!!! tip "Do" + Split code examples into ideally 1 (to 3) lines ONLY, with a short preface + to explain what each line is doing, even if it's obvious to you. + +### Move Docstring Material to the APIs +An issue with earlier versions of Sienna documentation was basic reference information +located in pages other than the APIs. +See how-to [Organize APIs and Write Docstrings](@ref) if needed to make that information +easier to find. +!!! tip "Do" + Preface each call to a new function with a hyperlink to that function's + docstring so the user can find more detail +!!! warning "Don't" + Include digressive details about different keyword arguments or versions of + a function. + +### Minimize or Eliminate How-To Guides with a Single Step +A how-to guide has a *sequence* of steps -- if your guide only has a single step, ask +yourself if you are compensating for a lack of information in the API's. +!!! tip "Do" + Move how-to guides with a single function to being Examples in that + function's docstring. See [Writing Documentation](@extref). + +### Remove Other Reference Material +Particularly when editing existing pages, watch out for other +[Reference](https://diataxis.fr/reference/) material. +!!! tip "Do" + Move tables and lists of information into Reference pages and link to them instead + +### Look at the compiled .html! +!!! tip "Do" + - [Compile](@ref "Compile and View Documentation Locally") the how-to guide regularly and + look at it + - Check all code examples gave the expected results without erroring + - Check for length of the code examples and iteratively adjust to make it easy + to read From 654cbce06d900511d20a870d6a171890eb2c1678 Mon Sep 17 00:00:00 2001 From: kdayday Date: Fri, 13 Dec 2024 20:46:43 -0700 Subject: [PATCH 26/40] Add tutorial warning --- .../how-to/write_a_tutorial.md | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/docs/src/docs_best_practices/how-to/write_a_tutorial.md b/docs/src/docs_best_practices/how-to/write_a_tutorial.md index cdaa56932..45bb4f927 100644 --- a/docs/src/docs_best_practices/how-to/write_a_tutorial.md +++ b/docs/src/docs_best_practices/how-to/write_a_tutorial.md @@ -1,7 +1,7 @@ # Write a Tutorial Tutorials are learning experiences to give our users confidence and experience in using -Sienna. +Sienna. ## Prepare @@ -12,6 +12,14 @@ Sienna. - Look at an example: `PowerSystems.jl`'s [Working with Time Series](https://nrel-sienna.github.io/PowerSystems.jl/stable/tutorials/working_with_time_series/) +!!! warning + Historically, many of Sienna's "tutorials" have blended all 4 types of documentation in + the [Diataxis](https://diataxis.fr/) framework. Be prepared to move material to related + Explanation and How-to pages and into function docstrings in the APIs as you work. + + If you starting a new tutorial, ask yourself if a tutorial is appropriate for what + you're trying to show, or if you should be writing a how-to instead. + See also how to [Write a How-to Guide](@ref). ## Follow the Do's and Don't's @@ -84,16 +92,16 @@ the exact results seen on the documentation page. information that isn't directly relevant to what you're trying to teach. ### Remove other types of documentation -Particularly when editting existing material, watch out for material that should be -moved elsewhere according to Diataxis principles, especially details and examples -that should live in the docstrings. +Particularly when editing existing material, watch out for material that should be +moved elsewhere according to Diataxis principles: !!! tip "Do" Preface each call to a new function with a hyperlink to that function's docstring so the user can find more detail !!! warning "Don't" - Include details about different keyword argument functions or versions of - a function in the tutorial itself. Some repetition is OK, but details and examples - live in the docstrings. + Include definitions and details about different keyword arguments or versions of + a function in the tutorial itself. Some basic information is OK, but details and + examples live in the docstrings, and they especially shouldn't be included in the + tutorial **in lieu of** being in the docstrings. ### Look at the compiled .html! !!! tip "Do" From 804305f4efd76e86fa9815160a523c0e057d26db Mon Sep 17 00:00:00 2001 From: kdayday Date: Mon, 16 Dec 2024 12:29:47 -0700 Subject: [PATCH 27/40] Wording fixes --- .../how-to/troubleshoot.md | 22 +++++++++---------- .../how-to/write_docstrings_org_api.md | 22 +++++++++---------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/docs/src/docs_best_practices/how-to/troubleshoot.md b/docs/src/docs_best_practices/how-to/troubleshoot.md index ac12d27f1..6aec9623a 100644 --- a/docs/src/docs_best_practices/how-to/troubleshoot.md +++ b/docs/src/docs_best_practices/how-to/troubleshoot.md @@ -5,15 +5,15 @@ **Problem**: Docstrings have been written, but have not been properly mapped to either a public or internal API. There may be multiple issues: -1. Verify there is an Internal API file to catch doctrings for structs/functions that are +1. Verify there is an Internal API .md file to catch doctrings for structs/functions that are not exported. [Example here](https://github.com/NREL-Sienna/SiennaTemplate.jl/blob/main/docs/src/reference/internal.md) 1. Identify the `*.jl` file for one of your missing docstrings. Are other docstrings in that file - visible in the API? - - If yes, check whether those other docstrings are listed in the API in a `@docs` block and - [switch to `@autodocs`](@ref use_autodocs) with the `*.jl` file as one of its `Pages` - instead. - - If no, add a new [`@autodocs` block](@extref) in the Public API with that `*.jl` file + visible in the compiled API .html? + - If yes, check whether those other docstrings are listed in the Public API .md file in a + `@docs` block and [switch to `@autodocs`](@ref use_autodocs) with the `*.jl` file as + one of its `Pages` instead. + - If no, add a new [`@autodocs` block](@extref) in the Public API .md file with that `*.jl` file as one of its `Pages`. - Iterate through the missing docstrings to find other missing `*.jl` files. 1. Are these docstrings from `InfrastructureSystems.jl`? Follow how-to @@ -28,16 +28,16 @@ based on the end of a file path. 1. Determine which file the function is located in > **Example**: `simulation_problem_results.jl` for `PowerSimulations.SimulationProblemResults` -2. Check whether that file is listed more than once in an `@autodocs` `Pages` list in the API - markdown file (e.g., `PowerSimulations.md` or `public.md`). Remove duplicates. -3. Also check for other files with the same partial ending in the `@autodocs` `Pages` lists. - Specify more of that file path to distinguish it. +2. Check whether that file is listed more than once in an `@autodocs` `Pages` list in the + API markdown file (e.g., `PowerSimulations.md` or `public.md`). Remove duplicates. +3. Also check for other files with the same partial ending in the `@autodocs` `Pages` lists + in the API .md file. Specify more of that file path to distinguish it. > **Example**: Change `Pages = ["problem_results.jl"]` to `Pages = ["operation/problem_results.jl"]` ## `Parsing error for input` from `JuliaFormatter` **Problem**: `JuliaFormatter` 1.0 typically errors on a single bracket in -the markdown, with an uninformative error message. Example: +a markdown file, with an uninformative error message. Example: ```julia ] add PowerSystems ``` diff --git a/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md b/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md index ac5da4eba..c5e4ee70b 100644 --- a/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md +++ b/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md @@ -36,8 +36,8 @@ Depth = 3:3 ### Ensure All Docstrings Are Located in the APIs !!! tip "Do" - Include a Public API for exported structs, functions, and methods, and an Internals API - for private functions. See + Include a Public API markdown file for exported structs, functions, and methods, and an + Internals API for private functions. See [`PowerSystems.jl`](https://nrel-sienna.github.io/PowerSystems.jl/stable/) for an example with a Public API organized with `@autodocs` ([see next](@ref use_autodocs)) or [`SiennaTemplate.jl`](https://github.com/NREL-Sienna/SiennaTemplate.jl) for a basic @@ -53,8 +53,8 @@ Depth = 3:3 ### [Automate Adding Docstrings in the Public API with `@autodocs`](@id use_autodocs) !!! tip "Do" - Use [`@autodocs` block](@extref)s in the Public API to automatically find all - docstrings in a file. Example: + Use [`@autodocs` block](@extref)s in the Public API markdown file to automatically find + all docstrings in a file. Example: ````markdown ## Variables ```@autodocs @@ -86,7 +86,7 @@ exports code from `InfrastructureSystems.jl`: !!! tip "Do" List the files containing necessary `InfrastructureSystems.jl` structs and methods in - `SomeSiennaPackage.jl`'s Public API, then explicitly filter by what + `SomeSiennaPackage.jl`'s Public API markdown file, then explicitly filter by what `SomeSiennaPackage.jl` exports. Example: ````markdown @@ -101,8 +101,8 @@ exports code from `InfrastructureSystems.jl`: ```` !!! warning "Don't" - List `InfrastructureSystems` as one of the `modules` in [`Documenter.makedocs`](@extref). - `Documenter.jl` will + List `InfrastructureSystems` as one of the `modules` in [`Documenter.makedocs`](@extref) + in the `make.jl` file. `Documenter.jl` will look to map **all** `InfrastructureSystems.jl` docstrings into the API, resulting in hundreds of [missing docstring](@ref miss_doc) errors. Example: @@ -157,7 +157,7 @@ This is not commonly done in Sienna yet, but a goal is to improve our use of !!! warning "Don't" Copy and paste arguments lists into the docstring, which opens opportunity for - out-of-date errors when arguments are added or regorded. Example: + out-of-date errors when arguments are added or reordered. Example: ````markdown """ SomeSiennaStruct(arg1, arg2) @@ -177,9 +177,9 @@ This is not commonly done in Sienna yet, but a goal is to improve our use of ### Add `See also` Links to Functions with the Same Name !!! tip "Do" - To help users navigate Julia's multiple dispatch, add `See also` to other versions of - the function with the same name, using the guidance on - [adding a specific hyperlink](@ref hyperlinks). + To help users navigate Julia's multiple dispatch, add `See also` paragraphs at the + bottom of function docstrings other versions of the function with the same name, using + the guidance on [adding a specific hyperlink](@ref hyperlinks). Example: ``` See also From 9a6d42ef953d86b87982539453ad79c752d43d8b Mon Sep 17 00:00:00 2001 From: kdayday Date: Mon, 16 Dec 2024 15:01:52 -0700 Subject: [PATCH 28/40] Update links --- docs/src/docs_best_practices/reference/useful_links.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/src/docs_best_practices/reference/useful_links.md b/docs/src/docs_best_practices/reference/useful_links.md index d772fd86d..db8b74f23 100644 --- a/docs/src/docs_best_practices/reference/useful_links.md +++ b/docs/src/docs_best_practices/reference/useful_links.md @@ -2,9 +2,10 @@ - [Diataxis](https://diataxis.fr/): Reference for the new documentation framework Sienna is striving to follow (not specific to Julia) +- Julia's guidance on [Writing Documentation](@extref) - [`Documenter.jl`](https://documenter.juliadocs.org/stable/): Julia's documentation package, the [Syntax](https://documenter.juliadocs.org/stable/man/syntax/) and [Showcase](https://documenter.juliadocs.org/stable/showcase/) pages are especially useful -- [`Sienna-Template` Git repository](https://github.com/NREL-Sienna/Sienna-Template): A +- [`SiennaTemplate.jl` Git repository](https://github.com/NREL-Sienna/SiennaTemplate.jl): A template for new Sienna packages that includes the required documentation framework. From b4a54fd698dfe030499cb2ecbb31014958fcf248 Mon Sep 17 00:00:00 2001 From: kdayday Date: Mon, 16 Dec 2024 15:02:09 -0700 Subject: [PATCH 29/40] Update troubleshooting --- .../how-to/troubleshoot.md | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/docs/src/docs_best_practices/how-to/troubleshoot.md b/docs/src/docs_best_practices/how-to/troubleshoot.md index 6aec9623a..37a196b4b 100644 --- a/docs/src/docs_best_practices/how-to/troubleshoot.md +++ b/docs/src/docs_best_practices/how-to/troubleshoot.md @@ -3,22 +3,30 @@ ## [`Error: ## docstrings not included in the manual`](@id miss_doc) **Problem**: Docstrings have been written, but have not been properly mapped to either a -public or internal API. There may be multiple issues: +public or internal API. There may be multiple issues to iterate through: 1. Verify there is an Internal API .md file to catch doctrings for structs/functions that are not exported. [Example here](https://github.com/NREL-Sienna/SiennaTemplate.jl/blob/main/docs/src/reference/internal.md) 1. Identify the `*.jl` file for one of your missing docstrings. Are other docstrings in that file visible in the compiled API .html? - - If yes, check whether those other docstrings are listed in the Public API .md file in a - `@docs` block and [switch to `@autodocs`](@ref use_autodocs) with the `*.jl` file as - one of its `Pages` instead. - - If no, add a new [`@autodocs` block](@extref) in the Public API .md file with that `*.jl` file - as one of its `Pages`. - - Iterate through the missing docstrings to find other missing `*.jl` files. + - **YES**: Check whether those other docstrings are listed in the Public API .md file in a + [`@docs` block](@extref). Either: + - Add the missing struct/function names to an appropriate `@docs` block in the + API .md if it is manually organized. See below if this creates a + [`no docs found`](@ref no_docs) error. + - Preferrably, [switch to `@autodocs`](@ref use_autodocs) with the `*.jl` file + as one of its `Pages` instead. + - **No**: add a new [`@autodocs` block](@extref) in the Public API .md file with that + `*.jl` file as one of its `Pages`. 1. Are these docstrings from `InfrastructureSystems.jl`? Follow how-to [selectively export docstrings from `InfrastructureSystems.jl`](@ref docs_from_is). +## [`Error: no docs found for SomeFunction` or `[:docs_block]` error](@id no_docs) + +No docstring has been written for `SomeFunction`. +Find the `*.jl` file containing `SomeFunction` and add a docstring. + ## `Error: duplicate docs found` > **Example**: `Error: duplicate docs found for 'PowerSimulations.SimulationProblemResults' in src\reference\PowerSimulations.md` From 33e2371c000d7595af5d3ffc5d73eac859dd6320 Mon Sep 17 00:00:00 2001 From: kdayday Date: Mon, 16 Dec 2024 15:02:59 -0700 Subject: [PATCH 30/40] Add basic formatting do --- docs/src/docs_best_practices/how-to/write_a_how-to.md | 5 +++++ docs/src/docs_best_practices/how-to/write_a_tutorial.md | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/docs/src/docs_best_practices/how-to/write_a_how-to.md b/docs/src/docs_best_practices/how-to/write_a_how-to.md index 1bab02988..2544775e9 100644 --- a/docs/src/docs_best_practices/how-to/write_a_how-to.md +++ b/docs/src/docs_best_practices/how-to/write_a_how-to.md @@ -63,6 +63,11 @@ Particularly when editing existing pages, watch out for other !!! tip "Do" Move tables and lists of information into Reference pages and link to them instead +### Follow the Guidelines on Cleaning Up General Formatting + +!!! tip "Do" + Follow How-to [Clean Up General Formatting](@ref). + ### Look at the compiled .html! !!! tip "Do" - [Compile](@ref "Compile and View Documentation Locally") the how-to guide regularly and diff --git a/docs/src/docs_best_practices/how-to/write_a_tutorial.md b/docs/src/docs_best_practices/how-to/write_a_tutorial.md index 45bb4f927..3f5ee62bc 100644 --- a/docs/src/docs_best_practices/how-to/write_a_tutorial.md +++ b/docs/src/docs_best_practices/how-to/write_a_tutorial.md @@ -103,6 +103,11 @@ moved elsewhere according to Diataxis principles: examples live in the docstrings, and they especially shouldn't be included in the tutorial **in lieu of** being in the docstrings. +### Follow the Guidelines on Cleaning Up General Formatting + +!!! tip "Do" + Follow How-to [Clean Up General Formatting](@ref). + ### Look at the compiled .html! !!! tip "Do" - [Compile](@ref "Compile and View Documentation Locally") the tutorial regularly and From 5ec4584ac74083c88b2be89fffd744357713df17 Mon Sep 17 00:00:00 2001 From: kdayday Date: Mon, 16 Dec 2024 15:03:22 -0700 Subject: [PATCH 31/40] Finish requirements as how-to --- docs/make.jl | 4 +- .../how-to/requirements_checklist.md | 35 ++++++++++++++++ .../reference/requirements_checklist.md | 40 ------------------- 3 files changed, 37 insertions(+), 42 deletions(-) create mode 100644 docs/src/docs_best_practices/how-to/requirements_checklist.md delete mode 100644 docs/src/docs_best_practices/reference/requirements_checklist.md diff --git a/docs/make.jl b/docs/make.jl index b9365a0eb..25aa2f8bf 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -27,6 +27,7 @@ pages = OrderedDict( "Documentation Best Practices" => Any[ "Explanation" => "docs_best_practices/explanation.md", "How to..." => Any[ + "Complete Basic Requirements Checklist" => "docs_best_practices/how-to/requirements_checklist.md", "Clean Up General Formatting" => "docs_best_practices/how-to/general_formatting.md", "Write a Tutorial" => "docs_best_practices/how-to/write_a_tutorial.md", "Write a How-To Guide" => "docs_best_practices/how-to/write_a_how-to.md", @@ -34,8 +35,7 @@ pages = OrderedDict( "Troubleshoot Common Errors" => "docs_best_practices/how-to/troubleshoot.md", "Compile and View Documentation Locally" => "docs_best_practices/how-to/compile.md", "View Draft Documentation on Github" => "docs_best_practices/how-to/view_github.md",], - "Reference" => Any["docs_best_practices/reference/requirements_checklist.md", - "docs_best_practices/reference/useful_links.md",], + "Reference" => Any["docs_best_practices/reference/useful_links.md",], ], "API" => "InfrastructureSystems.md" ) diff --git a/docs/src/docs_best_practices/how-to/requirements_checklist.md b/docs/src/docs_best_practices/how-to/requirements_checklist.md new file mode 100644 index 000000000..9ca99e75d --- /dev/null +++ b/docs/src/docs_best_practices/how-to/requirements_checklist.md @@ -0,0 +1,35 @@ +# Complete Basic Requirements Checklist + +Sienna packages should follow the [Diataxis](https://diataxis.fr/) +framework, be strictly compiled with [`Documenter.jl`](https://documenter.juliadocs.org/stable/) +v1.0 or greater, and be automatically formatted with +[`JuliaFormatter.jl`](https://domluna.github.io/JuliaFormatter.jl/stable/). + +## For New Packages + +The [`SiennaTemplate.jl`](https://github.com/NREL-Sienna/SiennaTemplate.jl) Git repo has the +required environments and formatting and documentation code. Start from this template. + +## For Existing Packages + +Existing Sienna packages will need to be updated with these requirements, but these will +only need to be addressed once: + +1. Organize the top-level documentation to follow the [Diataxis](https://diataxis.fr/) + framework (plus a welcome page/section). This might be a significant undertaking. See: + - How to [Write a How-to Guide](@ref) + - How to [Write a Tutorial](@ref) + - How to [Organize APIs and Write Docstrings](@ref) +1. Replace `compat` requirements of `Documenter = "0.27"` in `docs/` environment with + `Documenter = "1.0"` +1. Update the `docs/make.jl` file to call + [`Documenter.makedocs`](https://documenter.juliadocs.org/stable/lib/public/#Documenter.makedocs) + *without* the `warnonly` `kwarg` (i.e., all errors caught by `makedocs` must be resolved before + merging). [See an example here](https://github.com/NREL-Sienna/InfrastructureSystems.jl/blob/768438a40c46767560891ec493cf87ed232a2b2b/docs/make.jl#L47). + - See How-to [Troubleshoot Common Errors](@ref) if this results in a host of errors. +1. Update the `scripts/formatter/formatter_code.jl` to format the markdown .md files in the + `docs/` folder, calling `format`() with the `kwarg` `format_markdown = true`. See + [these](https://github.com/NREL-Sienna/InfrastructureSystems.jl/blob/768438a40c46767560891ec493cf87ed232a2b2b/scripts/formatter/formatter_code.jl#L13) + [three](https://github.com/NREL-Sienna/InfrastructureSystems.jl/blob/768438a40c46767560891ec493cf87ed232a2b2b/scripts/formatter/formatter_code.jl#L8) + [links](https://github.com/NREL-Sienna/InfrastructureSystems.jl/blob/768438a40c46767560891ec493cf87ed232a2b2b/scripts/formatter/formatter_code.jl#L23) + for examples of the updated lines. diff --git a/docs/src/docs_best_practices/reference/requirements_checklist.md b/docs/src/docs_best_practices/reference/requirements_checklist.md deleted file mode 100644 index f03ae7ea6..000000000 --- a/docs/src/docs_best_practices/reference/requirements_checklist.md +++ /dev/null @@ -1,40 +0,0 @@ -# Requirements Checklist - -## Code and Environment Requirements - -The [`Sienna-Template`](https://github.com/NREL-Sienna/Sienna-Template) Git repo has the -required environments and formatting and documentation code. New Sienna packages should -start from this template. - -Existing Sienna packages will need to be updated with these requirements, but these will -only need to be addressed once: - -1. `docs/` environment must use [`Documenter.jl`](https://documenter.juliadocs.org/stable/) - v1.0 or greater - - That is, previous `compat` requirements of `Documenter = "0.27"` must be removed. -1. `docs/make.jl` file must call - [`Documenter.makedocs`](https://documenter.juliadocs.org/stable/lib/public/#Documenter.makedocs) - *without* the `warnonly` `kwarg` (i.e., all errors caught by `makedocs` must be resolved before - merging). [See an example here](https://github.com/NREL-Sienna/InfrastructureSystems.jl/blob/768438a40c46767560891ec493cf87ed232a2b2b/docs/make.jl#L47). -1. The `scripts/formatter/formatter_code.jl` must be updated to format the markdown .md files in the - `docs/` folder, calling `format`() with the `kwarg` `format_markdown = true`. See - [these](https://github.com/NREL-Sienna/InfrastructureSystems.jl/blob/768438a40c46767560891ec493cf87ed232a2b2b/scripts/formatter/formatter_code.jl#L13) - [three](https://github.com/NREL-Sienna/InfrastructureSystems.jl/blob/768438a40c46767560891ec493cf87ed232a2b2b/scripts/formatter/formatter_code.jl#L8) - [links](https://github.com/NREL-Sienna/InfrastructureSystems.jl/blob/768438a40c46767560891ec493cf87ed232a2b2b/scripts/formatter/formatter_code.jl#L23) - for examples of the updated lines. - -## Diataxis Requirements - -1. Top-level documentation organization follows the [Diataxis](https://diataxis.fr/) - framework (plus a welcome page/section) - - -!!! todo - - -## Pull Request Requirements - -1. [Compile](@ref "Compile and View Documentation Locally") the documentation and look at - it! - -!!! todo \ No newline at end of file From 5a26008f90005ae1926b02b75e6abb3eb59aa8b7 Mon Sep 17 00:00:00 2001 From: kdayday Date: Mon, 16 Dec 2024 15:30:40 -0700 Subject: [PATCH 32/40] Format troubleshoot --- .../how-to/troubleshoot.md | 70 +++++++++++++------ scripts/formatter/formatter_code.jl | 2 +- 2 files changed, 48 insertions(+), 24 deletions(-) diff --git a/docs/src/docs_best_practices/how-to/troubleshoot.md b/docs/src/docs_best_practices/how-to/troubleshoot.md index 37a196b4b..f9da9cd57 100644 --- a/docs/src/docs_best_practices/how-to/troubleshoot.md +++ b/docs/src/docs_best_practices/how-to/troubleshoot.md @@ -5,24 +5,28 @@ **Problem**: Docstrings have been written, but have not been properly mapped to either a public or internal API. There may be multiple issues to iterate through: -1. Verify there is an Internal API .md file to catch doctrings for structs/functions that are + 1. Verify there is an Internal API .md file to catch doctrings for structs/functions that are not exported. [Example here](https://github.com/NREL-Sienna/SiennaTemplate.jl/blob/main/docs/src/reference/internal.md) -1. Identify the `*.jl` file for one of your missing docstrings. Are other docstrings in that file + + 2. Identify the `*.jl` file for one of your missing docstrings. Are other docstrings in that file visible in the compiled API .html? - - **YES**: Check whether those other docstrings are listed in the Public API .md file in a + + + **YES**: Check whether those other docstrings are listed in the Public API .md file in a [`@docs` block](@extref). Either: - - Add the missing struct/function names to an appropriate `@docs` block in the + + * Add the missing struct/function names to an appropriate `@docs` block in the API .md if it is manually organized. See below if this creates a [`no docs found`](@ref no_docs) error. - - Preferrably, [switch to `@autodocs`](@ref use_autodocs) with the `*.jl` file + * Preferrably, [switch to `@autodocs`](@ref use_autodocs) with the `*.jl` file as one of its `Pages` instead. - - **No**: add a new [`@autodocs` block](@extref) in the Public API .md file with that + + + **No**: add a new [`@autodocs` block](@extref) in the Public API .md file with that `*.jl` file as one of its `Pages`. -1. Are these docstrings from `InfrastructureSystems.jl`? Follow how-to + 3. Are these docstrings from `InfrastructureSystems.jl`? Follow how-to [selectively export docstrings from `InfrastructureSystems.jl`](@ref docs_from_is). -## [`Error: no docs found for SomeFunction` or `[:docs_block]` error](@id no_docs) +## [`Error: no docs found for SomeFunction` or `[:docs_block]` error](@id no_docs) No docstring has been written for `SomeFunction`. Find the `*.jl` file containing `SomeFunction` and add a docstring. @@ -34,35 +38,55 @@ Find the `*.jl` file containing `SomeFunction` and add a docstring. **Problem**: The same `.jl` file has been found more than once by `Documenter.jl`, which matches based on the end of a file path. -1. Determine which file the function is located in + 1. Determine which file the function is located in + > **Example**: `simulation_problem_results.jl` for `PowerSimulations.SimulationProblemResults` -2. Check whether that file is listed more than once in an `@autodocs` `Pages` list in the + + 2. Check whether that file is listed more than once in an `@autodocs` `Pages` list in the API markdown file (e.g., `PowerSimulations.md` or `public.md`). Remove duplicates. -3. Also check for other files with the same partial ending in the `@autodocs` `Pages` lists + 3. Also check for other files with the same partial ending in the `@autodocs` `Pages` lists in the API .md file. Specify more of that file path to distinguish it. - > **Example**: Change `Pages = ["problem_results.jl"]` to `Pages = ["operation/problem_results.jl"]` + + > **Example**: Change `Pages = ["problem_results.jl"]` to `Pages = ["operation/problem_results.jl"]` ## `Parsing error for input` from `JuliaFormatter` -**Problem**: `JuliaFormatter` 1.0 typically errors on a single bracket in -a markdown file, with an uninformative error message. Example: +**Problem**: `JuliaFormatter` 1.0 gives an uninformative error message when it can't parse +something, with unhelpful line numbers. Common causes are something that is not proper Julia +syntax inside a `julia` markdown block: + +````markdown +```julia +Whoops, +``` +```` + +Or a single bracket in a markdown file: + ```julia ] add PowerSystems ``` Workarounds: -- Avoid the single bracket with alternatives: + + - Avoid the single bracket with alternatives: + ```julia -using Pkg; Pkg.add(["PowerSystems"]) +using Pkg; +Pkg.add(["PowerSystems"]); ``` -- If you can't avoid it: - 1. Remove the text with single bracket temporarily - 2. Run the formatter once to format the rest of the file - 3. Add the text back in - 4. Add the `ignore` keyword argument with the file name to + + - If you can't avoid it: + + 1. Remove the text with single bracket (or other problem) temporarily + 2. Run the formatter once to format the rest of the file + 3. Add the text back in + 4. Add the `ignore` keyword argument with the file name to [`JuliaFormatter.format`](@extref `JuliaFormatter.format-Tuple{Any}`) in `scripts/formatter/formatter_code.jl` to skip the file in the future: + ```julia -ignore = ["problem-file.md"], +ignore = ["problem-file.md"] ``` -You might need to iterate through multiple files. \ No newline at end of file + +You might need to iterate through multiple files. diff --git a/scripts/formatter/formatter_code.jl b/scripts/formatter/formatter_code.jl index c501c6802..9ae5b8c36 100644 --- a/scripts/formatter/formatter_code.jl +++ b/scripts/formatter/formatter_code.jl @@ -22,7 +22,7 @@ for main_path in main_paths separate_kwargs_with_semicolon = true, format_markdown = true, # Brackets in code blocks cause formatter to fail, ignore for now - ignore = ["style.md", "index.md", "tests.md"], + ignore = ["style.md", "index.md", "tests.md", "troubleshoot.md"], # always_use_return = true. # Disabled since it throws a lot of false positives ) From ceaf77d2634e18e9dd314b3cb1ea9bb95fa697e9 Mon Sep 17 00:00:00 2001 From: kdayday Date: Mon, 16 Dec 2024 15:31:16 -0700 Subject: [PATCH 33/40] Run formatter --- .../src/docs_best_practices/how-to/compile.md | 17 +++-- .../how-to/general_formatting.md | 42 +++++++--- .../how-to/requirements_checklist.md | 23 +++--- .../docs_best_practices/how-to/view_github.md | 10 ++- .../how-to/write_a_how-to.md | 51 +++++++++---- .../how-to/write_a_tutorial.md | 76 +++++++++++++------ .../how-to/write_docstrings_org_api.md | 72 ++++++++++++------ .../reference/useful_links.md | 8 +- 8 files changed, 202 insertions(+), 97 deletions(-) diff --git a/docs/src/docs_best_practices/how-to/compile.md b/docs/src/docs_best_practices/how-to/compile.md index 1b7bd3bb2..bafa85a31 100644 --- a/docs/src/docs_best_practices/how-to/compile.md +++ b/docs/src/docs_best_practices/how-to/compile.md @@ -1,29 +1,32 @@ # Compile and View Documentation Locally ## Step 0a: Update Docs Environment (First Time) + The first time you compile documentation for a package, make sure the `docs/` environment (i.e., `docs/Manifest.toml`, not the main `Manifest.toml` in the root of the repository) is pointing to your local version of the package, so it compiles your local changes: -```julia +``` julia --project=docs using Pkg Pkg.develop(path = "..") ``` ## Step 0b: Auto-Generate Structs (If Needed) + Most documentation changes are made directly to markdown (.md) files, but if you changed one of Sienna's .json descriptor files, you must first [follow the instructions here](@ref "Auto-Generation of Component Structs") to auto-generate the structs from the .json to have your changes propagated into the markdown files used for -documentation. +documentation. **Example**: You updated `PowerSystems.jl`' [`power_system_structs.json`](https://github.com/NREL-Sienna/PowerSystems.jl/blob/main/src/descriptors/power_system_structs.json) file. From a terminal at the root of the repository (i.e., `PowerSystems.jl`), run: -```julia + +``` julia --project=. using InfrastructureSystems InfrastructureSystems.generate_structs( @@ -33,8 +36,10 @@ InfrastructureSystems.generate_structs( ``` ## Step 0c: Run the Formatter (Before Submitting a Pull Request) + To automatically format the documentation to conform with the [style guide](@ref style_guide), run in a terminal at the root of the repository: + ``` julia scripts/formatter/formatter_code.jl ``` @@ -43,11 +48,12 @@ Resolve any errors and re-run until error-free. See how to [Troubleshoot Common for help. This is not a necessary step to compile, but needs to be done at least once to pass pull -request checks. +request checks. ## Step 1: Compile To compile, run in a terminal at the root of the repository: + ``` julia --project=docs docs/make.jl ``` @@ -56,8 +62,9 @@ Resolve any errors and re-run until error-free. See how to [Troubleshoot Common for help. ## Step 2: View + Click on the newly-created `index.html` file (e.g., `SomeSiennaPackage/docs/build/index.html`) to view your locally compiled documentation in a -browser. +browser. Visually verify formatting and that code blocks compile as expected. diff --git a/docs/src/docs_best_practices/how-to/general_formatting.md b/docs/src/docs_best_practices/how-to/general_formatting.md index bd8f93059..2e137e832 100644 --- a/docs/src/docs_best_practices/how-to/general_formatting.md +++ b/docs/src/docs_best_practices/how-to/general_formatting.md @@ -1,4 +1,4 @@ -# Clean Up General Formatting +# Clean Up General Formatting These recommendations are to make navigating our documentation effortless for users, while addressing common markdown formatting issues in the existing Sienna documentation: @@ -7,28 +7,39 @@ addressing common markdown formatting issues in the existing Sienna documentatio All package names, types, functions, methods, and parameters, etc. should formatted in back-ticks: + !!! tip "Do" + ``` `max_active_power` ``` + compiles as `max_active_power` -!!! warning "Don't" + +!!! warning "Don't" + ``` max_active_power ``` + compiles as max_active_power ## [Put hyperlinks everywhere](@id hyperlinks) + All types, function, and methods should have hyperlinks to the correct docstring, accounting for multiple methods of the same name due to Julia's multiple dispatch. [`Documenter.jl`](https://documenter.juliadocs.org/stable/) will link to the first occurrance in documentation. If that's not the one you're referring to, copy the entire signature with types into the hyperlink reference. + !!! tip "Do" + ``` [`get_time_series_values`](@ref) ``` + Or + ``` [`get_time_series_values` from a `ForecastCache`](@ref get_time_series_values( owner::TimeSeriesOwners, @@ -38,29 +49,36 @@ signature with types into the hyperlink reference. ignore_scaling_factors = false, )) ``` -!!! warning "Don't" - ``` - `get_time_series_values` - ``` - Or - ``` - get_time_series_values - ``` + +!!! warning "Don't" + + +``get_time_series_values`` +Or +`get_time_series_values` ## Add links to other Sienna packages All other Sienna package names should have documentation (not Git repo) hyperlinks: + !!! tip "Do" - ``` [`PowerSystems.jl`](https://nrel-sienna.github.io/PowerSystems.jl/stable/) ``` -!!! warning "Don't" + + ```[`PowerSystems.jl`](https://nrel-sienna.github.io/PowerSystems.jl/stable/)``` + +!!! warning "Don't" + ``` `PowerSystems.jl` ``` + Or + ``` PSY ``` + Or + ``` [`PowerSystems.jl`](https://github.com/NREL-Sienna/PowerSystems.jl) ``` diff --git a/docs/src/docs_best_practices/how-to/requirements_checklist.md b/docs/src/docs_best_practices/how-to/requirements_checklist.md index 9ca99e75d..d39608cb0 100644 --- a/docs/src/docs_best_practices/how-to/requirements_checklist.md +++ b/docs/src/docs_best_practices/how-to/requirements_checklist.md @@ -3,7 +3,7 @@ Sienna packages should follow the [Diataxis](https://diataxis.fr/) framework, be strictly compiled with [`Documenter.jl`](https://documenter.juliadocs.org/stable/) v1.0 or greater, and be automatically formatted with -[`JuliaFormatter.jl`](https://domluna.github.io/JuliaFormatter.jl/stable/). +[`JuliaFormatter.jl`](https://domluna.github.io/JuliaFormatter.jl/stable/). ## For New Packages @@ -15,21 +15,24 @@ required environments and formatting and documentation code. Start from this tem Existing Sienna packages will need to be updated with these requirements, but these will only need to be addressed once: -1. Organize the top-level documentation to follow the [Diataxis](https://diataxis.fr/) + 1. Organize the top-level documentation to follow the [Diataxis](https://diataxis.fr/) framework (plus a welcome page/section). This might be a significant undertaking. See: - - How to [Write a How-to Guide](@ref) - - How to [Write a Tutorial](@ref) - - How to [Organize APIs and Write Docstrings](@ref) -1. Replace `compat` requirements of `Documenter = "0.27"` in `docs/` environment with + + + How to [Write a How-to Guide](@ref) + + How to [Write a Tutorial](@ref) + + How to [Organize APIs and Write Docstrings](@ref) + + 2. Replace `compat` requirements of `Documenter = "0.27"` in `docs/` environment with `Documenter = "1.0"` -1. Update the `docs/make.jl` file to call + 3. Update the `docs/make.jl` file to call [`Documenter.makedocs`](https://documenter.juliadocs.org/stable/lib/public/#Documenter.makedocs) *without* the `warnonly` `kwarg` (i.e., all errors caught by `makedocs` must be resolved before merging). [See an example here](https://github.com/NREL-Sienna/InfrastructureSystems.jl/blob/768438a40c46767560891ec493cf87ed232a2b2b/docs/make.jl#L47). - - See How-to [Troubleshoot Common Errors](@ref) if this results in a host of errors. -1. Update the `scripts/formatter/formatter_code.jl` to format the markdown .md files in the + + + See How-to [Troubleshoot Common Errors](@ref) if this results in a host of errors. + 4. Update the `scripts/formatter/formatter_code.jl` to format the markdown .md files in the `docs/` folder, calling `format`() with the `kwarg` `format_markdown = true`. See [these](https://github.com/NREL-Sienna/InfrastructureSystems.jl/blob/768438a40c46767560891ec493cf87ed232a2b2b/scripts/formatter/formatter_code.jl#L13) [three](https://github.com/NREL-Sienna/InfrastructureSystems.jl/blob/768438a40c46767560891ec493cf87ed232a2b2b/scripts/formatter/formatter_code.jl#L8) [links](https://github.com/NREL-Sienna/InfrastructureSystems.jl/blob/768438a40c46767560891ec493cf87ed232a2b2b/scripts/formatter/formatter_code.jl#L23) - for examples of the updated lines. + for examples of the updated lines. diff --git a/docs/src/docs_best_practices/how-to/view_github.md b/docs/src/docs_best_practices/how-to/view_github.md index d8f53f3a0..78d9ce3aa 100644 --- a/docs/src/docs_best_practices/how-to/view_github.md +++ b/docs/src/docs_best_practices/how-to/view_github.md @@ -1,6 +1,8 @@ # View Draft Documentation on Github -1. Create a pull request on Github. -2. Verify the Documentation/build check was successful (takes a few minutes). -2. Preview it in a browser following this url format: - > https://nrel-sienna.github.io/.jl/previews/PR/ \ No newline at end of file + 1. Create a pull request on Github. + + 2. Verify the Documentation/build check was successful (takes a few minutes). + 3. Preview it in a browser following this url format: + + > https://nrel-sienna.github.io/.jl/previews/PR/ diff --git a/docs/src/docs_best_practices/how-to/write_a_how-to.md b/docs/src/docs_best_practices/how-to/write_a_how-to.md index 2544775e9..78ab5ad71 100644 --- a/docs/src/docs_best_practices/how-to/write_a_how-to.md +++ b/docs/src/docs_best_practices/how-to/write_a_how-to.md @@ -5,11 +5,11 @@ problem or series of linked problems. ## Prepare -- If you have not read [Diataxis](https://diataxis.fr/), first read it in its entirety. -- If you have read it, skim the pages on [How-to guides](https://diataxis.fr/how-to-guides/) and + - If you have not read [Diataxis](https://diataxis.fr/), first read it in its entirety. + - If you have read it, skim the pages on [How-to guides](https://diataxis.fr/how-to-guides/) and the [difference between a tutorial and how-to guide](https://diataxis.fr/tutorials-how-to/) - to refresh your memory and refer back throughout the process. -- Look at an example: this page, how to [Compile and View Documentation Locally](@ref), and + to refresh your memory and refer back throughout the process. + - Look at an example: this page, how to [Compile and View Documentation Locally](@ref), and how to [Troubleshoot Common Errors](@ref) are all examples. ## Follow the Do's and Don't's @@ -25,53 +25,74 @@ Depth = 3:3 ``` ### Omit the Unnecessary -!!! tip "Do" - Jump the user right to a logical starting point in the code using `#hide` or - [`@setup`](https://documenter.juliadocs.org/stable/man/syntax/#reference-at-setup) - blocks. + +!!! tip "Do" + + +Jump the user right to a logical starting point in the code using `#hide` or +[`@setup`](https://documenter.juliadocs.org/stable/man/syntax/#reference-at-setup) +blocks. + !!! tip "Do" + [Configure the logger](@ref log) or load/build a `System` that returns very - few log statements. Use semi-colons at line ends to hide return statements if need be. + few log statements. Use semi-colons at line ends to hide return statements if need be. ### Make it effortless to read + !!! tip "Do" + Split code examples into ideally 1 (to 3) lines ONLY, with a short preface to explain what each line is doing, even if it's obvious to you. ### Move Docstring Material to the APIs + An issue with earlier versions of Sienna documentation was basic reference information located in pages other than the APIs. See how-to [Organize APIs and Write Docstrings](@ref) if needed to make that information easier to find. + !!! tip "Do" + Preface each call to a new function with a hyperlink to that function's - docstring so the user can find more detail + docstring so the user can find more detail + !!! warning "Don't" + Include digressive details about different keyword arguments or versions of - a function. + a function. ### Minimize or Eliminate How-To Guides with a Single Step + A how-to guide has a *sequence* of steps -- if your guide only has a single step, ask yourself if you are compensating for a lack of information in the API's. + !!! tip "Do" + Move how-to guides with a single function to being Examples in that function's docstring. See [Writing Documentation](@extref). ### Remove Other Reference Material + Particularly when editing existing pages, watch out for other [Reference](https://diataxis.fr/reference/) material. + !!! tip "Do" + Move tables and lists of information into Reference pages and link to them instead ### Follow the Guidelines on Cleaning Up General Formatting !!! tip "Do" - Follow How-to [Clean Up General Formatting](@ref). + + Follow How-to [Clean Up General Formatting](@ref). ### Look at the compiled .html! + !!! tip "Do" - - [Compile](@ref "Compile and View Documentation Locally") the how-to guide regularly and + + - [Compile](@ref "Compile and View Documentation Locally") the how-to guide regularly and look at it - - Check all code examples gave the expected results without erroring - - Check for length of the code examples and iteratively adjust to make it easy + - Check all code examples gave the expected results without erroring + - Check for length of the code examples and iteratively adjust to make it easy to read diff --git a/docs/src/docs_best_practices/how-to/write_a_tutorial.md b/docs/src/docs_best_practices/how-to/write_a_tutorial.md index 3f5ee62bc..b641ae1e8 100644 --- a/docs/src/docs_best_practices/how-to/write_a_tutorial.md +++ b/docs/src/docs_best_practices/how-to/write_a_tutorial.md @@ -1,18 +1,19 @@ # Write a Tutorial Tutorials are learning experiences to give our users confidence and experience in using -Sienna. +Sienna. ## Prepare -- If you have not read [Diataxis](https://diataxis.fr/), first read it in its entirety. -- If you have read it, skim the pages on [Tutorials](https://diataxis.fr/tutorials/) and + - If you have not read [Diataxis](https://diataxis.fr/), first read it in its entirety. + - If you have read it, skim the pages on [Tutorials](https://diataxis.fr/tutorials/) and the [difference between a tutorial and how-to guide](https://diataxis.fr/tutorials-how-to/) - to refresh your memory and refer back throughout the process. -- Look at an example: `PowerSystems.jl`'s + to refresh your memory and refer back throughout the process. + - Look at an example: `PowerSystems.jl`'s [Working with Time Series](https://nrel-sienna.github.io/PowerSystems.jl/stable/tutorials/working_with_time_series/) !!! warning + Historically, many of Sienna's "tutorials" have blended all 4 types of documentation in the [Diataxis](https://diataxis.fr/) framework. Be prepared to move material to related Explanation and How-to pages and into function docstrings in the APIs as you work. @@ -37,21 +38,27 @@ Depth = 3:3 The tutorial should have a logical flow, rather than be a series of disconnected code demonstrations. + !!! tip "Do" + Use either named [`@example`](https://documenter.juliadocs.org/stable/man/syntax/#reference-at-example) or named [`@repl`](https://documenter.juliadocs.org/stable/man/syntax/#@repl-block) blocks to ensure all code compiles in order in the same environment and ensuring each step builds on the previous steps in your story: + ````markdown ```@example my_tutorial ``` ```` + !!! warning "Don't" + Use a series of `julia` markdown blocks. These won't be compiled, failing the - intention of a tutorial and introducing high likelihood of errors as syntax changes. + intention of a tutorial and introducing high likelihood of errors as syntax changes. + ````markdown ```julia @@ -59,59 +66,84 @@ demonstrations. ```` ### Make it reproducible + A user should be able to copy and paste every code block in the tutorial in order and get -the exact results seen on the documentation page. +the exact results seen on the documentation page. + !!! tip "Do" - Display all code, starting from `using SomeSiennaPackage` -!!! warning "Don't" + + Display all code, starting from `using SomeSiennaPackage` + +!!! warning "Don't" + Use `#hide` or [`@setup`](https://documenter.juliadocs.org/stable/man/syntax/#reference-at-setup) blocks. ### Make it effortless to read + !!! tip "Do" + Split code examples into ideally 1 (to 3) lines ONLY, with a short preface to explain what each line is doing, even if it's obvious to you. -!!! warning "Don't" + +!!! warning "Don't" + Use blocks of example code and/or return statements that go over 1 screen length in the compiled .html. They are very hard to follow and allow a user to tune out or give up. ### Make it realistic and relatable + !!! tip "Do" - Take the time to define some realistic example data. -!!! warning "Don't" + + Take the time to define some realistic example data. + +!!! warning "Don't" + Use `zero()` or `one()` for all example data. ### Only show relevant log and return statements + !!! tip "Do" + [Configure the logger](@ref log) or load/build a `System` that returns very - few log statements. Use semi-colons at line ends to hide return statements if need be. -!!! warning "Don't" + few log statements. Use semi-colons at line ends to hide return statements if need be. + +!!! warning "Don't" + Show extensive or confusing log or return statements that bog down a reader with information that isn't directly relevant to what you're trying to teach. ### Remove other types of documentation + Particularly when editing existing material, watch out for material that should be moved elsewhere according to Diataxis principles: + !!! tip "Do" + Preface each call to a new function with a hyperlink to that function's - docstring so the user can find more detail + docstring so the user can find more detail + !!! warning "Don't" + Include definitions and details about different keyword arguments or versions of - a function in the tutorial itself. Some basic information is OK, but details and - examples live in the docstrings, and they especially shouldn't be included in the - tutorial **in lieu of** being in the docstrings. + a function in the tutorial itself. Some basic information is OK, but details and + examples live in the docstrings, and they especially shouldn't be included in the + tutorial **in lieu of** being in the docstrings. ### Follow the Guidelines on Cleaning Up General Formatting !!! tip "Do" - Follow How-to [Clean Up General Formatting](@ref). + + Follow How-to [Clean Up General Formatting](@ref). ### Look at the compiled .html! + !!! tip "Do" - - [Compile](@ref "Compile and View Documentation Locally") the tutorial regularly and + + - [Compile](@ref "Compile and View Documentation Locally") the tutorial regularly and look at it - - Check all code examples gave the expected results without erroring - - Check for length of the code examples and iteratively adjust to make it easy + - Check all code examples gave the expected results without erroring + - Check for length of the code examples and iteratively adjust to make it easy to read diff --git a/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md b/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md index c5e4ee70b..77cc191ab 100644 --- a/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md +++ b/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md @@ -7,14 +7,14 @@ guidance on common problems in our existing documentation. ## Prepare -- If you have not read [Diataxis](https://diataxis.fr/), first read it in its entirety. -- Refer back to the Diataxis [Reference](https://diataxis.fr/reference/) section while + - If you have not read [Diataxis](https://diataxis.fr/), first read it in its entirety. + - Refer back to the Diataxis [Reference](https://diataxis.fr/reference/) section while working. -- Read and follow Julia's guidance on [Writing Documentation](@extref), + - Read and follow Julia's guidance on [Writing Documentation](@extref), which mainly applies to docstrings -- Read the sections on `Documenter.jl`'s [`@docs` block](@extref) and + - Read the sections on `Documenter.jl`'s [`@docs` block](@extref) and [`@autodocs` block](@extref), and follow the guidance below on using `@autodocs` - wherever possible + wherever possible ## Follow the Do's and Don't's @@ -28,14 +28,17 @@ Depth = 3:3 ``` ### Look at the compiled .html! + !!! tip "Do" - - [Compile](@ref "Compile and View Documentation Locally") regularly and + + - [Compile](@ref "Compile and View Documentation Locally") regularly and look at the APIs - - Check method signatures and argument lists are formatted correctly + - Check method signatures and argument lists are formatted correctly ### Ensure All Docstrings Are Located in the APIs !!! tip "Do" + Include a Public API markdown file for exported structs, functions, and methods, and an Internals API for private functions. See [`PowerSystems.jl`](https://nrel-sienna.github.io/PowerSystems.jl/stable/) @@ -44,17 +47,21 @@ Depth = 3:3 template when starting a new package. !!! tip "Do" - Migrate all existing Formulation Libraries and Model Libraries into the Public API. + + Migrate all existing Formulation Libraries and Model Libraries into the Public API. !!! tip "Do" + If you want to make a docstring visible outside of the API (e.g., in a tutorial), use - a [non-canonical reference](@extref noncanonical-block). + a [non-canonical reference](@extref noncanonical-block). ### [Automate Adding Docstrings in the Public API with `@autodocs`](@id use_autodocs) !!! tip "Do" + Use [`@autodocs` block](@extref)s in the Public API markdown file to automatically find all docstrings in a file. Example: + ````markdown ## Variables ```@autodocs @@ -66,9 +73,11 @@ Depth = 3:3 ```` !!! warning "Don't" + Manually list out the struts or methods on a topic in a [`@docs` block](@extref), because that introduces more work whenever we add something new or make a change. Example: + ````markdown ## Variables ```@docs @@ -76,19 +85,21 @@ Depth = 3:3 variable2 ``` ```` + Consider re-organizing code if need be, so all related functions are in the same file(s) (e.g., `variables.jl`). ### [Selectively Export Docstrings from `InfrastructureSystems.jl`](@id docs_from_is) If you are working in another Sienna package (e.g., `SomeSiennaPackage.jl`) that imports and -exports code from `InfrastructureSystems.jl`: +exports code from `InfrastructureSystems.jl`: !!! tip "Do" + List the files containing necessary `InfrastructureSystems.jl` structs and methods in `SomeSiennaPackage.jl`'s Public API markdown file, then explicitly filter by what `SomeSiennaPackage.jl` exports. Example: - + ````markdown ```@autodocs Modules = [InfrastructureSystems] @@ -101,50 +112,56 @@ exports code from `InfrastructureSystems.jl`: ```` !!! warning "Don't" + List `InfrastructureSystems` as one of the `modules` in [`Documenter.makedocs`](@extref) in the `make.jl` file. `Documenter.jl` will look to map **all** `InfrastructureSystems.jl` docstrings into the API, resulting in hundreds of [missing docstring](@ref miss_doc) errors. Example: - + ```julia - makedocs( - modules = [SomeSiennaPackage, InfrastructureSystems], - format = Documenter.HTML( - prettyurls = haskey(ENV, "GITHUB_ACTIONS"), - size_threshold = nothing), - sitename = "SomeSiennaPackage.jl", - pages = Any[p for p in pages], + makedocs(; + modules = [SomeSiennaPackage, InfrastructureSystems], + format = Documenter.HTML(; + prettyurls = haskey(ENV, "GITHUB_ACTIONS"), + size_threshold = nothing), + sitename = "SomeSiennaPackage.jl", + pages = Any[p for p in pages], ) ``` ### Ensure All Docstrings Have a Function Signature and Arguments List !!! tip "Do" + Check all exported docstrings have a function signature and detailed arguments list *visible in the API when you compile it*. Example: - + ![A docstring with function signature and args list](../../assets/comp_after.png) !!! warning "Don't" + Leave docstrings that just have a description unaddressed. Example: - + ![A single line docstring](../../assets/comp_before.png) ### Automate Updating Docstring Arguments Lists + This is not commonly done in Sienna yet, but a goal is to improve our use of [`DocStringExtensions.jl`](https://docstringextensions.juliadocs.org/stable) for automation: !!! tip "Do" + Use [`DocStringExtensions.TYPEDFIELDS`](https://docstringextensions.juliadocs.org/stable/#DocStringExtensions.TYPEDFIELDS) to automatically compile arguments lists. Example: + ````markdown """ SomeSiennaStruct(arg1, arg2) # Arguments $(TYPEDFIELDS) - + This is the docstring line. """ struct SomeSiennaStruct <: OperationalCost @@ -156,14 +173,16 @@ This is not commonly done in Sienna yet, but a goal is to improve our use of ```` !!! warning "Don't" + Copy and paste arguments lists into the docstring, which opens opportunity for out-of-date errors when arguments are added or reordered. Example: + ````markdown """ SomeSiennaStruct(arg1, arg2) - + This is the docstring line. - + # Arguments - `arg2::Float64`: Documentation for argument 2 - `arg1::ProductionVariableCostCurve`: Documentation for argument 1 @@ -174,13 +193,15 @@ This is not commonly done in Sienna yet, but a goal is to improve our use of end ```` -### Add `See also` Links to Functions with the Same Name +### Add `See also` Links to Functions with the Same Name !!! tip "Do" + To help users navigate Julia's multiple dispatch, add `See also` paragraphs at the bottom of function docstrings other versions of the function with the same name, using the guidance on [adding a specific hyperlink](@ref hyperlinks). Example: + ``` See also [`get_time_series_array` by name from storage](@ref get_time_series_array( @@ -204,5 +225,6 @@ This is not commonly done in Sienna yet, but a goal is to improve our use of ### Follow the Guidelines on Cleaning Up General Formatting !!! tip "Do" + Follow How-to [Clean Up General Formatting](@ref), especially by adding hyperlinks to other Sienna structs that appear within an arguments list. diff --git a/docs/src/docs_best_practices/reference/useful_links.md b/docs/src/docs_best_practices/reference/useful_links.md index db8b74f23..7d1bc8654 100644 --- a/docs/src/docs_best_practices/reference/useful_links.md +++ b/docs/src/docs_best_practices/reference/useful_links.md @@ -1,11 +1,11 @@ # Useful Links -- [Diataxis](https://diataxis.fr/): Reference for the new + - [Diataxis](https://diataxis.fr/): Reference for the new documentation framework Sienna is striving to follow (not specific to Julia) -- Julia's guidance on [Writing Documentation](@extref) -- [`Documenter.jl`](https://documenter.juliadocs.org/stable/): Julia's documentation + - Julia's guidance on [Writing Documentation](@extref) + - [`Documenter.jl`](https://documenter.juliadocs.org/stable/): Julia's documentation package, the [Syntax](https://documenter.juliadocs.org/stable/man/syntax/) and [Showcase](https://documenter.juliadocs.org/stable/showcase/) pages are especially useful -- [`SiennaTemplate.jl` Git repository](https://github.com/NREL-Sienna/SiennaTemplate.jl): A + - [`SiennaTemplate.jl` Git repository](https://github.com/NREL-Sienna/SiennaTemplate.jl): A template for new Sienna packages that includes the required documentation framework. From c9b8e031d67cb4479331e0171c59a154f2653e9b Mon Sep 17 00:00:00 2001 From: kdayday Date: Mon, 16 Dec 2024 15:33:02 -0700 Subject: [PATCH 34/40] Minor wording --- docs/src/docs_best_practices/how-to/write_a_tutorial.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/src/docs_best_practices/how-to/write_a_tutorial.md b/docs/src/docs_best_practices/how-to/write_a_tutorial.md index b641ae1e8..9b28db9b9 100644 --- a/docs/src/docs_best_practices/how-to/write_a_tutorial.md +++ b/docs/src/docs_best_practices/how-to/write_a_tutorial.md @@ -15,8 +15,9 @@ Sienna. !!! warning Historically, many of Sienna's "tutorials" have blended all 4 types of documentation in - the [Diataxis](https://diataxis.fr/) framework. Be prepared to move material to related - Explanation and How-to pages and into function docstrings in the APIs as you work. + the [Diataxis](https://diataxis.fr/) framework. If you are editing, be prepared to move + material to related Explanation and How-to pages and into function docstrings in the APIs + as you work. If you starting a new tutorial, ask yourself if a tutorial is appropriate for what you're trying to show, or if you should be writing a how-to instead. From 7d58720cd5264a06e31553b1ee782b6e90d1e2d5 Mon Sep 17 00:00:00 2001 From: kdayday Date: Mon, 16 Dec 2024 15:45:16 -0700 Subject: [PATCH 35/40] github update --- docs/src/docs_best_practices/how-to/view_github.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/src/docs_best_practices/how-to/view_github.md b/docs/src/docs_best_practices/how-to/view_github.md index 78d9ce3aa..6da6ff6c9 100644 --- a/docs/src/docs_best_practices/how-to/view_github.md +++ b/docs/src/docs_best_practices/how-to/view_github.md @@ -6,3 +6,6 @@ 3. Preview it in a browser following this url format: > https://nrel-sienna.github.io/.jl/previews/PR/ + +*This only works if the PR is on the root repository, not a fork.* Otherwise, work with a +maintainer to move your PR to the root repository. From f9a4483e87fed2ca5ff5a8492f3db4addc995f4b Mon Sep 17 00:00:00 2001 From: kdayday Date: Tue, 17 Dec 2024 14:31:35 -0700 Subject: [PATCH 36/40] Rename pre-step --- docs/src/docs_best_practices/how-to/compile.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/docs_best_practices/how-to/compile.md b/docs/src/docs_best_practices/how-to/compile.md index bafa85a31..ebf377a2b 100644 --- a/docs/src/docs_best_practices/how-to/compile.md +++ b/docs/src/docs_best_practices/how-to/compile.md @@ -1,6 +1,6 @@ # Compile and View Documentation Locally -## Step 0a: Update Docs Environment (First Time) +## Pre-Step a: Update Docs Environment (First Time) The first time you compile documentation for a package, make sure the `docs/` environment (i.e., `docs/Manifest.toml`, not the main `Manifest.toml` in the root of the repository) @@ -12,7 +12,7 @@ using Pkg Pkg.develop(path = "..") ``` -## Step 0b: Auto-Generate Structs (If Needed) +## Pre-Step b: Auto-Generate Structs (If Needed) Most documentation changes are made directly to markdown (.md) files, but if you changed one of Sienna's .json descriptor files, you must first @@ -35,7 +35,7 @@ InfrastructureSystems.generate_structs( ) ``` -## Step 0c: Run the Formatter (Before Submitting a Pull Request) +## Pre-Step c: Run the Formatter (Before Submitting a Pull Request) To automatically format the documentation to conform with the [style guide](@ref style_guide), run in a terminal at the root of the repository: From 24614041b70acafcde49dfb535abc96336ab7e13 Mon Sep 17 00:00:00 2001 From: kdayday Date: Thu, 19 Dec 2024 17:22:12 -0700 Subject: [PATCH 37/40] Add reproducibility example --- docs/make.jl | 1 + docs/src/docs_best_practices/how-to/write_a_tutorial.md | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/make.jl b/docs/make.jl index 25aa2f8bf..d783d5ff2 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -7,6 +7,7 @@ links = InterLinks( "Documenter" => "https://documenter.juliadocs.org/stable/", "Julia" => "https://docs.julialang.org/en/v1/", "JuliaFormatter" => "https://domluna.github.io/JuliaFormatter.jl/stable/", + "PowerSystems" => "https://nrel-sienna.github.io/PowerSystems.jl/stable/", ) if haskey(ENV, "GITHUB_ACTIONS") diff --git a/docs/src/docs_best_practices/how-to/write_a_tutorial.md b/docs/src/docs_best_practices/how-to/write_a_tutorial.md index 9b28db9b9..fb1c9ea63 100644 --- a/docs/src/docs_best_practices/how-to/write_a_tutorial.md +++ b/docs/src/docs_best_practices/how-to/write_a_tutorial.md @@ -73,7 +73,8 @@ the exact results seen on the documentation page. !!! tip "Do" - Display all code, starting from `using SomeSiennaPackage` + Display all code, starting from `using SomeSiennaPackage`. Example: See + [Working with Time Series](@extref tutorial_time_series). !!! warning "Don't" From a8e4bbaf74ab88b1329c290b058205d4aa3f03e5 Mon Sep 17 00:00:00 2001 From: kdayday Date: Thu, 19 Dec 2024 17:22:32 -0700 Subject: [PATCH 38/40] Clarify toml file --- docs/src/docs_best_practices/how-to/requirements_checklist.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/docs_best_practices/how-to/requirements_checklist.md b/docs/src/docs_best_practices/how-to/requirements_checklist.md index d39608cb0..0ae72407f 100644 --- a/docs/src/docs_best_practices/how-to/requirements_checklist.md +++ b/docs/src/docs_best_practices/how-to/requirements_checklist.md @@ -22,8 +22,8 @@ only need to be addressed once: + How to [Write a Tutorial](@ref) + How to [Organize APIs and Write Docstrings](@ref) - 2. Replace `compat` requirements of `Documenter = "0.27"` in `docs/` environment with - `Documenter = "1.0"` + 2. Update the Project.toml file in the `docs/` folder to replace `compat` requirements of + `Documenter = "0.27"` with `Documenter = "1.0"` 3. Update the `docs/make.jl` file to call [`Documenter.makedocs`](https://documenter.juliadocs.org/stable/lib/public/#Documenter.makedocs) *without* the `warnonly` `kwarg` (i.e., all errors caught by `makedocs` must be resolved before From 037d0e069de8121838ff25bf2c13dedeb3389f19 Mon Sep 17 00:00:00 2001 From: kdayday Date: Thu, 19 Dec 2024 17:28:04 -0700 Subject: [PATCH 39/40] Fix formatter issues --- .../docs_best_practices/how-to/general_formatting.md | 11 ++++++++--- docs/src/docs_best_practices/how-to/write_a_how-to.md | 7 +++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/src/docs_best_practices/how-to/general_formatting.md b/docs/src/docs_best_practices/how-to/general_formatting.md index 2e137e832..a0181f447 100644 --- a/docs/src/docs_best_practices/how-to/general_formatting.md +++ b/docs/src/docs_best_practices/how-to/general_formatting.md @@ -52,10 +52,15 @@ signature with types into the hyperlink reference. !!! warning "Don't" + ``` + `get_time_series_values` + ``` + + Or -``get_time_series_values`` -Or -`get_time_series_values` + ``` + get_time_series_values + ``` ## Add links to other Sienna packages diff --git a/docs/src/docs_best_practices/how-to/write_a_how-to.md b/docs/src/docs_best_practices/how-to/write_a_how-to.md index 78ab5ad71..842065e47 100644 --- a/docs/src/docs_best_practices/how-to/write_a_how-to.md +++ b/docs/src/docs_best_practices/how-to/write_a_how-to.md @@ -28,10 +28,9 @@ Depth = 3:3 !!! tip "Do" - -Jump the user right to a logical starting point in the code using `#hide` or -[`@setup`](https://documenter.juliadocs.org/stable/man/syntax/#reference-at-setup) -blocks. + Jump the user right to a logical starting point in the code using `#hide` or + [`@setup`](https://documenter.juliadocs.org/stable/man/syntax/#reference-at-setup) + blocks. !!! tip "Do" From ce1f976dd7aabaf66643aeab0833f6e4b57ea1fa Mon Sep 17 00:00:00 2001 From: kdayday Date: Thu, 19 Dec 2024 17:30:17 -0700 Subject: [PATCH 40/40] Run formatter --- docs/src/docs_best_practices/how-to/general_formatting.md | 4 ++-- docs/src/docs_best_practices/how-to/write_a_tutorial.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/docs_best_practices/how-to/general_formatting.md b/docs/src/docs_best_practices/how-to/general_formatting.md index a0181f447..b0d5f02a6 100644 --- a/docs/src/docs_best_practices/how-to/general_formatting.md +++ b/docs/src/docs_best_practices/how-to/general_formatting.md @@ -55,9 +55,9 @@ signature with types into the hyperlink reference. ``` `get_time_series_values` ``` - + Or - + ``` get_time_series_values ``` diff --git a/docs/src/docs_best_practices/how-to/write_a_tutorial.md b/docs/src/docs_best_practices/how-to/write_a_tutorial.md index fb1c9ea63..41b79fe35 100644 --- a/docs/src/docs_best_practices/how-to/write_a_tutorial.md +++ b/docs/src/docs_best_practices/how-to/write_a_tutorial.md @@ -74,7 +74,7 @@ the exact results seen on the documentation page. !!! tip "Do" Display all code, starting from `using SomeSiennaPackage`. Example: See - [Working with Time Series](@extref tutorial_time_series). + [Working with Time Series](@extref tutorial_time_series). !!! warning "Don't"