まえがき
JavaScriptで2ファイルのテキストの差分を確認するためのDiff用ライブラリについて調べます。
difflib
GitHub:
https://github.com/cemerick/jsdifflib
デモサイト
http://cemerick.github.io/jsdifflib/demo.html
サンプルコード
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" href="diffview.css">
<script src="difflib.js"></script>
<script src="diffview.js"></script>
<script id="src1" type="sourcecode">
function b() {
console.log('TESTdddddddddddddddddddddddddddddddddddddddddddddddddddddddddsfafdasdfffffffffffffffffffffffffff0');
console.log('TEST');
console.log('TEST1');
}
</script>
<script id="src2" type="sourcecode">
function b() {
console.log('TEST');
console.log('TEST2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
console.log('TEST3');
}
</script>
<!-- End Matomo Code -->
</head>
<body>
<div id="output"></div>
<script type="text/javascript">
const src1 = document.getElementById('src1').innerText;
const src2 = document.getElementById('src2').innerText;
var base = difflib.stringAsLines(src1);
var newtxt = difflib.stringAsLines(src2);
// create a SequenceMatcher instance that diffs the two sets of lines
var sm = new difflib.SequenceMatcher(base, newtxt);
// get the opcodes from the SequenceMatcher instance
// opcodes is a list of 3-tuples describing what changes should be made to the base text
// in order to yield the new text
var opcodes = sm.get_opcodes();
var contextSize = 0;
document.getElementById('output').append(diffview.buildView({
baseTextLines: base,
newTextLines: newtxt,
opcodes: opcodes,
// set the display titles for each resource
baseTextName: "Base Text",
newTextName: "New Text",
contextSize: contextSize,
viewType: 1 // 0にするとbaseとnewTextが別の列になります
}));
</script>
</body>
</html>
使用感
・シンプルで使い易いですが、細かい調整はできないようです。(たとえば文字レベルでの差分の表示は現時点でできない)
・積極的な開発はおこなわれていないようです。
・BSDライセンスです。
prettydiff
GitHub
https://github.com/prettydiff/prettydiff/
ドキュメント
https://prettydiff.com/documentation.xhtml
サンプル
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script src="prettydiff/js/browser.js"></script>
<link href="prettydiff/css/index.css" media="all" rel="stylesheet" type="text/css"/>
<script id="src1" type="sourcecode">
function b() {
console.log('TESTdddddddddddddddddddddddddddddddddddddddddddddddddddddddddsfafdasdfffffffffffffffffffffffffff0');
console.log('TEST');
console.log('TEST1');
}
</script>
<script id="src2" type="sourcecode">
function b() {
console.log('TEST');
console.log('TEST2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
console.log('TEST3');
}
</script>
<!-- End Matomo Code -->
</head>
<body>
<div class="white" id="prettydiff"></div>
<script type="text/javascript">
const src1 = document.getElementById('src1').innerText;
const src2 = document.getElementById('src2').innerText;
// integrate into the browser
let output = "",
prettydiff = window.prettydiff,
options = window.prettydiff.options;
options.source_label = "修正前";
options.source = src1;
options.diff_label = "修正後";
options.diff = src2;
options.diff_format = "html";
options.mode = "diff";
options.language = "auto";
options.lexer = "text";
options.wrap = 10;
options.diff_view = 'inline'; // 'sidebyside'で別の列で表示
output = prettydiff();
console.log(output);
document.getElementById('prettydiff').innerHTML = output;
// You can include the Pretty Diff code in any way that is convenient,
// whether that is using an HTML script tag or concatenating the
// js/browser.js code with your other code.
</script>
</body>
</html>
使用感
・ブラウザで使用するbrowser.jsはnpmでインストール後、tscコマンドで作成されます
・さまざまなオプションがあります
・ライセンスはCC0
mergely
GitHub
https://github.com/wickedest/Mergely
サンプル
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>DIFF</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.32.0/codemirror.min.js"></script>
<link rel="stylesheet" media="all" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.32.0/codemirror.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.32.0/addon/search/searchcursor.min.js"></script>
<script src="mergely/libs/mergely.js" type="text/javascript"></script>
<link rel="stylesheet" media="all" href="mergely/libs/mergely.css" />
</head>
<script id="src1" type="sourcecode">
function b() {
console.log('TESTdddddddddddddddddddddddddddddddddddddddddddddddddddddddddsfafdasdfffffffffffffffffffffffffff0');
console.log('TEST');
console.log('TEST1');
}
</script>
<script id="src2" type="sourcecode">
function b() {
console.log('TEST');
console.log('TEST2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
console.log('TEST3');
}
</script>
<body>
<div class="mergely-full-screen-8">
<div class="mergely-resizer">
<div id="mergely"></div>
</div>
</div>
<script>
$(document).ready(function () {
$('#mergely').mergely({
wrap_lines : true,
cmsettings: {
readOnly: false,
lineNumbers: true
},
lhs: function(setValue) {
setValue(document.getElementById('src1').innerText);
},
rhs: function(setValue) {
setValue(document.getElementById('src2').innerText);
}
});
});
</script>
</body>
</body>
</html>
使用感
・依存ライブラリが多い(JQuery,codemirror)
・codemirrorがエディタ用のライブラリなので、修正したテキストの差分がすぐ確認できる
・ライセンスはGNU LGPL v3.0
まとめ
・差分を表示するだけならprettydiffがよさそうです。
・マージなどの編集が必要ならmergelyになるでしょうが、JQueryに依存しています。
・2ファイルを入力とするのでなく、diffの結果を入力としてHTML表示するならdiff2htmlも使えそうです。
・なお、画像の差分をとるならjs-imagediffが使えそうでした(未検証)
参考
JavaScript based diff utility [closed]
https://stackoverflow.com/questions/3053587/javascript-based-diff-utility