diff --git a/web/src/utils/wiki-link-util.test.ts b/web/src/utils/wiki-link-util.test.ts index 02becae6cd..85d024c575 100644 --- a/web/src/utils/wiki-link-util.test.ts +++ b/web/src/utils/wiki-link-util.test.ts @@ -21,6 +21,17 @@ describe('parseWikiLinkHref', () => { ['/artifact/dataset/entity/person/张角', 'entity', 'person/张角'], ['topic/智能体', 'topic', '智能体'], ['/entity/location/长社', 'entity', 'location/长社'], + [ + // Lexical prepends https:// to scheme-less hrefs when rendering DOM. + 'https://artifact/dataset/entity/person/张角', + 'entity', + 'person/张角', + ], + [ + 'http://artifact/fb9bfae2a00b43e59ecaea5e86d90c91/entity/org/荣国府', + 'entity', + 'org/荣国府', + ], ])('preserves internal link %s', (href, pageType, slug) => { expect(parseWikiLinkHref(href)).toEqual({ pageType, slug }); }); diff --git a/web/src/utils/wiki-link-util.ts b/web/src/utils/wiki-link-util.ts index 0e1f31e528..e00cad7810 100644 --- a/web/src/utils/wiki-link-util.ts +++ b/web/src/utils/wiki-link-util.ts @@ -17,6 +17,20 @@ export function parseWikiLinkHref( const normalized = href.trim(); if (!normalized) return null; + // Lexical's LinkNode renders scheme-less hrefs by prepending https://, so an + // internal `artifact/{id}/{pageType}/{slug}` link surfaces in the DOM as + // `https://artifact/{id}/{pageType}/{slug}` with a bogus "artifact" host. + // Recognise that normalized form before rejecting URLs with a scheme. + const lexicalArtifactMatch = normalized.match( + /^https?:\/\/artifact\/[^/]+\/(entity|concept|topic)\/([^\s"']+)/i, + ); + if (lexicalArtifactMatch) { + return { + pageType: lexicalArtifactMatch[1] as WikiPageType, + slug: lexicalArtifactMatch[2], + }; + } + // Leave URLs with a scheme or authority to normal link navigation. if (/^(?:[a-z][a-z\d+.-]*:|[\\/]{2})/i.test(normalized)) return null;