Repository navigation
Bundle Mermaid so diagrams need no extra install - #11
Merged
Merged
Conversation
Bring mermaid.min.js into the package so decks with diagrams no longer need the Mermaid CLI, Node or Chromium. The folder holds Mermaid's license, notices for every package the bundle includes (among them elkjs under EPL-2.0), and a manifest with the version, npm integrity hash and the file's SHA-256. scripts/update_mermaid.py rewrites the folder from an npm release. It checks the tarball against npm's integrity hash, escapes the one raw control character that sits in a string literal, and regenerates the notices, which needs npm. The pre-commit file hooks skip the folder so the file stays byte for byte, and git marks it as vendored.
A .mmd image used to need the Mermaid CLI at build time. Now the build checks each diagram with Mermaid's own parse(), run in V8 through mini-racer, so a syntax error still stops the build and names the line in the .mmd file. The page then draws the diagrams as inline SVG with the vendored Mermaid, which is embedded only when a slide has a diagram, under a comment carrying its license notices. Inline SVG leaves room for interactive diagrams later. Add akceo check, which runs every check a build runs and writes nothing, so authors and agents get errors on the command line fast. The demo's image slide now uses a Mermaid diagram, and the docs, changelog and license metadata cover the new dependency and the bundled code. Closes #10
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Runtime SVG URLs can violate self-contained output, and additional diagnostics, accessibility, and license-inventory issues remain.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 4
Open (4)
What changed in this PR
Bundles Mermaid for self-contained diagram validation and browser rendering without Node or Chromium.
Changes:
- Adds V8-based Mermaid syntax checking and browser SVG rendering.
- Adds
akceo check, dependency/package updates, and vendoring tooling. - Updates tests, documentation, examples, and licensing metadata.
| File | Description |
|---|---|
.gitattributes |
Marks Mermaid assets as vendored. |
.pre-commit-config.yaml |
Excludes vendored assets from hooks. |
CHANGELOG.md |
Records Mermaid and check-command changes. |
CLAUDE.md |
Updates repository guidance. |
README.md |
Documents bundled diagrams and checking. |
docs/how-it-works.md |
Describes the revised pipeline. |
docs/syntax.md |
Documents Mermaid behavior. |
examples/demo/deck.md |
Uses the Mermaid example. |
examples/demo/flow.mmd |
Adds the example diagram source. |
examples/demo/speaker-notes.md |
Updates demo narration. |
pyproject.toml |
Adds dependency and license metadata. |
scripts/update_mermaid.py |
Adds Mermaid vendoring automation. |
src/akceo/assets/base.css |
Styles rendered diagrams and errors. |
src/akceo/assets/diagrams.js |
Renders Mermaid SVGs in-browser. |
src/akceo/assets/mermaid-shims.js |
Provides build-time V8 shims. |
src/akceo/assets/page.html |
Adds diagram-script placeholder. |
src/akceo/assets/vendor/mermaid/LICENSE |
Includes Mermaid’s license. |
src/akceo/assets/vendor/mermaid/README.md |
Documents vendored assets. |
src/akceo/assets/vendor/mermaid/THIRD_PARTY_NOTICES |
Includes dependency notices. |
src/akceo/assets/vendor/mermaid/manifest.json |
Records source and checksum metadata. |
src/akceo/assets/vendor/mermaid/mermaid.min.js |
Vendors the Mermaid browser bundle. |
src/akceo/cli.py |
Adds the check command. |
src/akceo/images.py |
Removes external Mermaid CLI rendering. |
src/akceo/mermaid.py |
Adds parsing, diagnostics, and embedding. |
src/akceo/render.py |
Integrates diagram checking and output. |
tests/test_cli.py |
Tests CLI and self-contained output. |
tests/test_images.py |
Removes obsolete Mermaid CLI tests. |
tests/test_mermaid.py |
Tests the new Mermaid integration. |
tests/test_render.py |
Tests diagram markup rendering. |
uv.lock |
Locks the mini-racer dependency. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Build the license notices from the pnpm-lock.yaml at Mermaid's release tag, so each version matches the bundle; resolving ranges picked newer ones. The walk also follows the devDependencies that the parser workspace compiles in, which brings in langium. A new, unsorted one stops the update. Tarballs come straight from the registry and are checked against the lockfile, so npm is no longer needed. Stop the build on a diagram that would load or link to anything outside the deck: Mermaid fetches images while it draws, so this can't wait for the page. The page also strips any such reference as a backstop. Add the URL stand-in the check needed for click links. Point unknown diagram type errors at the right line, and let screen readers read the message when a diagram fails to draw.
Add a Content-Security-Policy to the page so the browser refuses any outside load, however a diagram or theme spells it. Mermaid fetches label images while it draws, so nothing done to the SVG afterwards could stop them. A web font or @import in a custom theme no longer loads as a result. Widen the build-time scan to every link, image and CSS form the review found, over the whole source, so it still stops the build with a clear message and line. Stop on diagrams over Mermaid's size limit, and give YAML and unknown-shape errors their line in the file. Run the V8 check in a child process. mini-racer can't interrupt async JavaScript, so a runaway parse or Ctrl-C used to hang the build; the child is now killed on a timeout, on Ctrl-C and when the build ends. In the page, one diagram's failure no longer stops the rest drawing, and Mermaid no longer leaves its error graphic behind. The update script walks optional dependencies, stops on a missing anchor package or license file, and writes nothing until every step succeeds.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The external-reference scanner rejects valid label text and misses later URLs in multi-candidate srcset attributes.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
Open (1)
A srcset holds a list of candidates, and the scan stopped at the first
comma, so a data: URI candidate hid an outside one after it. Capture
the whole value and split it the way the HTML spec does, where a URL
runs to the next whitespace, so a data: URI's own commas don't split
it.
Also let the patterns skip a backslash before a quote, so a URL in a
JSON string in an %%{init}%% line is reported as the URL rather than
as a backslash.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Closes #10.
What changes
A
.mmdimage no longer needs the Mermaid CLI, Node or Chromium. The repo now carries everything needed to build a deck.src/akceo/assets/vendor/mermaid/(12.0.0). It comes with its license, notices for every package in the bundle, and a manifest with the version, npm integrity hash and SHA-256. A test checks the file against that SHA-256.mermaid.pyruns Mermaid's ownparse()in V8 throughmini-racer, a new runtime dependency. V8 runs in a child process (python -m akceo.mermaid), because mini-racer can't interrupt async JavaScript: the child is killed if a diagram takes over 10 s, on Ctrl-C, and when the build ends, so a runaway parse can't hang the build. A syntax error stops the build and names the line in the.mmdfile. That line is right even after%%comments,%%{init}%%lines and front matter, which Mermaid strips before parsing. YAML errors in front matter or@{…}shape data get their file line too, and a diagram over Mermaid's 50,000-character limit stops the build rather than drawing Mermaid's "too large" notice.default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data:; font-src data:), so the browser refuses any outside load, whatever the syntax. Mermaid fetches label images while it draws, so nothing done to the SVG afterwards could stop that load.click,link,links,$link,<a href>), images (img:,src, everysrcsetcandidate, and similar) and CSS (url(),@import, includingthemeCSSin front matter or%%{init}%%) and names the line. Only#anchors anddata:URIs pass. The page also drops any outside link from the drawn SVG.viewBoxso they fit the frame the same way an<img>does. Unframed diagrams use the theme's colors; framed ones keep Mermaid's defaults. Inline SVG leaves room for interactive diagrams later.akceo check deck.mdruns every check a build runs and writes nothing.Costs
mini-raceris about 61 MB installed (a 15–22 MB download).@importin a custom theme no longer loads, even online. None of the built-in themes use one. The docs now suggest installed fonts or adata:@font-face.Licensing
The bundle includes code under MIT, ISC, BSD-3-Clause, Apache-2.0, MPL-2.0/Apache-2.0 (DOMPurify), Unlicense and EPL-2.0 (elkjs).
pyproject.tomlnow has a combined license expression.LICENSEandTHIRD_PARTY_NOTICES.pnpm-lock.yamlat Mermaid's release tag, so every version matches the bundle. They include langium, which@mermaid-js/parsercompiles into its output.Updating Mermaid
scripts/update_mermaid.py VERSIONrewrites the vendor folder. It checks every download against npm's or the lockfile's integrity hash and needs nothing but Python. It follows optional dependencies too, and writes nothing until every step succeeds. It stops if Mermaid's parser package gains a devDependency it hasn't seen, if the walk misses a package the bundle certainly holds, or if a package has no license file. See the README in the vendor folder.Testing
uv run pytest: 168 passed. The Mermaid tests run the real parser, not a mock.ruff format --check, pyright and every pre-commit hook pass.akceo buildandakceo checkwork on the demo.#links kept;themeCSS,style=and<img>are refused while the diagram still draws;url()scan, theURLstand-in, the outside-reference scan) turns the tests red.