MermaidImageRenderer: OFFICECLI_MERMAID_JS local asset override for render=image - #319
MermaidImageRenderer: OFFICECLI_MERMAID_JS local asset override for render=image#319hesong12 wants to merge 1 commit into
Conversation
Offline / sandboxed hosts have no path to the mirror or the CDN that render=image normally downloads mermaid.min.js from. Read OFFICECLI_MERMAID_JS first, when set and the file exists: use it directly as the <script src>, and skip both the download attempt and the daily cache-refresh network call.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 92b4974db6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (MermaidJsOverride is { } overridePath) | ||
| return new Uri(Path.GetFullPath(overridePath)).AbsoluteUri; |
There was a problem hiding this comment.
Honor the local override in the styled ESM path
When a diagram specifies theme, layout, or look, RenderViaChrome selects BuildHtmlEsm and never calls this resolver; that path still imports MermaidEsmUrl and, for ELK, ElkEsmUrl from jsDelivr. Consequently, on the offline or sandboxed hosts this override targets, styled render=image requests still fail—or auto mode falls back to native rendering and loses the requested styling—despite OFFICECLI_MERMAID_JS being set.
Useful? React with 👍 / 👎.
Files:
src/officecli/Core/Diagram/MermaidImageRenderer.cs(ResolveMermaidJsRef(),RefreshCacheIfPresent()),README.mdSummary
diagram --prop render=image's chrome-family backend renders with the realmermaid.js.
ResolveMermaidJsRef()resolves the script it points the pageat in three steps: an existing local cache → download from OfficeCLI's own
mirror → download from the jsDelivr CDN → give up and reference the CDN URL
live in the page. Every one of those needs a network path out. A host that
is offline, air-gapped, or sandboxed away from the network has no way to use
render=imageat all, even when it already has a validmermaid.min.jsondisk.
This PR adds
OFFICECLI_MERMAID_JS: when set to a path that exists,ResolveMermaidJsRef()returns afile://URI for it directly — no cachecheck, no download attempt, no network call of any kind — and
RefreshCacheIfPresent()(the daily background revalidation hook) returnsimmediately instead of trying to reach the mirror. Unset, behaviour is
unchanged.
Same shape as the existing
OFFICECLI_MMDCoverride two members away in thesame file.
Why
Same host as the sibling
OFFICECLI_BROWSERPR: a desktop app that runsinside a locked-down sandbox (network egress not guaranteed, no ability to
silently phone a CDN on the user's behalf) wants
render=imagediagrams towork from an asset it ships and pins itself.
Validation
Toolchain: same scratch .NET 10 SDK as the sibling PRs.
mermaid.min.jsdownloaded once fromhttps://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.jsinto a scratchdirectory (not committed, not part of the diff).
Precedence check (does the override actually get read, not just
"happen to work because the network was up anyway"): point
OFFICECLI_MERMAID_JSat a deliberately invalid JS file(
not_a_valid_mermaid_js_file();) and diagram add the same source on boththe unmodified
mainbranch and this branch, network fully reachable onboth runs:
Offline functional check — the real command from the task, with the
valid local copy and the network genuinely unreachable
(
http_proxy/https_proxypointed at a closed port; a rawHttpClientprobe against the same target confirms this fails in <0.1s rather than
silently succeeding):
Compatibility
Additive only. The existing cache → mirror → CDN → live-CDN cascade in
ResolveMermaidJsRef()is untouched and still runs wheneverOFFICECLI_MERMAID_JSis unset.RefreshCacheIfPresent()'s existingearly-return (
!File.Exists(CachedJsPath)) is untouched; the new check isstrictly earlier in the same method and only short-circuits when the new var
is set.