// Forked from https://github.com/inkling/htmldiff.js/blob/master/js/htmldiff.js
// The MIT License (MIT)
// Copyright (c) 2012 The Network Inc. and contributors
// Copyright (c) 2022 idesis GmbH, Max-Keith-Straße 66 (E 11), D-45136 Essen, https://www.idesis.de
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
/**
* htmldiff.js is a library that compares HTML content. It creates a diff between two
* HTML documents by combining the two documents and wrapping the differences with
* and tags. Here is a high-level overview of how the diff works.
*
* 1. Tokenize the before and after HTML with htmlToTokens.
* 2. Generate a list of operations that convert the before list of tokens to the after
* list of tokens with calculateOperations, which does the following:
* a. Find all the matching blocks of tokens between the before and after lists of
* tokens with findMatchingBlocks. This is done by finding the single longest
* matching block with findMatch, then iteratively finding the next longest
* matching blocks that precede and follow the longest matching block.
* b. Determine insertions, deletions, and replacements from the matching blocks.
* This is done in calculateOperations.
* 3. Render the list of operations by wrapping tokens with and tags where
* appropriate with renderOperations.
*
* Example usage:
*
* var htmldiff = require('htmldiff.js');
*
* htmldiff('this is some text
', 'this is some more text
')
* == 'this is some more text
'
*
* htmldiff('this is some text
', 'this is some more text
', 'diff-class')
* == 'this is some more text
'
*/
"use strict";
type Token = {
string: string;
key: string;
};
type Segment = {
beforeTokens: Array;
afterTokens: Array;
beforeIndex: number;
afterIndex: number;
beforeMap: object;
afterMap: object;
};
type MatchT = {
segment: Segment;
length: number;
startInBefore: number;
endInBefore: number;
startInAfter: number;
endInAfter: number;
segmentStartInBefore: number;
segmentStartInAfter: number;
segmentEndInBefore: number;
segmentEndInAfter: number;
};
type OperationType = "insert" | "delete" | "replace" | "equal" | "none";
type Operation = {
action: OperationType;
startInBefore: number;
endInBefore: number | null;
startInAfter: number | null;
endInAfter: number | null;
};
function isEndOfTag(char: string) {
return char === ">";
}
function isStartOfTag(char: string) {
return char === "<";
}
function isWhitespace(char: string) {
return /^\s+$/.test(char);
}
/**
* Determines if the given token is a tag.
*
* @param {string} token The token in question.
*
* @return {boolean|string} False if the token is not a tag, or the tag name otherwise.
*/
function isTag(token: string): boolean | string {
const match = token.match(/^\s*<([^!>][^>]*)>\s*$/);
return !!match && match[1].trim().split(" ")[0];
}
function isntTag(token: string) {
return !isTag(token);
}
function isStartofHTMLComment(word: string) {
return /^