Permalink
88dc255 Mar 16, 2016
@eGavr @tadatuta
464 lines (326 sloc) 14.9 KB

html-differ Build Status Coverage Status Dependency Status devDependency Status

Сравнивает два HTML.

Алгоритм сравнения

html-differ сравнивает HTML по следующим критериям:

  • Декларации <!DOCTYPE> не чувствителны к регистру, поэтому следующие два HTML будут считаться эквивалентными:
<!DOCTYPE HTML PUBLIC "_PUBLIC" "_SYSTEM">
<!doctype html public "_PUBLIC" "_SYSTEM">
  • Пробельные символы (пробелы, табуляция, переводы строк и т. д.) внутри открывающих и закрывающих тэгов игнорируются при сравнении.

Например, следующие два HTML будут считаться эквивалентными:

<span id="1"></span>
<span id=
    "1"    ></span   >
  • Два соответствующих списка атрибутов считаются эквивалентными, даже если они записаны в разном порядке.

Например, следующие два HTML будут считаться эквивалентными:

<span id="blah" class="ololo" tabIndex="1">Text</span>
<span tabIndex="1" id="blah" class="ololo">Text</span>
  • Два соответствующих атрибута class считаются эквивалентными, если они ссылаются на одни и те же группы CSS-стилей.

Например, следующие два HTML будут считаться эквивалентными:

<span class="ab bc cd">Text</span>
<span class=" cd  ab bc bc">Text</span>

ВНИМАНИЕ!
html-differ не проверяет валидность HTML, а сравнивает их по вышеуказанным критериям и заданным опциям (смотрите список возможных опций).

Установка

$ npm install html-differ

API

###HtmlDiffer###

var HtmlDiffer = require('html-differ').HtmlDiffer,
    htmlDiffer = new HtmlDiffer(options);

где options – это объект.

Опции

ignoreAttributes: [Array]

Устанавливает, значения каких атрибутов следует игнорировать при сравнении (по умолчанию: []).

Пример: ['id', 'for']
Следующие два HTML будут считаться эквивалентными:

<label for="random">Text</label>
<input id="random">
<label for="sfsdfksdf">Text</label>
<input id="sfsdfksdf">
compareAttributesAsJSON: [Array]

Устанавливает, значения каких атрибутов следует сравнивать как JSON-объекты, а не как строки (по умолчанию: []).
В тех случаях, когда в качестве значения атрибута выступает некорректный JSON или это значение нельзя обернуть в функцию, то оно будет сравниваться как undefined.

Пример: [{ name: 'data', isFunction: false }, { name: 'onclick', isFunction: true }]
Следующие два HTML будут считаться эквивалентными:

<div data='{"bla":{"first":"ololo","second":"trololo"}}'></div>
<span onclick='return {"aaa":"bbb","bbb":"aaa"}'></span>

<button data='REALLY BAD JSON'></button>
<button onclick='REALLY BAD FUNCTION'></button>
<div data='{"bla":{"second":"trololo","first":"ololo"}}'></div>
<span onclick='return {"bbb":"aaa","aaa":"bbb"}'></span>

<button data='undefined'></button>
<button onclick='undefined'></button>

ПРИМЕЧАНИЕ!
Первый элемент массива мог быть записан в короткой форме в качестве строки:
['data', { name: 'onclick', isFunction: true }].

ignoreWhitespaces: Boolean

html-differ будет игнорировать пробельные символы (пробелы, табуляция, переводы строк и т. д.) при сравнении (по умолчанию: true).

Пример: true
Следующие два HTML будут считаться эквивалентными:

<html>Text Text<head lang="en"><title></title></head><body>Text</body></html>
 <html>
 Text   Text
<head lang="en">
    <title>               </title>


            </head>

<body>
     Text

    </body>




</html>
ignoreComments: Boolean

html-differ будет игнорировать HTML-комментарии при сравнении (по умолчанию: true).

ПРИМЕЧАНИЕ!
Условные комментарии не игнорируются.

Пример: true
Следующие два HTML будут считаться эквивалентными:

<!DOCTYPE html>
<!-- comments1 -->
<html>
<head lang="en">
    <meta charset="UTF-8">
    <!--[if IE]>
        <link rel="stylesheet" type="text/css" href="all-ie-only.css" />
    <![endif]-->
    <!--[if !IE]><!-->
        <link href="non-ie.css" rel="stylesheet">
    <!--<![endif]-->
</head>
<body>
Text<!-- comments2 -->
</body>
</html>
<!DOCTYPE html>

<html>
<head lang="en">
    <meta charset="UTF-8">
    <!--[if IE]>
        <link href="all-ie-only.css" type="text/css" rel="stylesheet"/>
    <![endif]-->
    <!--[if !IE]><!-->
        <link href="non-ie.css" rel="stylesheet">
    <!--<![endif]-->
</head>
<body>
Text
</body>
</html>
ignoreEndTags: Boolean

html-differ будет игнорировать закрывающие тэги при сравнении (по умолчанию: false).

Пример: true
Следующие два HTML будут считаться эквивалентными:

