Skip to content

feat(docs): group framework functions by visibility#11537

Merged
luca-moser merged 15 commits into
developfrom
feat/move-docgen-visibility-grouping
May 29, 2026
Merged

feat(docs): group framework functions by visibility#11537
luca-moser merged 15 commits into
developfrom
feat/move-docgen-visibility-grouping

Conversation

@luca-moser
Copy link
Copy Markdown
Member

@luca-moser luca-moser commented May 15, 2026

Description of change

Restructures the generated Move framework reference docs (rendered at docs.iota.org/references/iota-move) so the public surface of each module is easier to scan.

image

What changed

move-docgen (external-crates/move/crates/move-docgen/src/docgen.rs)

  • Functions are grouped by visibility into Public / Entry / Public(package) / Public(friend) / Private buckets, alphabetized within each bucket. Only the legacy public(friend) bucket stays in a collapsed <details>.
  • Structs and enums are wrapped in top-level Structs and Enums sections so the page has clear categories alongside Constants and the function buckets.
  • Dot-syntax methods (functions whose first parameter is an in-module struct or enum) are emitted as headings directly under their datatype, alphabetized. Free functions stay in the visibility buckets.
  • The redundant Function / Macro function heading prefix is dropped (the parent bucket conveys the kind); macros are marked ### \name` (macro)`.
  • New DocgenFlags::include_module_toc (default true) lets renderers that build their own heading sidebar (Docusaurus) skip the duplicate in-page TOC.

move-packageBuildConfig gains a docgen_flags: DocgenFlags field, replacing a long-standing TODO this should be configurable and letting the framework build opt out of the in-page TOC.

iota-framework build (crates/iota-framework/tests/build-system-packages.rs) — sets docgen_flags.include_module_toc = false when building the system packages, and adds toc_max_heading_level: 4 to each module's frontmatter so per-struct method headings surface in Docusaurus's right-nav.

iota-genesis-builder — adds the new docgen_flags field to its exhaustive MoveBuildConfig construction (irrelevant in that path; generate_docs: false).

Testsmove-docgen-tests snapshots and the move-stdlib / iota-framework generated docs are refreshed.

Motivation

Addresses #6261: today public(package) helpers, entry admin functions, and the public consumer API are rendered as one flat list, making it hard to tell a module's actual API surface (iota::coin, iota_system) from its internals. Grouping by visibility and surfacing dot-syntax methods next to their struct directly mirrors what Alex asked for.

How the change has been tested

  • Basic tests (linting, compilation, formatting, unit/integration tests)
  • Patch-specific tests (correctness, functionality coverage)

