diff --git a/VERSION_11_UPGRADE.md b/VERSION_11_UPGRADE.md
index da70df2724..f97d20a454 100644
--- a/VERSION_11_UPGRADE.md
+++ b/VERSION_11_UPGRADE.md
@@ -2,6 +2,10 @@
- remove apache, http, nginx, properties, coffeescript from :common #2848
+### Feature Removal
+
+- HTML merging is now no longer included in core. You'll want to use a plugin instead. https://github.com/highlightjs/highlight.js/issues/2889
+- fixMarkup is gone now, provide your own replacement #2534
### Behavior changes
@@ -26,7 +30,6 @@
## API's changed
- rename second_best to secondBest (highlightAuto)
-- fixMarkup is gone now, provide your own replacement #2534
- highlightElement/highlightBlock result now no longer returns `re` key, use `relevance` instead
- `CSS_NUMBER_MODE` has now been moved into the internal `css-shared` library
diff --git a/src/highlight.js b/src/highlight.js
index 1fe2cc509f..a5b0cea49f 100644
--- a/src/highlight.js
+++ b/src/highlight.js
@@ -13,7 +13,6 @@ import * as MODES from './lib/modes.js';
import { compileLanguage } from './lib/mode_compiler.js';
import * as packageJSON from '../package.json';
import { BuildVuePlugin } from "./plugins/vue.js";
-import { mergeHTMLPlugin } from "./plugins/merge_html.js";
import * as logger from "./lib/logger.js";
const escape = utils.escapeHTML;
@@ -918,8 +917,6 @@ const HLJS = function(hljs) {
// merge all the modes/regexs into our main object
Object.assign(hljs, MODES);
- // built-in plugins, likely to be moved out of core in the future
- hljs.addPlugin(mergeHTMLPlugin);
return hljs;
};
diff --git a/src/plugins/merge_html.js b/src/plugins/merge_html.js
deleted file mode 100644
index a081df649f..0000000000
--- a/src/plugins/merge_html.js
+++ /dev/null
@@ -1,156 +0,0 @@
-import { escapeHTML } from "../lib/utils.js";
-
-/* plugin itself */
-
-/** @type {HLJSPlugin} */
-export const mergeHTMLPlugin = {
- "after:highlightElement": ({ el, result, text }) => {
- const originalStream = nodeStream(el);
- if (!originalStream.length) return;
-
- const resultNode = document.createElement('div');
- resultNode.innerHTML = result.value;
- result.value = mergeStreams(originalStream, nodeStream(resultNode), text);
- }
-};
-
-/* Stream merging support functions */
-
-/**
- * @typedef Event
- * @property {'start'|'stop'} event
- * @property {number} offset
- * @property {Node} node
- */
-
-/**
- * @param {Node} node
- */
-function tag(node) {
- return node.nodeName.toLowerCase();
-}
-
-/**
- * @param {Node} node
- */
-export function nodeStream(node) {
- /** @type Event[] */
- const result = [];
- (function _nodeStream(node, offset) {
- for (let child = node.firstChild; child; child = child.nextSibling) {
- if (child.nodeType === 3) {
- offset += child.nodeValue.length;
- } else if (child.nodeType === 1) {
- result.push({
- event: 'start',
- offset: offset,
- node: child
- });
- offset = _nodeStream(child, offset);
- // Prevent void elements from having an end tag that would actually
- // double them in the output. There are more void elements in HTML
- // but we list only those realistically expected in code display.
- if (!tag(child).match(/br|hr|img|input/)) {
- result.push({
- event: 'stop',
- offset: offset,
- node: child
- });
- }
- }
- }
- return offset;
- })(node, 0);
- return result;
-}
-
-/**
- * @param {any} original - the original stream
- * @param {any} highlighted - stream of the highlighted source
- * @param {string} value - the original source itself
- */
-export function mergeStreams(original, highlighted, value) {
- let processed = 0;
- let result = '';
- const nodeStack = [];
-
- function selectStream() {
- if (!original.length || !highlighted.length) {
- return original.length ? original : highlighted;
- }
- if (original[0].offset !== highlighted[0].offset) {
- return (original[0].offset < highlighted[0].offset) ? original : highlighted;
- }
-
- /*
- To avoid starting the stream just before it should stop the order is
- ensured that original always starts first and closes last:
-
- if (event1 == 'start' && event2 == 'start')
- return original;
- if (event1 == 'start' && event2 == 'stop')
- return highlighted;
- if (event1 == 'stop' && event2 == 'start')
- return original;
- if (event1 == 'stop' && event2 == 'stop')
- return highlighted;
-
- ... which is collapsed to:
- */
- return highlighted[0].event === 'start' ? original : highlighted;
- }
-
- /**
- * @param {Node} node
- */
- function open(node) {
- /** @param {Attr} attr */
- function attributeString(attr) {
- return ' ' + attr.nodeName + '="' + escapeHTML(attr.value) + '"';
- }
- // @ts-ignore
- result += '<' + tag(node) + [].map.call(node.attributes, attributeString).join('') + '>';
- }
-
- /**
- * @param {Node} node
- */
- function close(node) {
- result += '' + tag(node) + '>';
- }
-
- /**
- * @param {Event} event
- */
- function render(event) {
- (event.event === 'start' ? open : close)(event.node);
- }
-
- while (original.length || highlighted.length) {
- let stream = selectStream();
- result += escapeHTML(value.substring(processed, stream[0].offset));
- processed = stream[0].offset;
- if (stream === original) {
- /*
- On any opening or closing tag of the original markup we first close
- the entire highlighted node stack, then render the original tag along
- with all the following original tags at the same offset and then
- reopen all the tags on the highlighted stack.
- */
- nodeStack.reverse().forEach(close);
- do {
- render(stream.splice(0, 1)[0]);
- stream = selectStream();
- } while (stream === original && stream.length && stream[0].offset === processed);
- nodeStack.reverse().forEach(open);
- } else {
- if (stream[0].event === 'start') {
- nodeStack.push(stream[0].node);
- } else {
- nodeStack.pop();
- }
- render(stream.splice(0, 1)[0]);
- }
- }
- return result + escapeHTML(value.substr(processed));
-}
diff --git a/test/fixtures/expect/brInPre.txt b/test/fixtures/expect/brInPre.txt
deleted file mode 100644
index e065147ab3..0000000000
--- a/test/fixtures/expect/brInPre.txt
+++ /dev/null
@@ -1 +0,0 @@
->> '\x41\x42\x43'
'ABC'
<div id="contents">
- <p>Hello, World!Goodbye, cruel world!
-</div>
-
-
-
->> '\x41\x42\x43'
'ABC'
>> '\x61\x62\x63'
'abc'
-
-
-