<span>Text</span>
<span>Text</spane>
ignoreDuplicateAttributes: Boolean

html-differ будет игнорировать повторяющиеся атрибуты.
Из списка одинаковых атрибутов тэга, для сравнения будет взят тот, который идет первым, остальные будут проигнорированы (по умолчанию: false).

Пример: true
Следующие два HTML будут считаться эквивалентными:

<span id="blah" id="ololo">Text</span>
<span id="blah">Text</span>

Пресеты

  • bem - уставливает предопределенные опции для БЭМ.
Использование

Передача пресета конструктору:

var HtmlDiffer = require('html-differ').HtmlDiffer,
    htmlDiffer = new HtmlDiffer('bem');

Переопределение пресета через конструктор:

var HtmlDiffer = require('html-differ').HtmlDiffer,
    htmlDiffer = new HtmlDiffer({ preset: 'bem', ignoreAttributes: [] });

Методы

htmlDiffer.diffHtml

@param {String} - 1-й HTML
@param {String} - 2-й HTML
@returns {Array of objects} - массив с отличиями между HTML

htmlDiffer.isEqual

@param {String} - 1-й HTML
@param {String} - 2-й HTML
@returns {Boolean}

Logger

var logger = require('html-differ/lib/logger');

Методы

logger.getDiffText

@param {Array of objects} - результат работы метода htmlDiffer.diffHtml
@param {Object} - опции:

  • charsAroundDiff: Number - количество символов перед отличием между HTML и после него (по умолчанию: 40)

@returns {String}

logger.logDiffText

@param {Array of objects} - результат работы метода htmlDiffer.diffHtml
@param {Object} - опции:

  • charsAroundDiff: Number - количество символов перед отличием между HTML и после него (по умолчанию: 40)

@returns - вывод отличий:

Пример

var fs = require('fs'),
    HtmlDiffer = require('html-differ').HtmlDiffer,
    logger = require('html-differ/lib/logger');

var html1 = fs.readFileSync('1.html', 'utf-8'),
    html2 = fs.readFileSync('2.html', 'utf-8');

var options = {
        ignoreAttributes: [],
        compareAttributesAsJSON: [],
        ignoreWhitespaces: true,
        ignoreComments: true,
        ignoreEndTags: false,
        ignoreDuplicateAttributes: false
    };

var htmlDiffer = new HtmlDiffer(options);

var diff = htmlDiffer.diffHtml(html1, html2),
    isEqual = htmlDiffer.isEqual(html1, html2),
    res = logger.getDiffText(diff, { charsAroundDiff: 40 });

logger.logDiffText(diff, { charsAroundDiff: 40 });

Использование в качестве программы

$ html-differ --help
Сравнивает два HTML

Использование:
  html-differ [ОПЦИИ] [АРГУМЕНТЫ]

Опции:
  -h, --help : Помощь
  -v, --version : Показывает номер версии
  --config=CONFIG : Путь к конфигурационному JSON-файлу
  --bem : Использует предопределенные опции для БЭМ (устаревшая опция)
  -p PRESET, --preset=PRESET : Имя пресета
  --chars-around-diff=CHARSAROUNDDIFF : Количество символов перед отличием и после него (по умолчанию: 40)

Аргументы:
  PATH1 : Путь к 1-ому HTML-файлу (обязательный аргумент)
  PATH2 : Путь ко 2-ому HTML-файлу (обязательный аргумент)

Пример

$ html-differ путь/к/html1 путь/к/html2

$ html-differ --config=путь/к/конфигу --chars-around-diff=40 путь/к/html1 путь/к/html2

$ html-differ --preset=bem путь/к/html1 путь/к/html2

Конфигурационный файл

Рассмотрите следующий файл config.json:

{
    "ignoreAttributes": [],
    "compareAttributesAsJSON": [],
    "ignoreWhitespaces": true,
    "ignoreComments": true,
    "ignoreEndTags": false,
    "ignoreDuplicateAttributes": false
}

Маски

html-differ поддерживает использование масок в HTML.

Например, следующие два HTML будут считаться эквивалентными:

<div id="{{[a-z]*\s\d+}}">
<div id="text 12345">

Синтаксис

Для записи масок в html-differ используется следующий синтаксис:

{{RegExp}}

где:

  • {{ – открывающий идентификатор маски.

  • RegExp – регулярное выражение для сопоставления с соответствующим значением в сравниваемом HTML. Имеет такой же синтаксис как и регулярные выражения в JavaScript, записанные в literal notation.

  • }} – закрывающий идентификатор маски.

Экранирование

Правила экранирования символов такие же как и при использовании регулярных выражений в JavaScript, записанных в literal notation.

Например, следующие два HTML будут считаться эквивалентными:

<div id="{{\d\.\d}}">
<div id="1.1">

Если вы хотите хотите использовать {{ или }} внутри маски, вам необходимо экранировать обе фигурные скобки, то есть \{\} или \}\}

Например, следующие два HTML будут считаться эквивалентными:

<div class="{{a\{\{b\}\}c}}">
<div class="a{{b}}c">