{"id":13508341,"url":"https://github.com/bem/html-differ","last_synced_at":"2025-04-12T21:30:08.728Z","repository":{"id":16319255,"uuid":"19068352","full_name":"bem/html-differ","owner":"bem","description":"Сompares two HTML","archived":false,"fork":false,"pushed_at":"2024-08-06T04:52:22.000Z","size":262,"stargazers_count":212,"open_issues_count":28,"forks_count":45,"subscribers_count":14,"default_branch":"master","last_synced_at":"2024-10-16T02:04:53.124Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://bem.info/tools/testing/html-differ/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bem.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-04-23T12:14:52.000Z","updated_at":"2024-10-08T01:45:58.000Z","dependencies_parsed_at":"2024-09-15T19:21:54.032Z","dependency_job_id":null,"html_url":"https://github.com/bem/html-differ","commit_stats":{"total_commits":176,"total_committers":10,"mean_commits":17.6,"dds":"0.11931818181818177","last_synced_commit":"b3e83da780b2b2dad9c4b886e362acfe986e38be"},"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bem%2Fhtml-differ","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bem%2Fhtml-differ/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bem%2Fhtml-differ/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bem%2Fhtml-differ/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bem","download_url":"https://codeload.github.com/bem/html-differ/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248634827,"owners_count":21137125,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T02:00:51.712Z","updated_at":"2025-04-12T21:30:08.679Z","avatar_url":"https://github.com/bem.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# html-differ [![Build Status](https://travis-ci.org/bem/html-differ.svg)](https://travis-ci.org/bem/html-differ) [![Coverage Status](https://img.shields.io/coveralls/bem/html-differ.svg)](https://coveralls.io/r/bem/html-differ?branch=master) [![Dependency Status](https://david-dm.org/bem/html-differ.svg)](https://david-dm.org/bem/html-differ) [![devDependency Status](https://david-dm.org/bem/html-differ/dev-status.svg)](https://david-dm.org/bem/html-differ#info=devDependencies)\n\nCompares two HTML.\n\n\u003c!-- TOC --\u003e\n- [The comparison algorithm](#the-comparison-algorithm)\n- [Install](#install)\n- [API](#api)\n  - [HtmlDiffer](#htmldiffer)\n    - [Options](#options)\n      - [ignoreAttributes](#ignoreattributes-array)\n      - [compareAttributesAsJSON](#compareattributesasjson-array)\n      - [ignoreWhitespaces](#ignorewhitespaces-boolean)\n      - [ignoreComments](#ignorecomments-boolean)\n      - [ignoreEndTags](#ignoreendtags-boolean)\n      - [ignoreDuplicateAttributes](#ignoreduplicateattributes-boolean)\n    - [Presets](#presets)\n      - [Usage](#usage)\n    - [Methods](#methods)\n      - [htmlDiffer.diffHtml](#htmldifferdiffhtml)\n      - [htmlDiffer.isEqual](#htmldifferisequal)\n  - [Logger](#logger)\n    - [Methods](#methods-1)\n      - [logger.getDiffText](#loggergetdifftext)\n      - [logger.logDiffText](#loggerlogdifftext)\n  - [Example](#example)\n- [Usage as a program](#usage-as-a-program)\n  - [Example](#example-1)\n  - [Configuration file](#configuration-file)\n- [Masks](#masks)\n  - [Syntax](#syntax)\n  - [Screening](#screening)\n\n\u003c!-- TOC END --\u003e\n\n## The comparison algorithm\n\n**html-differ** compares HTML using the following criteria:\n\n* `\u003c!DOCTYPE\u003e` declarations are case-insensitive, so the following two code samples will be considered to be equivalent:\n\n```html\n\u003c!DOCTYPE HTML PUBLIC \"_PUBLIC\" \"_SYSTEM\"\u003e\n```\n\n```html\n\u003c!doctype html public \"_PUBLIC\" \"_SYSTEM\"\u003e\n```\n\n* Whitespaces (spaces, tabs, new lines etc.) inside start and end tags are ignored during the comparison.\n\nFor example, the following two code samples will be considered to be equivalent:\n\n```html\n\u003cspan id=\"1\"\u003e\u003c/span\u003e\n```\n\n```html\n\u003cspan id=\n    \"1\"    \u003e\u003c/span   \u003e\n```\n\n* Two respective lists of attributes are considered to be equivalent even if they are specified in different order.\n\nFor example, the following two code samples will be considered to be equivalent:\n\n```html\n\u003cspan id=\"blah\" class=\"ololo\" tabIndex=\"1\"\u003eText\u003c/span\u003e\n```\n\n```html\n\u003cspan tabIndex=\"1\" id=\"blah\" class=\"ololo\"\u003eText\u003c/span\u003e\n```\n\n* Two respective attributes `class` are considered to be equivalent if they refer to the same groups of CSS styles.\n\nFor example, the following two code samples will be considered to be equivalent:\n\n```html\n\u003cspan class=\"ab bc cd\"\u003eText\u003c/span\u003e\n```\n\n```html\n\u003cspan class=\" cd  ab bc bc\"\u003eText\u003c/span\u003e\n```\n\n**CAUTION!**\u003cbr\u003e\n**html-differ** does not check the validity of HTML, but compares them using the above shown criteria and specified options (see the list of possible [options](https://github.com/bem/html-differ/tree/master#options)).\n\n## Install\n\n```bash\n$ npm install html-differ\n```\n\n## API\n\n### HtmlDiffer\n\n```js\nvar HtmlDiffer = require('html-differ').HtmlDiffer,\n    htmlDiffer = new HtmlDiffer(options);\n```\n\nwhere `options` is an object.\n\n#### Options\n\n\u003c!-- TOC:display:ignoreAttributes --\u003e\n##### ignoreAttributes: [Array]\n\nSets what kind of respective attributes' content will be ignored during the comparison (default: `[]`).\n\n**Example**: `['id', 'for']`\u003cbr\u003e\nThe following two code samples will be considered to be equivalent:\n\n```html\n\u003clabel for=\"random\"\u003eText\u003c/label\u003e\n\u003cinput id=\"random\"\u003e\n```\n\n```html\n\u003clabel for=\"sfsdfksdf\"\u003eText\u003c/label\u003e\n\u003cinput id=\"sfsdfksdf\"\u003e\n```\n\n\u003c!-- TOC:display:compareAttributesAsJSON --\u003e\n##### compareAttributesAsJSON: [Array]\n\nSets what kind of respective attributes' content will be compared as JSON objects, but not as strings (default: `[]`).\u003cbr\u003e\nIn cases when the value of the attribute is an invalid JSON or can not be wrapped into a function, it will be compared as `undefined`.\n\n**Example**: `[{ name: 'data', isFunction: false }, { name: 'onclick', isFunction: true }]`\u003cbr\u003e\nThe following two code samples will be considered to be equivalent:\n\n```html\n\u003cdiv data='{\"bla\":{\"first\":\"ololo\",\"second\":\"trololo\"}}'\u003e\u003c/div\u003e\n\u003cspan onclick='return {\"aaa\":\"bbb\",\"bbb\":\"aaa\"}'\u003e\u003c/span\u003e\n\n\u003cbutton data='REALLY BAD JSON'\u003e\u003c/button\u003e\n\u003cbutton onclick='REALLY BAD FUNCTION'\u003e\u003c/button\u003e\n```\n\n```html\n\u003cdiv data='{\"bla\":{\"second\":\"trololo\",\"first\":\"ololo\"}}'\u003e\u003c/div\u003e\n\u003cspan onclick='return {\"bbb\":\"aaa\",\"aaa\":\"bbb\"}'\u003e\u003c/span\u003e\n\n\u003cbutton data='undefined'\u003e\u003c/button\u003e\n\u003cbutton onclick='undefined'\u003e\u003c/button\u003e\n```\n\n**REMARK!**\u003cbr\u003e\nThe first element of the array could be written in a short form as string:\u003cbr\u003e\n`['data', { name: 'onclick', isFunction: true }]`.\n\n\u003c!-- TOC:display:ignoreWhitespaces --\u003e\n##### ignoreWhitespaces: Boolean\n\nMakes **html-differ** ignore whitespaces (spaces, tabs, new lines etc.) during the comparison (default: `true`).\n\n**Example**: `true`\u003cbr\u003e\nThe following two code samples will be considered to be equivalent:\n\n```html\n\u003chtml\u003eText Text\u003chead lang=\"en\"\u003e\u003ctitle\u003e\u003c/title\u003e\u003c/head\u003e\u003cbody\u003eText\u003c/body\u003e\u003c/html\u003e\n```\n\n```html\n \u003chtml\u003e\n Text   Text\n\u003chead lang=\"en\"\u003e\n    \u003ctitle\u003e               \u003c/title\u003e\n\n\n            \u003c/head\u003e\n\n\u003cbody\u003e\n     Text\n\n    \u003c/body\u003e\n\n\n\n\n\u003c/html\u003e\n\n```\n\n\u003c!-- TOC:display:ignoreComments --\u003e\n##### ignoreComments: Boolean\n\nMakes **html-differ** ignore HTML comments during the comparison (default: `true`).\n\n**REMARK!**\u003cbr\u003e\nDoes not ignore [conditional comments](http://en.wikipedia.org/wiki/Conditional_comment).\n\n\n**Example**: `true`\u003cbr\u003e\nThe following two code samples will be considered to be equivalent:\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003c!-- comments1 --\u003e\n\u003chtml\u003e\n\u003chead lang=\"en\"\u003e\n    \u003cmeta charset=\"UTF-8\"\u003e\n    \u003c!--[if IE]\u003e\n        \u003clink rel=\"stylesheet\" type=\"text/css\" href=\"all-ie-only.css\" /\u003e\n    \u003c![endif]--\u003e\n    \u003c!--[if !IE]\u003e\u003c!--\u003e\n        \u003clink href=\"non-ie.css\" rel=\"stylesheet\"\u003e\n    \u003c!--\u003c![endif]--\u003e\n\u003c/head\u003e\n\u003cbody\u003e\nText\u003c!-- comments2 --\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n```html\n\u003c!DOCTYPE html\u003e\n\n\u003chtml\u003e\n\u003chead lang=\"en\"\u003e\n    \u003cmeta charset=\"UTF-8\"\u003e\n    \u003c!--[if IE]\u003e\n        \u003clink href=\"all-ie-only.css\" type=\"text/css\" rel=\"stylesheet\"/\u003e\n    \u003c![endif]--\u003e\n    \u003c!--[if !IE]\u003e\u003c!--\u003e\n        \u003clink href=\"non-ie.css\" rel=\"stylesheet\"\u003e\n    \u003c!--\u003c![endif]--\u003e\n\u003c/head\u003e\n\u003cbody\u003e\nText\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n\u003c!-- TOC:display:ignoreEndTags --\u003e\n##### ignoreEndTags: Boolean\n\nMakes **html-differ** ignore end tags during the comparison (default: `false`).\n\n**Example**: `true`\u003cbr\u003e\nThe following two code samples will be considered to be equivalent:\n\n```html\n\u003cspan\u003eText\u003c/span\u003e\n```\n\n```html\n\u003cspan\u003eText\u003c/spane\u003e\n```\n\n\u003c!-- TOC:display:ignoreDuplicateAttributes --\u003e\n##### ignoreDuplicateAttributes: Boolean\n\nMakes **html-differ** ignore tags' duplicate attributes during the comparison.\u003cbr\u003e\nFrom the list of the same tag's attributes, the attribute which goes the first will be taken for comparison, others will be ignored (default: `false`).\n\n**Example**: `true`\u003cbr\u003e\nFor example, the following two code samples will be considered to be equivalent:\n\n```html\n\u003cspan id=\"blah\" id=\"ololo\"\u003eText\u003c/span\u003e\n```\n\n```html\n\u003cspan id=\"blah\"\u003eText\u003c/span\u003e\n```\n\n#### Presets\n\n* [bem](https://github.com/bem/html-differ/blob/master/presets/bem.json) - sets predefined options for [BEM](http://bem.info/).\n\n\n##### Usage\n\nPassing of a preset via the constructor:\n\n```js\nvar HtmlDiffer = require('html-differ').HtmlDiffer,\n    htmlDiffer = new HtmlDiffer('bem');\n```\n\nRedefinition of a preset via the constructor:\n\n```js\nvar HtmlDiffer = require('html-differ').HtmlDiffer,\n    htmlDiffer = new HtmlDiffer({ preset: 'bem', ignoreAttributes: [] });\n```\n\n#### Methods\n\n##### htmlDiffer.diffHtml\n\n**@param** *{String}* - the 1-st HTML code\u003cbr\u003e\n**@param** *{String}* - the 2-nd HTML code\u003cbr\u003e\n**@returns** *{Array of objects}* - [array with diffs](https://github.com/kpdecker/jsdiff#change-objects) between HTML\n\n##### htmlDiffer.isEqual\n\n**@param** *{String}* - the 1-st HTML code\u003cbr\u003e\n**@param** *{String}* - the 2-nd HTML code\u003cbr\u003e\n**@returns** *{Boolean}*\n\n\n### Logger\n\n```js\nvar logger = require('html-differ/lib/logger');\n```\n\n#### Methods\n\n##### logger.getDiffText\n\n**@param** *{Array of objects}* - the result of the work of the method [htmlDiffer.diffHtml](https://github.com/bem/html-differ/tree/master#htmldifferdiffhtml)\u003cbr\u003e\n**@param** *{Object}* - options:\u003cbr\u003e\n\n* **charsAroundDiff: Number** - the number of characters around the diff result between two HTML (default: `40`).\n\n**@returns** *{String}*\n\n##### logger.logDiffText\n**@param** *{Array of objects}* - the result of the work of the method [htmlDiffer.diffHtml](https://github.com/bem/html-differ/tree/master#htmldifferdiffhtml)\u003cbr\u003e\n**@param** *{Object}* - options:\u003cbr\u003e\n\n* **charsAroundDiff: Number** - the number of characters around the diff result between two HTML (default: `40`).\n\n**@returns** - pretty logging of diffs:\n\n\u003cimg src='https://cloud.githubusercontent.com/assets/6376693/3648928/a6b9d48a-110d-11e4-8a07-d9b156145017.png'/\u003e\n\n\n### Example\n\n```js\nvar fs = require('fs'),\n    HtmlDiffer = require('html-differ').HtmlDiffer,\n    logger = require('html-differ/lib/logger');\n\nvar html1 = fs.readFileSync('1.html', 'utf-8'),\n    html2 = fs.readFileSync('2.html', 'utf-8');\n\nvar options = {\n        ignoreAttributes: [],\n        compareAttributesAsJSON: [],\n        ignoreWhitespaces: true,\n        ignoreComments: true,\n        ignoreEndTags: false,\n        ignoreDuplicateAttributes: false\n    };\n\nvar htmlDiffer = new HtmlDiffer(options);\n\nvar diff = htmlDiffer.diffHtml(html1, html2),\n    isEqual = htmlDiffer.isEqual(html1, html2),\n    res = logger.getDiffText(diff, { charsAroundDiff: 40 });\n\nlogger.logDiffText(diff, { charsAroundDiff: 40 });\n```\n\n## Usage as a program\n\n```bash\n$ html-differ --help\nCompares two HTML\n\nUsage:\n  html-differ [OPTIONS] [ARGS]\n\nOptions:\n  -h, --help : Help\n  -v, --version : Shows the version number\n  --config=CONFIG : Path to a configuration JSON file\n  --bem : Uses predefined options for BEM (deprecated)\n  -p PRESET, --preset=PRESET : Name of a preset\n  --chars-around-diff=CHARSAROUNDDIFF : The number of characters around the diff (default: 40)\n\nArguments:\n  PATH1 : Path to the 1-st HTML file (required)\n  PATH2 : Path to the 2-nd HTML file (required)\n```\n\n### Example\n\n```bash\n$ html-differ path/to/html1 path/to/html2\n\n$ html-differ --config=path/to/config --chars-around-diff=40 path/to/html1 path/to/html2\n\n$ html-differ --preset=bem path/to/html1 path/to/html2\n```\n\n### Configuration file\n\nStudy the following file `config.json`:\n\n```js\n{\n    \"ignoreAttributes\": [],\n    \"compareAttributesAsJSON\": [],\n    \"ignoreWhitespaces\": true,\n    \"ignoreComments\": true,\n    \"ignoreEndTags\": false,\n    \"ignoreDuplicateAttributes\": false\n}\n```\n\n## Masks\n\n**html-differ** supports handling of _masks_ in HTML.\n\nFor example, the following two code samples will be considered to be equivalent:\n\n```html\n\u003cdiv id=\"{{[a-z]*\\s\\d+}}\"\u003e\n```\n\n```html\n\u003cdiv id=\"text 12345\"\u003e\n```\n\n### Syntax\n\n_Masks_ in **html-differ** have the following syntax:\n\n```js\n{{RegExp}}\n```\n\nwhere:\n\n* `{{` – opening identifier of the _mask_.\n\n* `RegExp` – regular expression for matching with the corresponding value in another HTML. The syntax is similar to regular expressions in JavaScript written in a literal notation.\n\n* `}}` – closing identifier of the _mask_.\n\n### Screening\n\nThe rules of screening of symbols are similar to the rules which are used in regular expressions in JavaScript written in a literal notation.\n\nFor example, the following two code samples will be considered to be equivalent:\n\n```html\n\u003cdiv id=\"{{\\d\\.\\d}}\"\u003e\n```\n\n```html\n\u003cdiv id=\"1.1\"\u003e\n```\n\nIf you want to use `{{` or `}}` inside a mask, you should screen both curly braces, i.e. `\\{\\}` or `\\}\\}`.\n\nFor example, the following two code samples will be considered to be equivalent:\n\n```html\n\u003cdiv class=\"{{a\\{\\{b\\}\\}c}}\"\u003e\n```\n\n```html\n\u003cdiv class=\"a{{b}}c\"\u003e\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbem%2Fhtml-differ","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbem%2Fhtml-differ","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbem%2Fhtml-differ/lists"}