Diff.mjs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /**
  2. * @author n1474335 [n1474335@gmail.com]
  3. * @copyright Crown Copyright 2016
  4. * @license Apache-2.0
  5. */
  6. import Operation from "../Operation";
  7. import Utils from "../Utils";
  8. import * as JsDiff from "diff";
  9. import OperationError from "../errors/OperationError";
  10. /**
  11. * Diff operation
  12. */
  13. class Diff extends Operation {
  14. /**
  15. * Diff constructor
  16. */
  17. constructor() {
  18. super();
  19. this.name = "Diff";
  20. this.module = "Diff";
  21. this.description = "Compares two inputs (separated by the specified delimiter) and highlights the differences between them.";
  22. this.inputType = "string";
  23. this.outputType = "html";
  24. this.args = [
  25. {
  26. "name": "Sample delimiter",
  27. "type": "binaryString",
  28. "value": "\\n\\n"
  29. },
  30. {
  31. "name": "Diff by",
  32. "type": "option",
  33. "value": ["Character", "Word", "Line", "Sentence", "CSS", "JSON"]
  34. },
  35. {
  36. "name": "Show added",
  37. "type": "boolean",
  38. "value": true
  39. },
  40. {
  41. "name": "Show removed",
  42. "type": "boolean",
  43. "value": true
  44. },
  45. {
  46. "name": "Ignore whitespace (relevant for word and line)",
  47. "type": "boolean",
  48. "value": false
  49. }
  50. ];
  51. }
  52. /**
  53. * @param {string} input
  54. * @param {Object[]} args
  55. * @returns {html}
  56. */
  57. run(input, args) {
  58. const [
  59. sampleDelim,
  60. diffBy,
  61. showAdded,
  62. showRemoved,
  63. ignoreWhitespace
  64. ] = args,
  65. samples = input.split(sampleDelim);
  66. let output = "",
  67. diff;
  68. // Node and Webpack load modules slightly differently
  69. const jsdiff = JsDiff.default ? JsDiff.default : JsDiff;
  70. if (!samples || samples.length !== 2) {
  71. throw new OperationError("Incorrect number of samples, perhaps you need to modify the sample delimiter or add more samples?");
  72. }
  73. switch (diffBy) {
  74. case "Character":
  75. diff = jsdiff.diffChars(samples[0], samples[1]);
  76. break;
  77. case "Word":
  78. if (ignoreWhitespace) {
  79. diff = jsdiff.diffWords(samples[0], samples[1]);
  80. } else {
  81. diff = jsdiff.diffWordsWithSpace(samples[0], samples[1]);
  82. }
  83. break;
  84. case "Line":
  85. if (ignoreWhitespace) {
  86. diff = jsdiff.diffTrimmedLines(samples[0], samples[1]);
  87. } else {
  88. diff = jsdiff.diffLines(samples[0], samples[1]);
  89. }
  90. break;
  91. case "Sentence":
  92. diff = jsdiff.diffSentences(samples[0], samples[1]);
  93. break;
  94. case "CSS":
  95. diff = jsdiff.diffCss(samples[0], samples[1]);
  96. break;
  97. case "JSON":
  98. diff = jsdiff.diffJson(samples[0], samples[1]);
  99. break;
  100. default:
  101. throw new OperationError("Invalid 'Diff by' option.");
  102. }
  103. for (let i = 0; i < diff.length; i++) {
  104. if (diff[i].added) {
  105. if (showAdded) output += "<span class='hl5'>" + Utils.escapeHtml(diff[i].value) + "</span>";
  106. } else if (diff[i].removed) {
  107. if (showRemoved) output += "<span class='hl3'>" + Utils.escapeHtml(diff[i].value) + "</span>";
  108. } else {
  109. output += Utils.escapeHtml(diff[i].value);
  110. }
  111. }
  112. return output;
  113. }
  114. }
  115. export default Diff;