From 7134fc272e9e60be4b80dfd294ff8926d5995188 Mon Sep 17 00:00:00 2001 From: Freddy Boulton Date: Wed, 16 Oct 2024 15:11:39 -0700 Subject: [PATCH] Custom component fixes (#9711) * add code * Add code * add changeset * compatible lockfile * add code * add changeset * trigger-ci --------- Co-authored-by: gradio-pr-bot Co-authored-by: pngwn --- .changeset/hot-dancers-drop.md | 9 +++++ js/atoms/package.json | 3 +- js/build/out/index.js | 3 +- js/build/src/index.ts | 3 +- js/markdown/package.json | 8 ++-- js/markdown/shared/MarkdownCode.svelte | 51 +------------------------- js/sanitize/browser.ts | 43 ++++++++++++++++++++++ js/sanitize/index.d.ts | 1 + js/sanitize/package.json | 34 +++++++++++++++++ js/sanitize/server.ts | 5 +++ pnpm-lock.yaml | 28 +++++++++----- 11 files changed, 122 insertions(+), 66 deletions(-) create mode 100644 .changeset/hot-dancers-drop.md create mode 100644 js/sanitize/browser.ts create mode 100644 js/sanitize/index.d.ts create mode 100644 js/sanitize/package.json create mode 100644 js/sanitize/server.ts diff --git a/.changeset/hot-dancers-drop.md b/.changeset/hot-dancers-drop.md new file mode 100644 index 0000000000000..472c1955511ab --- /dev/null +++ b/.changeset/hot-dancers-drop.md @@ -0,0 +1,9 @@ +--- +"@gradio/atoms": patch +"@gradio/markdown": patch +"@gradio/sanitize": patch +"@self/build": patch +"gradio": patch +--- + +fix:Custom component fixes diff --git a/js/atoms/package.json b/js/atoms/package.json index f1c964664c64b..c3a8384bbe573 100644 --- a/js/atoms/package.json +++ b/js/atoms/package.json @@ -8,7 +8,8 @@ "license": "ISC", "dependencies": { "@gradio/icons": "workspace:^", - "@gradio/utils": "workspace:^" + "@gradio/utils": "workspace:^", + "@gradio/markdown": "workspace:^" }, "peerDependencies": { "svelte": "^4.0.0" diff --git a/js/build/out/index.js b/js/build/out/index.js index b8edee8112d56..83e8597128ade 100644 --- a/js/build/out/index.js +++ b/js/build/out/index.js @@ -149,7 +149,8 @@ var ignore_list = [ "tooltip", "upload", "utils", - "wasm" + "wasm", + "sanitize" ]; function generate_component_imports() { const exports = readdirSync(join(__dirname, "..", "..")).map((dir) => { diff --git a/js/build/src/index.ts b/js/build/src/index.ts index 77a1055b3cc75..db743386769aa 100644 --- a/js/build/src/index.ts +++ b/js/build/src/index.ts @@ -211,7 +211,8 @@ const ignore_list = [ "tooltip", "upload", "utils", - "wasm" + "wasm", + "sanitize" ]; function generate_component_imports(): string { const exports = readdirSync(join(__dirname, "..", "..")) diff --git a/js/markdown/package.json b/js/markdown/package.json index bb01a23dfa807..0e7d8653849e6 100644 --- a/js/markdown/package.json +++ b/js/markdown/package.json @@ -26,10 +26,10 @@ "@gradio/icons": "workspace:^", "@gradio/statustracker": "workspace:^", "@gradio/utils": "workspace:^", + "@gradio/sanitize": "workspace:^", "@types/dompurify": "^3.0.2", "@types/katex": "^0.16.0", "@types/prismjs": "1.26.4", - "amuchina": "^1.0.12", "dom-parser": "^1.1.5", "github-slugger": "^2.0.0", "isomorphic-dompurify": "^2.14.0", @@ -37,12 +37,10 @@ "marked": "^12.0.0", "marked-gfm-heading-id": "^3.1.2", "marked-highlight": "^2.0.1", - "prismjs": "1.29.0", - "sanitize-html": "^2.13.0" + "prismjs": "1.29.0" }, "devDependencies": { - "@gradio/preview": "workspace:^", - "@types/sanitize-html": "^2.13.0" + "@gradio/preview": "workspace:^" }, "peerDependencies": { "svelte": "^4.0.0" diff --git a/js/markdown/shared/MarkdownCode.svelte b/js/markdown/shared/MarkdownCode.svelte index 84ce5b6be1410..efa582d89dd6e 100644 --- a/js/markdown/shared/MarkdownCode.svelte +++ b/js/markdown/shared/MarkdownCode.svelte @@ -3,8 +3,7 @@ import render_math_in_element from "katex/contrib/auto-render"; import "katex/dist/katex.min.css"; import { create_marked } from "./utils"; - import sanitize_server from "sanitize-html"; - import Amuchina from "amuchina"; + import { sanitize } from "@gradio/sanitize"; import "./prism.css"; export let chatbot = true; @@ -29,52 +28,6 @@ latex_delimiters }); - const amuchina = new Amuchina(); - const is_browser = typeof window !== "undefined"; - - let sanitize = is_browser ? sanitize_browser : sanitize_server; - - function sanitize_browser(source: string): string { - const node = new DOMParser().parseFromString(source, "text/html"); - walk_nodes(node.body, "A", (node) => { - if (node instanceof HTMLElement && "target" in node) { - if (is_external_url(node.getAttribute("href"))) { - node.setAttribute("target", "_blank"); - node.setAttribute("rel", "noopener noreferrer"); - } - } - }); - - return amuchina.sanitize(node).body.innerHTML; - } - - function walk_nodes( - node: Node | null | HTMLElement, - test: string | ((node: Node | HTMLElement) => boolean), - callback: (node: Node | HTMLElement) => void - ): void { - if ( - node && - ((typeof test === "string" && node.nodeName === test) || - (typeof test === "function" && test(node))) - ) { - callback(node); - } - const children = node?.childNodes || []; - for (let i = 0; i < children.length; i++) { - // @ts-ignore - walk_nodes(children[i], test, callback); - } - } - - const is_external_url = (link: string | null): boolean => { - try { - return !!link && new URL(link).origin !== new URL(root).origin; - } catch (e) { - return false; - } - }; - function escapeRegExp(string: string): string { return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } @@ -106,7 +59,7 @@ } if (sanitize_html && sanitize) { - parsedValue = sanitize(parsedValue); + parsedValue = sanitize(parsedValue, root); } return parsedValue; diff --git a/js/sanitize/browser.ts b/js/sanitize/browser.ts new file mode 100644 index 0000000000000..40242d99a1831 --- /dev/null +++ b/js/sanitize/browser.ts @@ -0,0 +1,43 @@ +import Amuchina from "amuchina"; + +const is_external_url = (link: string | null, root: string): boolean => { + try { + return !!link && new URL(link).origin !== new URL(root).origin; + } catch (e) { + return false; + } +}; + +export function sanitize(source: string, root: string): string { + const amuchina = new Amuchina(); + const node = new DOMParser().parseFromString(source, "text/html"); + walk_nodes(node.body, "A", (node) => { + if (node instanceof HTMLElement && "target" in node) { + if (is_external_url(node.getAttribute("href"), root)) { + node.setAttribute("target", "_blank"); + node.setAttribute("rel", "noopener noreferrer"); + } + } + }); + + return amuchina.sanitize(node).body.innerHTML; +} + +function walk_nodes( + node: Node | null | HTMLElement, + test: string | ((node: Node | HTMLElement) => boolean), + callback: (node: Node | HTMLElement) => void +): void { + if ( + node && + ((typeof test === "string" && node.nodeName === test) || + (typeof test === "function" && test(node))) + ) { + callback(node); + } + const children = node?.childNodes || []; + for (let i = 0; i < children.length; i++) { + // @ts-ignore + walk_nodes(children[i], test, callback); + } +} diff --git a/js/sanitize/index.d.ts b/js/sanitize/index.d.ts new file mode 100644 index 0000000000000..9690133388361 --- /dev/null +++ b/js/sanitize/index.d.ts @@ -0,0 +1 @@ +export declare function sanitize(source: string, root: string): string; diff --git a/js/sanitize/package.json b/js/sanitize/package.json new file mode 100644 index 0000000000000..1f1a06473d383 --- /dev/null +++ b/js/sanitize/package.json @@ -0,0 +1,34 @@ +{ + "name": "@gradio/sanitize", + "version": "0.1.0", + "description": "Gradio UI packages", + "type": "module", + "author": "", + "main": "./dist/server.js", + "license": "ISC", + "dependencies": { + "sanitize-html": "^2.13.0", + "amuchina": "^1.0.12" + }, + "devDependencies": { + "@types/sanitize-html": "^2.13.0" + }, + "main_changeset": true, + "repository": { + "type": "git", + "url": "git+https://github.com/gradio-app/gradio.git", + "directory": "js/utils" + }, + "exports": { + ".": { + "types": "./dist/index.d.ts", + "browser": "./dist/browser.js", + "import": "./dist/server.js", + "default": "./dist/server.js" + }, + "./package.json": "./package.json" + }, + "scripts": { + "package": "svelte-package --input=. --cwd=../../.config/" + } +} diff --git a/js/sanitize/server.ts b/js/sanitize/server.ts new file mode 100644 index 0000000000000..85ac45b391a39 --- /dev/null +++ b/js/sanitize/server.ts @@ -0,0 +1,5 @@ +import { default as sanitize_html_ } from "sanitize-html"; + +export function sanitize(source: string, root: string): string { + return sanitize_html_(source); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b3aac00e6ffe2..f3ae0b89d53aa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -625,6 +625,9 @@ importers: '@gradio/icons': specifier: workspace:^ version: link:../icons + '@gradio/markdown': + specifier: workspace:^ + version: link:../markdown '@gradio/utils': specifier: workspace:^ version: link:../utils @@ -1669,6 +1672,9 @@ importers: '@gradio/icons': specifier: workspace:^ version: link:../icons + '@gradio/sanitize': + specifier: workspace:^ + version: link:../sanitize '@gradio/statustracker': specifier: workspace:^ version: link:../statustracker @@ -1684,9 +1690,6 @@ importers: '@types/prismjs': specifier: 1.26.4 version: 1.26.4 - amuchina: - specifier: ^1.0.12 - version: 1.0.12 dom-parser: specifier: ^1.1.5 version: 1.1.5 @@ -1711,9 +1714,6 @@ importers: prismjs: specifier: 1.29.0 version: 1.29.0 - sanitize-html: - specifier: ^2.13.0 - version: 2.13.0 svelte: specifier: ^4.0.0 version: 4.2.15 @@ -1721,9 +1721,6 @@ importers: '@gradio/preview': specifier: workspace:^ version: link:../preview - '@types/sanitize-html': - specifier: ^2.13.0 - version: 2.13.0 js/model3D: dependencies: @@ -2034,6 +2031,19 @@ importers: specifier: workspace:^ version: link:../utils + js/sanitize: + dependencies: + amuchina: + specifier: ^1.0.12 + version: 1.0.12 + sanitize-html: + specifier: ^2.13.0 + version: 2.13.0 + devDependencies: + '@types/sanitize-html': + specifier: ^2.13.0 + version: 2.13.0 + js/simpledropdown: dependencies: '@gradio/atoms':