From 550219c5469555d59cc3c7bbbd23f5fccb2c162a Mon Sep 17 00:00:00 2001 From: octo-patch Date: Sat, 18 Apr 2026 10:07:57 +0800 Subject: [PATCH] fix: support formatter functions in ECharts code blocks (fixes #6536) When an ECharts config contains formatter or other function values, json5.parse() fails silently and the chart renders as a blank box. Add a fallback that evaluates the config as a JavaScript expression using the Function constructor, enabling formatter callbacks to work. json5.parse() is still attempted first as it is safer for standard JSON5 configs. --- .../Markdown/img/EChartsCodeBlock.tsx | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/projects/app/src/components/Markdown/img/EChartsCodeBlock.tsx b/projects/app/src/components/Markdown/img/EChartsCodeBlock.tsx index e1239efb83a3..8665297d00c3 100644 --- a/projects/app/src/components/Markdown/img/EChartsCodeBlock.tsx +++ b/projects/app/src/components/Markdown/img/EChartsCodeBlock.tsx @@ -34,26 +34,37 @@ const EChartsCodeBlock = ({ code }: { code: string }) => { }); useLayoutEffect(() => { + const buildOption = (userOption: any) => { + const userToolbox = userOption.toolbox || {}; + const userFeature = userToolbox.feature || {}; + return { + ...userOption, + toolbox: { + ...userToolbox, + // show: true, + feature: { + saveAsImage: {}, + ...userFeature + } + } + }; + }; + const option = (() => { + // First try json5 parse (safe, handles JSON5 syntax like comments/trailing commas) try { const userOption = json5.parse(code.trim()); - const userToolbox = userOption.toolbox || {}; - const userFeature = userToolbox.feature || {}; - - const parse = { - ...userOption, - toolbox: { - ...userToolbox, - // show: true, - feature: { - saveAsImage: {}, - ...userFeature - } - } - }; + return buildOption(userOption); + } catch (_e) {} - return parse; - } catch (error) {} + // Fallback: evaluate as JS expression to support formatter functions and other JS values + try { + // eslint-disable-next-line no-new-func + const userOption = new Function(`return (${code.trim()})`)(); + if (userOption && typeof userOption === 'object') { + return buildOption(userOption); + } + } catch (_e) {} })(); setOption(option ?? {});