From 979d9a412d7b1428cd42bef8a92fd1767c375928 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Wed, 25 Mar 2026 22:59:57 -0400 Subject: [PATCH] Mermaid improvements (#11874) * fix: Upgrade mermaid to 11.13.0 Includes a fix for incorrect viewBox casing in Radar and Packet diagram renderers (mermaid-js/mermaid#7076) and other improvements. Co-Authored-By: Claude Opus 4.6 * fix: Use visibility:hidden for mermaid rendering element Instead of positioning the temporary render element offscreen at -9999px, use visibility:hidden with position:fixed so the browser computes correct bounding boxes for SVG elements. Offscreen elements can produce incorrect getBBox() results, leading to wrong viewBox dimensions and diagrams rendering too big or too small. Fixes #11782 Co-Authored-By: Claude Opus 4.6 * Add session storage for generated diagrams to reduce relayout * fix: Use LRU eviction for mermaid sessionStorage cache Track access order via a dedicated LRU index key so the cache evicts least-recently-used entries rather than arbitrary ones. Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.6 --- package.json | 2 +- shared/editor/extensions/Mermaid.ts | 84 ++++++++++-- shared/utils/string.test.ts | 19 +++ shared/utils/string.ts | 14 ++ yarn.lock | 192 +++++++++++++++------------- 5 files changed, 208 insertions(+), 103 deletions(-) create mode 100644 shared/utils/string.test.ts diff --git a/package.json b/package.json index d45090b30a..ee169b0bc7 100644 --- a/package.json +++ b/package.json @@ -169,7 +169,7 @@ "markdown-it": "^14.1.0", "markdown-it-container": "^3.0.0", "markdown-it-emoji": "^3.0.0", - "mermaid": "11.12.1", + "mermaid": "11.13.0", "mime-types": "^3.0.1", "mobx": "^4.15.4", "mobx-react": "^6.3.1", diff --git a/shared/editor/extensions/Mermaid.ts b/shared/editor/extensions/Mermaid.ts index 1361af6513..af93e10365 100644 --- a/shared/editor/extensions/Mermaid.ts +++ b/shared/editor/extensions/Mermaid.ts @@ -15,6 +15,7 @@ import { findParentNode } from "../queries/findParentNode"; import type { NodeWithPos } from "../types"; import type { Editor } from "../../../app/editor"; import { LightboxImageFactory } from "../lib/Lightbox"; +import { hashString } from "../../utils/string"; import { sanitizeUrl } from "../../utils/urls"; export const pluginKey = new PluginKey("mermaid"); @@ -25,21 +26,72 @@ export type MermaidState = { editingId?: string; }; +const STORAGE_PREFIX = "mermaid:"; +const MAX_STORAGE_ENTRIES = 20; + class Cache { - static get(key: string) { - return this.data.get(key); + /** Get a cached SVG by diagram text and theme. */ + static get(key: string): string | undefined { + try { + const hash = hashString(key); + const value = sessionStorage.getItem(STORAGE_PREFIX + hash); + if (value) { + this.touchLru(hash); + return value; + } + } catch { + // sessionStorage unavailable + } + return undefined; } + /** Cache a rendered SVG in sessionStorage. */ static set(key: string, value: string) { - this.data.set(key, value); - - if (this.data.size > this.maxSize) { - this.data.delete(this.data.keys().next().value); + try { + const hash = hashString(key); + this.touchLru(hash); + this.pruneStorage(); + sessionStorage.setItem(STORAGE_PREFIX + hash, value); + } catch { + // sessionStorage full or unavailable } } - private static maxSize = 20; - private static data: Map = new Map(); + /** Move or append a hash to the end (most recent) of the LRU list. */ + private static touchLru(hash: string) { + const lru = this.getLru(); + const idx = lru.indexOf(hash); + if (idx !== -1) { + lru.splice(idx, 1); + } + lru.push(hash); + sessionStorage.setItem(STORAGE_PREFIX + "lru", JSON.stringify(lru)); + } + + /** Evict least-recently-used entries when over the limit. */ + private static pruneStorage() { + const lru = this.getLru(); + + while (lru.length > MAX_STORAGE_ENTRIES) { + const evict = lru.shift()!; + sessionStorage.removeItem(STORAGE_PREFIX + evict); + } + + sessionStorage.setItem(STORAGE_PREFIX + "lru", JSON.stringify(lru)); + } + + /** Read the LRU order list from sessionStorage. */ + private static getLru(): string[] { + try { + const raw = sessionStorage.getItem(STORAGE_PREFIX + "lru"); + if (raw) { + return JSON.parse(raw); + } + } catch { + // corrupted or unavailable + } + return []; + } } let mermaid: typeof MermaidUnsafe; @@ -104,16 +156,20 @@ class MermaidRenderer { return; } - // Create a temporary element that will render the diagram off-screen. This is necessary - // as Mermaid will error if the element is not visible or the element is removed while the - // diagram is being rendered. + // Create a temporary element for rendering. We use visibility:hidden instead of + // offscreen positioning so the browser computes correct bounding boxes for SVG + // elements — offscreen elements can produce incorrect getBBox() results, leading + // to wrong viewBox dimensions (see mermaid-js/mermaid#6146). const renderElement = document.createElement("div"); const tempId = "offscreen-mermaid-" + Math.random().toString(36).substr(2, 9); renderElement.id = tempId; - renderElement.style.position = "absolute"; - renderElement.style.left = "-9999px"; - renderElement.style.top = "-9999px"; + renderElement.style.position = "fixed"; + renderElement.style.visibility = "hidden"; + renderElement.style.top = "0"; + renderElement.style.left = "0"; + renderElement.style.width = "100%"; + renderElement.style.zIndex = "-1"; document.body.appendChild(renderElement); try { diff --git a/shared/utils/string.test.ts b/shared/utils/string.test.ts new file mode 100644 index 0000000000..f9b84606ac --- /dev/null +++ b/shared/utils/string.test.ts @@ -0,0 +1,19 @@ +import { hashString } from "./string"; + +describe("hashString", () => { + it("returns a hex string", () => { + expect(hashString("hello")).toMatch(/^[0-9a-f]+$/); + }); + + it("returns consistent results for the same input", () => { + expect(hashString("test")).toBe(hashString("test")); + }); + + it("returns different hashes for different inputs", () => { + expect(hashString("abc")).not.toBe(hashString("def")); + }); + + it("handles empty string", () => { + expect(hashString("")).toMatch(/^[0-9a-f]+$/); + }); +}); diff --git a/shared/utils/string.ts b/shared/utils/string.ts index 3079bb681c..ef5ae9c614 100644 --- a/shared/utils/string.ts +++ b/shared/utils/string.ts @@ -1,3 +1,17 @@ +/** + * Simple string hash using the djb2 algorithm, returns a hex string. + * + * @param str the string to hash. + * @returns a hex-encoded 32-bit hash. + */ +export function hashString(str: string): string { + let hash = 5381; + for (let i = 0; i < str.length; i++) { + hash = ((hash << 5) + hash + str.charCodeAt(i)) | 0; + } + return (hash >>> 0).toString(16); +} + /** * Returns the index of the first occurrence of a substring in a string that matches a regular expression. * diff --git a/yarn.lock b/yarn.lock index ae5b33ff25..65fc9a9c27 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2897,45 +2897,45 @@ __metadata: languageName: node linkType: hard -"@chevrotain/cst-dts-gen@npm:11.0.3": - version: 11.0.3 - resolution: "@chevrotain/cst-dts-gen@npm:11.0.3" +"@chevrotain/cst-dts-gen@npm:11.1.2": + version: 11.1.2 + resolution: "@chevrotain/cst-dts-gen@npm:11.1.2" dependencies: - "@chevrotain/gast": "npm:11.0.3" - "@chevrotain/types": "npm:11.0.3" - lodash-es: "npm:4.17.21" - checksum: 10c0/9e945a0611386e4e08af34c2d0b3af36c1af08f726b58145f11310f2aeafcb2d65264c06ec65a32df6b6a65771e6a55be70580c853afe3ceb51487e506967104 + "@chevrotain/gast": "npm:11.1.2" + "@chevrotain/types": "npm:11.1.2" + lodash-es: "npm:4.17.23" + checksum: 10c0/372a9573a404a1d717c92875024588a53d1eb078f12d2cd1d79d9c2c888c9b429eb62bbc85501b8ff168c14b22a675da99d97bb39b0a774e9fee000dc60fd8ff languageName: node linkType: hard -"@chevrotain/gast@npm:11.0.3": - version: 11.0.3 - resolution: "@chevrotain/gast@npm:11.0.3" +"@chevrotain/gast@npm:11.1.2": + version: 11.1.2 + resolution: "@chevrotain/gast@npm:11.1.2" dependencies: - "@chevrotain/types": "npm:11.0.3" - lodash-es: "npm:4.17.21" - checksum: 10c0/54fc44d7b4a7b0323f49d957dd88ad44504922d30cb226d93b430b0e09925efe44e0726068581d777f423fabfb878a2238ed2c87b690c0c0014ebd12b6968354 + "@chevrotain/types": "npm:11.1.2" + lodash-es: "npm:4.17.23" + checksum: 10c0/540bfc9270d752f398b29efe9c89bb907d2984a47db4308a943e50c1cbd261ee13ecbef15c0e07808cf476d835bc36e65854db0bd214c277296cc14013eca8f4 languageName: node linkType: hard -"@chevrotain/regexp-to-ast@npm:11.0.3": - version: 11.0.3 - resolution: "@chevrotain/regexp-to-ast@npm:11.0.3" - checksum: 10c0/6939c5c94fbfb8c559a4a37a283af5ded8e6147b184a7d7bcf5ad1404d9d663c78d81602bd8ea8458ec497358a9e1671541099c511835d0be2cad46f00c62b3f +"@chevrotain/regexp-to-ast@npm:11.1.2": + version: 11.1.2 + resolution: "@chevrotain/regexp-to-ast@npm:11.1.2" + checksum: 10c0/645f02ac94cb33e04c10547b197762c6936c7b7668966240684795ce131cb515a76b63e0cc500e787d669f1a36bd2f902ec518f27843ec857ecf9043c717527e languageName: node linkType: hard -"@chevrotain/types@npm:11.0.3": - version: 11.0.3 - resolution: "@chevrotain/types@npm:11.0.3" - checksum: 10c0/72fe8f0010ebef848e47faea14a88c6fdc3cdbafaef6b13df4a18c7d33249b1b675e37b05cb90a421700c7016dae7cd4187ab6b549e176a81cea434f69cd2503 +"@chevrotain/types@npm:11.1.2": + version: 11.1.2 + resolution: "@chevrotain/types@npm:11.1.2" + checksum: 10c0/c0c4679a3d407df34e18d5adfa7ac599b4a2bfddbf68da6e43678b9b3e16ab911de7766b37b9fc466261c3dead3db1b620e2e344f800fa9f0f381720475eda8f languageName: node linkType: hard -"@chevrotain/utils@npm:11.0.3": - version: 11.0.3 - resolution: "@chevrotain/utils@npm:11.0.3" - checksum: 10c0/b31972d1b2d444eef1499cf9b7576fc1793e8544910de33a3c18e07c270cfad88067f175d0ee63e7bc604713ebed647f8190db45cc8311852cd2d4fe2ef14068 +"@chevrotain/utils@npm:11.1.2": + version: 11.1.2 + resolution: "@chevrotain/utils@npm:11.1.2" + checksum: 10c0/72989e7051781b9084252486712844c55e3b454318c7da4a5f6ded28dcd3947ba2882773a6bf09b7e744599e8c8025df8d3de0d487121734e6edb66999450438 languageName: node linkType: hard @@ -3666,7 +3666,7 @@ __metadata: languageName: node linkType: hard -"@iconify/utils@npm:^3.0.1": +"@iconify/utils@npm:^3.0.2": version: 3.1.0 resolution: "@iconify/utils@npm:3.1.0" dependencies: @@ -4389,12 +4389,12 @@ __metadata: languageName: node linkType: hard -"@mermaid-js/parser@npm:^0.6.3": - version: 0.6.3 - resolution: "@mermaid-js/parser@npm:0.6.3" +"@mermaid-js/parser@npm:^1.0.1": + version: 1.0.1 + resolution: "@mermaid-js/parser@npm:1.0.1" dependencies: - langium: "npm:3.3.1" - checksum: 10c0/9711174ff31f32d93c8da03ed6b1a1380f5ccfb27ffcdfaf42236da4b381aa0602752b3afc7893582d5ccdfc79b0465c69afe963b825328049575831f4ddd28e + langium: "npm:^4.0.0" + checksum: 10c0/34231cb63412ddbb3c8c6dba6366b958f98b66293b2e5748d3bd6c286acde47862a6ac86b2f6a33e7b5dee6a1895035af06ee48863c787bc20415b89fe77d705 languageName: node linkType: hard @@ -9039,6 +9039,21 @@ __metadata: languageName: node linkType: hard +"@upsetjs/venn.js@npm:^2.0.0": + version: 2.0.0 + resolution: "@upsetjs/venn.js@npm:2.0.0" + dependencies: + d3-selection: "npm:^3.0.0" + d3-transition: "npm:^3.0.1" + dependenciesMeta: + d3-selection: + optional: true + d3-transition: + optional: true + checksum: 10c0/b12014d94708ab4df7f5a4b6205c6f23ff235cca2ffe91df3314862b109b826e52f9020c2a2f7527d3712d21c578d6db9cdb60ce46a528739cc18e58d111f724 + languageName: node + linkType: hard + "@vitejs/plugin-react-oxc@npm:^0.2.3": version: 0.2.3 resolution: "@vitejs/plugin-react-oxc@npm:0.2.3" @@ -10288,7 +10303,7 @@ __metadata: languageName: node linkType: hard -"chevrotain-allstar@npm:~0.3.0": +"chevrotain-allstar@npm:~0.3.1": version: 0.3.1 resolution: "chevrotain-allstar@npm:0.3.1" dependencies: @@ -10299,17 +10314,17 @@ __metadata: languageName: node linkType: hard -"chevrotain@npm:~11.0.3": - version: 11.0.3 - resolution: "chevrotain@npm:11.0.3" +"chevrotain@npm:~11.1.1": + version: 11.1.2 + resolution: "chevrotain@npm:11.1.2" dependencies: - "@chevrotain/cst-dts-gen": "npm:11.0.3" - "@chevrotain/gast": "npm:11.0.3" - "@chevrotain/regexp-to-ast": "npm:11.0.3" - "@chevrotain/types": "npm:11.0.3" - "@chevrotain/utils": "npm:11.0.3" - lodash-es: "npm:4.17.21" - checksum: 10c0/ffd425fa321e3f17e9833d7f44cd39f2743f066e92ca74b226176080ca5d455f853fe9091cdfd86354bd899d85c08b3bdc3f55b267e7d07124b048a88349765f + "@chevrotain/cst-dts-gen": "npm:11.1.2" + "@chevrotain/gast": "npm:11.1.2" + "@chevrotain/regexp-to-ast": "npm:11.1.2" + "@chevrotain/types": "npm:11.1.2" + "@chevrotain/utils": "npm:11.1.2" + lodash-es: "npm:4.17.23" + checksum: 10c0/7f0b5780035c582d4c620c81e1fbb58c9f41a69f1c7efdae96819c7bc0928ddb4f046bb8239e71539f383b3b8ce460bd11f44b5fb5107e1d45a0cc91bd6a4198 languageName: node linkType: hard @@ -11074,7 +11089,7 @@ __metadata: languageName: node linkType: hard -"cytoscape@npm:^3.29.3": +"cytoscape@npm:^3.33.1": version: 3.33.1 resolution: "cytoscape@npm:3.33.1" checksum: 10c0/dffcf5f74df4d91517c4faf394df880d8283ce76edef19edba0c762941cf4f18daf7c4c955ec50c794f476ace39ad4394f8c98483222bd2682e1fd206e976411 @@ -11318,7 +11333,7 @@ __metadata: languageName: node linkType: hard -"d3-selection@npm:2 - 3, d3-selection@npm:3": +"d3-selection@npm:2 - 3, d3-selection@npm:3, d3-selection@npm:^3.0.0": version: 3.0.0 resolution: "d3-selection@npm:3.0.0" checksum: 10c0/e59096bbe8f0cb0daa1001d9bdd6dbc93a688019abc97d1d8b37f85cd3c286a6875b22adea0931b0c88410d025563e1643019161a883c516acf50c190a11b56b @@ -11368,7 +11383,7 @@ __metadata: languageName: node linkType: hard -"d3-transition@npm:2 - 3, d3-transition@npm:3": +"d3-transition@npm:2 - 3, d3-transition@npm:3, d3-transition@npm:^3.0.1": version: 3.0.1 resolution: "d3-transition@npm:3.0.1" dependencies: @@ -11434,13 +11449,13 @@ __metadata: languageName: node linkType: hard -"dagre-d3-es@npm:7.0.13": - version: 7.0.13 - resolution: "dagre-d3-es@npm:7.0.13" +"dagre-d3-es@npm:7.0.14": + version: 7.0.14 + resolution: "dagre-d3-es@npm:7.0.14" dependencies: d3: "npm:^7.9.0" lodash-es: "npm:^4.17.21" - checksum: 10c0/4eca80dbbad4075311e3853930f99486024785b54210541796d4216140d91744738ee51125e2692c3532af148fbc2e690171750583916ed2ad553150abb198c7 + checksum: 10c0/0dc91fc79300eb0a4eab5a48a76c2baf3ce439c389d19e2f015729bb57dafd75e1e9a4c2880daf016e81ee45caca7b21745c13b23b6cd2a786ce84767e88323e languageName: node linkType: hard @@ -11515,10 +11530,10 @@ __metadata: languageName: node linkType: hard -"dayjs@npm:^1.11.18": - version: 1.11.19 - resolution: "dayjs@npm:1.11.19" - checksum: 10c0/7d8a6074a343f821f81ea284d700bd34ea6c7abbe8d93bce7aba818948957c1b7f56131702e5e890a5622cdfc05dcebe8aed0b8313bdc6838a594d7846b0b000 +"dayjs@npm:^1.11.19": + version: 1.11.20 + resolution: "dayjs@npm:1.11.20" + checksum: 10c0/8af525e2aa100c8db9923d706c42b2b2d30579faf89456619413a5c10916efc92c2b166e193c27c02eb3174b30aa440ee1e7b72b0a2876b3da651d204db848a0 languageName: node linkType: hard @@ -11833,15 +11848,15 @@ __metadata: languageName: node linkType: hard -"dompurify@npm:^3.2.5": - version: 3.3.1 - resolution: "dompurify@npm:3.3.1" +"dompurify@npm:^3.3.1": + version: 3.3.3 + resolution: "dompurify@npm:3.3.3" dependencies: "@types/trusted-types": "npm:^2.0.7" dependenciesMeta: "@types/trusted-types": optional: true - checksum: 10c0/fa0a8c55a436ba0d54389195e3d2337e311f56de709a2fc9efc98dbbc7746fa53bb4b74b6ac043b77a279a8f2ebd8685f0ebaa6e58c9e32e92051d529bc0baf8 + checksum: 10c0/097c14a21a3f6cb95beded9ecd255f7c3512c42767b048390c747b0fe35736f6a71e02320fc50a9ac2be645834b463e4760915d595d502a56452daf339d0ea9c languageName: node linkType: hard @@ -15645,7 +15660,7 @@ __metadata: languageName: node linkType: hard -"katex@npm:^0.16.22, katex@npm:^0.16.25": +"katex@npm:^0.16.25": version: 0.16.27 resolution: "katex@npm:0.16.27" dependencies: @@ -15889,16 +15904,16 @@ __metadata: languageName: node linkType: hard -"langium@npm:3.3.1": - version: 3.3.1 - resolution: "langium@npm:3.3.1" +"langium@npm:^4.0.0": + version: 4.2.1 + resolution: "langium@npm:4.2.1" dependencies: - chevrotain: "npm:~11.0.3" - chevrotain-allstar: "npm:~0.3.0" + chevrotain: "npm:~11.1.1" + chevrotain-allstar: "npm:~0.3.1" vscode-languageserver: "npm:~9.0.1" vscode-languageserver-textdocument: "npm:~1.0.11" - vscode-uri: "npm:~3.0.8" - checksum: 10c0/0c54803068addb0f7c16a57fdb2db2e5d4d9a21259d477c3c7d0587c2c2f65a313f9eeef3c95ac1c2e41cd11d4f2eaf620d2c03fe839a3350ffee59d2b4c7647 + vscode-uri: "npm:~3.1.0" + checksum: 10c0/19ddf79cc3c435ec70f8eb50de255571711db7cea89d171cf80bc97e7ed73d4d0bb6b4215899df8369fa6d0e17f442f30af4ec2e9657041bf2f93be1310ba50a languageName: node linkType: hard @@ -16225,10 +16240,10 @@ __metadata: languageName: node linkType: hard -"lodash-es@npm:4.17.21, lodash-es@npm:^4.17.21": - version: 4.17.21 - resolution: "lodash-es@npm:4.17.21" - checksum: 10c0/fb407355f7e6cd523a9383e76e6b455321f0f153a6c9625e21a8827d10c54c2a2341bd2ae8d034358b60e07325e1330c14c224ff582d04612a46a4f0479ff2f2 +"lodash-es@npm:4.17.23, lodash-es@npm:^4.17.21, lodash-es@npm:^4.17.23": + version: 4.17.23 + resolution: "lodash-es@npm:4.17.23" + checksum: 10c0/3150fb6660c14c7a6b5f23bd11597d884b140c0e862a17fdb415aaa5ef7741523182904a6b7929f04e5f60a11edb5a79499eb448734381c99ffb3c4734beeddd languageName: node linkType: hard @@ -16598,7 +16613,7 @@ __metadata: languageName: node linkType: hard -"marked@npm:^16.2.1": +"marked@npm:^16.3.0": version: 16.4.2 resolution: "marked@npm:16.4.2" bin: @@ -16673,31 +16688,32 @@ __metadata: languageName: node linkType: hard -"mermaid@npm:11.12.1": - version: 11.12.1 - resolution: "mermaid@npm:11.12.1" +"mermaid@npm:11.13.0": + version: 11.13.0 + resolution: "mermaid@npm:11.13.0" dependencies: "@braintree/sanitize-url": "npm:^7.1.1" - "@iconify/utils": "npm:^3.0.1" - "@mermaid-js/parser": "npm:^0.6.3" + "@iconify/utils": "npm:^3.0.2" + "@mermaid-js/parser": "npm:^1.0.1" "@types/d3": "npm:^7.4.3" - cytoscape: "npm:^3.29.3" + "@upsetjs/venn.js": "npm:^2.0.0" + cytoscape: "npm:^3.33.1" cytoscape-cose-bilkent: "npm:^4.1.0" cytoscape-fcose: "npm:^2.2.0" d3: "npm:^7.9.0" d3-sankey: "npm:^0.12.3" - dagre-d3-es: "npm:7.0.13" - dayjs: "npm:^1.11.18" - dompurify: "npm:^3.2.5" - katex: "npm:^0.16.22" + dagre-d3-es: "npm:7.0.14" + dayjs: "npm:^1.11.19" + dompurify: "npm:^3.3.1" + katex: "npm:^0.16.25" khroma: "npm:^2.1.0" - lodash-es: "npm:^4.17.21" - marked: "npm:^16.2.1" + lodash-es: "npm:^4.17.23" + marked: "npm:^16.3.0" roughjs: "npm:^4.6.6" stylis: "npm:^4.3.6" ts-dedent: "npm:^2.2.0" uuid: "npm:^11.1.0" - checksum: 10c0/0dd07a5986bb25ca038f68f7a187a0b6ccf5fa8c738603c3145bd4b6289d50312053818f52617cf575a6652e6c57809ae115c016725f7ce446496be5971a150a + checksum: 10c0/9d908314d26cdb23d8fbb6a1183f3dc48440efa2cf25f31fd5f75ef3f72e973ef7c3b77768eb8399898035366d2b4a3a2bf0a0de9e35757848754935bf1288c0 languageName: node linkType: hard @@ -17734,7 +17750,7 @@ __metadata: markdown-it: "npm:^14.1.0" markdown-it-container: "npm:^3.0.0" markdown-it-emoji: "npm:^3.0.0" - mermaid: "npm:11.12.1" + mermaid: "npm:11.13.0" mime-types: "npm:^3.0.1" mobx: "npm:^4.15.4" mobx-react: "npm:^6.3.1" @@ -22534,10 +22550,10 @@ __metadata: languageName: node linkType: hard -"vscode-uri@npm:~3.0.8": - version: 3.0.8 - resolution: "vscode-uri@npm:3.0.8" - checksum: 10c0/f7f217f526bf109589969fe6e66b71e70b937de1385a1d7bb577ca3ee7c5e820d3856a86e9ff2fa9b7a0bc56a3dd8c3a9a557d3fedd7df414bc618d5e6b567f9 +"vscode-uri@npm:~3.1.0": + version: 3.1.0 + resolution: "vscode-uri@npm:3.1.0" + checksum: 10c0/5f6c9c10fd9b1664d71fab4e9fbbae6be93c7f75bb3a1d9d74399a88ab8649e99691223fd7cef4644376cac6e94fa2c086d802521b9a8e31c5af3e60f0f35624 languageName: node linkType: hard