diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 0e4f023..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,26 +0,0 @@ -# Keeps every git submodule's pinned commit from silently drifting behind -# its own repo's default branch. Reads .gitmodules directly, so a new -# submodule (a future tool repo registered in scripts/external-jobs.js) -# is covered automatically — nothing here is specific to any one repo. -# See "Refreshing submodule pins automatically" in -# docs/website/how-it-works.mdx for the full story, including why the -# actual safety gate is the "build-and-test" required status check on the -# prToMain ruleset (not this file) and how the opened PR gets approved and -# merged without a human (.github/workflows/dependabot-auto-merge.yml). -version: 2 -updates: - - package-ecosystem: "gitsubmodule" - directory: "/" - schedule: - interval: "daily" - # Without this, Dependabot applies a default 3-day cooldown to version - # updates and ignores any tool-repo commit younger than that, so a docs - # change took 3-4 days to reach the site and "Check for updates" didn't - # help. The cooldown guards against freshly published third-party - # releases; every submodule here is a first-party Robotiq repo, so it's - # switched off for all of them. `default-days` can't be 0 (minimum 1), - # hence excluding every dependency instead. - cooldown: - default-days: 1 - exclude: - - "*" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4f56c34..1d15d2b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,15 +1,15 @@ name: CI -# Verifies the documentation site builds and passes basic smoke tests. -# Intended to be a required status check for merging into main. +# Checks that the site still builds before a change is merged. The build +# also fetches robotiq/.github's profile/README.md (see +# scripts/fetch-profile-readme.js), so it fails if that can't be fetched. +# Keep the job id `build-and-test`: the main branch ruleset requires a +# check with that exact name. on: pull_request: branches: - main - push: - branches: - - main workflow_dispatch: permissions: @@ -23,10 +23,6 @@ jobs: build-and-test: runs-on: ubuntu-latest steps: - # Submodules aren't checked out here — scripts/sync-external-docs.js - # runs `git submodule update --init --force` itself as part of the - # build (needed for local `npm start`/`npm run build` too), so doing - # it again via actions/checkout would just be a redundant second fetch. - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -37,85 +33,19 @@ jobs: - name: Install dependencies run: npm ci - # Fails the build if any production dependency, direct or transitive, - # isn't under an allowlisted permissive license (fails closed, so - # copyleft GPL/AGPL/LGPL/SSPL/BUSL — which would require this site's - # own source to be distributed under matching terms, conflicting with - # its BSD-3-Clause license — and unknown licenses both fail). Reads - # package-lock.json, so it's OS-independent and needs no install. - # Catches this at the point a dependency is added, rather than during - # a manual audit later. + # Fails if any production dependency, direct or transitive, isn't + # under an allowlisted permissive license (fails closed, so copyleft + # and unknown licenses both fail) — copyleft would conflict with this + # site's BSD-3-Clause license, and src/pages/license.md states none + # is used. Reads package-lock.json. Not `license-checker --failOn`: + # it compares whole license strings, so "GPL" never matches a real + # SPDX id like GPL-3.0-only. - name: Check dependency licenses run: node scripts/check-dependency-licenses.js - # scripts/sync-external-docs.js shells out to the `doxygen` binary - # (see its doxygen2docusaurus job handling) to build the C++ library's - # API reference — not an npm package, so `npm ci` above can't provide - # it. ubuntu-latest doesn't have it preinstalled. graphviz (`dot`) is - # also required even though this repo's own Doxyfiles never set - # HAVE_DOT=YES: the apt-installed Doxygen version's own default is - # YES (newer Doxygen releases default it to NO, which is why this - # was never hit testing locally against a newer local install) — so - # it tries to render inheritance/collaboration graphs regardless. - # Without `dot`, that fails outright ("problems opening map file ... - # for inclusion in the docs"), and WARN_AS_ERROR=FAIL_ON_WARNINGS - # (see the submodule's own Doxyfile) turns that into a hard failure - # here. Confirmed by reproducing this exact failure in a clean - # Ubuntu container with the apt-installed Doxygen version, then - # confirming `apt install graphviz` alone fixes it. - - name: Install Doxygen and Graphviz - run: sudo apt-get update && sudo apt-get install -y doxygen graphviz - - # Pure logic, no build/network/submodule checkout needed — runs before - # Build so a failure here is fast and doesn't waste a Doxygen run. - # See test/ for what's covered: list-submodule-tags.js's tag parsing, - # sync-external-docs.js's stale-file pruning (scripts/lib/prune.js), - # the YouTube-embed remark plugin (both .md and .mdx compilation — - # regression coverage for the bug in PR #14's review), and - # site-nav-tree.mjs's versioned-sidebar drift guard (below). - - name: Unit tests - run: npm run test:unit - - # Fails on broken internal links / anchors (onBrokenLinks: 'throw') - # and runs the sync + tools-table generators via the prebuild hook. + # GITHUB_TOKEN only lifts the GitHub API rate limit for the README + # fetch; it grants nothing extra. - name: Build run: npm run build - - # generate-tools-table.js (run above, via the prebuild hook) rewrites - # docs/intro.mdx and, under software-tools/ (every product/tool page, - # versioned or not — see docs/website/versioning.mdx), every - # product's own index.mdx/ROS/index.mdx and any tool/guide page - # that's grown a self-installed sub-section list — all committed - # files, none of them gitignored (only the submodule-synced - # software-tools/**/*.md content is — see the comment above that - # rule in .gitignore). Nothing else regenerates and commits these - # after a merge, so a PR that changes something the generator - # depends on (e.g. a Dependabot submodule bump) without also - # re-running it locally would otherwise silently ship a deployed - # site that doesn't match what's committed. This catches that here, - # generically — no file list to keep in sync as the generator's own - # output grows. (Stable's own frozen content — - # software-tools_versioned_docs/, software-tools_versioned_sidebars/, - # software-tools_versions.json — is gitignored now, materialized - # fresh by every build's own prebuild hook - # (scripts/ensure-stable-version.js) rather than committed, so there's - # nothing to verify-committed for it here; see docs/website/versioning.mdx.) - - name: Verify generated content is committed - run: git diff --exit-code -- docs/ software-tools/ - - # Smoke-tests the generated output (key pages + tools table present). - - name: Test - run: npm test - - # Catches forgetting to point external/ back at its real - # branch after prototyping against a WIP one (see "Previewing local - # edits to a submodule" in docs/website/index.mdx) — the pin must - # be reachable from the submodule repo's own actual default branch - # (checked directly against the remote, not external-jobs.js's - # `branch` field — see check-submodule-pins.js's own header comment - # for why that field can't be trusted as ground truth here). Runs - # after Build/Test (not before) so it reuses the submodule checkout - # sync-external-docs.js's own build step already did, rather than - # fetching it again here. - - name: Verify submodule pins are on their repo's default branch - run: node scripts/check-submodule-pins.js + env: + GITHUB_TOKEN: ${{ github.token }} diff --git a/.github/workflows/cut-versions.yml b/.github/workflows/cut-versions.yml deleted file mode 100644 index 8cb26cf..0000000 --- a/.github/workflows/cut-versions.yml +++ /dev/null @@ -1,132 +0,0 @@ -name: Auto-cut Stable versions - -# Checks every versioned tool for a newer tag upstream (see -# scripts/auto-cut-versions.js) and, if one exists, records it in -# software-tools-stable.json, then merges the result straight to main — -# see "Cutting Stable" in docs/website/versioning.mdx. Stable's own -# frozen content isn't committed to git (see .gitignore); the Build step -# below is what actually materializes it from the newly-recorded tags -# (scripts/ensure-stable-version.js, the same prebuild step every other -# build already runs) and the Test step verifies the result — so build + -# test passing here is both "does this tag actually work" AND "does the -# small commit about to be pushed produce it," not a separate concern. -# Fully automatic end to end: a newer tag existing upstream is itself the -# only signal this waits for, and that build + test run is the gate, not a -# human. Runs on a schedule so nobody has to remember to run that script -# by hand after a release, and nobody has to click merge either. - -on: - schedule: - - cron: '0 6 * * *' # daily, 06:00 UTC - workflow_dispatch: - -permissions: - contents: write - pull-requests: write - -concurrency: - group: auto-cut-versions - cancel-in-progress: false - -jobs: - auto-cut: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-node@v4 - with: - node-version: 20 - cache: npm - - - name: Install dependencies - run: npm ci - - # See the matching comment in ci.yml for why both are needed. - - name: Install Doxygen and Graphviz - run: sudo apt-get update && sudo apt-get install -y doxygen graphviz - - - name: Check for new tags and cut Stable - run: node scripts/auto-cut-versions.js - - - name: Determine whether anything was cut - id: check - run: | - if [ -f cut-version-summary.md ]; then - echo "changed=true" >> "$GITHUB_OUTPUT" - else - echo "changed=false" >> "$GITHUB_OUTPUT" - fi - - # A cut is never pushed unverified — build/test have to pass on the - # actual result before a PR is opened or updated with it. - - name: Build - if: steps.check.outputs.changed == 'true' - run: npm run build - - - name: Test - if: steps.check.outputs.changed == 'true' - run: npm test - - # Needed so the push and PR-open below read as a real, distinct - # actor instead of GITHUB_TOKEN — same reasoning as this same - # pattern in dependabot-auto-merge.yml. GitHub doesn't start - # workflow runs (ci.yml's own "build-and-test" required check - # included) from a GITHUB_TOKEN-authored push or PR-open event, so - # a GITHUB_TOKEN-pushed cut can never pick up the check prToMain - # requires, and a GITHUB_TOKEN merge wouldn't fire deploy.yml's - # `push` trigger either, even if branch protection somehow let it - # through. - - name: Mint App token - if: steps.check.outputs.changed == 'true' - id: app-token - uses: actions/create-github-app-token@v1 - with: - app-id: ${{ vars.APP_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - - # One fixed branch, force-pushed each run — a run the next day with - # no further upstream changes has nothing new to add, and a run - # while an earlier auto-cut PR somehow still exists updates that - # same PR in place instead of opening a duplicate. - - name: Push the cut and open (or update) the PR - if: steps.check.outputs.changed == 'true' - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - run: | - BRANCH="automated/cut-versions" - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git checkout -B "$BRANCH" - git add -- software-tools-stable.json - git commit -m "$(printf 'Auto-cut Stable version(s)\n\n%s' "$(cat cut-version-summary.md)")" - git push --force "https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git" "$BRANCH" - if [ -z "$(gh pr list --head "$BRANCH" --state open --json number --jq '.[0].number')" ]; then - gh pr create --title "Auto-cut Stable version(s)" --body-file cut-version-summary.md --head "$BRANCH" --base main - else - gh pr edit "$BRANCH" --body-file cut-version-summary.md - fi - - # The approval has to come from a different actor than the PR's own - # author (the App, just above) — GITHUB_TOKEN's own actor - # (github-actions, distinct from the App) qualifies, same reasoning - # as dependabot-auto-merge.yml's own approval step. - - name: Approve - if: steps.check.outputs.changed == 'true' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh pr review --approve "automated/cut-versions" - - # Build + Test above already validated this exact commit, so this - # queues the merge rather than waiting on anything further by hand — - # `--auto` still only completes the merge once ci.yml's own - # "build-and-test" check (now actually running, since the PR has a - # real author) reports success, so a cut that somehow fails it sits - # open for a human instead of merging partway. Uses the App token, - # not GITHUB_TOKEN, so the merge commit on main is attributed to a - # real actor and fires deploy.yml. - - name: Enable auto-merge - if: steps.check.outputs.changed == 'true' - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - run: gh pr merge --auto --merge --delete-branch "automated/cut-versions" diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml deleted file mode 100644 index 52cddec..0000000 --- a/.github/workflows/dependabot-auto-merge.yml +++ /dev/null @@ -1,75 +0,0 @@ -name: Dependabot auto-merge - -# Approves and merges Dependabot's own PRs (currently just the gitsubmodule -# pin bumps from .github/dependabot.yml) without a human — see "Refreshing -# submodule pins automatically" in docs/website/how-it-works.mdx. -# -# Why this doesn't need a dedicated bot account: the prToMain ruleset's -# required-review rule blocks a PR's *author* from approving its own PR — -# it doesn't block a different actor from doing so. Dependabot opens the -# PR; this workflow's own GITHUB_TOKEN (a distinct actor, github-actions -# rather than dependabot) submits the approval. That's not self-approval, -# so GitHub accepts it. -# -# Why this is safe to merge without further human review: prToMain also -# requires the "build-and-test" status check (ci.yml) to pass before -# anything can merge — `gh pr merge --auto` queues the merge but won't -# complete it until that check reports success, so a submodule bump that -# breaks the build sits as an open, unmerged, failing PR instead of ever -# reaching main. -# -# Why pull_request_target and not pull_request: GitHub deliberately hands -# a read-only, secret-less token to a plain `pull_request`-triggered run -# on a Dependabot PR, specifically to stop a malicious bumped dependency -# from exfiltrating secrets — `gh pr review`/`gh pr merge` need a real -# token, so this needs pull_request_target's full-permission token instead. -# That trigger is a well-known footgun ONLY when a job also checks out and -# executes code from the PR head with that same elevated token — this job -# never does (no checkout step at all, just two API calls) — keep it that -# way; don't add one. -# -# Why auto-merge is enabled with the robotiq-readme-bot App token and not -# GITHUB_TOKEN: GitHub doesn't start workflow runs from events created by -# GITHUB_TOKEN, and an auto-merge is completed as whoever enabled it. With -# GITHUB_TOKEN, the merge commit on main never fired deploy.yml's `push` -# trigger, so main kept advancing while the live site stayed frozen for -# over a week. With the App token, the merge is attributed to the App, a -# real actor, and deploy.yml runs as it does for a human merge. The -# approval stays on GITHUB_TOKEN: it only needs to come from someone other -# than the PR's author (Dependabot). Same App as robotiq/.github's -# update-readme.yml; it must be installed on this repo, with APP_ID and -# APP_PRIVATE_KEY available here. -# -# If dependabot.yml ever grows a second ecosystem (npm, etc.), this same -# workflow will auto-merge those too, gated only by the actor check below -# and whatever ci.yml catches — revisit whether that's still desired then. - -on: pull_request_target - -permissions: - contents: write - pull-requests: write - -jobs: - automerge: - if: github.actor == 'dependabot[bot]' - runs-on: ubuntu-latest - steps: - - name: Approve - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_URL: ${{ github.event.pull_request.html_url }} - run: gh pr review --approve "$PR_URL" - - - name: Mint App token - id: app-token - uses: actions/create-github-app-token@v1 - with: - app-id: ${{ vars.APP_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - - - name: Enable auto-merge - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - PR_URL: ${{ github.event.pull_request.html_url }} - run: gh pr merge --auto --squash "$PR_URL" diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index a603668..311d1bc 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,16 +1,16 @@ name: Deploy to GitHub Pages +# Runs on every push to main, and daily via rebuild-daily.yml. Visitors see +# README changes without a rebuild (the Software Tools page fetches the latest +# robotiq/.github profile/README.md in their browser, see +# src/pages/software-tools.js); the daily rebuild keeps the build-time copy +# used as a fallback no more than a day old. No `schedule:` here: see +# rebuild-daily.yml for why. on: push: branches: - main workflow_dispatch: - # Backstop only: pushes to main (including Dependabot auto-merges, see - # dependabot-auto-merge.yml) are the normal trigger. This catches any - # merge path that ever fails to fire `push` again, within a day. It - # rebuilds even when main hasn't changed, which is harmless. - schedule: - - cron: '30 6 * * *' permissions: contents: read @@ -25,10 +25,6 @@ jobs: build: runs-on: ubuntu-latest steps: - # Submodules aren't checked out here — scripts/sync-external-docs.js - # runs `git submodule update --init --force` itself as part of the - # build, so doing it again via actions/checkout would just be a - # redundant second fetch. - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -39,14 +35,13 @@ jobs: - name: Install dependencies run: npm ci - # scripts/sync-external-docs.js shells out to the `doxygen` binary to - # build the C++ library's API reference, and needs graphviz (`dot`) too — - # see the matching step in ci.yml for why both are required. - - name: Install Doxygen and Graphviz - run: sudo apt-get update && sudo apt-get install -y doxygen graphviz - + # GITHUB_TOKEN only lifts the GitHub API rate limit for the README + # fetch in scripts/fetch-profile-readme.js (shared runner IPs can hit + # the unauthenticated 60 requests/hour); it grants nothing extra. - name: Build run: npm run build + env: + GITHUB_TOKEN: ${{ github.token }} - name: Upload artifact uses: actions/upload-pages-artifact@v3 diff --git a/.github/workflows/rebuild-daily.yml b/.github/workflows/rebuild-daily.yml new file mode 100644 index 0000000..06d518b --- /dev/null +++ b/.github/workflows/rebuild-daily.yml @@ -0,0 +1,32 @@ +name: Daily rebuild + +# Rebuilds the site once a day, so the build-time copy of robotiq/.github's +# profile/README.md (what search engines, no-JS and rate-limited visitors +# see on the Software Tools page) is never more than a day old, even when +# this repo doesn't change. +# +# Kept separate from deploy.yml on purpose: in a public repo GitHub disables +# a workflow with a `schedule:` trigger after 60 days without commits, and a +# disabled workflow stops running on every trigger. Here that only pauses +# this daily refresh (re-enable it from the Actions tab); deploys on push +# keep working. +# +# A workflow_dispatch created with GITHUB_TOKEN does start a new run (one of +# the exceptions to GitHub's "no runs from GITHUB_TOKEN events" rule), so no +# extra token or permission outside this repo is needed. +on: + schedule: + - cron: '30 6 * * *' + workflow_dispatch: + +permissions: + actions: write + +jobs: + trigger-deploy: + runs-on: ubuntu-latest + steps: + - name: Trigger deploy.yml + env: + GH_TOKEN: ${{ github.token }} + run: gh workflow run deploy.yml --repo "${{ github.repository }}" --ref main diff --git a/.gitignore b/.gitignore index d90fb16..545669d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,64 +7,9 @@ # Generated files .docusaurus .cache-loader -# Deliberately gitignored, not a gap: this is build-only, submodule-synced -# content with no independent source of truth to drift from — unlike -# docs/intro.mdx and every product's own index.mdx/ROS/index.mdx, which -# *are* committed and checked for drift in ci.yml's "Verify generated -# content is committed" step. -# -# Every page scripts/sync-external-docs.js produces under software-tools/ -# — a synced README partial, a synced docs/ guide, or the whole -# doxygen2docusaurus API tree — is plain CommonMark (.md); every -# hand-authored wrapper/landing page (including a folder's own index.mdx -# sitting next to synced siblings, e.g. -# software-tools///docs/index.mdx) is MDX (.mdx) — see the -# `markdown.format: 'detect'` comment in docusaurus.config.js, which relies on -# that same split. One generic pattern by extension, not a per-product path -# list: covers every current product (Adaptive grippers, EPick, Force -# Torque Sensor, Tactile Sensor) and any future one with no edit needed -# here when a new tool repo is onboarded — see "Checklist: onboarding a -# new C++ tool repo" in docs/website/api-reference-cpp.mdx. -software-tools/**/*.md -# Exception: Force Torque Sensor's C driver has no submodule/sync job in -# external-jobs.js yet (unlike every other _readme.md under -# software-tools/) — this one is a plain static file its wrapper -# index.mdx imports directly, so it must stay tracked despite the -# extension. Confirmed the only one: `find software-tools -iname '*.md' -# -not -iname '*.mdx'` cross-checked against every job's actual output -# before adding the blanket rule above. -!software-tools/Force Torque Sensor/Libraries/C/_readme.md - -# Stable's own Docusaurus version — used to be committed as a permanent, -# deliberate snapshot; isn't anymore. Every build now re-derives it fresh -# from source (scripts/ensure-stable-version.js, run via the `generate` -# prebuild hook — see docs/website/versioning.mdx), the exact same way -# software-tools/**/*.md above is: not because nothing decides its -# content, but because that decision — which tag each tool's Stable -# should track — lives in the one small file that *does* stay committed, -# software-tools-stable.json. Regenerating this from that file on every -# build, rather than freezing and committing the result once, is what -# stops Stable's content from being a full second copy of Latest's own -# content sitting in the repo. -software-tools_versioned_docs/ -software-tools_versioned_sidebars/ -software-tools_versions.json -# scripts/ensure-stable-version.js's own local cache — lets a repeated -# `npm start` during a normal dev session skip re-materializing Stable -# when software-tools-stable.json hasn't changed since the last run in -# this same working directory. Purely local bookkeeping, not something -# any other checkout needs to see. -/.stable-materialized.json - -# doxygen2docusaurus scratch output (scripts/sync-external-docs.js stages -# here, then copies the filtered result into docs/ — see external-jobs.js) -/.doxygen2docusaurus-staging -/doxygen2docusaurus.json -/scripts/generated/ - -# scripts/auto-cut-versions.js's own scratch output — read by -# .github/workflows/cut-versions.yml, never committed itself. -/cut-version-summary.md +# Snapshot of robotiq/.github's profile/README.md, fetched on every build by +# scripts/fetch-profile-readme.js — that repo is the source of truth. +/src/generated/ # Editor / machine-specific .vscode/ diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index b22fd13..0000000 --- a/.gitmodules +++ /dev/null @@ -1,12 +0,0 @@ -[submodule "external/tactile_sensors"] - path = external/tactile_sensors - url = https://github.com/Robotiq/tactile_sensors -[submodule "external/2f85_cpp"] - path = external/2f85_cpp - url = https://github.com/robotiq/grippers -[submodule "external/isaacsim_assets"] - path = external/isaacsim_assets - url = https://github.com/robotiq/isaacsim_assets -[submodule "external/robotiq_ros"] - path = external/robotiq_ros - url = https://github.com/robotiq/ros diff --git a/README.md b/README.md index 76474ea..e661cd9 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,40 @@ -# Purpose of this repository +# robotiq.github.io -This repository contains general documentation about Robotiq software tools for -developers. -The documentation is rendered into a static documentation website -accessible at the followng URL: -https://robotiq.github.io/ +Source of https://robotiq.github.io/: a landing page, a License page, and +a **Software Tools** page that renders the Robotiq GitHub organization's +landing page, +[`robotiq/.github`'s `profile/README.md`](https://github.com/robotiq/.github/blob/main/profile/README.md), +which indexes the software tools available for Robotiq products. +**To change the Software Tools page, edit that README in `robotiq/.github`.** +Nothing in this repository needs to change. Each tool's own documentation +lives in its repository. + +## How it works + +- The Software Tools page (`src/pages/software-tools.js`) shows the README + as rendered by GitHub. `scripts/fetch-profile-readme.js` saves a snapshot + at build time (`src/generated/`, gitignored; it runs automatically before + `npm start` and `npm run build`), so the page loads instantly and can be + indexed. The page then fetches the latest version in the visitor's + browser, so README changes appear without rebuilding this site. +- `.github/workflows/deploy.yml` rebuilds and redeploys the site on every + push to `main` in this repository, and daily via + `.github/workflows/rebuild-daily.yml`, which keeps the build-time copy of + the README no more than a day old. +- The landing page is `src/pages/index.js` (with + `src/components/HomepageFeatures`), the License page `src/pages/license.md`. +- Any other URL, including links to pages of the former documentation + site, redirects to https://github.com/robotiq (`src/theme/NotFound/Content`). + +## Local development + +```bash +npm ci +npm start # fetches the README, then serves the site at http://localhost:3000 +npm run build # fetches the README, then builds the static site into build/ +``` + +CI (`.github/workflows/ci.yml`) builds the site on every pull request and +checks that no production dependency is under a copyleft license +(`scripts/check-dependency-licenses.js`). diff --git a/docs/api-stability.mdx b/docs/api-stability.mdx deleted file mode 100644 index cfd828c..0000000 --- a/docs/api-stability.mdx +++ /dev/null @@ -1,41 +0,0 @@ ---- -title: Software Stability Policy -sidebar_label: Software stability policy ---- - -# Software stability policy - -This page applies to every Robotiq-maintained software tool covered by -this site's sitewide **Stable / Development (main)** switcher (see -[Documentation versioning](/docs/website/versioning) for how that -switcher works). - -## Only a tagged release is a commitment - -**Stable** always tracks a tool's newest tagged release. That's the only -version this site makes any compatibility commitment about — once a tag -is cut, the API it documents doesn't change under you. - -**Development (main)** documents whatever is currently on the source -repository's default branch, which can include work in progress: renamed -methods, changed signatures, new required parameters, or symbols removed -entirely, all without notice. Nothing on a Development (main) page is a -commitment, even if it looks finished. If you're integrating against one -of these tools, build against **Stable**, not Development (main). - -## Versioning scheme - -Each tool tags its own releases independently — there's no single -site-wide version number, since this site aggregates several -independently-released repositories. A tool's tags follow `vMAJOR.MINOR.PATCH` -(semantic versioning): a `MAJOR` bump can break compatibility, `MINOR` -adds functionality without breaking existing callers, and `PATCH` is a -fix with no API change. - -## Older releases - -Older tagged releases aren't archived on this site — only **Stable** and -**Development (main)** are real, rebuilt states. If you need documentation for a -specific older release, check out that tag in the tool's own GitHub -repository directly — the source and its own README/docs are the matching -reference for that exact release. diff --git a/docs/intro.mdx b/docs/intro.mdx deleted file mode 100644 index b867345..0000000 --- a/docs/intro.mdx +++ /dev/null @@ -1,81 +0,0 @@ ---- -title: Overview -sidebar_label: Overview -sidebar_position: 0 ---- - -## Introduction - -Many software tools are available for working with `Robotiq` products. Some -are developed and maintained by `Robotiq`, others by the developer community. - -This site documents the software tools developed and maintained by `Robotiq` -and references those developed by the community. - -:::info -For details about `Robotiq` product hardware, please refer to the corresponding -hardware manual on the [Robotiq support website](https://robotiq.com/support). -::: - -This site has a sitewide **Stable / Development (main)** switcher at the -top of every page that covers every `Robotiq`-maintained tool. **Stable** is -the version you want if you're integrating against one of these tools — -it always tracks that tool's newest tagged release, and is the only -version for which this site makes any compatibility commitment. -**Development (main)** documents in-progress work and can change without -notice. See the [software stability policy](/docs/api-stability) for the -full details. - -## Software tools - -Below is a summary of the available tools. - -Badge colors indicate who maintains the integration: ![Robotiq](https://img.shields.io/badge/Robotiq-blue) an official `Robotiq`-maintained driver, ![Third party](https://img.shields.io/badge/Third_party-lightgrey) a community-maintained project. - -{/* AUTO-GENERATED-LIBRARIES-TABLE:START */} -### Libraries - -| Product | C | C++ | Python | -|---|---|---|---| -| [Adaptive grippers](drivers/Adaptive%20grippers) | - | [![Robotiq](https://img.shields.io/badge/Robotiq-blue)](drivers/Adaptive%20grippers/Libraries/C++) | [![Third party](https://img.shields.io/badge/Third_party-lightgrey)](drivers/Adaptive%20grippers/Libraries/Python) | -| [Force Torque Sensor](drivers/Force%20Torque%20Sensor) | [![Robotiq](https://img.shields.io/badge/Robotiq-blue)](drivers/Force%20Torque%20Sensor/Libraries/C) | - | [![Third party](https://img.shields.io/badge/Third_party-lightgrey)](drivers/Force%20Torque%20Sensor/Libraries/Python) | -| [Tactile Sensor](drivers/Tactile%20Sensor) | - | [![Robotiq](https://img.shields.io/badge/Robotiq-blue)](drivers/Tactile%20Sensor/Libraries/C++) | [![Robotiq](https://img.shields.io/badge/Robotiq-blue)](drivers/Tactile%20Sensor/Libraries/Python) | - -- **C** — Compiled, performance-oriented language. -- **C++** — Compiled, performance-oriented object-oriented language. -- **Python** — Interpreted, prototyping-oriented language. -{/* AUTO-GENERATED-LIBRARIES-TABLE:END */} - -{/* AUTO-GENERATED-ROS-TABLE:START */} -### ROS - -| Product | ROS | -|---|---| -| [Adaptive grippers](drivers/Adaptive%20grippers) | [![Robotiq](https://img.shields.io/badge/Robotiq-blue)](drivers/Adaptive%20grippers/ROS) | -| [EPick](drivers/EPick) | [![Third party](https://img.shields.io/badge/Third_party-lightgrey)](drivers/EPick/ROS) | -| [Force Torque Sensor](drivers/Force%20Torque%20Sensor) | [![Third party](https://img.shields.io/badge/Third_party-lightgrey)](drivers/Force%20Torque%20Sensor/ROS) | -| [Tactile Sensor](drivers/Tactile%20Sensor) | [![Robotiq](https://img.shields.io/badge/Robotiq-blue)](drivers/Tactile%20Sensor/ROS) | -{/* AUTO-GENERATED-ROS-TABLE:END */} - -{/* AUTO-GENERATED-SIMULATION-TABLE:START */} -### Simulation - -| Product | Isaac Sim | PyBullet | MuJoCo | -|---|---|---|---| -| [Adaptive grippers](drivers/Adaptive%20grippers) | [![Robotiq](https://img.shields.io/badge/Robotiq-blue)](drivers/Adaptive%20grippers/Simulation/Isaac%20Sim) | [![Third party](https://img.shields.io/badge/Third_party-lightgrey)](drivers/Adaptive%20grippers/Simulation/PyBullet) | [![Third party](https://img.shields.io/badge/Third_party-lightgrey)](drivers/Adaptive%20grippers/Simulation/MuJoCo) | -| [Tactile Sensor](drivers/Tactile%20Sensor) | [![Third party](https://img.shields.io/badge/Third_party-lightgrey)](drivers/Tactile%20Sensor/Simulation/Isaac%20Sim) | - | - | - -- **Isaac Sim** — NVIDIA Isaac Sim integration for simulating the hardware. -- **PyBullet** — PyBullet integration for physics-based simulation. -- **MuJoCo** — MuJoCo (MJCF) model for physics-based simulation. -{/* AUTO-GENERATED-SIMULATION-TABLE:END */} - -{/* AUTO-GENERATED-OTHER-TABLE:START */} -### Other community projects - -| Product | GraspGen | -|---|---| -| [Adaptive grippers](drivers/Adaptive%20grippers) | [![Third party](https://img.shields.io/badge/Third_party-lightgrey)](drivers/Adaptive%20grippers/Other/GraspGen) | - -- **GraspGen** — NVIDIA GraspGen asset/model package with Robotiq gripper definitions for grasp synthesis research. -{/* AUTO-GENERATED-OTHER-TABLE:END */} \ No newline at end of file diff --git a/docs/license.mdx b/docs/license.mdx deleted file mode 100644 index a77aedc..0000000 --- a/docs/license.mdx +++ /dev/null @@ -1,63 +0,0 @@ ---- -title: License -sidebar_label: License ---- - -# License - -## This site - -The content and source code of this documentation site are licensed -under the BSD 3-Clause License — see the -[`LICENSE`](https://github.com/robotiq/robotiq.github.io/blob/main/LICENSE) -file at the root of the repository for the full text. - -## Third-party packages - -This site is built with a number of open-source npm packages, each under -its own license. None of its production dependencies, direct or -transitive, carry a copyleft license (GPL, AGPL, LGPL, SSPL, or BUSL-1.1) -— this is checked automatically on every pull request. See -[Third-party notices](/docs/third-party-notices) for the generated list -of direct dependencies. - -## Documentation content - -Documentation pages under `software-tools/` are synced from the source -repositories of the tools they document (e.g. `tactile_sensors`, -`2f85_cpp`, `robotiq_ros`); each tool's own repository is the authoritative -source for its license. - -Some pages reference third-party product or project logos to identify -the technologies a given tool integrates with. These are used for -identification purposes only and remain the property of their respective -owners: - -| Logo | File | Source | -|---|---|---| -| C++ | `C++-Logo.wine.png` | logo.wine (third-party aggregator — not fetched directly from the ISO C++ Foundation) | -| GitHub | `GitHub_Invertocat_blue.png` | GitHub's own logo/brand kit | -| GraspGen | `graspgen.jpg` | NVIDIA | -| MuJoCo | `mujoco.jpg` | Google DeepMind | -| NVIDIA Isaac Sim | `nvidia-isaac.webp` | NVIDIA | -| PyBullet | `pybullet.png` | PyBullet / Bullet Physics | -| Python | `python-logo-master-v3-TM-flattened.png` | Python.org's own brand kit | -| ROS | `ros2.webp` | Open Robotics / ROS | - -## Firmware and other non-website content - -Some linked source repositories contain files under licenses other than -this site's own — for example, `tactile_sensors`' `firmware/bootloader_host.py` -is licensed GPL-3.0-or-later. This documentation site does not bundle or -redistribute that file; it only links to it as source-code documentation. -Anyone redistributing that file, or a product that bundles it, should -consult `tactile_sensors`' own repository and license directly — that -obligation is out of scope for this site. - -## Keeping this page current - -The [third-party notices](/docs/third-party-notices) list regenerates on -every build, so it never drifts from `package.json`. The rest of -this page (the logo inventory and the firmware note above) is reviewed -manually whenever a submodule or a dependency changes in a way that -affects it, and at least once a year regardless. diff --git a/docs/third-party-notices.mdx b/docs/third-party-notices.mdx deleted file mode 100644 index 5d9858b..0000000 --- a/docs/third-party-notices.mdx +++ /dev/null @@ -1,24 +0,0 @@ ---- -title: Third-Party Notices -sidebar_label: Third-party notices ---- - -# Third-party notices - -This site is built with the open-source packages listed below, each under -its own license, and their transitive dependencies — see -[`package-lock.json`](https://github.com/robotiq/robotiq.github.io/blob/main/package-lock.json) -for the full tree. Every production dependency, direct or transitive, is -checked against a permissive-license allowlist on each pull request. See -[License](/docs/license) for this site's own license. - -- [@docusaurus/core](https://www.npmjs.com/package/@docusaurus/core) — MIT -- [@docusaurus/faster](https://www.npmjs.com/package/@docusaurus/faster) — MIT -- [@docusaurus/plugin-client-redirects](https://www.npmjs.com/package/@docusaurus/plugin-client-redirects) — MIT -- [@docusaurus/preset-classic](https://www.npmjs.com/package/@docusaurus/preset-classic) — MIT -- [@docusaurus/theme-mermaid](https://www.npmjs.com/package/@docusaurus/theme-mermaid) — MIT -- [@mdx-js/react](https://www.npmjs.com/package/@mdx-js/react) — MIT -- [clsx](https://www.npmjs.com/package/clsx) — MIT -- [prism-react-renderer](https://www.npmjs.com/package/prism-react-renderer) — MIT -- [react](https://www.npmjs.com/package/react) — MIT -- [react-dom](https://www.npmjs.com/package/react-dom) — MIT diff --git a/docs/website/adding-a-tool.mdx b/docs/website/adding-a-tool.mdx deleted file mode 100644 index c87b241..0000000 --- a/docs/website/adding-a-tool.mdx +++ /dev/null @@ -1,296 +0,0 @@ ---- -title: Adding a New Software Tool -sidebar_label: Adding a new tool -displayed_sidebar: websiteSidebar ---- - -# Step-by-step: adding a new software tool - -The steps below add a Python tool for the **Adaptive grippers** family hosted -at `https://github.com/robotiq/2f85-python-driver`. Every product/tool page -(versioned or not) lives under `software-tools/` and is served by the -shared `software-tools` Docusaurus instance — see -[Documentation versioning](./versioning) for why: two plugin instances -can't split ownership of one URL prefix, and every tool's page lives under -`/docs/drivers/*`. - -**If the new tool is Robotiq-maintained and submodule-synced** (as opposed -to a third-party or not-yet-available tool), it should usually also join -the sitewide **Stable / Development (main)** switcher, matching every -other Robotiq-maintained tool on this site — see -[Documentation versioning](./versioning) once the steps below are done. -That's just two extra steps (tagging the sync job with a `toolId`, and -one `versioned(...)` entry in the nav tree — see -[Documentation versioning](./versioning#checklist-adding-versioning-to-a-new-tool)'s -checklist) — it doesn't change where the tool's files live or how the -sync job itself is declared, both already the same either way; only -whether that tool participates in Stable/Development (main) cuts. - -## 1. Add the submodule - -This registers the tool's repository as a pinned import under -`external/`. Every contributor who clones this site will get the -same version of the source repo. - -```bash -git submodule add \ - https://github.com/robotiq/2f85-python-driver \ - external/2f85_python -git submodule update --init -``` - -## 2. Declare the sync job - -Open [`scripts/external-jobs.js`](https://github.com/robotiq/robotiq.github.io/blob/main/scripts/external-jobs.js) -and add an entry inside a `submoduleJobs(submodule, { repoUrl, branch }, -[...])` call — that helper merges the shared `submodule`/`repoUrl`/`branch` -fields into every job passed to it, so a submodule with several jobs -(README, docs/, API reference, ...) states them once instead of repeating -them on each entry. Start a new call for a new submodule: - -```js -...submoduleJobs('2f85_python', { repoUrl: 'https://github.com/robotiq/2f85-python-driver', branch: 'main' }, [ - { from: 'README.md', to: 'Adaptive grippers/Libraries/Python/_readme.md', destRoot: 'software-tools' }, -]), -``` - -`destRoot: 'software-tools'` is what every driver job needs (see -[Documentation versioning](./versioning)) — content outside `software-tools/` -lands in the default `docs` instance's own tree instead, which doesn't -serve anything under `/docs/drivers/*`. - -For a repo that contains multiple tools, add one job per tool inside the -same call: - -```js -...submoduleJobs('2f85_drivers', { repoUrl: '...', branch: 'main' }, [ - // C++ tool - { from: 'sdk_cpp/README.md', to: 'Adaptive grippers/Libraries/C++/_readme.md', destRoot: 'software-tools' }, - // Python tool - { from: 'python/README.md', to: 'Adaptive grippers/Libraries/Python/_readme.md', destRoot: 'software-tools' }, -]), -``` - -If the submodule already has a `submoduleJobs(...)` call elsewhere in -`JOBS` (e.g. you're adding a second tool from a repo already used for -another one), add your job to its existing `jobs` array instead of -starting a new call — one `submoduleJobs(...)` per submodule. - -Test locally: - -```bash -node scripts/sync-external-docs.js -``` - -## 3. Create the wrapper page - -Create `software-tools/Adaptive grippers/Libraries/Python/index.mdx`. This file -is tracked in git and controls the page title, sidebar label, and -any introductory text above the synced README: - -```mdx ---- -title: Python -sidebar_label: Python -sidebar_position: 2 ---- - -![Libraries](https://img.shields.io/badge/Category-Libraries-lightgrey) - -![Supported by Robotiq](https://img.shields.io/badge/Supported_by-Robotiq-blue) - -Brief description and link to the source repository. - -## Intro - -import Readme from './_readme.md'; - - -``` - -The `## Intro` heading and the import are optional — omit them if -there is no synced README or if the content should start directly. - -**Both badges are required, not decorative** — `generate-tools-table.js` -walks the folder tree looking for the `Category` badge to decide which -table a page belongs to, and reads the `Supported_by` badge for the cell -shown in that table (see -[Auto-generated software tools tables](./tools-tables)). Valid `Category` -values: `Libraries`, `Simulation`, `Other`, `ROS`. Use -`Supported_by-Robotiq-blue` for tools developed and maintained by Robotiq, -or `Supported_by-Third_party-lightgrey` for community-maintained tools. - -**`ROS` is one page per product, not one per distro or generation.** -There's no `ROS1`/`ROS2` split — a product gets at most a single -`Category-ROS` leaf, `software-tools//ROS/index.mdx`, covering -whatever ROS integration that product has. Which specific ROS distros it -supports is the driver's own repo README's job, not this page's. For a -Robotiq-maintained ROS driver, this page is synced exactly like the -Tactile Sensor C++ library page in [step 3 above](#3-create-the-wrapper-page) — -a submodule, a sync job pulling its README, and a thin wrapper importing -it: - -```mdx ---- -title: ROS -sidebar_label: ROS ---- - -![Category](https://img.shields.io/badge/Category-ROS-lightgrey) -![Supported by Robotiq](https://img.shields.io/badge/Supported_by-Robotiq-blue) - -Brief description and link to the source repository. - -## Intro - -import Readme from './_readme.md'; - - -``` - -For a third-party ROS integration, write it by hand instead, same as any -other no-README tool (see "No README or no software tool yet?" below) — -`Supported_by-Third_party-lightgrey`, short description, and a -**Reference:** link to the community repository. - -Since this page is now a single leaf directly under `ROS/`, not a -container, it does **not** get a separate dedicated landing page the way -Libraries/Simulation/Other do — see -[step 4](#4-create-the-product-landing-page) for why. - -**No README or no software tool yet?** Skip steps 1 and 2 entirely -and write the `index.mdx` manually. This is the right approach when -a tool is planned but not yet available, or when the source repo has -no suitable README to pull in. Write the page content directly with -no import: - -```mdx ---- -title: Python -sidebar_label: Python -sidebar_position: 2 ---- - -![Libraries](https://img.shields.io/badge/Category-Libraries-lightgrey) - -![Supported by Robotiq](https://img.shields.io/badge/Supported_by-Third_party-lightgrey) - -Coming soon. In the meantime, see -[org/repo](https://github.com/robotiq/...) on GitHub. -``` - -The page still appears in the sidebar and can be updated to import -a synced README later, once the tool or its documentation exists. - -## 4. Create the product landing page - -If the product folder has no `index.mdx` yet, create -`software-tools/Adaptive grippers/index.mdx`: - -```mdx ---- -title: Adaptive grippers -sidebar_label: Adaptive grippers -sidebar_position: 0 ---- - -Short description of the product family. - -## Available drivers - -{/* AUTO-GENERATED-PRODUCT-LIBRARIES-TABLE:START */} -{/* AUTO-GENERATED-PRODUCT-LIBRARIES-TABLE:END */} - -{/* AUTO-GENERATED-PRODUCT-ROS-TABLE:START */} -{/* AUTO-GENERATED-PRODUCT-ROS-TABLE:END */} - -{/* AUTO-GENERATED-PRODUCT-SIMULATION-TABLE:START */} -{/* AUTO-GENERATED-PRODUCT-SIMULATION-TABLE:END */} - -{/* AUTO-GENERATED-PRODUCT-OTHER-TABLE:START */} -{/* AUTO-GENERATED-PRODUCT-OTHER-TABLE:END */} -``` - -Don't write any of these tables by hand — leave each marker pair where -shown and `scripts/generate-tools-table.js` fills in a single-row version -of the matching category's table (see -[Auto-generated software tools tables](./tools-tables)) on the next -build, including that category's own heading (e.g. `### Libraries`, -`### ROS`) written *inside* the marker pair. A category with no tool yet -writes nothing between its markers at all — heading included — so leave -each empty pair exactly as shown above; the whole section simply won't -appear until it has its first tool. - -**For each of `Libraries`/`Simulation`/`Other` the product actually has -any tool pages in**, *also* create a matching dedicated sub-page, e.g. -`software-tools/Adaptive grippers/Libraries/index.mdx`: - -```mdx ---- -title: Libraries -sidebar_label: Libraries ---- - -{/* AUTO-GENERATED-PRODUCT-LIBRARIES-TABLE:START */} -{/* AUTO-GENERATED-PRODUCT-LIBRARIES-TABLE:END */} -``` - -This is what a click on that category in the sidebar actually lands on — -the product page's own table is a quick, at-a-glance summary, and the -dedicated page is where that summary is reachable as its own page. -`generate-tools-table.js` throws a build error naming the missing file if -a product has tool pages in one of these three categories but no matching -`/index.mdx` with these markers; a category with **no** tool -pages for this product never gets one at all — nothing to make a page -out of, so that category's whole section simply doesn't appear on the -product's own page, above, and there's no dedicated page either. - -**`ROS` is the one exception — it never gets a dedicated landing page.** -A product has at most one `Category-ROS` leaf, so there's no multi-item -table to land on beyond the leaf page itself; `ROS/index.mdx` created in -[step 3](#3-create-the-wrapper-page) above is both the category folder -*and* the real content page, with no separate landing step here. - -## 5. Register in `site-nav-tree.mjs` - -Add the tool's node to `scripts/site-nav-tree.mjs`'s `SITE_TREE` — the -single source of truth for the whole "Software Tools" nav tree, shared by -`sidebars.software-tools.js` (the real sidebar) and `sidebars.js`'s -`overviewSidebar` (the plain-link copy shown on `docs/intro.mdx`, which -lives on a different plugin instance and can't display this one's sidebar -directly). Doc ids are relative to `software-tools/`, with no `drivers/` -prefix — that prefix is only the URL's own `routeBasePath`, added by -Docusaurus itself, not part of the doc id: - -```js -category('Adaptive grippers', [ - category('Libraries', [ - leaf('Adaptive grippers/Libraries/C++/index'), - leaf('Adaptive grippers/Libraries/Python/index'), - ]), - leaf('Adaptive grippers/ROS/index'), - category('Simulation', [ - leaf('Adaptive grippers/Simulation/Isaac Sim/index'), - leaf('Adaptive grippers/Simulation/PyBullet/index'), - ]), - category('Other', [ - leaf('Adaptive grippers/Other/GraspGen/index'), - ]), -], 'Adaptive grippers/index'), -``` - -`ROS` is a plain `leaf`/`versioned` node, not a `category` — a product -has at most one `Category-ROS` page, so there's nothing to expand into. -`category(label, items, docId?)` takes an optional trailing doc id, only -when that category's own landing page exists (e.g. the product's own -`index.mdx`) — omit it and the category header is still expandable, just -not itself clickable, same as Force Torque Sensor's entry (no -`Simulation`/`Other` groups yet, since it has no tools there). - -**A submodule-backed tool that also joins Stable/Development (main) versioning** uses -a `versioned(label, toolId)` node instead of `leaf(docId)` — see -[Documentation versioning](./versioning#checklist-adding-versioning-to-a-new-tool) -for the full checklist (it also needs its sync job in -`scripts/external-jobs.js` tagged with that same `toolId` — everything -else, `scripts/versioned-tools.js` and `sidebars.software-tools.js`'s -`activeItems` map, derives from that automatically). diff --git a/docs/website/api-reference-cpp.mdx b/docs/website/api-reference-cpp.mdx deleted file mode 100644 index b9a5c9b..0000000 --- a/docs/website/api-reference-cpp.mdx +++ /dev/null @@ -1,669 +0,0 @@ ---- -title: C++ API Reference — Doxygen + doxygen2docusaurus -sidebar_label: C++ (Doxygen) -displayed_sidebar: websiteSidebar ---- - -# C++ — Doxygen + doxygen2docusaurus - -**In the tool repository**, add Doxygen-style comments to headers -and commit a `Doxyfile` configured to output both XML (for -doxygen2docusaurus, below) and Doxygen's own HTML (for the standalone -preview): - -``` -# Doxyfile (relevant lines) -GENERATE_XML = YES -XML_OUTPUT = doxygen-xml -GENERATE_HTML = YES -HTML_OUTPUT = doxygen-html -INPUT = . -RECURSIVE = YES -# Without these, every generated page's "#include <...>" line collapses to -# the bare filename (Doxygen's default: the shortest name that's still -# unique across the whole scanned tree) instead of the real, usable path — -# e.g. "#include " instead of -# "#include ". -FULL_PATH_NAMES = YES -STRIP_FROM_INC_PATH = include -``` - -## Controlling what's included - -Two independent knobs decide what ends up in the generated reference — -both live in the **tool repository**, not in this site's -`scripts/sync-external-docs.js`: - -- **`Doxyfile` — what gets documented at all**, symbol by symbol. Standard - Doxygen options: `EXCLUDE` / `EXCLUDE_PATTERNS` skip whole files or - directories from being scanned (e.g. `third_party/`, `tests/`). With the - default `EXTRACT_ALL = NO`, anything left undocumented simply never gets - a page — and `WARN_IF_UNDOCUMENTED = YES` plus `WARN_AS_ERROR = - FAIL_ON_WARNINGS` (both on the `2f85_cpp` submodule's own `Doxyfile`) turns - a forgotten doc comment into a CI failure instead of a silent gap. - - **To keep one specific, already-documented symbol out of the generated - docs entirely, wrap it — not the whole file — in - `//! \cond DOXYGEN_EXCLUDE` / `//! \endcond`.** This is the only - mechanism that removes a symbol from Doxygen's XML output completely, so - there's nothing left for either `WARN_IF_UNDOCUMENTED` or this site's own - build to trip over. **`EXCLUDE_SYMBOLS` does *not* do this** — it only - drops a symbol out of *group* listings; the symbol still shows up as a - fully documented, ungrouped namespace member, which is exactly the - "ungrouped, no page" problem the next bullet describes. `\internal ... - \endinternal` has the same gap as `EXCLUDE_SYMBOLS` for this purpose. -- **A symbol's own `\ingroup` vs `\addtogroup` — which group it belongs to, - and *how*.** `\ingroup ` on a single entity (a class, a function, a - namespace) records only that one entity as a group member — it does - **not** cascade to whatever's declared inside it. A free function/enum/ - variable tagged `\ingroup` still shows up in its own namespace's XML too, - but only as a lightweight cross-reference — the full definition (and the - only page that documents it) lives on its **group's** page. This is why - this site's Global Index (see below) has to resolve those cross-references - itself rather than trust Doxygen's or doxygen2docusaurus's own indices, - which are both organized by lexical scope (class/namespace), not by - group. To make a batch of free functions or constants themselves *direct* - members of a group — so they render right on the group's own page — wrap - them in `\addtogroup ` / `@{ ... @}`: - ```cpp - //! \addtogroup - //! @{ - - inline constexpr int kSomeConstant = 1; //!< ... - // every declaration up to the matching @} becomes a direct group member - - //! @} - ``` - (Illustrative — nothing in the `2f85_cpp` submodule currently uses - `\addtogroup`; the last symbol that did, `register_map.hpp`'s constants, - is now excluded entirely. Don't point this example at a real symbol name — - that's exactly the kind of reference that goes stale the next time - something upstream gets renamed, regrouped, or excluded.) - This is also what makes a group's content show up in this site's sidebar - automatically with no extra sync job — see - [The sidebar mirrors the Doxygen group hierarchy automatically](#the-sidebar-mirrors-the-doxygen-group-hierarchy-automatically) - below. - - **A documented-but-ungrouped symbol is easy to miss by hand** — Doxygen - stays completely silent about it; it just quietly never shows up under - any Topic in the generated navigation, even though it's technically - "documented." `sdk_cpp/tools/check_doc_groups.py` (vendored in the - `2f85_cpp` submodule; see - [templates/check_doc_groups.py](https://github.com/robotiq/robotiq.github.io/blob/main/templates/check_doc_groups.py) - here for the copy-pasteable starting point for a new tool repo) closes - that gap: it cross-references Doxygen's own XML (run `doxygen Doxyfile` - first) for every namespace-scope symbol with no `\ingroup`, and exits - non-zero listing each one — wired into that repo's own CI as part of the - `api-docs` job, right after `doxygen Doxyfile`. This site's own Global - Index (below) still lists an ungrouped symbol regardless — unlinked, - since there's no group page to point at — so a gap that slips past CI - is still visible here, just not where a reader would expect it. -- **`scripts/external-jobs.js`'s own `exclude` option** (on the - `doxygen2docusaurus` job) trims specific generated files/folders this - site doesn't want — `files`, `folders`, `namespaces` and their matching - `indices/*` alphabetical listings are dropped entirely (superseded by the - Global Index — see below), and a handful of the "Classes" category's own - A-Z listings are dropped too (its tree overview at `indices/classes/index` - already covers browsing by class; the flat by-kind lists next to it were - pure duplication). See the comments on that job's `exclude` array for the - current list and why each entry is there. - -## Compile-checked examples with `\snippet` - -**Don't write example code directly inside a `\code{.cpp}` ... `\endcode` -block in a doc comment.** Nothing compiles it — it can drift out of sync -with the API it's demonstrating (a renamed member, a changed signature) -and nobody finds out until a reader copy-pastes it and it fails to build. -This applies to the **C++ library only** — Python's API reference is generated -by [pydoc-markdown](./api-reference-python) from docstrings directly, which -has no equivalent mechanism; a compile/run-checked Python example story -would need something else entirely (e.g. doctest-style testing) and isn't -covered here. - -Instead, put the example in a real file under `sdk_cpp/examples/` — already -built by the tool repo's own CMake (`GRIPPERS_BUILD_EXAMPLES`), so a change -that breaks the example is a compile error in that build, not a silently -stale doc page — and pull the relevant part into the doc comment with -Doxygen's `\snippet`, tagging the region in the example file: - -```cpp -// sdk_cpp/examples/move_gripper.cpp -//! [activation-recovery] -ActivationResult activation = Robotiq::activate(*gripper); -if(activation == ActivationResult::FaultLatched) -{ - activation = Robotiq::recoverFromFault(*gripper); -} -//! [activation-recovery] -``` - -```cpp -// sdk_cpp/include/Robotiq/gripper.hpp -//! \par Example -//! \snippet move_gripper.cpp activation-recovery -[[nodiscard]] ActivationResult activate(Gripper& gripper, ...); -``` - -Doxygen resolves `\snippet` into the actual tagged source before it ever -writes the XML doxygen2docusaurus reads — so this needs nothing new from -`sync-external-docs.js` or any other script in this repo; it flows through -the existing Doxygen → doxygen2docusaurus → sync pipeline exactly like a -hand-written `\code` block would, just backed by real, compiled source -instead. - -**Setting up a new submodule for this** — everything below lives in the -**tool repo**, not here; once it's in place, `\snippet` just works through -the existing pipeline with no change needed in this site: - -1. Add `EXAMPLE_PATH = examples` to that submodule's `Doxyfile` (relative to - the Doxyfile itself, same as `INPUT = include`) — the folder containing - the example files you'll tag. -2. Set `WARN_AS_ERROR = YES` (or `WARN_AS_ERROR = FAIL_ON_WARNINGS` on newer - Doxygen) so a `\snippet` referencing a typo'd or renamed tag fails the - docs build instead of silently degrading to a warning. -3. Make sure that submodule's example files are actually built somewhere in - CI (e.g. a CMake option like `GRIPPERS_BUILD_EXAMPLES`, on by default) — - `\snippet` only guarantees the *doc comment* matches the *tagged region*; - a real build is what guarantees the tagged region itself still compiles. -4. Tag the region you want to reuse with a `//! [tag]` ... `//! [tag]` pair - in a real, compiled file under `EXAMPLE_PATH`. -5. Replace the doc comment's `\code{.cpp}` ... `\endcode` block with - `\par Example` followed by `\snippet `. - -The `2f85_cpp` submodule this site already builds against follows this -exact pattern across three files under `sdk_cpp/examples/`: `quick_start.cpp` -(the walkthrough guide cites this one, tag by tag), `move_gripper.cpp` (a -full runtime example — `activation-recovery` above comes from here), and a -catch-all `snippets.cpp` for concepts that don't fit either narrative (a -custom `Logger`/`Serial` subclass, `NamedBitArray`, `Throttle`, raw -register-map byte decoding, ...) — each snippet its own never-called -function or class, tagged and referenced the same way. - -Not every `\code` block needs converting: a few (e.g. the byte-layout -tables in `command.hpp` / `register_map.hpp`) are ASCII diagrams, not -compilable statements, and should stay as plain `\code` blocks. - -## Verifying markdown code examples against real source - -`\snippet` only reaches Doxygen doc-comments — it can't help a hand-authored -guide page (e.g. `docs/02-quick-start.md`, walking through `quick_start.cpp` -step by step). Those pages still risk the exact same drift a `\code` block -does: a hand-typed code fence that quietly stops matching the real file it -claims to demonstrate. - -A tool repo opts a fence into the same guarantee with an HTML-comment marker -directly above it: - -`````md - -```cpp -Robotiq::ConnectionConfig config; -config.serial.port = "COM4"; //or "/dev/ttyUSB0" for linux. Adjust the port name according to your system. -``` -````` - -— pointing at the same kind of `//! [qs-config]`-bracketed region in -`sdk_cpp/examples/quick_start.cpp` that `\snippet` itself would use. Two -independent things check this claim, both in the **tool repo**: - -- `sdk_cpp/tools/check_doc_snippets.py` (grippers vendors this; see - [templates/check_doc_snippets.py](https://github.com/robotiq/robotiq.github.io/blob/main/templates/check_doc_snippets.py) - in *this* repo for the copy-pasteable starting point for a new tool repo), - wired into that repo's own CI — fails a PR the moment the doc and the - source disagree. -- `scripts/check-doc-snippets.js` **here**, driven by a `docSnippetsCheck` - entry on that submodule's job in `external-jobs.js`. It runs the exact - script vendored *in the submodule at its pinned commit* (never the - `templates/` copy above — that one is never executed, only copied from) as - part of `npm run generate`/`npm run preview`, so this site's own build - fails too, not just the tool repo's CI. This is deliberately redundant: - it's the only one of the two that runs while you're previewing - **uncommitted** edits to a submodule you're actively working on (see - [Previewing local edits to a submodule](./#previewing-local-edits-to-a-submodule) - above) — that tool repo's own CI hasn't seen those edits yet at all. This - check is entirely independent of the Doxygen/doxygen2docusaurus pipeline - below — it only concerns the submodule's own hand-authored `docs/` guides. - -Unlike `\snippet`, nothing here regenerates or rewrites the markdown — both -checks only fail loudly on a mismatch, the same way a broken `\snippet` tag -fails the Doxygen build. Fixing a reported mismatch always means editing the -**tool repo** (either side: the guide's fence or the tagged region in the -example file) — never this repo. - -**Adopting this for a new tool repo:** -1. Copy `templates/check_doc_snippets.py` into that repo (e.g. - `sdk_cpp/tools/check_doc_snippets.py`), adjusting `--examples-dir`'s - default if its example files don't live under `sdk_cpp/examples/`. -2. Bracket the region a guide page cites with a `//! [tag]` ... `//! [tag]` - marker pair in the real example file, and mark the guide's fence with - `` directly above it. -3. Wire the script into that repo's own CI (`python3 docs/*.md`). -4. Add a `docSnippetsCheck: { script, markdownGlob, examplesDir }` entry to - that submodule's job in `scripts/external-jobs.js` here (see the - `2f85_cpp` docs job for a worked example) — no other change needed; - `scripts/check-doc-snippets.js` picks up any job that declares one. - -## The sidebar mirrors the Doxygen group hierarchy automatically - -`sidebars.software-tools.js` doesn't hand-list the C++ API's groups. -doxygen2docusaurus generates its own sidebar subtree directly from the -Doxygen XML — no scanning generated Markdown for backlinks the way this -site's previous Doxybook2-based pipeline needed a whole dedicated script -for. `scripts/sync-external-docs.js` prunes and adapts that generated -subtree (dropping the excluded folders/pages mentioned above), writes the -result to `scripts/generated/doxygen-sidebar--.json`, -and `sidebars.software-tools.js` just reads it back: - -```js -items: loadDoxygenSidebarItems('Adaptive grippers/Libraries/C++/API'), -``` - -**Classes are re-nested under their owning group.** doxygen2docusaurus's own -sidebar keeps two separate top-level trees — "Topics" (the -`\defgroup`/`\ingroup` hierarchy) and "Classes" (every class flattened -together) — with no built-in option to merge them. `sync-external-docs.js` -does that merge itself: each group page's own generated "Classes" heading -(inside its member-overview table — see below) already lists exactly which -classes it owns, so that's read back out of the *finished* docs output and -those sidebar nodes are moved from "Classes" into their owning group. This -runs a **post-order** walk (children before parents) specifically because -several group pages roll their subgroups' classes up onto their own -overview too — without processing the deepest group first and removing a -class from consideration once claimed, a class ends up double-listed under -both its true owner and every ancestor that rolled it up. - -Once every class that has a group has moved, the old "Classes" category — -by then just a tree-overview link with nothing of its own left to add — is -removed outright in favor of the [Global Index](#global-index) below. - -This means adding, renaming, or removing a `\defgroup`/`\ingroup` upstream -needs no `sidebars.software-tools.js` edit — but see the ⚠️ note in -[Previewing local edits to a submodule](./#previewing-local-edits-to-a-submodule) -above: sidebar generation only runs once, at dev-server startup (as part of -`npm run generate`), so adding or removing a *group* (not just editing one's -content) needs a server restart to show up while previewing. - -## Global Index - -Doxygen's own alphabetical indices — and doxygen2docusaurus's — split by -*lexical scope*: "Class Members" vs. "Namespace Members". Because this library -organizes almost everything free-standing into Modules via -`\ingroup`/`\addtogroup` instead (see -[Controlling what's included](#controlling-whats-included) above), a -grouped free function/enum/variable/typedef doesn't fully appear in either -index — its namespace's XML only holds a bare cross-reference to it, not -the full definition. - -`generateFreeSymbolsIndex` in `scripts/sync-external-docs.js` builds a -page that actually is exhaustive — every class, and every free function, -variable, data type, and enum in the project, regardless of how it's -grouped — by reading the Doxygen XML directly rather than relying on either -tool's own indices: - -- Walks every namespace this library actually has, discovered fresh each run - from Doxygen's own `index.xml` (`discoverNamespaceXmlPaths`) rather than a - hand-maintained list of namespace names — so a namespace added upstream - (this library has grown `Robotiq::profiles` and `Robotiq::units` since this - page was first written) needs no matching edit here. `std` is skipped as - external, and any namespace named `detail` at any nesting level is skipped - as this codebase's internal-implementation convention (`Robotiq::detail` - is where `\snippet`-tagged doc-comment examples live, not real API - surface) — both excluded by that general rule, never by naming a specific - namespace. -- For an entry that's only a bare `` reference (i.e. - it's `\ingroup`-owned), resolves the refid to whichever group's compound - XML actually holds the full ``, and links to that group page's - anchor — Doxygen's refid convention is always - `_1`, and that anchor half is exactly the HTML - id doxygen2docusaurus renders on the page that documents it. -- For a genuinely ungrouped entry (Doxygen inlines the full `` - directly in the namespace's own XML in this case — e.g. this library's free - `operator==`/`operator!=` overloads), lists it without a link, since - there's no other page on this site that documents it either (Namespaces - are excluded — see above). See `check_doc_groups.py` above for catching - this upstream, before it ever reaches this fallback. -- Classes are listed by enumerating the already-generated `classes/`/ - `structs/` pages directly (they always have their own page, unlike free - symbols), reusing the same group resolution - `attachClassesToGroups` already computed for the sidebar merge above so a - class's listed group can never disagree between the sidebar and this - page. -- A brief description is attached to each entry: read from the resolving - group's own XML (skipping past any `` children first, so an - enum's *own* brief isn't mistaken for its first enumerator's — Doxygen - lists per-value briefs before the enum's own), or from the class page's - own intro paragraph. -- **A function lists as a bare `name()`, and an overloaded name appears only - once**, no matter how many overloads it actually has. This is an index of - names to scan, not signatures to read — the group page a name links to - already shows every overload in full, so repeating each one here (or - spelling out parameter lists to tell them apart) would only add noise a - reader has to read past. Sort is stable, so which overload's own brief - ends up attached is whichever the source declares first. - -This page is generated fresh on every run (`indices/free-symbols.md`) and -added to the sidebar as "Global Index" — there's nothing to hand-maintain -here as classes, groups, or free symbols are added, renamed, or removed -upstream. - -## Matching Doxygen's own reference look - -doxygen2docusaurus's raw output is close to, but not the same as, what -`doxygen` itself renders in `doxygen-html/` — a few of its default choices -read noticeably flatter or noisier once you have something to compare -against. `sync-external-docs.js` post-processes its generated Markdown to -close those gaps before it ever reaches `docs/`: - -- **A group/class/struct page's own description is whole, right under the - title** (`moveDetailedDescriptionToTop`), not split into a truncated - brief-plus-"More..." link with the full text repeated later, past the - whole Members table, under its own "## Description" heading — the split - doxygen2docusaurus reproduces from classic Doxygen HTML, where a reader - could at least still see the surrounding chrome while deciding whether to - click through. On a plain generated page, clicking "More..." is a bigger - cost for the same payoff: a scroll-past-the-member-list round trip just to - read what the page is actually about before you had any of its members in - front of you yet. The `#details` anchor other pages' own "More..." links - point at (e.g. a parent group's Members table linking to - `.../thisGroup/#details`) is preserved in place — just with no visible - heading left to jump to, now that the text it used to point at sits at the - top instead. -- **Private members are stripped** (`stripPrivateMemberSections`) from - every class/struct page and from the alphabetical "Class Members" index - entries that would otherwise still list them by name — Doxygen's XML - always records a private member regardless of the Doxyfile's - `EXTRACT_PRIVATE` setting (verified against this library's own XML), so - filtering happens here instead. -- **A class's member-overview table is one continuous table** - (`mergeMemberIndexTables`), with a bold in-table heading per kind - (Public Member Functions, Public Attributes, ...) instead of a separate - `"## Index"` heading and its own `` per kind, and no blank separator - row between members — matching Doxygen's own single `memberdecls` table - instead of doxygen2docusaurus's default of unconditionally emitting a - description row and a separator row after *every* member, used or not. -- **Multi-parameter signatures render as a real aligned table** - (`splitMemberSignatures`) — four columns (prefix / paren / type / name), - left empty on every row but where they actually have something to say, - exactly like Doxygen's own `.memname` table. Because it's one continuous - table, every parameter lines up right after wherever `(` landed on the - first line regardless of how long that line's own namespace-qualified - prefix was — doxygen2docusaurus instead dumps the whole signature as flat - text in one cell, which wraps into a hard-to-follow run-on paragraph past - two or three parameters. -- **`src/css/custom.css`** carries the styling for all of the above, adapted - from doxygen2docusaurus's own shipped reference stylesheet - (`templates/css/custom.css` in the npm package) rather than written from - scratch, so it already themes through this site's existing Infima - variables. Watch for two easy-to-miss gotchas when touching this CSS - further: - - **Docusaurus's default markdown table styling** (alternating row - background, per-cell borders) only shows up on a table with more than - one row — several of doxygen2docusaurus's own tables (the multi-row - signature table above, in particular) were always single-row before - these transforms, so nothing here ever disabled those defaults, and - they reappeared the moment a table gained real rows. Where that - happens, resetting every visual property at once - (`background`/`border`/`border-radius`/`box-shadow`, `!important`) has - proven more reliable than specificity-matching Docusaurus's rule for - one property at a time. - - **Prefer `table-layout: auto` with `max-width`/`overflow-wrap` over - `table-layout: fixed` with a fixed percentage** for any column that can - hold either very short content (a bare `class`/`struct` label, or - nothing at all for a group/topic listing) or a very long one (a - generic type like `std::array< uint8_t, N - M >`). `fixed` applies the - *same* column width to every row sharing that column, project-wide — - fixing the long case by reserving, say, 35% of the row leaves a large - wasted gap on every row that doesn't need it, including ones with no - type text at all. `auto` sizes each column from its own content, with - `max-width` only capping the rare pathological case and `overflow-wrap: - break-word` (not `anywhere`, which is happy to break a short word too) - as the last resort. - -## Standalone preview — entirely inside the tool repo, no site clone needed - -While you're tuning Doxygen comments, don't loop through this site at all — -everything below runs against a plain clone of the tool repo (`grippers`), -with no dependency on robotiq.github.io whatsoever: - -1. **Quick sanity check — Doxygen's own HTML, zero extra tools:** - ```bash - doxygen # reads the Doxyfile above - # open doxygen-html/index.html directly in a browser — no server needed - ``` - This alone catches most problems: missing/malformed comments, broken - `\ref`/`@see` links, wrong grouping. It won't look like the final site, - but it's the fastest possible loop — re-run `doxygen` and refresh the - tab. -2. **Closer check — the actual markdown doxygen2docusaurus will hand to the - site:** - ```bash - npx @xpack/doxygen2docusaurus --config doxygen2docusaurus.json - ``` - with a minimal `doxygen2docusaurus.json` alongside it (see - [Wiring it into this site's build](#wiring-it-into-this-sites-build) - below for the fields this site's own build writes dynamically). Browse - the resulting output folder directly — it's HTML-in-Markdown rather than - plain Markdown, so a plain Markdown previewer won't render it faithfully; - pushing the branch and viewing the folder on GitHub gets closer, but - [Optional: full-fidelity preview on this site](#optional-full-fidelity-preview-on-this-site) - below is the only way to see it exactly as readers will. - -## Wiring it into this site's build - -Once the Doxyfile above is committed upstream, this site can generate and -publish the reference automatically. - -**Install both tools once:** -- **Doxygen**: installer at https://www.doxygen.nl/download.html (or - `choco install doxygen.install -y` on Windows, if Chocolatey isn't - blocked on your network). -- **doxygen2docusaurus**: an ordinary npm `devDependency` — - `npm install --save-dev @xpack/doxygen2docusaurus` — no separate binary - download or PATH setup needed (unlike this site's previous - Doxybook2-based pipeline). - -Add a job with a `doxygen2docusaurus` field (instead of `from`) to that -submodule's list in `scripts/external-jobs.js`. It needs `destRoot: -'software-tools'` and `routeBasePath` — every product/tool's own job -does, versioned or not (see [Documentation versioning](./versioning)) — -see the comment on both, and on `apiFolderPath`/`docsBaseUrl` below, for -why a `destRoot` job needs `routeBasePath` spelled out explicitly: - -```js -{ - doxygen2docusaurus: { doxyfileDir: 'sdk_cpp' }, - to: 'Adaptive grippers/Libraries/C++/API', - destRoot: 'software-tools', - routeBasePath: '/docs/drivers', - exclude: [ - 'files', 'folders', 'indices/files', - 'namespaces', 'indices/namespaces', - // ...see the comments on the real job for the full, current list. - ], -}, -``` - -`routeBasePath` is the *shared* `software-tools` instance's own -routeBasePath (`/docs/drivers`), not this tool's own sub-path — every -tool's job uses the exact same value. If the tool is also versioned (see -[Documentation versioning](./versioning)), also set `currentVersionPath: -'next'`, matching that instance's `versions.current.path` exactly. - -`sync-external-docs.js`'s handling of a `doxygen2docusaurus` job first -deletes that submodule's `doxygen-xml/` output folder, then runs `doxygen`. -**Doxygen never cleans its own `OUTPUT_DIRECTORY` between runs** — an XML -compound for a file or symbol that existed in some *previous* run (before it -was excluded, or before it was deleted upstream) is simply left behind, not -regenerated and not removed, and every step downstream reads that folder as -if it were authoritative. Skipping the delete is a real, reproducible bug, -not a hypothetical one: it's exactly how a `register_map.hpp` constant kept -appearing in this site's Global Index for several runs after the library put -that file behind `EXCLUDE` — the stale compound XML from before the -exclusion just sat there, untouched, until something finally deleted the -folder. - -It then writes a `doxygen2docusaurus.json` config next to the repo root -and runs the tool against it, staged into a gitignored folder rather than -straight into `software-tools/` (doxygen2docusaurus also wipes its own -*output* folder on every run — staging keeps that separate from the -post-processing pipeline below, and lets `pruneStale` compare "what should -exist now" against what's actually there before touching anything). -`apiFolderPath`/`apiBaseUrl` are always the job's own `to` — the doc id -relative to the shared `software-tools` instance's own root (e.g. -`'Adaptive grippers/Libraries/C++/API'`), never shortened to a bare tail -like `'API'`: several tools' own doxygen jobs share that one instance, so -a shortened, tool-agnostic value would let two of them collide on the -same generated doc ids and the same sidebar cache file. `docsBaseUrl` is -set from the job's own `routeBasePath` (the shared instance's own, -plus `currentVersionPath` when set) instead of the default `'docs'`, so -the absolute `` backlinks doxygen2docusaurus bakes directly -into the generated HTML resolve correctly. See the big comment on -`destRoot`/`currentDocsRoot`/`currentRoutePrefix` near the top of -`sync-external-docs.js` for the full mechanics. It then applies the -transforms described in -[Matching Doxygen's own reference look](#matching-doxygens-own-reference-look) -above, copies the result into place, builds the [Global -Index](#global-index), and writes the pruned/merged sidebar JSON to -`scripts/generated/doxygen-sidebar--.json` — all before -`sidebars.software-tools.js` ever reads it back. - -**Every page under this job comes from the submodule alone — nothing here is -hand-authored on this site**, including the section's own landing page: -doxygen2docusaurus generates a top-level `index.md` itself (a "Topics" -overview, titled from the submodule's own `Doxyfile` `PROJECT_BRIEF`), and -that job's `exclude` list deliberately does **not** drop it, unlike the -`files`/`folders`/`namespaces` categories above. A previous version of this -site's pipeline instead hand-wrote `API/index.mdx` here and excluded the -generated one — don't reintroduce that: any hand-authored page in this repo -can only ever describe upstream content as of whenever someone last remembered -to update it (this exact page went stale within days, listing a group that -had already been renamed upstream), where the generated page is correct by -construction on every run. - -Nothing to hand-add in `sidebars.software-tools.js` for this — a -`doxygen2docusaurus` job for a `toolId` is itself the signal -`sidebars.software-tools.js`'s `activeItemFor` checks for, so the API -reference's `index` doc (Docusaurus resolves a doc's `id` from its path, -regardless of whether the underlying file is `.md` or `.mdx`) and -everything under it — `loadDoxygenSidebarItems(...)`, as described in -[The sidebar mirrors the Doxygen group hierarchy automatically](#the-sidebar-mirrors-the-doxygen-group-hierarchy-automatically) -above — gets wired in automatically. The doc id is relative to the shared -`software-tools` instance's own root — e.g. -`'Adaptive grippers/Libraries/C++/API/index'` for -`loadDoxygenSidebarItems('Adaptive grippers/Libraries/C++/API')` (the -job's own `to`, unchanged by `destRoot`) — see `doxygenApiCategory` in -`sidebars.software-tools.js` for the real, current implementation, and -[Documentation versioning](./versioning) for the rest of what a new -versioned tool needs. - -## Optional: full-fidelity preview on this site - -Everyday comment-tuning is covered by the standalone preview above and -needs nothing from this repo. Only reach for this — typically once, right -before opening a PR — to confirm the reference looks right with the site's -actual theme, sidebar, and page chrome: - -1. Point `external/2f85_cpp` at your WIP branch (or copy your generated - output into it) — see - [Previewing local edits to a submodule](./#previewing-local-edits-to-a-submodule) - above. -2. Run with the submodule reset disabled and open the real page: - ```bash - # macOS/Linux - SKIP_SUBMODULE_RESET=1 npm start - - # Windows PowerShell - $env:SKIP_SUBMODULE_RESET = "1"; npm start - ``` - `http://localhost:3000/docs/drivers/Adaptive grippers/Libraries/C++/API` - -## Checklist: onboarding a new C++ tool repo - -Everything above is written against the `2f85_cpp` submodule (`grippers`) -as a worked example, but none of the pipeline it describes is specific to -that repo — every piece reads from the submodule's own `Doxyfile`/XML/`docs/` -folder, or from a job entry naming that submodule, never from a hardcoded -repo name, group name, or namespace. Bringing up a second C++ tool repo -against this same pipeline is a matter of matching the conventions below in -the **tool repo**, then adding one job entry **here** — nothing in -`scripts/sync-external-docs.js` itself should need to change. - -**In the tool repo:** - -1. **A `Doxyfile`** generating both outputs this pipeline needs — see the - top of this page for the - `GENERATE_XML`/`FULL_PATH_NAMES`/`STRIP_FROM_INC_PATH` lines. Also set, - matching `2f85_cpp`'s own: - ``` - WARN_IF_UNDOCUMENTED = YES - WARN_AS_ERROR = FAIL_ON_WARNINGS - ``` - so an undocumented or misattached comment fails the tool repo's own CI - instead of silently shipping a gap — see - [Controlling what's included](#controlling-whats-included) above for what - `EXCLUDE`/`EXCLUDE_PATTERNS` and, for a single symbol, `\cond - DOXYGEN_EXCLUDE` / `\endcond` are each actually for. -2. **A `groups.dox`** (or equivalent — any file Doxygen scans) declaring the - `\defgroup`/`\ingroup` hierarchy that becomes this site's sidebar and - Topics page — see - [The sidebar mirrors the Doxygen group hierarchy automatically](#the-sidebar-mirrors-the-doxygen-group-hierarchy-automatically) - above. Nest freely (`\ingroup` on a `\defgroup` itself, arbitrarily deep) - — `2f85_cpp`'s own goes four levels in places (Core API → Commands & - Status → Status → Fault Status). Every documented symbol needs an - `\ingroup` somewhere in this tree, or it's the "ungrouped, no page" gap - `check_doc_groups.py` (next) exists to catch. -3. **`tools/check_doc_groups.py`** — copy - [templates/check_doc_groups.py](https://github.com/robotiq/robotiq.github.io/blob/main/templates/check_doc_groups.py) - in, adjusting the namespace glob near the bottom (`namespace_robotiq*`) - to this repo's own top-level namespace. Wire it into CI right after - `doxygen Doxyfile`: - ```yaml - - run: doxygen Doxyfile - working-directory: sdk_cpp - - run: python3 tools/check_doc_groups.py - working-directory: sdk_cpp - ``` -4. **`tools/check_doc_snippets.py`** (only needed if the repo has - hand-authored markdown guides quoting real code) — see - [Verifying markdown code examples against real source](#verifying-markdown-code-examples-against-real-source) - above for the full adoption steps and CI wiring. -5. **Guide files under `docs/` named `NN-kebab-case.md`** (zero-padded, - kebab-case) if the repo has hand-authored guides beyond the README — see - ["Excluding content from a synced README" and "Splitting a tool page..."](./how-it-works#excluding-content-from-a-synced-readme) - in "How it works" for this naming convention and the README's own - `` markers (for content — like a "full docs at - robotiq.github.io" blurb, or a `docs/` links list this site's own sidebar - already covers — that belongs on GitHub but would be redundant or - circular once copied onto this site). -6. **Every C++ `\code{.cpp}` block backed by `\snippet`**, and every markdown - fence quoting real code marked with ``, per - [Compile-checked examples with `\snippet`](#compile-checked-examples-with-snippet) - above — not required, but a `\code`/hand-copied fence is exactly the kind - of thing that silently drifts once nothing compiles it. - -**Here, in `robotiq.github.io`:** - -7. Add a `doxygen2docusaurus` job to that submodule's list in - `scripts/external-jobs.js` — see - [Wiring it into this site's build](#wiring-it-into-this-sites-build) - above for the shape, and the `2f85_cpp` job for a full worked `exclude` - list (the `files`/`folders`/`namespaces`/redundant-`Classes`-listings - entries there apply to any doxygen2docusaurus output, not just this library — - copy them as a starting point). -8. If the repo also has its own README and/or `docs/` guides, add those as - plain `{ from, to }` jobs in the same `submoduleJobs(...)` call — see - [Splitting a tool page into overview, API reference, and guides](./how-it-works#splitting-a-tool-page-into-overview-api-reference-and-guides) - in "How it works". Same `destRoot`/`routeBasePath` as - [Wiring it into this site's build](#wiring-it-into-this-sites-build) - above. If the tool is also joining the sitewide Stable/Development (main) - switcher (see [Documentation versioning](./versioning)'s checklist for - the rest of that setup), also set `currentVersionPath` on the - `doxygen2docusaurus` job specifically. -9. Nothing to add to `sidebars.software-tools.js` — if the tool is - versioned (its job(s) wrapped in `versionedTool(toolId, toolPath, ...)` - per [Documentation versioning](./versioning#checklist-adding-versioning-to-a-new-tool)'s - checklist), the generated API reference's category and the `docs/` - guides category (if either job exists) are detected and wired in - automatically. -10. Run `npm run generate` (or `npm start`) once and check the console for - warnings — a missing `doxygen`/Doxyfile, a broken cross-reference link, - or `pruneStale` removing something unexpected are all surfaced there, - not silently. diff --git a/docs/website/api-reference-python.mdx b/docs/website/api-reference-python.mdx deleted file mode 100644 index 7f3f513..0000000 --- a/docs/website/api-reference-python.mdx +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: Python API Reference — pydoc-markdown -sidebar_label: Python (pydoc-markdown) -displayed_sidebar: websiteSidebar ---- - -# Python — pydoc-markdown - -Software tool repos can expose a machine-generated API reference -page — no manual writing required. The sync script runs the -generation tool against the submodule during build. - -**In the tool repository**, add docstrings following Google or NumPy -style, and commit a `pydoc-markdown.yml` config at the repo root: - -```yaml -# pydoc-markdown.yml (in the tool repo) -loaders: - - type: python - search_path: [.] - packages: [your_package_name] -renderer: - type: markdown - filename: docs/api.md - render_toc: true -``` - -**In this site**, install the tool once: - -```bash -npm install --save-dev pydoc-markdown -``` - -Then add a generation step to `scripts/sync-external-docs.js` -**before** the `JOBS` loop: - -```js -const { execSync } = require('child_process'); - -execSync('pydoc-markdown', { - cwd: path.join(ROOT, 'external', '2f85_python'), - stdio: 'inherit', -}); -``` - -This writes `external/2f85_python/docs/api.md`. Copy it with a -normal job, inside `2f85_python`'s `submoduleJobs(...)` call: - -```js -{ from: 'docs/api.md', to: 'Adaptive grippers/Libraries/Python/api.md', destRoot: 'software-tools' }, -``` - -Add `'Adaptive grippers/Libraries/Python/api'` to the tool's entry in -`sidebars.software-tools.js`'s active-items map. - -See [C++ — Doxygen + doxygen2docusaurus](./api-reference-cpp) for the C++ -equivalent — it's a different toolchain with no `\snippet`-style -compile-checked-example mechanism; a Python equivalent would need -something else entirely (e.g. doctest-style testing) and isn't covered -here. diff --git a/docs/website/how-it-works.mdx b/docs/website/how-it-works.mdx deleted file mode 100644 index b9f9c97..0000000 --- a/docs/website/how-it-works.mdx +++ /dev/null @@ -1,357 +0,0 @@ ---- -title: How It Works -sidebar_label: How it works -displayed_sidebar: websiteSidebar ---- - -# How it works - -Each software tool (library, driver, ROS package, …) lives in its own -GitHub repository. Embedding it here works in two steps: - -1. **Submodule** — a Git submodule under `external/` acts as a - pinned import of the tool's repository. It does not copy files; - it records the exact commit of the source repo that this site - should use. Running `git submodule update --init` checks out - those commits locally so their files become available. - -2. **Sync script** — [`scripts/sync-external-docs.js`](https://github.com/robotiq/robotiq.github.io/blob/main/scripts/sync-external-docs.js) - reads the checked-out submodule files and copies the ones you - declare into `software-tools/`, rewriting relative links so they - resolve correctly on this site. For a folder job, it also removes any - previously-synced file that source no longer has (e.g. the source repo - renamed or deleted a page) — except a folder's own hand-authored - `index.mdx`/`README`, which the sync never writes and never touches. - -## Repository layout - -``` -robotiq.github.io/ -├── external/ ← pinned imports of source repos -│ └── tactile_sensors/ ← Tactile Sensor library repo -├── docs/ -│ ├── intro.mdx ← overview page, includes the -│ │ auto-generated software tools tables -│ ├── api-stability.mdx ← Software stability policy -│ └── website/ ← this doc, and its siblings -├── software-tools/ ← every product/tool page, versioned -│ │ or not — one shared Docusaurus -│ │ plugin instance, sitewide Stable/ -│ │ Development (main), see -│ │ website/versioning.mdx for why -│ │ this can't be split across two -│ │ instances -│ ├── Tactile Sensor/ -│ │ ├── index.mdx ← product landing page (in git) -│ │ ├── Libraries/ -│ │ │ ├── C++/ ← VERSIONED tool -│ │ │ │ ├── index.mdx ← wrapper page (in git) -│ │ │ │ ├── _readme.md ← synced from submodule -│ │ │ │ ├── API/ ← generated API reference (Doxygen + -│ │ │ │ │ └── index.mdx doxygen2docusaurus), see below -│ │ │ │ └── docs/ ← synced copy of the submodule's own -│ │ │ │ └── index.mdx docs/ folder (guides, design notes) -│ │ │ └── Python/ ← VERSIONED tool, single page -│ │ │ ├── index.mdx -│ │ │ └── _readme.md -│ │ ├── ROS/ -│ │ │ ├── index.mdx ← VERSIONED tool, the ROS leaf page -│ │ │ │ itself (not a landing page — see -│ │ │ │ below) -│ │ │ └── _readme.md ← synced from submodule -│ │ └── Simulation/ -│ │ └── Isaac Sim/index.mdx ← NOT versioned yet (own Isaac Sim -│ │ page, distinct from Adaptive -│ │ grippers' below) -│ ├── Force Torque Sensor/ ← no submodule at all, entirely -│ │ │ hand-authored -│ │ ├── index.mdx -│ │ ├── Libraries/C/ … -│ │ ├── Libraries/Python/ … -│ │ └── ROS/index.mdx ← NOT versioned, third-party -│ │ integration, hand-authored -│ ├── EPick/ ← same, no submodule -│ │ ├── index.mdx -│ │ └── ROS/index.mdx ← same, third-party -│ └── Adaptive grippers/ -│ ├── index.mdx -│ ├── Libraries/ -│ │ ├── C++/ … ← VERSIONED tool, same guides+API -│ │ │ shape as Tactile Sensor's above -│ │ └── Python/ … ← NOT versioned yet -│ ├── ROS/ -│ │ ├── index.mdx ← VERSIONED tool, the ROS leaf page -│ │ └── _readme.md ← synced from submodule -│ ├── Simulation/ -│ │ ├── Isaac Sim/ … ← VERSIONED tool -│ │ ├── PyBullet/ … -│ │ └── MuJoCo/ … -│ └── Other/GraspGen/ … ← "Other" category -├── draft/ ← content with no nav link yet (never -│ built into a page — outside docs/) -├── scripts/ -│ ├── sync-external-docs.js -│ ├── generate-tools-table.js -│ └── site-nav-tree.mjs ← shared nav tree, see -│ website/versioning.mdx -├── sidebars.js ← default instance's sidebar (just -│ docs/intro.mdx, api-stability.mdx, -│ and website/*) -└── sidebars.software-tools.js ← shared software-tools instance's - own sidebar, the whole Software - Tools tree at once -``` - -Files prefixed with `_` are Docusaurus **partials** — imported by a -wrapper `.mdx` but not standalone pages themselves. - -**A tool listed above as "VERSIONED" has its sync job tagged with a -`toolId` in `scripts/external-jobs.js` (`scripts/versioned-tools.js` and -`sidebars.software-tools.js`'s active-items map both derive from that), -and participates in Stable/Development (main) cuts** — see -[Documentation versioning](./versioning) for the whole mechanism and how -to add it to a new tool. Every product/tool, versioned or not, lives -under `software-tools/` (not `docs/`) — see that same page for why: the -shared instance owns the entire `/docs/drivers/*` URL space, so a -non-versioned tool living in `docs/` instead would collide with it. -Everything else on this page -(the sync script, the exclude-content markers, splitting a tool into -guides/API/overview, refreshing submodule pins) applies identically to a -versioned or non-versioned tool — versioning only changes *where* the -files live and *how many builds* exist of them, not how they're -authored or synced. - -The `Libraries/`, `Simulation/`, and `Other/` folders are just -organizational containers — `generate-tools-table.js` doesn't care about -folder names, only about which `index.mdx` files carry a `Category` badge -(see [step 3](./adding-a-tool#3-create-the-wrapper-page) of adding a new -tool). A tool page could just as well sit directly under the product -folder with no wrapper folder at all — it would still land in the right -table, because classification comes from the badge, not the path. The -wrapper folders exist purely to keep the repo tidy for humans browsing it. -`ROS/` is the one exception: its own `index.mdx` carries the -`Category-ROS` badge directly, so it's a leaf, not a container — a -product has at most one ROS page (no distro or generation split; which -ROS distros a driver supports lives in that driver's own repo README, not -as a page on this site). - -Any of the three container folders can *also* carry its own `index.mdx` -landing page (no `Category` badge, so the script still treats it as a -container and recurses into it) — once a product has any tool pages in -that category, that page gets the same auto-generated table the -product's own top-level `index.mdx` already shows as a quick summary, as -its own dedicated page (see -[step 4](./adding-a-tool#4-create-the-product-landing-page)). `ROS/` -never gets one of these: there's only ever the one leaf, so its -`index.mdx` is already the real content page — synced from -[robotiq/ros](https://github.com/robotiq/ros) the same way the Tactile -Sensor C++ library page syncs from `tactile_sensors` (see the tree above) -for a Robotiq-maintained integration, hand-authored for a third-party -one. - -## Excluding content from a synced README - -A tool repo's README often carries things that only make sense on -GitHub — e.g. a "full documentation at robotiq.github.io/..." blurb, -which would be redundant (or circular) once that same README is -copied onto this site. Wrap that content in a pair of HTML comment -markers: - -```markdown - -📖 Full documentation: https://robotiq.github.io/... - -``` - -GitHub renders the text between the markers normally on the tool -repo's own README (HTML comments are invisible), but -`sync-external-docs.js` strips everything between -`` and `` -before copying content into `docs/`, so it never reaches this site. - -A submodule's own guides are also written for GitHub's renderer, which -turns `> **Note:** ...`/`> **Warning:** ...` into a plain, unstyled -indented quote. `sync-external-docs.js`'s `convertBlockquoteAdmonitions` -converts these into real Docusaurus callouts (`:::note`/`:::warning`, styled -in `src/css/custom.css`'s `.alert--*` rules) during the sync, for every -synced doc from any submodule — nothing to do upstream or here, a source -repo's README/guides can keep writing plain GitHub-style callouts. - -The same applies to a video link: a guide embeds one as a YouTube -thumbnail image wrapped in a link to that same video — -`[![Title](https://img.youtube.com/vi//...)](https://youtu.be/)` -— rather than a raw `