diff --git a/src/components/structures/ViewSource.tsx b/src/components/structures/ViewSource.tsx index 7cc3b0dbcd..3b8250991c 100644 --- a/src/components/structures/ViewSource.tsx +++ b/src/components/structures/ViewSource.tsx @@ -71,13 +71,13 @@ export default class ViewSource extends React.Component { { _t("Decrypted event source") } - { JSON.stringify(decryptedEventSource, null, 2) } + { JSON.stringify(decryptedEventSource, null, 2) }
{ _t("Original event source") } - { JSON.stringify(originalEventSource, null, 2) } + { JSON.stringify(originalEventSource, null, 2) }
); @@ -85,7 +85,7 @@ export default class ViewSource extends React.Component { return ( <>
{ _t("Original event source") }
- { JSON.stringify(originalEventSource, null, 2) } + { JSON.stringify(originalEventSource, null, 2) } ); } diff --git a/src/components/views/dialogs/DevtoolsDialog.tsx b/src/components/views/dialogs/DevtoolsDialog.tsx index 8b698acd7c..c2e7a49adb 100644 --- a/src/components/views/dialogs/DevtoolsDialog.tsx +++ b/src/components/views/dialogs/DevtoolsDialog.tsx @@ -501,7 +501,7 @@ class RoomStateExplorer extends React.PureComponent
- + { JSON.stringify(this.state.event.event, null, 2) }
@@ -634,7 +634,7 @@ class AccountDataExplorer extends React.PureComponent
- + { JSON.stringify(this.state.event.event, null, 2) }
diff --git a/src/components/views/elements/SyntaxHighlight.tsx b/src/components/views/elements/SyntaxHighlight.tsx index 96ad1f2c02..bc4b3111f3 100644 --- a/src/components/views/elements/SyntaxHighlight.tsx +++ b/src/components/views/elements/SyntaxHighlight.tsx @@ -15,41 +15,26 @@ limitations under the License. */ import React from 'react'; -import highlight from 'highlight.js'; +import hljs from 'highlight.js'; import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { - className?: string; - children?: React.ReactNode; + language?: string; + children: string; } @replaceableComponent("views.elements.SyntaxHighlight") -export default class SyntaxHighlight extends React.Component { - private el: HTMLPreElement = null; - - constructor(props: IProps) { - super(props); - } - - // componentDidUpdate used here for reusability - public componentDidUpdate(): void { - if (this.el) highlight.highlightElement(this.el); - } - - // call componentDidUpdate because _ref is fired on initial render - // which does not fire componentDidUpdate - private ref = (el: HTMLPreElement): void => { - this.el = el; - this.componentDidUpdate(); - }; - +export default class SyntaxHighlight extends React.PureComponent { public render(): JSX.Element { - const { className, children } = this.props; + const { children: content, language } = this.props; + const highlighted = language ? hljs.highlight(language, content) : hljs.highlightAuto(content); - return
-            { children }
-        
; + return ( +
+                
+            
+ ); } } diff --git a/src/rageshake/rageshake.ts b/src/rageshake/rageshake.ts index 5dcf8bc67b..acffa254af 100644 --- a/src/rageshake/rageshake.ts +++ b/src/rageshake/rageshake.ts @@ -40,6 +40,8 @@ limitations under the License. // the frequency with which we flush to indexeddb import { logger } from "matrix-js-sdk/src/logger"; +import { getCircularReplacer } from "../utils/JSON"; + const FLUSH_RATE_MS = 30 * 1000; // the length of log data we keep in indexeddb (and include in the reports) @@ -90,21 +92,7 @@ export class ConsoleLogger { } else if (arg instanceof Error) { return arg.message + (arg.stack ? `\n${arg.stack}` : ''); } else if (typeof (arg) === 'object') { - try { - return JSON.stringify(arg); - } catch (e) { - // In development, it can be useful to log complex cyclic - // objects to the console for inspection. This is fine for - // the console, but default `stringify` can't handle that. - // We workaround this by using a special replacer function - // to only log values of the root object and avoid cycles. - return JSON.stringify(arg, (key, value) => { - if (key && typeof value === "object") { - return ""; - } - return value; - }); - } + return JSON.stringify(arg, getCircularReplacer()); } else { return arg; } diff --git a/src/utils/JSON.ts b/src/utils/JSON.ts new file mode 100644 index 0000000000..fb00d7cd14 --- /dev/null +++ b/src/utils/JSON.ts @@ -0,0 +1,32 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +type StringifyReplacer = (this: any, key: string, value: any) => any; + +// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value#circular_references +// Injects `<$ cycle-trimmed $>` wherever it cuts a cyclical object relationship +export const getCircularReplacer = (): StringifyReplacer => { + const seen = new WeakSet(); + return (key: string, value: any): any => { + if (typeof value === "object" && value !== null) { + if (seen.has(value)) { + return "<$ cycle-trimmed $>"; + } + seen.add(value); + } + return value; + }; +};