mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-08-29 04:26:20 +00:00
MarkdownContentViewer.tsx exported the isSafeUrl helper alongside the component so it could be unit tested, which tripped react-refresh/only-export-components. Move the helper into a sibling pure module, markdownUrlSafety.ts, following the existing GraphWorkspace convention for testable non-component logic (graphAnalytics.ts, pluginRegistryPredicates.ts, temporalLifecyclePredicates.ts). The function body is moved verbatim — the scheme allowlist, protocol-relative rejection, whitespace-only guard and malformed-URL handling are unchanged — so the existing URL-safety tests pass untouched apart from the import path. The component module now exports only its component and prop type, clearing the lint error without any change to the lint configuration. Co-authored-by: Pravit Ampapathini <pravit.amp@gmail.com>
This commit is contained in:
co-authored by
Pravit Ampapathini
parent
5e8caadcb4
commit
c7d608570c
@@ -3,6 +3,7 @@ import ReactMarkdown from "react-markdown";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import { Check, Copy, Code2, Eye, ExternalLink, Image as ImageIcon } from "lucide-react";
|
||||
import { GRAPH_THEME } from "./graphTheme";
|
||||
import { isSafeUrl } from "./markdownUrlSafety";
|
||||
|
||||
export interface MarkdownContentViewerProps {
|
||||
content?: string | null;
|
||||
@@ -10,25 +11,6 @@ export interface MarkdownContentViewerProps {
|
||||
defaultMode?: "preview" | "source";
|
||||
}
|
||||
|
||||
export function isSafeUrl(url?: string): boolean {
|
||||
if (!url) return false;
|
||||
const trimmed = url.trim();
|
||||
// Reject whitespace-only strings — new URL("", base) would resolve to the base
|
||||
// protocol and produce a false positive. This guards direct callers of the exported
|
||||
// function; markdown parsers normalise whitespace-only destinations to "" which
|
||||
// already fails the !url check above.
|
||||
if (!trimmed) return false;
|
||||
if (trimmed.startsWith("//")) return false;
|
||||
if (trimmed.startsWith("#")) return true;
|
||||
if (trimmed.startsWith("/")) return true;
|
||||
try {
|
||||
const parsed = new URL(trimmed, "http://localhost");
|
||||
return ["http:", "https:", "mailto:"].includes(parsed.protocol);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function MarkdownContentViewer({
|
||||
content,
|
||||
className,
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* URL-safety predicate for the Markdown content viewer.
|
||||
*
|
||||
* Extracted into a pure module so the check can be unit-tested without
|
||||
* importing the MarkdownContentViewer React component, and so the component
|
||||
* module exports only components (react-refresh/only-export-components,
|
||||
* issue #1119). The behaviour is unchanged from the original in-component
|
||||
* implementation: only http, https, mailto, in-document fragments, and
|
||||
* root-relative paths are permitted.
|
||||
*/
|
||||
|
||||
export function isSafeUrl(url?: string): boolean {
|
||||
if (!url) return false;
|
||||
const trimmed = url.trim();
|
||||
// Reject whitespace-only strings — new URL("", base) would resolve to the base
|
||||
// protocol and produce a false positive. This guards direct callers of the exported
|
||||
// function; markdown parsers normalise whitespace-only destinations to "" which
|
||||
// already fails the !url check above.
|
||||
if (!trimmed) return false;
|
||||
if (trimmed.startsWith("//")) return false;
|
||||
if (trimmed.startsWith("#")) return true;
|
||||
if (trimmed.startsWith("/")) return true;
|
||||
try {
|
||||
const parsed = new URL(trimmed, "http://localhost");
|
||||
return ["http:", "https:", "mailto:"].includes(parsed.protocol);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,8 @@ import { renderToString } from "react-dom/server";
|
||||
|
||||
(globalThis as any).React = React;
|
||||
|
||||
import { isSafeUrl, MarkdownContentViewer } from "../src/workspaces/GraphWorkspace/MarkdownContentViewer.tsx";
|
||||
import { MarkdownContentViewer } from "../src/workspaces/GraphWorkspace/MarkdownContentViewer.tsx";
|
||||
import { isSafeUrl } from "../src/workspaces/GraphWorkspace/markdownUrlSafety.ts";
|
||||
|
||||
test("isSafeUrl permits safe http, https, and mailto URLs and relative paths", () => {
|
||||
assert.equal(isSafeUrl("https://example.com"), true);
|
||||
|
||||
Reference in New Issue
Block a user