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
+ }
}