From a95b2d7d7d0e34ecea228222ec5a14bf0bc890f8 Mon Sep 17 00:00:00 2001 From: Tilman Vatteroth Date: Mon, 17 Apr 2023 14:55:09 +0200 Subject: [PATCH] feat: add priorities for replacers Signed-off-by: Tilman Vatteroth --- .../utils/node-to-react-transformer.spec.tsx | 52 ++++++++++++++++++- .../utils/node-to-react-transformer.tsx | 14 ++++- .../replace-components/component-replacer.ts | 15 ++++++ .../highlighted-code-replacer.tsx | 9 +++- 4 files changed, 86 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/markdown-renderer/markdown-to-react/utils/node-to-react-transformer.spec.tsx b/frontend/src/components/markdown-renderer/markdown-to-react/utils/node-to-react-transformer.spec.tsx index 9f4fd3e2f..2c03b4432 100644 --- a/frontend/src/components/markdown-renderer/markdown-to-react/utils/node-to-react-transformer.spec.tsx +++ b/frontend/src/components/markdown-renderer/markdown-to-react/utils/node-to-react-transformer.spec.tsx @@ -4,7 +4,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ import type { NodeReplacement } from '../../replace-components/component-replacer' -import { ComponentReplacer, DO_NOT_REPLACE } from '../../replace-components/component-replacer' +import { ComponentReplacer, DO_NOT_REPLACE, ReplacerPriority } from '../../replace-components/component-replacer' import { NodeToReactTransformer } from './node-to-react-transformer' import { Element } from 'domhandler' import type { ReactElement, ReactHTMLElement } from 'react' @@ -37,6 +37,56 @@ describe('node to react transformer', () => { expect(translation).toEqual(null) }) + it('will prioritize a high priority replacer over a normal priority replacer', () => { + nodeToReactTransformer.setReplacers([ + new (class extends ComponentReplacer { + getPriority(): ReplacerPriority { + return ReplacerPriority.NORMAL + } + + replace(): NodeReplacement { + return Replacer O + } + })(), + new (class extends ComponentReplacer { + getPriority(): ReplacerPriority { + return ReplacerPriority.HIGHER + } + + replace(): NodeReplacement { + return Replacer X + } + })() + ]) + const translation = nodeToReactTransformer.translateNodeToReactElement(defaultTestSpanElement, 1) as ReactElement + expect(translation).toMatchSnapshot() + }) + + it('will prioritize a normal priority replacer over a low priority replacer', () => { + nodeToReactTransformer.setReplacers([ + new (class extends ComponentReplacer { + getPriority(): ReplacerPriority { + return ReplacerPriority.LOWER + } + + replace(): NodeReplacement { + return Replacer M + } + })(), + new (class extends ComponentReplacer { + getPriority(): ReplacerPriority { + return ReplacerPriority.NORMAL + } + + replace(): NodeReplacement { + return Replacer Y + } + })() + ]) + const translation = nodeToReactTransformer.translateNodeToReactElement(defaultTestSpanElement, 1) as ReactElement + expect(translation).toMatchSnapshot() + }) + it('can translate an element with no matching replacer', () => { nodeToReactTransformer.setReplacers([ new (class extends ComponentReplacer { diff --git a/frontend/src/components/markdown-renderer/markdown-to-react/utils/node-to-react-transformer.tsx b/frontend/src/components/markdown-renderer/markdown-to-react/utils/node-to-react-transformer.tsx index a7d2027d7..fb2534f63 100644 --- a/frontend/src/components/markdown-renderer/markdown-to-react/utils/node-to-react-transformer.tsx +++ b/frontend/src/components/markdown-renderer/markdown-to-react/utils/node-to-react-transformer.tsx @@ -31,7 +31,19 @@ export class NodeToReactTransformer { } public setReplacers(replacers: ComponentReplacer[]): void { - this.replacers = replacers + this.replacers = new Array(...replacers).sort(this.compareReplacers.bind(this)) + } + + private compareReplacers(replacerA: ComponentReplacer, replacerB: ComponentReplacer): number { + const priorityA = replacerA.getPriority() + const priorityB = replacerB.getPriority() + if (priorityA === priorityB) { + return 0 + } else if (priorityA < priorityB) { + return -1 + } else { + return 1 + } } /** diff --git a/frontend/src/components/markdown-renderer/replace-components/component-replacer.ts b/frontend/src/components/markdown-renderer/replace-components/component-replacer.ts index 4d77f1749..d05c682ca 100644 --- a/frontend/src/components/markdown-renderer/replace-components/component-replacer.ts +++ b/frontend/src/components/markdown-renderer/replace-components/component-replacer.ts @@ -17,6 +17,12 @@ export const DO_NOT_REPLACE = Symbol() export type NodeReplacement = ValidReactDomElement | typeof DO_NOT_REPLACE +export enum ReplacerPriority { + LOWER = 1, + NORMAL = 0, + HIGHER = -1 +} + /** * Base class for all component replacers. * Component replacers detect structures in the HTML DOM from markdown it @@ -65,4 +71,13 @@ export abstract class ComponentReplacer { subNodeTransform: SubNodeTransform, nativeRenderer: NativeRenderer ): NodeReplacement + + /** + * Defines that a replacer should be preferred more or less than other replacers. + * + * @return the replacer priority that gets compared to others. + */ + public getPriority(): ReplacerPriority { + return ReplacerPriority.NORMAL + } } diff --git a/frontend/src/extensions/essential-app-extensions/highlighted-code-fence/highlighted-code-replacer.tsx b/frontend/src/extensions/essential-app-extensions/highlighted-code-fence/highlighted-code-replacer.tsx index 5ed2ff893..e0dfce7e1 100644 --- a/frontend/src/extensions/essential-app-extensions/highlighted-code-fence/highlighted-code-replacer.tsx +++ b/frontend/src/extensions/essential-app-extensions/highlighted-code-fence/highlighted-code-replacer.tsx @@ -4,11 +4,12 @@ * SPDX-License-Identifier: AGPL-3.0-only */ import HighlightedCode from '../../../components/common/highlighted-code/highlighted-code' +import type { NodeReplacement } from '../../../components/markdown-renderer/replace-components/component-replacer' import { ComponentReplacer, - DO_NOT_REPLACE + DO_NOT_REPLACE, + ReplacerPriority } from '../../../components/markdown-renderer/replace-components/component-replacer' -import type { NodeReplacement } from '../../../components/markdown-renderer/replace-components/component-replacer' import type { Element } from 'domhandler' import React from 'react' @@ -56,4 +57,8 @@ export class HighlightedCodeReplacer extends ComponentReplacer { reset() { this.lastLineNumber = 0 } + + getPriority(): ReplacerPriority { + return ReplacerPriority.LOWER + } }