Specifically:

  • cargo test -p move-docgen-tests — all 12 snapshots pass.
  • cargo clippy -p move-docgen -p iota-framework --all-targets -- -D warnings — clean.
  • UPDATE=1 cargo test -p iota-framework --test build-system-packages and UPDATE=1 cargo test -p move-stdlib check_that_docs_are_updated — regenerates docs/generated-docs/framework/ and the in-tree move-stdlib/docs/std/*.md; inspected iota/coin.mdx, iota_system/iota_system.mdx, and std/vector.md confirm the new layout (visibility buckets, alphabetized, per-struct method sections).
  • Local Docusaurus dev server — regenerated framework pages render without MDX errors and the right-hand TOC shows Structs / Enums / Constants / Public Functions / … as top-level categories with method names nested under each struct.

No protocol, node, indexer, RPC, GraphQL, CLI, SDK, or gRPC behaviour changes — purely affects the build-time documentation generator and the markdown it emits, so no Release Notes section.

@luca-moser luca-moser requested review from a team as code owners May 15, 2026 10:29
include_dep_diagrams: false
include_call_diagrams: false
include_module_toc: true
snapshot_kind: text
Copy link
Copy Markdown
Member

@alexsporn alexsporn May 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to get rid of these snapshot_kind: text changes you should update your cargo-insta with cargo install cargo-insta --force

@luca-moser luca-moser force-pushed the feat/move-docgen-visibility-grouping branch 2 times, most recently from 80554c5 to 9b3f6fd Compare May 15, 2026 10:47
@luca-moser luca-moser changed the title feat(move-docgen): group framework functions by visibility feat(docs): group framework functions by visibility May 15, 2026
@luca-moser luca-moser force-pushed the feat/move-docgen-visibility-grouping branch from 9b3f6fd to 5f5328c Compare May 15, 2026 11:09
# Description of change

The Move framework reference docs hosted at docs.iota.org/references/iota-move
are generated by `move-docgen` from the Move sources of the system packages.
Today, every function in a module is rendered as a flat list under the module
heading, so `public(package)` helpers, `entry` admin functions, and the
genuinely-public consumer API all sit side by side. For modules like
`iota::coin` or `iota_system`, that makes it tedious to figure out what part
of the surface is actually meant to be called by a downstream developer.

This change makes `move-docgen` group functions by visibility and tunes the
output for the Docusaurus site that consumes it.

## What changed

**`move-docgen` (`external-crates/move/crates/move-docgen/src/docgen.rs`)**

- Functions in each module are now emitted in five buckets, in this order:

  1. `Public Functions` – the surface most consumers care about.
  2. `Entry Functions` – everything tagged `entry` (PTB-callable).
  3. `Public Package Functions` – `public(package)` cross-module helpers.
  4. `Public Friend Functions` – legacy `public(friend)`.
  5. `Private Functions` – module-internal.

  Each non-empty bucket becomes its own `H2` section with a heading anchor,
  and individual function headings inside the bucket are `H3`. Definition
  order is preserved within a bucket.

- Buckets 3–5 are wrapped in a collapsed `<details>` block, so the public
  surface is what's open by default and the internals do not push it below
  the fold on large modules.

- The redundant `Function` / `Macro function` prefix on per-function
  headings has been dropped. The parent bucket already conveys the kind,
  so `### Function \`join\`` is now just `### \`join\``. Macros are marked
  as `### \`name\` (macro)`.

- New `DocgenFlags::include_module_toc` (default `true`, preserving plain
  markdown rendering). When the output is hosted by a renderer that builds
  its own heading sidebar (Docusaurus, in our case), the in-page TOC is
  pure duplication.

**`move-package` (`external-crates/move/crates/move-package/src/...`)**

- `BuildConfig` gains a `docgen_flags: DocgenFlags` field (skip from clap;
  consumers driving the build programmatically can override the defaults).
  This replaces a long-standing `TODO this should be configurable` in
  `compiled_package.rs` and lets the framework build opt out of the
  in-page TOC without further plumbing.

**`iota-framework` build (`crates/iota-framework/tests/build-system-packages.rs`)**

- Sets `docgen_flags: DocgenFlags { include_module_toc: false, .. }` when
  building the system packages, so the published docs no longer carry the
  duplicate in-page table of contents next to Docusaurus's auto-generated
  one.

**Tests**

- Every `move-docgen-tests` insta snapshot has been refreshed to reflect
  the new heading layout. The 12 docgen tests cover annotations, code
  blocks, constants, all visibility levels, enums, and root templates.

## Motivation

This is the fix for the `move-docgen` improvement Alexander Sporn asked for
in #6261: today `public(package)` functions are interleaved with public and
entry functions, which makes it hard for a developer browsing the system
package docs to quickly understand the module's public API. Grouping by
visibility and collapsing internals addresses the first half of that
request. The second half of the issue — surfacing dot-syntax callable
methods next to their struct, and optionally splitting each module across
multiple pages — is a larger change and will be a separate follow-up.

## Links to any relevant issues

Refs #6261

## How the change has been tested

- [x] Basic tests (linting, compilation, formatting, unit/integration tests)
- [x] Patch-specific tests (correctness, functionality coverage)
- [x] I have added tests that prove my fix is effective or that my feature works
- [x] I have checked that new and existing unit tests pass locally with my changes

Specifically:

- `cargo test -p move-docgen-tests` — all 12 snapshots pass after the
  heading-format/grouping/collapse changes.
- `cargo clippy -p move-docgen --no-deps` — clean.
- `cargo check -p iota-framework` and `cargo check -p move-docgen
  -p move-package` — clean.
- `UPDATE=1 cargo test -p iota-framework --test build-system-packages` —
  regenerates `docs/generated-docs/framework/` end-to-end; inspected
  `iota/coin.mdx` and `iota_system/iota_system.mdx` show the five
  visibility buckets in the new order, with Public/Entry expanded and
  Package/Private wrapped in `<details>`. No in-page TOC.
- Local Docusaurus dev server (`pnpm iota-docs dev`): the regenerated
  framework pages render without MDX errors (the 4 pre-existing MDX
  failures on `IotaSystemStateSummaryV1/V2.md` are unrelated — they come
  from `super::...` rustdoc-style links in the TS SDK's JSDoc).

### Release Notes

- [ ] Protocol:
- [ ] Nodes (Validators and Full nodes):
- [ ] Indexer:
- [ ] JSON-RPC:
- [ ] GraphQL:
- [ ] CLI:
- [ ] Rust SDK:
- [ ] gRPC:
@luca-moser luca-moser force-pushed the feat/move-docgen-visibility-grouping branch from 5f5328c to f146e96 Compare May 15, 2026 11:30
Copy link
Copy Markdown
Member

@lzpap lzpap left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tried it out locally, worked as expected.

Question: didn't we have a vercel test deployment before on every pr that changed docs?

@luca-moser luca-moser linked an issue May 15, 2026 that may be closed by this pull request
@alexsporn
Copy link
Copy Markdown
Member

Question: didn't we have a vercel test depoyment before on every pr that changed docs?

Yes, but needs a change in the docs folder to trigger:

@alexsporn
Copy link
Copy Markdown
Member

I ran the wiki-preview action manually from this branch but it seems to not re-generate the files:
https://iota-docs-6z6kruesh-iota1.vercel.app

@alexsporn
Copy link
Copy Markdown
Member

Got the docs to work locally. I would remove this blue dropdown that hides these functions by default, since they are visible in the index to the right anyway:
screenshot_2026-05-18_at_09 17 28_720

luca-moser and others added 2 commits May 18, 2026 10:19
…TOC sections

- Alphabetize functions within each visibility bucket.
- Stop wrapping Public Package and Private buckets in <details>; only the
  legacy Public Friend bucket stays collapsed.
- Emit dot-syntax methods (functions whose first parameter is an in-module
  datatype) as section headers directly under their struct/enum.
- Wrap all structs and enums in top-level "Structs" and "Enums" sections so
  the right-hand TOC has explicit categories alongside Constants and the
  function buckets.
- Bump per-module frontmatter to `toc_max_heading_level: 4` so per-struct
  method headings surface in Docusaurus's right-nav.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ntmatter

Per-file `toc_max_heading_level: 4` in the generated framework MDX
broke MDX compilation ("Expected component Details to be defined")
on every framework page. Move the setting into themeConfig in
docusaurus.config.js so methods (H4) appear in the right-hand TOC
without poisoning the per-file frontmatter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

✅ Vercel Preview Deployment is ready!

View Preview

Copy link
Copy Markdown
Member

@alexsporn alexsporn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice improvement 🎉

`move-docgen` emits framework reference code as raw `<pre><code>` with
`<b>` keywords and inline `<a>` cross-references. Adding `class` or
`className` to these tags breaks MDX's HTML mode on the multi-line
content, so syntax styling has to live in the docs site stylesheet
instead. Adds rules in `docs/site/src/css/custom.css` that:

- give the keyword `<b>` tags the primary color so `public`, `fun`,
  `struct`, etc. pop visually,
- strip the spurious `<p>` margin MDX adds inside `<code>`,
- style inline cross-reference `<a>` links with a subtle dashed
  underline that becomes solid on hover,
- give the block a proper background, padding, and rounded border.

The selectors use `:has(> code > b)` so they only match the docgen
flavor of code blocks — Prism-rendered fenced ```move blocks elsewhere
in the site are untouched.

Also picks up two missed `move-docgen-tests` snapshot updates in
`const_string/` left over from the `DocgenFlags` change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

✅ Vercel Preview Deployment is ready!

View Preview

MDX strips leading whitespace from each line inside `<code>` because it
parses the content as a paragraph, which silently dropped the 4-space
indent from every Move implementation body. Encode the leading spaces
as `&nbsp;` in the framework MDX post-processing so the browser still
renders them as regular spaces.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

✅ Vercel Preview Deployment is ready!

View Preview

`clippy::uninlined_format_args` enforced as deny in CI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

✅ Vercel Preview Deployment is ready!

View Preview

Methods listed under each struct/enum now appear in the same order as
the module's free-function buckets (Public, Entry, Public(package),
Public(friend), Private), alphabetized within each visibility group.
Same ordering shows up directly in the right-hand TOC.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

✅ Vercel Preview Deployment is ready!

View Preview

Methods on a struct/enum now get the same visibility-bucket
sub-sections as free functions (Public, Entry, Public(package),
Public(friend), Private), each non-empty bucket emitted as its own
heading under the datatype. Public(friend) stays in a collapsed
`<details>` like the module-level bucket; the others render inline.

Docusaurus TOC max heading level bumped from 4 to 5 so the deeper
method headings show in the right-hand navigation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

✅ Vercel Preview Deployment is ready!

View Preview

Drop the per-visibility section headers (Public Functions / Entry
Functions / …) and flatten every function/method into a single sorted
list. Each function heading carries an inline color-coded visibility
marker — `pub`, `entry`, `pub-pkg`, `pub-friend`, `prv` — which the
right-hand TOC picks up automatically because Docusaurus extracts the
full heading content.

- `move-docgen`: every function heading now ends in
  `<span class="move-vis move-vis-<vis>">…</span>` and the module's
  free functions live under one `Module Functions` heading.
- `docs/site/src/css/custom.css`: stylesheet hooks color each marker
  (blue for public, green for entry, purple for package, gray for
  friend, orange for private) and the same colors carry over into the
  TOC entries.
- `docs/site/docusaurus.config.js`: TOC max heading level back to 4
  (one level shallower now that the visibility sub-headers are gone).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

✅ Vercel Preview Deployment is ready!

View Preview

luca-moser and others added 2 commits May 18, 2026 14:03
…unctions

- Constants named `E[A-Z]…` (the Move convention for abort codes,
  e.g. `EMaximumSupplyReached`) are emitted as section headers with
  a red `err` tag and appear in the right-hand TOC under `Constants`.
  Non-error constants stay as flat code blocks under the heading so
  the TOC doesn't fill up with numeric / config constants.
- Free module functions get an additional yellow `module` tag next to
  the visibility tag, so a reader scanning the TOC can tell a free
  function from a struct/enum method at a glance.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Every named constant now gets a section header so it appears in the
right-hand TOC, with an inline tag indicating its role:
- `err` (red) for error abort codes (`E[A-Z]…`).
- `const` (teal) for everything else.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

✅ Vercel Preview Deployment is ready!

View Preview

Each struct heading gets a green `struct` tag and each enum heading a
magenta `enum` tag, matching the visibility/role tag pattern already
used for functions and constants. Helps the right-hand TOC stay
self-describing now that the per-visibility section headers are gone.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

✅ Vercel Preview Deployment is ready!

View Preview

…he top

- Move the visibility / role tag to the front of each heading (`pub
  module \`create_currency\`` instead of `\`create_currency\` pub module`).
  Easier to skim a long TOC when the tag is the leftmost element.
- Reorder module sections so `Module Functions` is the first H2 in the
  page, followed by `Structs`, `Enums`, `Constants`. Modules usually have
  only a handful of free functions but many struct methods, so keeping the
  free functions at the top of the right-hand TOC keeps the scannable
  surface above the long datatype lists.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

✅ Vercel Preview Deployment is ready!

View Preview

luca-moser and others added 2 commits May 18, 2026 15:46
- Remove the yellow `module` tag from free module functions; the visibility
  tag alone is enough now that Module Functions is the first section in
  the page. Cleans up the `extra_marker` parameter that fell out of use.
- Rename `pub-pkg` → `pub(pkg)` and `pub-friend` → `pub(friend)` so the
  inline tag matches the actual Move source-level visibility syntax.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ions

`public` and `entry` are orthogonal in Move: `public` controls
cross-module callability, `entry` controls top-level PTB callability.
A `public entry fun` is reachable both ways, so emit both tags side by
side instead of collapsing the function into a single `entry` bucket.

- `public entry fun` → `pub entry`
- `public(pkg) entry fun` → `pub(pkg) entry`
- `entry fun` (private+entry) → `entry` only (the `prv` tag would be
  noise since `entry` already conveys PTB-callability).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

✅ Vercel Preview Deployment is ready!

View Preview

Copy link
Copy Markdown
Contributor

@miker83z miker83z left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@luca-moser luca-moser merged commit f92dbcc into develop May 29, 2026
43 checks passed
@luca-moser luca-moser deleted the feat/move-docgen-visibility-grouping branch May 29, 2026 07:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Generated Move documentation improvements

4 participants