@limetech/lime-elements 39.6.0 → 39.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/lime-elements.cjs.js +1 -1
  3. package/dist/cjs/{limel-action-bar_2.cjs.entry.js → limel-action-bar_3.cjs.entry.js} +111 -93
  4. package/dist/cjs/limel-ai-avatar.cjs.entry.js +1 -1
  5. package/dist/cjs/limel-breadcrumbs_7.cjs.entry.js +6 -6
  6. package/dist/cjs/limel-button-group.cjs.entry.js +7 -8
  7. package/dist/cjs/limel-callout.cjs.entry.js +1 -1
  8. package/dist/cjs/limel-chart.cjs.entry.js +1 -1
  9. package/dist/cjs/limel-chip_2.cjs.entry.js +1 -1
  10. package/dist/cjs/limel-code-diff.cjs.entry.js +1758 -0
  11. package/dist/cjs/limel-code-editor.cjs.entry.js +2 -2
  12. package/dist/cjs/limel-collapsible-section.cjs.entry.js +2 -2
  13. package/dist/cjs/limel-color-picker-palette.cjs.entry.js +2 -2
  14. package/dist/cjs/limel-color-picker.cjs.entry.js +1 -1
  15. package/dist/cjs/limel-dialog.cjs.entry.js +2 -2
  16. package/dist/cjs/limel-dock.cjs.entry.js +2 -2
  17. package/dist/cjs/limel-drag-handle.cjs.entry.js +2 -2
  18. package/dist/cjs/limel-email-viewer.cjs.entry.js +2 -2
  19. package/dist/cjs/limel-file-dropzone_2.cjs.entry.js +2 -2
  20. package/dist/cjs/limel-file-viewer.cjs.entry.js +1 -1
  21. package/dist/cjs/limel-file.cjs.entry.js +2 -2
  22. package/dist/cjs/limel-flatpickr-adapter.cjs.entry.js +2 -2
  23. package/dist/cjs/limel-flex-container.cjs.entry.js +1 -1
  24. package/dist/cjs/limel-form.cjs.entry.js +1 -1
  25. package/dist/cjs/limel-grid.cjs.entry.js +1 -1
  26. package/dist/cjs/limel-header.cjs.entry.js +1 -1
  27. package/dist/cjs/limel-help-content.cjs.entry.js +1 -1
  28. package/dist/cjs/limel-help.cjs.entry.js +2 -2
  29. package/dist/cjs/limel-helper-line_2.cjs.entry.js +3 -3
  30. package/dist/cjs/limel-icon-button.cjs.entry.js +1 -1
  31. package/dist/cjs/limel-icon.cjs.entry.js +1 -1
  32. package/dist/cjs/limel-info-tile.cjs.entry.js +2 -2
  33. package/dist/cjs/limel-linear-progress.cjs.entry.js +1 -1
  34. package/dist/cjs/limel-list-item.cjs.entry.js +3 -3
  35. package/dist/cjs/limel-markdown.cjs.entry.js +1 -1
  36. package/dist/cjs/limel-menu-item-meta.cjs.entry.js +1 -1
  37. package/dist/cjs/limel-picker.cjs.entry.js +1 -1
  38. package/dist/cjs/limel-popover_2.cjs.entry.js +2 -2
  39. package/dist/cjs/limel-portal_3.cjs.entry.js +4 -4
  40. package/dist/cjs/limel-profile-picture.cjs.entry.js +1 -1
  41. package/dist/cjs/limel-prosemirror-adapter.cjs.entry.js +2 -2
  42. package/dist/cjs/limel-radio-button-group.cjs.entry.js +1 -1
  43. package/dist/cjs/limel-radio-button.cjs.entry.js +2 -2
  44. package/dist/cjs/limel-select.cjs.entry.js +1 -1
  45. package/dist/cjs/limel-shortcut.cjs.entry.js +1 -1
  46. package/dist/cjs/limel-slider.cjs.entry.js +1 -1
  47. package/dist/cjs/limel-snackbar.cjs.entry.js +3 -3
  48. package/dist/cjs/limel-split-button.cjs.entry.js +2 -2
  49. package/dist/cjs/limel-tab-bar.cjs.entry.js +2 -2
  50. package/dist/cjs/limel-tab-panel.cjs.entry.js +1 -1
  51. package/dist/cjs/limel-table.cjs.entry.js +4 -4
  52. package/dist/cjs/limel-text-editor-link-menu.cjs.entry.js +120 -0
  53. package/dist/cjs/limel-text-editor.cjs.entry.js +1 -1
  54. package/dist/cjs/loader.cjs.js +1 -1
  55. package/dist/cjs/{translations-BBGWKIVD.js → translations-Bu_0fli7.js} +236 -4
  56. package/dist/collection/collection-manifest.json +1 -0
  57. package/dist/collection/components/button-group/button-group.css +38 -650
  58. package/dist/collection/components/button-group/button-group.js +6 -7
  59. package/dist/collection/components/code-diff/code-diff.css +519 -0
  60. package/dist/collection/components/code-diff/code-diff.js +775 -0
  61. package/dist/collection/components/code-diff/content-utils.js +49 -0
  62. package/dist/collection/components/code-diff/diff-engine.js +308 -0
  63. package/dist/collection/components/code-diff/search-utils.js +41 -0
  64. package/dist/collection/components/code-diff/syntax-highlighter.js +87 -0
  65. package/dist/collection/components/code-diff/types.js +1 -0
  66. package/dist/collection/components/code-editor/code-editor.js +1 -1
  67. package/dist/collection/components/collapsible-section/collapsible-section.js +1 -1
  68. package/dist/collection/components/color-picker/color-picker-palette.js +2 -2
  69. package/dist/collection/components/color-picker/color-picker.js +1 -1
  70. package/dist/collection/components/date-picker/flatpickr-adapter/flatpickr-adapter.js +1 -1
  71. package/dist/collection/components/dialog/dialog.js +2 -2
  72. package/dist/collection/components/dock/dock.js +2 -2
  73. package/dist/collection/components/drag-handle/drag-handle.js +1 -1
  74. package/dist/collection/components/email-viewer/email-viewer.js +1 -1
  75. package/dist/collection/components/file/file.js +1 -1
  76. package/dist/collection/components/file-dropzone/file-dropzone.js +1 -1
  77. package/dist/collection/components/file-input/file-input.js +1 -1
  78. package/dist/collection/components/flex-container/flex-container.js +1 -1
  79. package/dist/collection/components/form/form.js +1 -1
  80. package/dist/collection/components/grid/grid.js +1 -1
  81. package/dist/collection/components/header/header.js +1 -1
  82. package/dist/collection/components/help/help-content.js +1 -1
  83. package/dist/collection/components/help/help.js +2 -2
  84. package/dist/collection/components/helper-line/helper-line.js +2 -2
  85. package/dist/collection/components/icon/icon.js +1 -1
  86. package/dist/collection/components/icon-button/icon-button.js +1 -1
  87. package/dist/collection/components/info-tile/info-tile.js +2 -2
  88. package/dist/collection/components/input-field/input-field.js +1 -1
  89. package/dist/collection/components/list/list.js +1 -1
  90. package/dist/collection/components/list-item/list-item.js +2 -2
  91. package/dist/collection/components/list-item/menu-item-meta/menu-item-meta.js +1 -1
  92. package/dist/collection/components/markdown/markdown.js +1 -1
  93. package/dist/collection/components/menu/menu.js +1 -1
  94. package/dist/collection/components/menu-list/menu-list.js +1 -1
  95. package/dist/collection/components/menu-surface/menu-surface.js +1 -1
  96. package/dist/collection/components/notched-outline/notched-outline.js +1 -1
  97. package/dist/collection/components/picker/picker.js +1 -1
  98. package/dist/collection/components/popover/popover.js +1 -1
  99. package/dist/collection/components/popover-surface/popover-surface.js +1 -1
  100. package/dist/collection/components/portal/portal.js +1 -1
  101. package/dist/collection/components/radio-button-group/radio-button-group.js +1 -1
  102. package/dist/collection/components/radio-button-group/radio-button.js +2 -2
  103. package/dist/collection/components/select/select.js +1 -1
  104. package/dist/collection/components/shortcut/shortcut.js +1 -1
  105. package/dist/collection/components/slider/slider.js +1 -1
  106. package/dist/collection/components/snackbar/snackbar.js +2 -2
  107. package/dist/collection/components/spinner/spinner.js +1 -1
  108. package/dist/collection/components/split-button/split-button.js +2 -2
  109. package/dist/collection/components/tab-bar/tab-bar.js +2 -2
  110. package/dist/collection/components/tab-panel/tab-panel.js +1 -1
  111. package/dist/collection/components/table/table.js +3 -3
  112. package/dist/collection/components/text-editor/link-menu/editor-link-menu.js +3 -3
  113. package/dist/collection/components/text-editor/prosemirror-adapter/prosemirror-adapter.js +1 -1
  114. package/dist/collection/components/text-editor/text-editor.js +1 -1
  115. package/dist/collection/components/tooltip/tooltip-content.js +1 -1
  116. package/dist/collection/components/tooltip/tooltip.js +2 -2
  117. package/dist/collection/translations/da.js +29 -0
  118. package/dist/collection/translations/de.js +29 -0
  119. package/dist/collection/translations/en.js +29 -0
  120. package/dist/collection/translations/fi.js +29 -0
  121. package/dist/collection/translations/fr.js +33 -4
  122. package/dist/collection/translations/nl.js +29 -0
  123. package/dist/collection/translations/no.js +29 -0
  124. package/dist/collection/translations/sv.js +29 -0
  125. package/dist/esm/lime-elements.js +1 -1
  126. package/dist/esm/{limel-action-bar_2.entry.js → limel-action-bar_3.entry.js} +110 -93
  127. package/dist/esm/limel-ai-avatar.entry.js +1 -1
  128. package/dist/esm/limel-breadcrumbs_7.entry.js +6 -6
  129. package/dist/esm/limel-button-group.entry.js +7 -8
  130. package/dist/esm/limel-callout.entry.js +1 -1
  131. package/dist/esm/limel-chart.entry.js +1 -1
  132. package/dist/esm/limel-chip_2.entry.js +1 -1
  133. package/dist/esm/limel-code-diff.entry.js +1756 -0
  134. package/dist/esm/limel-code-editor.entry.js +2 -2
  135. package/dist/esm/limel-collapsible-section.entry.js +2 -2
  136. package/dist/esm/limel-color-picker-palette.entry.js +2 -2
  137. package/dist/esm/limel-color-picker.entry.js +1 -1
  138. package/dist/esm/limel-dialog.entry.js +2 -2
  139. package/dist/esm/limel-dock.entry.js +2 -2
  140. package/dist/esm/limel-drag-handle.entry.js +2 -2
  141. package/dist/esm/limel-email-viewer.entry.js +2 -2
  142. package/dist/esm/limel-file-dropzone_2.entry.js +2 -2
  143. package/dist/esm/limel-file-viewer.entry.js +1 -1
  144. package/dist/esm/limel-file.entry.js +2 -2
  145. package/dist/esm/limel-flatpickr-adapter.entry.js +2 -2
  146. package/dist/esm/limel-flex-container.entry.js +1 -1
  147. package/dist/esm/limel-form.entry.js +1 -1
  148. package/dist/esm/limel-grid.entry.js +1 -1
  149. package/dist/esm/limel-header.entry.js +1 -1
  150. package/dist/esm/limel-help-content.entry.js +1 -1
  151. package/dist/esm/limel-help.entry.js +2 -2
  152. package/dist/esm/limel-helper-line_2.entry.js +3 -3
  153. package/dist/esm/limel-icon-button.entry.js +1 -1
  154. package/dist/esm/limel-icon.entry.js +1 -1
  155. package/dist/esm/limel-info-tile.entry.js +2 -2
  156. package/dist/esm/limel-linear-progress.entry.js +1 -1
  157. package/dist/esm/limel-list-item.entry.js +3 -3
  158. package/dist/esm/limel-markdown.entry.js +1 -1
  159. package/dist/esm/limel-menu-item-meta.entry.js +1 -1
  160. package/dist/esm/limel-picker.entry.js +1 -1
  161. package/dist/esm/limel-popover_2.entry.js +2 -2
  162. package/dist/esm/limel-portal_3.entry.js +4 -4
  163. package/dist/esm/limel-profile-picture.entry.js +1 -1
  164. package/dist/esm/limel-prosemirror-adapter.entry.js +2 -2
  165. package/dist/esm/limel-radio-button-group.entry.js +1 -1
  166. package/dist/esm/limel-radio-button.entry.js +2 -2
  167. package/dist/esm/limel-select.entry.js +1 -1
  168. package/dist/esm/limel-shortcut.entry.js +1 -1
  169. package/dist/esm/limel-slider.entry.js +1 -1
  170. package/dist/esm/limel-snackbar.entry.js +3 -3
  171. package/dist/esm/limel-split-button.entry.js +2 -2
  172. package/dist/esm/limel-tab-bar.entry.js +2 -2
  173. package/dist/esm/limel-tab-panel.entry.js +1 -1
  174. package/dist/esm/limel-table.entry.js +4 -4
  175. package/dist/esm/limel-text-editor-link-menu.entry.js +118 -0
  176. package/dist/esm/limel-text-editor.entry.js +1 -1
  177. package/dist/esm/loader.js +1 -1
  178. package/dist/esm/{translations-BHybIZJs.js → translations-DVRaJQvC.js} +236 -4
  179. package/dist/lime-elements/lime-elements.esm.js +1 -1
  180. package/dist/lime-elements/{p-58176f7b.entry.js → p-05ff053d.entry.js} +1 -1
  181. package/dist/lime-elements/{p-7dd4e4bb.entry.js → p-08d1b87a.entry.js} +1 -1
  182. package/dist/lime-elements/{p-94f78e7a.entry.js → p-0fa2add8.entry.js} +1 -1
  183. package/dist/lime-elements/{p-40883e25.entry.js → p-1547b9c8.entry.js} +1 -1
  184. package/dist/lime-elements/{p-16a5f421.entry.js → p-1c244f85.entry.js} +1 -1
  185. package/dist/lime-elements/{p-ba9d6d42.entry.js → p-21dc4586.entry.js} +1 -1
  186. package/dist/lime-elements/{p-8e6a36a7.entry.js → p-2292181d.entry.js} +1 -1
  187. package/dist/lime-elements/{p-889d0000.entry.js → p-26bc957e.entry.js} +1 -1
  188. package/dist/lime-elements/{p-d4a51f0a.entry.js → p-287c4fb1.entry.js} +1 -1
  189. package/dist/lime-elements/p-358b277c.entry.js +1 -0
  190. package/dist/lime-elements/{p-f43e4cb8.entry.js → p-44295cc0.entry.js} +1 -1
  191. package/dist/lime-elements/{p-78fffaa9.entry.js → p-5178cc39.entry.js} +1 -1
  192. package/dist/lime-elements/{p-ec5b360a.entry.js → p-518fe33c.entry.js} +2 -2
  193. package/dist/lime-elements/{p-911db0aa.entry.js → p-53b94806.entry.js} +1 -1
  194. package/dist/lime-elements/p-5be668d8.entry.js +1 -0
  195. package/dist/lime-elements/{p-f49e5d8a.entry.js → p-68ffd790.entry.js} +1 -1
  196. package/dist/lime-elements/{p-fdfecf3d.entry.js → p-6a26ea78.entry.js} +1 -1
  197. package/dist/lime-elements/{p-5f593160.entry.js → p-6b05db4a.entry.js} +1 -1
  198. package/dist/lime-elements/p-70e2e60c.entry.js +1 -0
  199. package/dist/lime-elements/{p-3ad102a1.entry.js → p-756f452c.entry.js} +1 -1
  200. package/dist/lime-elements/{p-fa6aea91.entry.js → p-8784a57c.entry.js} +1 -1
  201. package/dist/lime-elements/{p-6d28c7b4.entry.js → p-89dfbd4a.entry.js} +1 -1
  202. package/dist/lime-elements/{p-5280d11e.entry.js → p-8ec4fdee.entry.js} +1 -1
  203. package/dist/lime-elements/{p-1b0eec07.entry.js → p-90f8d2ef.entry.js} +1 -1
  204. package/dist/lime-elements/p-965288d2.entry.js +1 -0
  205. package/dist/lime-elements/{p-8b77d2a8.entry.js → p-9908b57a.entry.js} +1 -1
  206. package/dist/lime-elements/{p-2d7a2258.entry.js → p-9e3e4f2c.entry.js} +1 -1
  207. package/dist/lime-elements/p-DVRaJQvC.js +1 -0
  208. package/dist/lime-elements/{p-3b18ef34.entry.js → p-a2295fa6.entry.js} +1 -1
  209. package/dist/lime-elements/{p-14bfd676.entry.js → p-a489f4b0.entry.js} +1 -1
  210. package/dist/lime-elements/{p-d5e954d4.entry.js → p-aeebf410.entry.js} +1 -1
  211. package/dist/lime-elements/{p-f4c9301d.entry.js → p-b11751c9.entry.js} +1 -1
  212. package/dist/lime-elements/{p-a1c1c40d.entry.js → p-b6ccc921.entry.js} +1 -1
  213. package/dist/lime-elements/{p-60f12574.entry.js → p-b95a42ea.entry.js} +1 -1
  214. package/dist/lime-elements/{p-8118cd4f.entry.js → p-bb38bb3c.entry.js} +1 -1
  215. package/dist/lime-elements/{p-d93f1c5f.entry.js → p-c3d565e2.entry.js} +1 -1
  216. package/dist/lime-elements/{p-a113dc9d.entry.js → p-c3ff8518.entry.js} +1 -1
  217. package/dist/lime-elements/{p-e00a96bd.entry.js → p-c6b9425b.entry.js} +1 -1
  218. package/dist/lime-elements/{p-373b7df7.entry.js → p-c6e9af7c.entry.js} +1 -1
  219. package/dist/lime-elements/{p-7997c118.entry.js → p-ce22f3da.entry.js} +1 -1
  220. package/dist/lime-elements/{p-8c6dfb19.entry.js → p-d5da5b05.entry.js} +1 -1
  221. package/dist/lime-elements/{p-b255e8e6.entry.js → p-da4429a8.entry.js} +1 -1
  222. package/dist/lime-elements/{p-6aa7cd43.entry.js → p-dcf3cc71.entry.js} +1 -1
  223. package/dist/lime-elements/{p-97f719ae.entry.js → p-de1e5ad9.entry.js} +1 -1
  224. package/dist/lime-elements/{p-13d0ec04.entry.js → p-eaac5ad2.entry.js} +1 -1
  225. package/dist/lime-elements/{p-ce178fbd.entry.js → p-ed8129db.entry.js} +1 -1
  226. package/dist/lime-elements/{p-b92431c8.entry.js → p-ee3afb60.entry.js} +3 -3
  227. package/dist/lime-elements/{p-8eff8a18.entry.js → p-ef75eed9.entry.js} +1 -1
  228. package/dist/lime-elements/{p-46b95d7c.entry.js → p-ef9bb368.entry.js} +1 -1
  229. package/dist/lime-elements/{p-912f53a3.entry.js → p-f70b8487.entry.js} +1 -1
  230. package/dist/lime-elements/{p-d53b8de5.entry.js → p-f9d5513d.entry.js} +1 -1
  231. package/dist/lime-elements/{p-bc4b4e46.entry.js → p-fb6c42a6.entry.js} +1 -1
  232. package/dist/types/components/code-diff/code-diff.d.ts +147 -0
  233. package/dist/types/components/code-diff/content-utils.d.ts +27 -0
  234. package/dist/types/components/code-diff/diff-engine.d.ts +36 -0
  235. package/dist/types/components/code-diff/search-utils.d.ts +30 -0
  236. package/dist/types/components/code-diff/syntax-highlighter.d.ts +19 -0
  237. package/dist/types/components/code-diff/types.d.ts +50 -0
  238. package/dist/types/components.d.ts +175 -0
  239. package/dist/types/translations/da.d.ts +29 -0
  240. package/dist/types/translations/de.d.ts +29 -0
  241. package/dist/types/translations/en.d.ts +29 -0
  242. package/dist/types/translations/fi.d.ts +29 -0
  243. package/dist/types/translations/fr.d.ts +29 -0
  244. package/dist/types/translations/nl.d.ts +29 -0
  245. package/dist/types/translations/no.d.ts +29 -0
  246. package/dist/types/translations/sv.d.ts +29 -0
  247. package/package.json +2 -1
  248. package/dist/cjs/limel-action-bar-item_2.cjs.entry.js +0 -137
  249. package/dist/esm/limel-action-bar-item_2.entry.js +0 -134
  250. package/dist/lime-elements/p-854a3ffe.entry.js +0 -1
  251. package/dist/lime-elements/p-8f2ac274.entry.js +0 -1
  252. package/dist/lime-elements/p-BHybIZJs.js +0 -1
  253. package/dist/lime-elements/p-accc6cc0.entry.js +0 -1
@@ -0,0 +1,1758 @@
1
+ 'use strict';
2
+
3
+ var index = require('./index-BjHIBY-I.js');
4
+ var translations = require('./translations-Bu_0fli7.js');
5
+
6
+ function Diff() {}
7
+ Diff.prototype = {
8
+ diff: function diff(oldString, newString) {
9
+ var _options$timeout;
10
+ var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
11
+ var callback = options.callback;
12
+ if (typeof options === 'function') {
13
+ callback = options;
14
+ options = {};
15
+ }
16
+ var self = this;
17
+ function done(value) {
18
+ value = self.postProcess(value, options);
19
+ if (callback) {
20
+ setTimeout(function () {
21
+ callback(value);
22
+ }, 0);
23
+ return true;
24
+ } else {
25
+ return value;
26
+ }
27
+ }
28
+
29
+ // Allow subclasses to massage the input prior to running
30
+ oldString = this.castInput(oldString, options);
31
+ newString = this.castInput(newString, options);
32
+ oldString = this.removeEmpty(this.tokenize(oldString, options));
33
+ newString = this.removeEmpty(this.tokenize(newString, options));
34
+ var newLen = newString.length,
35
+ oldLen = oldString.length;
36
+ var editLength = 1;
37
+ var maxEditLength = newLen + oldLen;
38
+ if (options.maxEditLength != null) {
39
+ maxEditLength = Math.min(maxEditLength, options.maxEditLength);
40
+ }
41
+ var maxExecutionTime = (_options$timeout = options.timeout) !== null && _options$timeout !== void 0 ? _options$timeout : Infinity;
42
+ var abortAfterTimestamp = Date.now() + maxExecutionTime;
43
+ var bestPath = [{
44
+ oldPos: -1,
45
+ lastComponent: undefined
46
+ }];
47
+
48
+ // Seed editLength = 0, i.e. the content starts with the same values
49
+ var newPos = this.extractCommon(bestPath[0], newString, oldString, 0, options);
50
+ if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
51
+ // Identity per the equality and tokenizer
52
+ return done(buildValues(self, bestPath[0].lastComponent, newString, oldString, self.useLongestToken));
53
+ }
54
+
55
+ // Once we hit the right edge of the edit graph on some diagonal k, we can
56
+ // definitely reach the end of the edit graph in no more than k edits, so
57
+ // there's no point in considering any moves to diagonal k+1 any more (from
58
+ // which we're guaranteed to need at least k+1 more edits).
59
+ // Similarly, once we've reached the bottom of the edit graph, there's no
60
+ // point considering moves to lower diagonals.
61
+ // We record this fact by setting minDiagonalToConsider and
62
+ // maxDiagonalToConsider to some finite value once we've hit the edge of
63
+ // the edit graph.
64
+ // This optimization is not faithful to the original algorithm presented in
65
+ // Myers's paper, which instead pointlessly extends D-paths off the end of
66
+ // the edit graph - see page 7 of Myers's paper which notes this point
67
+ // explicitly and illustrates it with a diagram. This has major performance
68
+ // implications for some common scenarios. For instance, to compute a diff
69
+ // where the new text simply appends d characters on the end of the
70
+ // original text of length n, the true Myers algorithm will take O(n+d^2)
71
+ // time while this optimization needs only O(n+d) time.
72
+ var minDiagonalToConsider = -Infinity,
73
+ maxDiagonalToConsider = Infinity;
74
+
75
+ // Main worker method. checks all permutations of a given edit length for acceptance.
76
+ function execEditLength() {
77
+ for (var diagonalPath = Math.max(minDiagonalToConsider, -editLength); diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {
78
+ var basePath = void 0;
79
+ var removePath = bestPath[diagonalPath - 1],
80
+ addPath = bestPath[diagonalPath + 1];
81
+ if (removePath) {
82
+ // No one else is going to attempt to use this value, clear it
83
+ bestPath[diagonalPath - 1] = undefined;
84
+ }
85
+ var canAdd = false;
86
+ if (addPath) {
87
+ // what newPos will be after we do an insertion:
88
+ var addPathNewPos = addPath.oldPos - diagonalPath;
89
+ canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;
90
+ }
91
+ var canRemove = removePath && removePath.oldPos + 1 < oldLen;
92
+ if (!canAdd && !canRemove) {
93
+ // If this path is a terminal then prune
94
+ bestPath[diagonalPath] = undefined;
95
+ continue;
96
+ }
97
+
98
+ // Select the diagonal that we want to branch from. We select the prior
99
+ // path whose position in the old string is the farthest from the origin
100
+ // and does not pass the bounds of the diff graph
101
+ if (!canRemove || canAdd && removePath.oldPos < addPath.oldPos) {
102
+ basePath = self.addToPath(addPath, true, false, 0, options);
103
+ } else {
104
+ basePath = self.addToPath(removePath, false, true, 1, options);
105
+ }
106
+ newPos = self.extractCommon(basePath, newString, oldString, diagonalPath, options);
107
+ if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
108
+ // If we have hit the end of both strings, then we are done
109
+ return done(buildValues(self, basePath.lastComponent, newString, oldString, self.useLongestToken));
110
+ } else {
111
+ bestPath[diagonalPath] = basePath;
112
+ if (basePath.oldPos + 1 >= oldLen) {
113
+ maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1);
114
+ }
115
+ if (newPos + 1 >= newLen) {
116
+ minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1);
117
+ }
118
+ }
119
+ }
120
+ editLength++;
121
+ }
122
+
123
+ // Performs the length of edit iteration. Is a bit fugly as this has to support the
124
+ // sync and async mode which is never fun. Loops over execEditLength until a value
125
+ // is produced, or until the edit length exceeds options.maxEditLength (if given),
126
+ // in which case it will return undefined.
127
+ if (callback) {
128
+ (function exec() {
129
+ setTimeout(function () {
130
+ if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {
131
+ return callback();
132
+ }
133
+ if (!execEditLength()) {
134
+ exec();
135
+ }
136
+ }, 0);
137
+ })();
138
+ } else {
139
+ while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) {
140
+ var ret = execEditLength();
141
+ if (ret) {
142
+ return ret;
143
+ }
144
+ }
145
+ }
146
+ },
147
+ addToPath: function addToPath(path, added, removed, oldPosInc, options) {
148
+ var last = path.lastComponent;
149
+ if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
150
+ return {
151
+ oldPos: path.oldPos + oldPosInc,
152
+ lastComponent: {
153
+ count: last.count + 1,
154
+ added: added,
155
+ removed: removed,
156
+ previousComponent: last.previousComponent
157
+ }
158
+ };
159
+ } else {
160
+ return {
161
+ oldPos: path.oldPos + oldPosInc,
162
+ lastComponent: {
163
+ count: 1,
164
+ added: added,
165
+ removed: removed,
166
+ previousComponent: last
167
+ }
168
+ };
169
+ }
170
+ },
171
+ extractCommon: function extractCommon(basePath, newString, oldString, diagonalPath, options) {
172
+ var newLen = newString.length,
173
+ oldLen = oldString.length,
174
+ oldPos = basePath.oldPos,
175
+ newPos = oldPos - diagonalPath,
176
+ commonCount = 0;
177
+ while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(oldString[oldPos + 1], newString[newPos + 1], options)) {
178
+ newPos++;
179
+ oldPos++;
180
+ commonCount++;
181
+ if (options.oneChangePerToken) {
182
+ basePath.lastComponent = {
183
+ count: 1,
184
+ previousComponent: basePath.lastComponent,
185
+ added: false,
186
+ removed: false
187
+ };
188
+ }
189
+ }
190
+ if (commonCount && !options.oneChangePerToken) {
191
+ basePath.lastComponent = {
192
+ count: commonCount,
193
+ previousComponent: basePath.lastComponent,
194
+ added: false,
195
+ removed: false
196
+ };
197
+ }
198
+ basePath.oldPos = oldPos;
199
+ return newPos;
200
+ },
201
+ equals: function equals(left, right, options) {
202
+ if (options.comparator) {
203
+ return options.comparator(left, right);
204
+ } else {
205
+ return left === right || options.ignoreCase && left.toLowerCase() === right.toLowerCase();
206
+ }
207
+ },
208
+ removeEmpty: function removeEmpty(array) {
209
+ var ret = [];
210
+ for (var i = 0; i < array.length; i++) {
211
+ if (array[i]) {
212
+ ret.push(array[i]);
213
+ }
214
+ }
215
+ return ret;
216
+ },
217
+ castInput: function castInput(value) {
218
+ return value;
219
+ },
220
+ tokenize: function tokenize(value) {
221
+ return Array.from(value);
222
+ },
223
+ join: function join(chars) {
224
+ return chars.join('');
225
+ },
226
+ postProcess: function postProcess(changeObjects) {
227
+ return changeObjects;
228
+ }
229
+ };
230
+ function buildValues(diff, lastComponent, newString, oldString, useLongestToken) {
231
+ // First we convert our linked list of components in reverse order to an
232
+ // array in the right order:
233
+ var components = [];
234
+ var nextComponent;
235
+ while (lastComponent) {
236
+ components.push(lastComponent);
237
+ nextComponent = lastComponent.previousComponent;
238
+ delete lastComponent.previousComponent;
239
+ lastComponent = nextComponent;
240
+ }
241
+ components.reverse();
242
+ var componentPos = 0,
243
+ componentLen = components.length,
244
+ newPos = 0,
245
+ oldPos = 0;
246
+ for (; componentPos < componentLen; componentPos++) {
247
+ var component = components[componentPos];
248
+ if (!component.removed) {
249
+ if (!component.added && useLongestToken) {
250
+ var value = newString.slice(newPos, newPos + component.count);
251
+ value = value.map(function (value, i) {
252
+ var oldValue = oldString[oldPos + i];
253
+ return oldValue.length > value.length ? oldValue : value;
254
+ });
255
+ component.value = diff.join(value);
256
+ } else {
257
+ component.value = diff.join(newString.slice(newPos, newPos + component.count));
258
+ }
259
+ newPos += component.count;
260
+
261
+ // Common case
262
+ if (!component.added) {
263
+ oldPos += component.count;
264
+ }
265
+ } else {
266
+ component.value = diff.join(oldString.slice(oldPos, oldPos + component.count));
267
+ oldPos += component.count;
268
+ }
269
+ }
270
+ return components;
271
+ }
272
+
273
+ function longestCommonPrefix(str1, str2) {
274
+ var i;
275
+ for (i = 0; i < str1.length && i < str2.length; i++) {
276
+ if (str1[i] != str2[i]) {
277
+ return str1.slice(0, i);
278
+ }
279
+ }
280
+ return str1.slice(0, i);
281
+ }
282
+ function longestCommonSuffix(str1, str2) {
283
+ var i;
284
+
285
+ // Unlike longestCommonPrefix, we need a special case to handle all scenarios
286
+ // where we return the empty string since str1.slice(-0) will return the
287
+ // entire string.
288
+ if (!str1 || !str2 || str1[str1.length - 1] != str2[str2.length - 1]) {
289
+ return '';
290
+ }
291
+ for (i = 0; i < str1.length && i < str2.length; i++) {
292
+ if (str1[str1.length - (i + 1)] != str2[str2.length - (i + 1)]) {
293
+ return str1.slice(-i);
294
+ }
295
+ }
296
+ return str1.slice(-i);
297
+ }
298
+ function replacePrefix(string, oldPrefix, newPrefix) {
299
+ if (string.slice(0, oldPrefix.length) != oldPrefix) {
300
+ throw Error("string ".concat(JSON.stringify(string), " doesn't start with prefix ").concat(JSON.stringify(oldPrefix), "; this is a bug"));
301
+ }
302
+ return newPrefix + string.slice(oldPrefix.length);
303
+ }
304
+ function replaceSuffix(string, oldSuffix, newSuffix) {
305
+ if (!oldSuffix) {
306
+ return string + newSuffix;
307
+ }
308
+ if (string.slice(-oldSuffix.length) != oldSuffix) {
309
+ throw Error("string ".concat(JSON.stringify(string), " doesn't end with suffix ").concat(JSON.stringify(oldSuffix), "; this is a bug"));
310
+ }
311
+ return string.slice(0, -oldSuffix.length) + newSuffix;
312
+ }
313
+ function removePrefix(string, oldPrefix) {
314
+ return replacePrefix(string, oldPrefix, '');
315
+ }
316
+ function removeSuffix(string, oldSuffix) {
317
+ return replaceSuffix(string, oldSuffix, '');
318
+ }
319
+ function maximumOverlap(string1, string2) {
320
+ return string2.slice(0, overlapCount(string1, string2));
321
+ }
322
+
323
+ // Nicked from https://stackoverflow.com/a/60422853/1709587
324
+ function overlapCount(a, b) {
325
+ // Deal with cases where the strings differ in length
326
+ var startA = 0;
327
+ if (a.length > b.length) {
328
+ startA = a.length - b.length;
329
+ }
330
+ var endB = b.length;
331
+ if (a.length < b.length) {
332
+ endB = a.length;
333
+ }
334
+ // Create a back-reference for each index
335
+ // that should be followed in case of a mismatch.
336
+ // We only need B to make these references:
337
+ var map = Array(endB);
338
+ var k = 0; // Index that lags behind j
339
+ map[0] = 0;
340
+ for (var j = 1; j < endB; j++) {
341
+ if (b[j] == b[k]) {
342
+ map[j] = map[k]; // skip over the same character (optional optimisation)
343
+ } else {
344
+ map[j] = k;
345
+ }
346
+ while (k > 0 && b[j] != b[k]) {
347
+ k = map[k];
348
+ }
349
+ if (b[j] == b[k]) {
350
+ k++;
351
+ }
352
+ }
353
+ // Phase 2: use these references while iterating over A
354
+ k = 0;
355
+ for (var i = startA; i < a.length; i++) {
356
+ while (k > 0 && a[i] != b[k]) {
357
+ k = map[k];
358
+ }
359
+ if (a[i] == b[k]) {
360
+ k++;
361
+ }
362
+ }
363
+ return k;
364
+ }
365
+
366
+ // Based on https://en.wikipedia.org/wiki/Latin_script_in_Unicode
367
+ //
368
+ // Ranges and exceptions:
369
+ // Latin-1 Supplement, 0080–00FF
370
+ // - U+00D7 × Multiplication sign
371
+ // - U+00F7 ÷ Division sign
372
+ // Latin Extended-A, 0100–017F
373
+ // Latin Extended-B, 0180–024F
374
+ // IPA Extensions, 0250–02AF
375
+ // Spacing Modifier Letters, 02B0–02FF
376
+ // - U+02C7 ˇ &#711; Caron
377
+ // - U+02D8 ˘ &#728; Breve
378
+ // - U+02D9 ˙ &#729; Dot Above
379
+ // - U+02DA ˚ &#730; Ring Above
380
+ // - U+02DB ˛ &#731; Ogonek
381
+ // - U+02DC ˜ &#732; Small Tilde
382
+ // - U+02DD ˝ &#733; Double Acute Accent
383
+ // Latin Extended Additional, 1E00–1EFF
384
+ var extendedWordChars = "a-zA-Z0-9_\\u{C0}-\\u{FF}\\u{D8}-\\u{F6}\\u{F8}-\\u{2C6}\\u{2C8}-\\u{2D7}\\u{2DE}-\\u{2FF}\\u{1E00}-\\u{1EFF}";
385
+
386
+ // Each token is one of the following:
387
+ // - A punctuation mark plus the surrounding whitespace
388
+ // - A word plus the surrounding whitespace
389
+ // - Pure whitespace (but only in the special case where this the entire text
390
+ // is just whitespace)
391
+ //
392
+ // We have to include surrounding whitespace in the tokens because the two
393
+ // alternative approaches produce horribly broken results:
394
+ // * If we just discard the whitespace, we can't fully reproduce the original
395
+ // text from the sequence of tokens and any attempt to render the diff will
396
+ // get the whitespace wrong.
397
+ // * If we have separate tokens for whitespace, then in a typical text every
398
+ // second token will be a single space character. But this often results in
399
+ // the optimal diff between two texts being a perverse one that preserves
400
+ // the spaces between words but deletes and reinserts actual common words.
401
+ // See https://github.com/kpdecker/jsdiff/issues/160#issuecomment-1866099640
402
+ // for an example.
403
+ //
404
+ // Keeping the surrounding whitespace of course has implications for .equals
405
+ // and .join, not just .tokenize.
406
+
407
+ // This regex does NOT fully implement the tokenization rules described above.
408
+ // Instead, it gives runs of whitespace their own "token". The tokenize method
409
+ // then handles stitching whitespace tokens onto adjacent word or punctuation
410
+ // tokens.
411
+ var tokenizeIncludingWhitespace = new RegExp("[".concat(extendedWordChars, "]+|\\s+|[^").concat(extendedWordChars, "]"), 'ug');
412
+ var wordDiff = new Diff();
413
+ wordDiff.equals = function (left, right, options) {
414
+ if (options.ignoreCase) {
415
+ left = left.toLowerCase();
416
+ right = right.toLowerCase();
417
+ }
418
+ return left.trim() === right.trim();
419
+ };
420
+ wordDiff.tokenize = function (value) {
421
+ var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
422
+ var parts;
423
+ if (options.intlSegmenter) {
424
+ if (options.intlSegmenter.resolvedOptions().granularity != 'word') {
425
+ throw new Error('The segmenter passed must have a granularity of "word"');
426
+ }
427
+ parts = Array.from(options.intlSegmenter.segment(value), function (segment) {
428
+ return segment.segment;
429
+ });
430
+ } else {
431
+ parts = value.match(tokenizeIncludingWhitespace) || [];
432
+ }
433
+ var tokens = [];
434
+ var prevPart = null;
435
+ parts.forEach(function (part) {
436
+ if (/\s/.test(part)) {
437
+ if (prevPart == null) {
438
+ tokens.push(part);
439
+ } else {
440
+ tokens.push(tokens.pop() + part);
441
+ }
442
+ } else if (/\s/.test(prevPart)) {
443
+ if (tokens[tokens.length - 1] == prevPart) {
444
+ tokens.push(tokens.pop() + part);
445
+ } else {
446
+ tokens.push(prevPart + part);
447
+ }
448
+ } else {
449
+ tokens.push(part);
450
+ }
451
+ prevPart = part;
452
+ });
453
+ return tokens;
454
+ };
455
+ wordDiff.join = function (tokens) {
456
+ // Tokens being joined here will always have appeared consecutively in the
457
+ // same text, so we can simply strip off the leading whitespace from all the
458
+ // tokens except the first (and except any whitespace-only tokens - but such
459
+ // a token will always be the first and only token anyway) and then join them
460
+ // and the whitespace around words and punctuation will end up correct.
461
+ return tokens.map(function (token, i) {
462
+ if (i == 0) {
463
+ return token;
464
+ } else {
465
+ return token.replace(/^\s+/, '');
466
+ }
467
+ }).join('');
468
+ };
469
+ wordDiff.postProcess = function (changes, options) {
470
+ if (!changes || options.oneChangePerToken) {
471
+ return changes;
472
+ }
473
+ var lastKeep = null;
474
+ // Change objects representing any insertion or deletion since the last
475
+ // "keep" change object. There can be at most one of each.
476
+ var insertion = null;
477
+ var deletion = null;
478
+ changes.forEach(function (change) {
479
+ if (change.added) {
480
+ insertion = change;
481
+ } else if (change.removed) {
482
+ deletion = change;
483
+ } else {
484
+ if (insertion || deletion) {
485
+ // May be false at start of text
486
+ dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, change);
487
+ }
488
+ lastKeep = change;
489
+ insertion = null;
490
+ deletion = null;
491
+ }
492
+ });
493
+ if (insertion || deletion) {
494
+ dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, null);
495
+ }
496
+ return changes;
497
+ };
498
+ function diffWords(oldStr, newStr, options) {
499
+ return wordDiff.diff(oldStr, newStr, options);
500
+ }
501
+ function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep) {
502
+ // Before returning, we tidy up the leading and trailing whitespace of the
503
+ // change objects to eliminate cases where trailing whitespace in one object
504
+ // is repeated as leading whitespace in the next.
505
+ // Below are examples of the outcomes we want here to explain the code.
506
+ // I=insert, K=keep, D=delete
507
+ // 1. diffing 'foo bar baz' vs 'foo baz'
508
+ // Prior to cleanup, we have K:'foo ' D:' bar ' K:' baz'
509
+ // After cleanup, we want: K:'foo ' D:'bar ' K:'baz'
510
+ //
511
+ // 2. Diffing 'foo bar baz' vs 'foo qux baz'
512
+ // Prior to cleanup, we have K:'foo ' D:' bar ' I:' qux ' K:' baz'
513
+ // After cleanup, we want K:'foo ' D:'bar' I:'qux' K:' baz'
514
+ //
515
+ // 3. Diffing 'foo\nbar baz' vs 'foo baz'
516
+ // Prior to cleanup, we have K:'foo ' D:'\nbar ' K:' baz'
517
+ // After cleanup, we want K'foo' D:'\nbar' K:' baz'
518
+ //
519
+ // 4. Diffing 'foo baz' vs 'foo\nbar baz'
520
+ // Prior to cleanup, we have K:'foo\n' I:'\nbar ' K:' baz'
521
+ // After cleanup, we ideally want K'foo' I:'\nbar' K:' baz'
522
+ // but don't actually manage this currently (the pre-cleanup change
523
+ // objects don't contain enough information to make it possible).
524
+ //
525
+ // 5. Diffing 'foo bar baz' vs 'foo baz'
526
+ // Prior to cleanup, we have K:'foo ' D:' bar ' K:' baz'
527
+ // After cleanup, we want K:'foo ' D:' bar ' K:'baz'
528
+ //
529
+ // Our handling is unavoidably imperfect in the case where there's a single
530
+ // indel between keeps and the whitespace has changed. For instance, consider
531
+ // diffing 'foo\tbar\nbaz' vs 'foo baz'. Unless we create an extra change
532
+ // object to represent the insertion of the space character (which isn't even
533
+ // a token), we have no way to avoid losing information about the texts'
534
+ // original whitespace in the result we return. Still, we do our best to
535
+ // output something that will look sensible if we e.g. print it with
536
+ // insertions in green and deletions in red.
537
+
538
+ // Between two "keep" change objects (or before the first or after the last
539
+ // change object), we can have either:
540
+ // * A "delete" followed by an "insert"
541
+ // * Just an "insert"
542
+ // * Just a "delete"
543
+ // We handle the three cases separately.
544
+ if (deletion && insertion) {
545
+ var oldWsPrefix = deletion.value.match(/^\s*/)[0];
546
+ var oldWsSuffix = deletion.value.match(/\s*$/)[0];
547
+ var newWsPrefix = insertion.value.match(/^\s*/)[0];
548
+ var newWsSuffix = insertion.value.match(/\s*$/)[0];
549
+ if (startKeep) {
550
+ var commonWsPrefix = longestCommonPrefix(oldWsPrefix, newWsPrefix);
551
+ startKeep.value = replaceSuffix(startKeep.value, newWsPrefix, commonWsPrefix);
552
+ deletion.value = removePrefix(deletion.value, commonWsPrefix);
553
+ insertion.value = removePrefix(insertion.value, commonWsPrefix);
554
+ }
555
+ if (endKeep) {
556
+ var commonWsSuffix = longestCommonSuffix(oldWsSuffix, newWsSuffix);
557
+ endKeep.value = replacePrefix(endKeep.value, newWsSuffix, commonWsSuffix);
558
+ deletion.value = removeSuffix(deletion.value, commonWsSuffix);
559
+ insertion.value = removeSuffix(insertion.value, commonWsSuffix);
560
+ }
561
+ } else if (insertion) {
562
+ // The whitespaces all reflect what was in the new text rather than
563
+ // the old, so we essentially have no information about whitespace
564
+ // insertion or deletion. We just want to dedupe the whitespace.
565
+ // We do that by having each change object keep its trailing
566
+ // whitespace and deleting duplicate leading whitespace where
567
+ // present.
568
+ if (startKeep) {
569
+ insertion.value = insertion.value.replace(/^\s*/, '');
570
+ }
571
+ if (endKeep) {
572
+ endKeep.value = endKeep.value.replace(/^\s*/, '');
573
+ }
574
+ // otherwise we've got a deletion and no insertion
575
+ } else if (startKeep && endKeep) {
576
+ var newWsFull = endKeep.value.match(/^\s*/)[0],
577
+ delWsStart = deletion.value.match(/^\s*/)[0],
578
+ delWsEnd = deletion.value.match(/\s*$/)[0];
579
+
580
+ // Any whitespace that comes straight after startKeep in both the old and
581
+ // new texts, assign to startKeep and remove from the deletion.
582
+ var newWsStart = longestCommonPrefix(newWsFull, delWsStart);
583
+ deletion.value = removePrefix(deletion.value, newWsStart);
584
+
585
+ // Any whitespace that comes straight before endKeep in both the old and
586
+ // new texts, and hasn't already been assigned to startKeep, assign to
587
+ // endKeep and remove from the deletion.
588
+ var newWsEnd = longestCommonSuffix(removePrefix(newWsFull, newWsStart), delWsEnd);
589
+ deletion.value = removeSuffix(deletion.value, newWsEnd);
590
+ endKeep.value = replacePrefix(endKeep.value, newWsFull, newWsEnd);
591
+
592
+ // If there's any whitespace from the new text that HASN'T already been
593
+ // assigned, assign it to the start:
594
+ startKeep.value = replaceSuffix(startKeep.value, newWsFull, newWsFull.slice(0, newWsFull.length - newWsEnd.length));
595
+ } else if (endKeep) {
596
+ // We are at the start of the text. Preserve all the whitespace on
597
+ // endKeep, and just remove whitespace from the end of deletion to the
598
+ // extent that it overlaps with the start of endKeep.
599
+ var endKeepWsPrefix = endKeep.value.match(/^\s*/)[0];
600
+ var deletionWsSuffix = deletion.value.match(/\s*$/)[0];
601
+ var overlap = maximumOverlap(deletionWsSuffix, endKeepWsPrefix);
602
+ deletion.value = removeSuffix(deletion.value, overlap);
603
+ } else if (startKeep) {
604
+ // We are at the END of the text. Preserve all the whitespace on
605
+ // startKeep, and just remove whitespace from the start of deletion to
606
+ // the extent that it overlaps with the end of startKeep.
607
+ var startKeepWsSuffix = startKeep.value.match(/\s*$/)[0];
608
+ var deletionWsPrefix = deletion.value.match(/^\s*/)[0];
609
+ var _overlap = maximumOverlap(startKeepWsSuffix, deletionWsPrefix);
610
+ deletion.value = removePrefix(deletion.value, _overlap);
611
+ }
612
+ }
613
+ var wordWithSpaceDiff = new Diff();
614
+ wordWithSpaceDiff.tokenize = function (value) {
615
+ // Slightly different to the tokenizeIncludingWhitespace regex used above in
616
+ // that this one treats each individual newline as a distinct tokens, rather
617
+ // than merging them into other surrounding whitespace. This was requested
618
+ // in https://github.com/kpdecker/jsdiff/issues/180 &
619
+ // https://github.com/kpdecker/jsdiff/issues/211
620
+ var regex = new RegExp("(\\r?\\n)|[".concat(extendedWordChars, "]+|[^\\S\\n\\r]+|[^").concat(extendedWordChars, "]"), 'ug');
621
+ return value.match(regex) || [];
622
+ };
623
+
624
+ var lineDiff = new Diff();
625
+ lineDiff.tokenize = function (value, options) {
626
+ if (options.stripTrailingCr) {
627
+ // remove one \r before \n to match GNU diff's --strip-trailing-cr behavior
628
+ value = value.replace(/\r\n/g, '\n');
629
+ }
630
+ var retLines = [],
631
+ linesAndNewlines = value.split(/(\n|\r\n)/);
632
+
633
+ // Ignore the final empty token that occurs if the string ends with a new line
634
+ if (!linesAndNewlines[linesAndNewlines.length - 1]) {
635
+ linesAndNewlines.pop();
636
+ }
637
+
638
+ // Merge the content and line separators into single tokens
639
+ for (var i = 0; i < linesAndNewlines.length; i++) {
640
+ var line = linesAndNewlines[i];
641
+ if (i % 2 && !options.newlineIsToken) {
642
+ retLines[retLines.length - 1] += line;
643
+ } else {
644
+ retLines.push(line);
645
+ }
646
+ }
647
+ return retLines;
648
+ };
649
+ lineDiff.equals = function (left, right, options) {
650
+ // If we're ignoring whitespace, we need to normalise lines by stripping
651
+ // whitespace before checking equality. (This has an annoying interaction
652
+ // with newlineIsToken that requires special handling: if newlines get their
653
+ // own token, then we DON'T want to trim the *newline* tokens down to empty
654
+ // strings, since this would cause us to treat whitespace-only line content
655
+ // as equal to a separator between lines, which would be weird and
656
+ // inconsistent with the documented behavior of the options.)
657
+ if (options.ignoreWhitespace) {
658
+ if (!options.newlineIsToken || !left.includes('\n')) {
659
+ left = left.trim();
660
+ }
661
+ if (!options.newlineIsToken || !right.includes('\n')) {
662
+ right = right.trim();
663
+ }
664
+ } else if (options.ignoreNewlineAtEof && !options.newlineIsToken) {
665
+ if (left.endsWith('\n')) {
666
+ left = left.slice(0, -1);
667
+ }
668
+ if (right.endsWith('\n')) {
669
+ right = right.slice(0, -1);
670
+ }
671
+ }
672
+ return Diff.prototype.equals.call(this, left, right, options);
673
+ };
674
+ function diffLines(oldStr, newStr, callback) {
675
+ return lineDiff.diff(oldStr, newStr, callback);
676
+ }
677
+
678
+ var sentenceDiff = new Diff();
679
+ sentenceDiff.tokenize = function (value) {
680
+ return value.split(/(\S.+?[.!?])(?=\s+|$)/);
681
+ };
682
+
683
+ var cssDiff = new Diff();
684
+ cssDiff.tokenize = function (value) {
685
+ return value.split(/([{}:;,]|\s+)/);
686
+ };
687
+ function _typeof(o) {
688
+ "@babel/helpers - typeof";
689
+
690
+ return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
691
+ return typeof o;
692
+ } : function (o) {
693
+ return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
694
+ }, _typeof(o);
695
+ }
696
+
697
+ var jsonDiff = new Diff();
698
+ // Discriminate between two lines of pretty-printed, serialized JSON where one of them has a
699
+ // dangling comma and the other doesn't. Turns out including the dangling comma yields the nicest output:
700
+ jsonDiff.useLongestToken = true;
701
+ jsonDiff.tokenize = lineDiff.tokenize;
702
+ jsonDiff.castInput = function (value, options) {
703
+ var undefinedReplacement = options.undefinedReplacement,
704
+ _options$stringifyRep = options.stringifyReplacer,
705
+ stringifyReplacer = _options$stringifyRep === void 0 ? function (k, v) {
706
+ return typeof v === 'undefined' ? undefinedReplacement : v;
707
+ } : _options$stringifyRep;
708
+ return typeof value === 'string' ? value : JSON.stringify(canonicalize(value, null, null, stringifyReplacer), stringifyReplacer, ' ');
709
+ };
710
+ jsonDiff.equals = function (left, right, options) {
711
+ return Diff.prototype.equals.call(jsonDiff, left.replace(/,([\r\n])/g, '$1'), right.replace(/,([\r\n])/g, '$1'), options);
712
+ };
713
+
714
+ // This function handles the presence of circular references by bailing out when encountering an
715
+ // object that is already on the "stack" of items being processed. Accepts an optional replacer
716
+ function canonicalize(obj, stack, replacementStack, replacer, key) {
717
+ stack = stack || [];
718
+ replacementStack = replacementStack || [];
719
+ if (replacer) {
720
+ obj = replacer(key, obj);
721
+ }
722
+ var i;
723
+ for (i = 0; i < stack.length; i += 1) {
724
+ if (stack[i] === obj) {
725
+ return replacementStack[i];
726
+ }
727
+ }
728
+ var canonicalizedObj;
729
+ if ('[object Array]' === Object.prototype.toString.call(obj)) {
730
+ stack.push(obj);
731
+ canonicalizedObj = new Array(obj.length);
732
+ replacementStack.push(canonicalizedObj);
733
+ for (i = 0; i < obj.length; i += 1) {
734
+ canonicalizedObj[i] = canonicalize(obj[i], stack, replacementStack, replacer, key);
735
+ }
736
+ stack.pop();
737
+ replacementStack.pop();
738
+ return canonicalizedObj;
739
+ }
740
+ if (obj && obj.toJSON) {
741
+ obj = obj.toJSON();
742
+ }
743
+ if (_typeof(obj) === 'object' && obj !== null) {
744
+ stack.push(obj);
745
+ canonicalizedObj = {};
746
+ replacementStack.push(canonicalizedObj);
747
+ var sortedKeys = [],
748
+ _key;
749
+ for (_key in obj) {
750
+ /* istanbul ignore else */
751
+ if (Object.prototype.hasOwnProperty.call(obj, _key)) {
752
+ sortedKeys.push(_key);
753
+ }
754
+ }
755
+ sortedKeys.sort();
756
+ for (i = 0; i < sortedKeys.length; i += 1) {
757
+ _key = sortedKeys[i];
758
+ canonicalizedObj[_key] = canonicalize(obj[_key], stack, replacementStack, replacer, _key);
759
+ }
760
+ stack.pop();
761
+ replacementStack.pop();
762
+ } else {
763
+ canonicalizedObj = obj;
764
+ }
765
+ return canonicalizedObj;
766
+ }
767
+
768
+ var arrayDiff = new Diff();
769
+ arrayDiff.tokenize = function (value) {
770
+ return value.slice();
771
+ };
772
+ arrayDiff.join = arrayDiff.removeEmpty = function (value) {
773
+ return value;
774
+ };
775
+
776
+ /**
777
+ * Compute a structured diff between two strings.
778
+ *
779
+ * @param oldText - the "before" text
780
+ * @param newText - the "after" text
781
+ * @param contextLines - number of unchanged lines to show around each change
782
+ * @returns a DiffResult with hunks, additions, and deletions counts
783
+ */
784
+ function computeDiff(oldText, newText, contextLines = 3) {
785
+ const allLines = buildDiffLines(oldText, newText);
786
+ return groupIntoHunks(allLines, contextLines);
787
+ }
788
+ /**
789
+ * Build paired rows for split (side-by-side) view from flat diff lines.
790
+ * Context lines appear on both sides. Adjacent removed+added lines
791
+ * are paired into the same row.
792
+ *
793
+ * @param lines - flat diff lines
794
+ * @returns paired rows for split rendering
795
+ */
796
+ function buildSplitLines(lines) {
797
+ const rows = [];
798
+ let i = 0;
799
+ while (i < lines.length) {
800
+ const line = lines[i];
801
+ if (line.type === 'context') {
802
+ rows.push({ left: line, right: line });
803
+ i++;
804
+ continue;
805
+ }
806
+ i = collectAndPairChanges(lines, i, rows);
807
+ }
808
+ return rows;
809
+ }
810
+ /**
811
+ * Collect consecutive removed then added lines starting at `index`,
812
+ * pair them into split rows, and return the new index.
813
+ * @param lines - flat diff lines
814
+ * @param index - starting index
815
+ * @param rows - output array to push paired rows into
816
+ */
817
+ function collectAndPairChanges(lines, index, rows) {
818
+ const removed = [];
819
+ while (index < lines.length && lines[index].type === 'removed') {
820
+ removed.push(lines[index]);
821
+ index++;
822
+ }
823
+ const added = [];
824
+ while (index < lines.length && lines[index].type === 'added') {
825
+ added.push(lines[index]);
826
+ index++;
827
+ }
828
+ const maxPairs = Math.max(removed.length, added.length);
829
+ for (let j = 0; j < maxPairs; j++) {
830
+ rows.push({
831
+ left: j < removed.length ? removed[j] : undefined,
832
+ right: j < added.length ? added[j] : undefined,
833
+ });
834
+ }
835
+ return index;
836
+ }
837
+ /**
838
+ * Normalize values for diffing. If `reformatJson` is true,
839
+ * parse and re-stringify with sorted keys and consistent indentation.
840
+ * @param value
841
+ * @param reformatJson
842
+ */
843
+ function normalizeForDiff(value, reformatJson = false) {
844
+ if (typeof value === 'object' && value !== null) {
845
+ return JSON.stringify(sortKeysDeep(value), null, 4);
846
+ }
847
+ if (typeof value === 'string' && reformatJson) {
848
+ try {
849
+ const parsed = JSON.parse(value);
850
+ return JSON.stringify(sortKeysDeep(parsed), null, 4);
851
+ }
852
+ catch (_a) {
853
+ return value;
854
+ }
855
+ }
856
+ return String(value !== null && value !== void 0 ? value : '');
857
+ }
858
+ function sortKeysDeep(obj) {
859
+ if (Array.isArray(obj)) {
860
+ return obj.map(sortKeysDeep);
861
+ }
862
+ if (obj !== null && typeof obj === 'object') {
863
+ const sorted = {};
864
+ const keys = Object.keys(obj).sort((a, b) => a.localeCompare(b));
865
+ for (const key of keys) {
866
+ sorted[key] = sortKeysDeep(obj[key]);
867
+ }
868
+ return sorted;
869
+ }
870
+ return obj;
871
+ }
872
+ /**
873
+ * Build a flat list of DiffLines from two text strings.
874
+ * @param oldText
875
+ * @param newText
876
+ */
877
+ function buildDiffLines(oldText, newText) {
878
+ const changes = diffLines(oldText, newText);
879
+ const lines = [];
880
+ let oldLineNum = 1;
881
+ let newLineNum = 1;
882
+ for (const change of changes) {
883
+ const changeLines = splitIntoLines(change.value);
884
+ for (const line of changeLines) {
885
+ if (change.added) {
886
+ lines.push({
887
+ type: 'added',
888
+ content: line,
889
+ newLineNumber: newLineNum++,
890
+ });
891
+ }
892
+ else if (change.removed) {
893
+ lines.push({
894
+ type: 'removed',
895
+ content: line,
896
+ oldLineNumber: oldLineNum++,
897
+ });
898
+ }
899
+ else {
900
+ lines.push({
901
+ type: 'context',
902
+ content: line,
903
+ oldLineNumber: oldLineNum++,
904
+ newLineNumber: newLineNum++,
905
+ });
906
+ }
907
+ }
908
+ }
909
+ addWordLevelHighlighting(lines);
910
+ return lines;
911
+ }
912
+ /**
913
+ * Split a string into lines, handling the trailing newline
914
+ * that jsdiff includes in each change value.
915
+ * @param text
916
+ */
917
+ function splitIntoLines(text) {
918
+ if (!text) {
919
+ return [];
920
+ }
921
+ const lines = text.split('\n');
922
+ // jsdiff includes a trailing newline, producing an empty last element
923
+ if (lines.length > 0 && lines.at(-1) === '') {
924
+ lines.pop();
925
+ }
926
+ return lines;
927
+ }
928
+ /**
929
+ * Pair adjacent removed+added lines and compute word-level diffs
930
+ * to highlight only the specific segments that changed.
931
+ * @param lines
932
+ */
933
+ function addWordLevelHighlighting(lines) {
934
+ let i = 0;
935
+ while (i < lines.length) {
936
+ // Find consecutive removed lines
937
+ const removedStart = i;
938
+ while (i < lines.length && lines[i].type === 'removed') {
939
+ i++;
940
+ }
941
+ const removedEnd = i;
942
+ // Find consecutive added lines right after
943
+ const addedStart = i;
944
+ while (i < lines.length && lines[i].type === 'added') {
945
+ i++;
946
+ }
947
+ const addedEnd = i;
948
+ const removedCount = removedEnd - removedStart;
949
+ const addedCount = addedEnd - addedStart;
950
+ // Pair them up for word-level highlighting
951
+ if (removedCount > 0 && addedCount > 0) {
952
+ const pairCount = Math.min(removedCount, addedCount);
953
+ for (let j = 0; j < pairCount; j++) {
954
+ const removedLine = lines[removedStart + j];
955
+ const addedLine = lines[addedStart + j];
956
+ const [removedSegments, addedSegments] = computeWordSegments(removedLine.content, addedLine.content);
957
+ removedLine.segments = removedSegments;
958
+ addedLine.segments = addedSegments;
959
+ }
960
+ }
961
+ // Skip context lines
962
+ if (i === removedStart) {
963
+ i++;
964
+ }
965
+ }
966
+ }
967
+ /**
968
+ * Compute word-level diff segments for a pair of lines.
969
+ * @param oldContent
970
+ * @param newContent
971
+ */
972
+ function computeWordSegments(oldContent, newContent) {
973
+ const wordChanges = diffWords(oldContent, newContent);
974
+ const removedSegments = [];
975
+ const addedSegments = [];
976
+ for (const change of wordChanges) {
977
+ if (change.added) {
978
+ addedSegments.push({ value: change.value, type: 'added' });
979
+ }
980
+ else if (change.removed) {
981
+ removedSegments.push({ value: change.value, type: 'removed' });
982
+ }
983
+ else {
984
+ removedSegments.push({ value: change.value, type: 'equal' });
985
+ addedSegments.push({ value: change.value, type: 'equal' });
986
+ }
987
+ }
988
+ return [removedSegments, addedSegments];
989
+ }
990
+ /**
991
+ * Group a flat list of diff lines into hunks with context.
992
+ * @param lines
993
+ * @param contextLines
994
+ */
995
+ function groupIntoHunks(lines, contextLines) {
996
+ if (lines.length === 0) {
997
+ return { hunks: [], additions: 0, deletions: 0, allLines: lines };
998
+ }
999
+ let additions = 0;
1000
+ let deletions = 0;
1001
+ for (const line of lines) {
1002
+ if (line.type === 'added') {
1003
+ additions++;
1004
+ }
1005
+ else if (line.type === 'removed') {
1006
+ deletions++;
1007
+ }
1008
+ }
1009
+ // If there are no changes, return a single empty result
1010
+ if (additions === 0 && deletions === 0) {
1011
+ return { hunks: [], additions: 0, deletions: 0, allLines: lines };
1012
+ }
1013
+ // Find ranges of changed lines with their context
1014
+ const changeIndices = [];
1015
+ for (const [i, line] of lines.entries()) {
1016
+ if (line.type !== 'context') {
1017
+ changeIndices.push(i);
1018
+ }
1019
+ }
1020
+ // Build hunk boundaries
1021
+ const hunkBoundaries = buildHunkBoundaries(changeIndices, lines.length, contextLines);
1022
+ const hunks = [];
1023
+ let prevEnd = 0;
1024
+ for (const boundary of hunkBoundaries) {
1025
+ const hunkLines = lines.slice(boundary.start, boundary.end);
1026
+ const hiddenBefore = boundary.start - prevEnd;
1027
+ const collapsedBefore = hiddenBefore > 0 ? hiddenBefore : undefined;
1028
+ hunks.push({
1029
+ lines: hunkLines,
1030
+ collapsedBefore,
1031
+ startIndex: boundary.start,
1032
+ });
1033
+ prevEnd = boundary.end;
1034
+ }
1035
+ // Calculate collapsed lines after the last hunk
1036
+ const lastBoundary = hunkBoundaries.at(-1);
1037
+ const collapsedAfter = lastBoundary.end < lines.length
1038
+ ? lines.length - lastBoundary.end
1039
+ : undefined;
1040
+ return { hunks, additions, deletions, collapsedAfter, allLines: lines };
1041
+ }
1042
+ /**
1043
+ * Build the start/end boundaries of each hunk based on change positions.
1044
+ * Merges hunks that overlap or are adjacent.
1045
+ * @param changeIndices
1046
+ * @param totalLines
1047
+ * @param contextLines
1048
+ */
1049
+ function buildHunkBoundaries(changeIndices, totalLines, contextLines) {
1050
+ if (changeIndices.length === 0) {
1051
+ return [];
1052
+ }
1053
+ const boundaries = [];
1054
+ let currentStart = Math.max(0, changeIndices[0] - contextLines);
1055
+ let currentEnd = Math.min(totalLines, changeIndices[0] + contextLines + 1);
1056
+ for (let i = 1; i < changeIndices.length; i++) {
1057
+ const changeStart = Math.max(0, changeIndices[i] - contextLines);
1058
+ const changeEnd = Math.min(totalLines, changeIndices[i] + contextLines + 1);
1059
+ if (changeStart <= currentEnd) {
1060
+ // Merge overlapping hunks
1061
+ currentEnd = Math.max(currentEnd, changeEnd);
1062
+ }
1063
+ else {
1064
+ boundaries.push({ start: currentStart, end: currentEnd });
1065
+ currentStart = changeStart;
1066
+ currentEnd = changeEnd;
1067
+ }
1068
+ }
1069
+ boundaries.push({ start: currentStart, end: currentEnd });
1070
+ return boundaries;
1071
+ }
1072
+
1073
+ /**
1074
+ * Tokenize a text fragment for syntax highlighting.
1075
+ * Returns the original text as a single plain token when the
1076
+ * language is not supported.
1077
+ *
1078
+ * @param text - the text to tokenize
1079
+ * @param language - the language identifier (e.g. "json")
1080
+ * @returns array of syntax tokens
1081
+ */
1082
+ function tokenize(text, language) {
1083
+ if (!language || text.length === 0) {
1084
+ return [{ value: text, type: 'plain' }];
1085
+ }
1086
+ if (language === 'json') {
1087
+ return tokenizeJson(text);
1088
+ }
1089
+ return [{ value: text, type: 'plain' }];
1090
+ }
1091
+ // ─── JSON tokenizer ─────────────────────────────────────────────────
1092
+ /**
1093
+ * Regex-based JSON tokenizer.
1094
+ * Handles partial lines (individual lines of a JSON document).
1095
+ */
1096
+ const JSON_PATTERNS = [
1097
+ // String literals (keys and values)
1098
+ [/"(?:[^"\\]|\\.)*"/, 'string'],
1099
+ // Numbers
1100
+ [/-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/, 'number'],
1101
+ // Booleans
1102
+ [/\b(?:true|false)\b/, 'boolean'],
1103
+ // Null
1104
+ [/\bnull\b/, 'null'],
1105
+ // Punctuation
1106
+ [/[{}[\]:,]/, 'punctuation'],
1107
+ ];
1108
+ const JSON_REGEX = new RegExp(JSON_PATTERNS.map(([re]) => `(${re.source})`).join('|'), 'g');
1109
+ function tokenizeJson(text) {
1110
+ const tokens = [];
1111
+ let lastIndex = 0;
1112
+ JSON_REGEX.lastIndex = 0;
1113
+ let match = JSON_REGEX.exec(text);
1114
+ while (match !== null) {
1115
+ // Plain text before this match
1116
+ if (match.index > lastIndex) {
1117
+ tokens.push({
1118
+ value: text.slice(lastIndex, match.index),
1119
+ type: 'plain',
1120
+ });
1121
+ }
1122
+ // Determine which capture group matched
1123
+ const tokenType = getMatchedTokenType(match);
1124
+ const value = match[0];
1125
+ // Distinguish JSON keys from string values:
1126
+ // A key is a string followed by optional whitespace and a colon
1127
+ if (tokenType === 'string') {
1128
+ const afterMatch = text.slice(match.index + value.length);
1129
+ if (/^\s*:/.test(afterMatch)) {
1130
+ tokens.push({ value, type: 'key' });
1131
+ }
1132
+ else {
1133
+ tokens.push({ value, type: 'string' });
1134
+ }
1135
+ }
1136
+ else {
1137
+ tokens.push({ value, type: tokenType });
1138
+ }
1139
+ lastIndex = match.index + value.length;
1140
+ match = JSON_REGEX.exec(text);
1141
+ }
1142
+ // Remaining plain text
1143
+ if (lastIndex < text.length) {
1144
+ tokens.push({ value: text.slice(lastIndex), type: 'plain' });
1145
+ }
1146
+ return tokens;
1147
+ }
1148
+ /**
1149
+ * Determine which pattern matched by checking capture groups.
1150
+ * @param match - the regex match result
1151
+ */
1152
+ function getMatchedTokenType(match) {
1153
+ for (const [index, [, type]] of JSON_PATTERNS.entries()) {
1154
+ if (match[index + 1] !== undefined) {
1155
+ return type;
1156
+ }
1157
+ }
1158
+ return 'plain';
1159
+ }
1160
+
1161
+ /**
1162
+ * Pure utility functions for search-within-diff functionality.
1163
+ */
1164
+ /**
1165
+ * Escape special regex characters in a search term so it can
1166
+ * be used as a literal pattern in a RegExp constructor.
1167
+ *
1168
+ * @param term - the raw search string
1169
+ * @returns regex-safe string
1170
+ */
1171
+ function escapeRegex(term) {
1172
+ return term.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw `\$&`);
1173
+ }
1174
+ /**
1175
+ * Build a case-insensitive regex that captures the search term.
1176
+ * Returns `null` when the term is empty.
1177
+ *
1178
+ * @param term - the raw search string
1179
+ * @returns a RegExp with a single capture group, or null
1180
+ */
1181
+ function buildSearchRegex(term) {
1182
+ if (!term) {
1183
+ return null;
1184
+ }
1185
+ return new RegExp(`(${escapeRegex(term)})`, 'gi');
1186
+ }
1187
+ /**
1188
+ * Calculate the next match index when navigating forward or backward,
1189
+ * wrapping around at the boundaries.
1190
+ *
1191
+ * @param currentIndex - current zero-based match index
1192
+ * @param direction - +1 for next, -1 for previous
1193
+ * @param total - total number of matches
1194
+ * @returns the new match index
1195
+ */
1196
+ function navigateMatchIndex(currentIndex, direction, total) {
1197
+ if (total === 0) {
1198
+ return 0;
1199
+ }
1200
+ return (currentIndex + direction + total) % total;
1201
+ }
1202
+
1203
+ /**
1204
+ * Pure utility functions for extracting text content from diff structures.
1205
+ */
1206
+ /**
1207
+ * Extract the text content of removed lines from a unified change block.
1208
+ *
1209
+ * @param lines - consecutive changed lines from a unified diff hunk
1210
+ * @returns the removed lines joined by newlines, or empty string if none
1211
+ */
1212
+ function extractRemovedContent(lines) {
1213
+ return lines
1214
+ .filter((line) => line.type === 'removed')
1215
+ .map((line) => line.content)
1216
+ .join('\n');
1217
+ }
1218
+ /**
1219
+ * Extract the text content of removed lines from a split change block.
1220
+ *
1221
+ * @param rows - consecutive changed rows from a split diff hunk
1222
+ * @returns the removed lines joined by newlines, or empty string if none
1223
+ */
1224
+ function extractRemovedContentFromSplit(rows) {
1225
+ return rows
1226
+ .filter((row) => { var _a; return ((_a = row.left) === null || _a === void 0 ? void 0 : _a.type) === 'removed'; })
1227
+ .map((row) => row.left.content)
1228
+ .join('\n');
1229
+ }
1230
+
1231
+ const codeDiffCss = () => `@charset "UTF-8";*,*::before,*::after{box-sizing:border-box;min-width:0;min-height:0}:host(limel-code-diff){--diff-added-bg:rgb(var(--color-green-default), 0.1);--diff-added-bg-hover:rgb(var(--color-green-default), 0.3);--diff-added-highlight-bg:rgb(var(--color-green-default), 0.3);--diff-removed-bg:rgb(var(--color-red-default), 0.1);--diff-removed-bg-hover:rgb(var(--color-red-default), 0.3);--diff-removed-highlight-bg:rgb(var(--color-red-default), 0.3);--diff-context-bg:transparent;--diff-indicator-added-color:rgb(var(--color-green-default));--diff-indicator-removed-color:rgb(var(--color-red-default));--diff-stat-added-color:rgb(var(--color-green-default));--diff-stat-removed-color:rgb(var(--color-red-default));--search-match-bg:rgb(var(--color-amber-default), 0.3);--search-match-current-bg:rgb(var(--color-amber-default), 0.6);--diff-line-hover-bg:rgb(var(--contrast-800), 0.08);--diff-gutter-bg:rgb(var(--contrast-200));--diff-gutter-text-color:rgb(var(--contrast-700));--diff-text-color:rgb(var(--contrast-1100));--diff-border-color:rgb(var(--contrast-400));--diff-collapsed-bg:rgb(var(--contrast-200));--diff-collapsed-text-color:rgb(var(--contrast-800));--diff-header-bg:rgb(var(--contrast-200));--diff-empty-text-color:rgb(var(--contrast-700));--diff-split-divider-color:rgb(var(--contrast-400));--diff-empty-cell-bg:rgb(var(--contrast-100));--syntax-string-color:rgb(var(--color-green-dark));--syntax-number-color:rgb(var(--color-blue-default));--syntax-boolean-color:rgb(var(--color-amber-darker));--syntax-key-color:rgb(var(--color-sky-dark));--syntax-null-color:rgb(var(--contrast-700));--syntax-punctuation-color:rgb(var(--contrast-700));--search-bar-bg:rgb(var(--contrast-100));--search-bar-border:rgb(var(--contrast-400));--limel-code-diff-line-number-padding:0.25rem;font-family:ui-sans-serif, system-ui, sans-serif;display:flex;flex-direction:column;width:100%;height:100%;color:var(--diff-text-color);border:1px solid var(--diff-border-color);border-radius:0.5rem;max-height:var(--code-diff-max-height, none)}.screen-reader-only{position:absolute;width:0;height:0;margin:-1px;padding:0;border:0;overflow:hidden;clip:rect(0, 0, 0, 0);clip-path:inset(50%);white-space:nowrap}.diff-header{flex-shrink:0;display:flex;align-items:center;justify-content:space-between;padding:0.125rem 0.125rem 0.125rem 0.5rem;background:var(--diff-header-bg);border-bottom:1px solid var(--diff-border-color);font-family:ui-sans-serif, system-ui, sans-serif;font-size:0.75rem;border-radius:0.5rem 0.5rem 0 0}.diff-header__labels{display:flex;gap:0.75rem;font-weight:500}.diff-header__old,.diff-header__new{padding:0.125rem 0.25rem;border-radius:0.25rem;box-shadow:var(--shadow-brighten-edges-outside)}.diff-header__old{background-color:var(--diff-removed-bg)}.diff-header__new{background-color:var(--diff-added-bg)}.diff-header__actions{display:flex;align-items:center;gap:0.25rem}.search-toggle--active{--limel-theme-on-surface-color:var(--mdc-theme-primary)}.diff-header__stats{font-family:ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, "DejaVu Sans Mono", monospace;display:flex;gap:0.5rem;margin-right:0.5rem}.stat{font-family:ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, "DejaVu Sans Mono", monospace;font-size:0.8125rem;font-weight:600}.stat--added{color:var(--diff-stat-added-color)}.stat--removed{color:var(--diff-stat-removed-color)}.search-bar{flex-shrink:0;display:flex;align-items:center;gap:0.25rem;padding:0.25rem 0 0.25rem 0.25rem;background:var(--search-bar-bg);border-bottom:1px solid var(--search-bar-border)}.search-bar limel-action-bar{--action-bar-background-color:transparent;min-width:2.5rem;flex-shrink:0}.search-bar limel-input-field{flex-grow:1}.search-bar__count{color:var(--diff-collapsed-text-color);white-space:nowrap;min-width:4rem;text-align:center;font-size:0.75rem}.search-match{background:var(--search-match-bg);color:inherit;border-radius:0.125rem}.search-match--current{background:var(--search-match-current-bg);outline:1px solid rgb(var(--color-amber-dark), 0.5)}.change-group{position:relative}.change-group__copy{--icon-background-color:rgb(var(--contrast-100));scale:0.9;position:absolute;top:0.125rem;right:0.5rem;display:none}.change-group:hover .change-group__copy{display:inline-flex}.diff-body{flex-grow:1;overflow-x:auto;font-family:ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, "DejaVu Sans Mono", monospace;font-size:var(--code-diff-font-size, 0.75rem)}.diff-body:focus{outline:none}.diff-body:focus-visible{outline:0.125rem solid rgb(var(--color-blue-default));outline-offset:0.125rem;border-radius:0.25rem}.diff-line{display:flex;align-items:stretch;min-height:1.25rem;line-height:1.25rem}.diff-line:hover .line-content{transition-duration:0.2s;background:var(--diff-line-hover-bg)}.diff-line--added .line-content{background:var(--diff-added-bg)}.diff-line--added .line-indicator{color:var(--diff-indicator-added-color)}.diff-line--added:hover .line-content{background:var(--diff-added-bg-hover)}.diff-line--removed .line-content{background:var(--diff-removed-bg)}.diff-line--removed .line-indicator{color:var(--diff-indicator-removed-color)}.diff-line--removed:hover .line-content{background:var(--diff-removed-bg-hover)}.diff-line--context .line-content{background:var(--diff-context-bg)}.diff-line--collapsed{display:flex;justify-content:center;background:var(--diff-collapsed-bg);border-top:1px solid var(--diff-border-color);border-bottom:1px solid var(--diff-border-color)}.diff-line--focused{outline:0.125rem solid rgb(var(--color-blue-default));outline-offset:-0.125rem;z-index:1}.line-number{display:inline-flex;align-items:center;justify-content:flex-end;min-width:calc(1ch + 2 * var(--limel-code-diff-line-number-padding));width:var(--limel-line-number-min-width);padding:0 var(--limel-code-diff-line-number-padding);background:var(--diff-gutter-bg);color:var(--diff-gutter-text-color);user-select:none;text-align:right;flex-shrink:0}.line-number--old{border-right:1px solid var(--diff-border-color)}.line-indicator{display:inline-flex;align-items:center;justify-content:center;width:1.25rem;flex-shrink:0;user-select:none;font-weight:600;background:var(--diff-gutter-bg)}.line-content{flex:1;padding:0 0.75rem;white-space:pre;overflow-x:visible;min-width:0;transition:background-color 0.6s ease}mark{background:transparent;color:inherit;border-radius:0.125rem}mark.segment--added{background:var(--diff-added-highlight-bg)}mark.segment--removed{background:var(--diff-removed-highlight-bg)}.syntax--string{color:var(--syntax-string-color)}.syntax--number{color:var(--syntax-number-color)}.syntax--boolean{color:var(--syntax-boolean-color)}.syntax--null{color:var(--syntax-null-color);font-style:italic}.syntax--key{color:var(--syntax-key-color)}.syntax--punctuation{color:var(--syntax-punctuation-color)}.expand-button{all:unset;transition:color var(--limel-clickable-transition-speed, 0.4s) ease, background-color var(--limel-clickable-transition-speed, 0.4s) ease, box-shadow var(--limel-clickable-transform-speed, 0.4s) ease, transform var(--limel-clickable-transform-speed, 0.4s) var(--limel-clickable-transform-timing-function, ease);cursor:pointer;color:var(--limel-theme-on-surface-color);background-color:transparent}.expand-button:hover,.expand-button:focus,.expand-button:focus-visible{will-change:color, background-color, box-shadow, transform}.expand-button:hover,.expand-button:focus-visible{transform:translate3d(0, 0.01rem, 0);color:var(--limel-theme-on-surface-color);background-color:var(--lime-elevated-surface-background-color)}.expand-button:hover{box-shadow:var(--button-shadow-hovered)}.expand-button:active{--limel-clickable-transform-timing-function:cubic-bezier( 0.83, -0.15, 0.49, 1.16 );transform:translate3d(0, 0.05rem, 0);box-shadow:var(--button-shadow-pressed)}.expand-button:hover,.expand-button:active{--limel-clickable-transition-speed:0.2s;--limel-clickable-transform-speed:0.16s}.expand-button:focus{outline:none}.expand-button:focus-visible{outline:none;box-shadow:var(--shadow-depth-8-focused)}.expand-button{padding:0 0.75rem;border-radius:0.25rem;margin:0.125rem;width:calc(100% - 0.25rem);text-align:center}.diff-empty{padding:2rem;text-align:center;color:var(--diff-empty-text-color);font-style:italic}.diff-line--split{display:flex;align-items:stretch;min-height:1.25rem;line-height:1.25rem}.diff-line--split:hover .split-content--removed{background:var(--diff-removed-bg-hover)}.diff-line--split:hover .split-content--added{background:var(--diff-added-bg-hover)}.diff-line--split:hover .split-content--context{background:var(--diff-line-hover-bg)}.split-content{flex:1;padding:0 0.75rem;white-space:pre;overflow-x:visible;min-width:0}.split-content--left{border-right:1px solid var(--diff-split-divider-color)}.split-content--removed{background:var(--diff-removed-bg)}.split-content--added{background:var(--diff-added-bg)}.split-content--context{background:var(--diff-context-bg)}.split-content--empty{background:var(--diff-empty-cell-bg)}.split-content--left{overflow-x:hidden;text-overflow:ellipsis}.change-group:has(.diff-line--split)>.change-group__copy{right:calc(50% - var(--limel-line-number-min-width))}:host(limel-code-diff[line-wrapping]) .diff-body{overflow-x:hidden}:host(limel-code-diff[line-wrapping]) .line-content,:host(limel-code-diff[line-wrapping]) .split-content{white-space:pre-wrap;overflow-wrap:break-word;word-break:break-all}:host(limel-code-diff[line-wrapping]) .diff-line--split .split-content{flex:1 1 0%;max-width:calc(50% - var(--limel-line-number-min-width))}`;
1232
+
1233
+ const CodeDiff = class {
1234
+ constructor(hostRef) {
1235
+ index.registerInstance(this, hostRef);
1236
+ /**
1237
+ * The "before" value to compare.
1238
+ * Can be a string or an object (which will be serialized to JSON).
1239
+ */
1240
+ this.oldValue = '';
1241
+ /**
1242
+ * The "after" value to compare.
1243
+ * Can be a string or an object (which will be serialized to JSON).
1244
+ */
1245
+ this.newValue = '';
1246
+ /**
1247
+ * The layout of the diff view.
1248
+ * - `unified` — single column with interleaved additions and removals
1249
+ * - `split` — side-by-side comparison with old on left, new on right
1250
+ */
1251
+ this.layout = 'unified';
1252
+ /**
1253
+ * Number of unchanged context lines to display around each change.
1254
+ */
1255
+ this.contextLines = 3;
1256
+ /**
1257
+ * When `true`, long lines are wrapped instead of causing
1258
+ * horizontal scrolling. Useful when comparing prose or
1259
+ * config files with long values.
1260
+ */
1261
+ this.lineWrapping = true;
1262
+ /**
1263
+ * When `true`, JSON values are parsed, keys are sorted,
1264
+ * and indentation is normalized before diffing.
1265
+ * This eliminates noise from formatting or key-order differences.
1266
+ */
1267
+ this.reformatJson = false;
1268
+ /**
1269
+ * Defines the language for translations.
1270
+ * Will translate all visible labels and announcements.
1271
+ */
1272
+ this.translationLanguage = 'en';
1273
+ this.diffResult = {
1274
+ hunks: [],
1275
+ additions: 0,
1276
+ deletions: 0,
1277
+ allLines: [],
1278
+ };
1279
+ this.liveAnnouncement = '';
1280
+ this.copyState = 'idle';
1281
+ this.searchVisible = false;
1282
+ this.searchTerm = '';
1283
+ this.currentMatchIndex = 0;
1284
+ this.focusedRowIndex = -1;
1285
+ this.normalizedOldText = '';
1286
+ /**
1287
+ * Render-time counter that increments for each search match
1288
+ * found while rendering removed lines. Used to determine which
1289
+ * match is the "current" one for navigation highlighting.
1290
+ */
1291
+ this.searchMatchCounter = 0;
1292
+ /**
1293
+ * Total search matches found during the last render pass.
1294
+ */
1295
+ this.totalSearchMatches = 0;
1296
+ /**
1297
+ * Whether the current render is inside a removed line,
1298
+ * so search highlighting knows when to activate.
1299
+ */
1300
+ this.isRenderingRemovedLine = false;
1301
+ /**
1302
+ * Cached search regex for the current render pass.
1303
+ * Built once in render() and reused across all renderSearchableText calls.
1304
+ */
1305
+ this.activeSearchRegex = null;
1306
+ this.prevSearchVisible = false;
1307
+ }
1308
+ componentWillLoad() {
1309
+ this.recomputeDiff();
1310
+ }
1311
+ componentDidRender() {
1312
+ var _a, _b;
1313
+ if (this.searchVisible && !this.prevSearchVisible) {
1314
+ (_a = this.searchInputEl) === null || _a === void 0 ? void 0 : _a.focus();
1315
+ }
1316
+ this.prevSearchVisible = this.searchVisible;
1317
+ if (this.searchTerm && this.totalSearchMatches > 0) {
1318
+ const current = (_b = this.host.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('.search-match--current');
1319
+ current === null || current === void 0 ? void 0 : current.scrollIntoView({ block: 'center', behavior: 'smooth' });
1320
+ }
1321
+ }
1322
+ render() {
1323
+ this.searchMatchCounter = 0;
1324
+ this.activeSearchRegex = buildSearchRegex(this.searchTerm);
1325
+ const diffContent = this.renderDiff();
1326
+ // Capture total matches after rendering completes
1327
+ this.totalSearchMatches = this.searchMatchCounter;
1328
+ const lineNumberWidth = this.computeLineNumberWidth();
1329
+ return (index.h(index.Host, { key: '8122ede0d323b9021dae44cd5f65703d03083617', style: { '--limel-line-number-min-width': lineNumberWidth } }, this.renderHeader(), this.renderScreenReaderSummary(), this.searchVisible && this.renderSearchBar(), index.h("div", { key: 'fefe6e4898cbc82b6eb87f7dff7af71a14c7c91e', class: "diff-body", role: "table", "aria-label": this.getTranslation('code-diff.table-label'), tabindex: "0", onKeyDown: (event) => this.handleKeyDown(event) }, diffContent), index.h("div", { key: '2af1c7b29f2060a58af13d67fb174cb4de085efb', class: "screen-reader-only", role: "status", "aria-live": "polite", "aria-atomic": "true" }, this.liveAnnouncement)));
1330
+ }
1331
+ watchInputs() {
1332
+ this.recomputeDiff();
1333
+ }
1334
+ recomputeDiff() {
1335
+ const oldText = normalizeForDiff(this.oldValue, this.reformatJson);
1336
+ const newText = normalizeForDiff(this.newValue, this.reformatJson);
1337
+ this.normalizedOldText = oldText;
1338
+ this.diffResult = computeDiff(oldText, newText, this.contextLines);
1339
+ this.focusedRowIndex = -1;
1340
+ }
1341
+ formatSrSummary() {
1342
+ const { additions, deletions } = this.diffResult;
1343
+ if (additions === 0 && deletions === 0) {
1344
+ return null;
1345
+ }
1346
+ const parts = [];
1347
+ if (additions > 0) {
1348
+ const key = additions === 1
1349
+ ? 'code-diff.diff-addition'
1350
+ : 'code-diff.diff-additions';
1351
+ parts.push(this.getTranslation(key, { count: additions }));
1352
+ }
1353
+ if (deletions > 0) {
1354
+ const key = deletions === 1
1355
+ ? 'code-diff.diff-deletion'
1356
+ : 'code-diff.diff-deletions';
1357
+ parts.push(this.getTranslation(key, { count: deletions }));
1358
+ }
1359
+ return this.getTranslation('code-diff.diff-summary', {
1360
+ parts: parts.join(', '),
1361
+ });
1362
+ }
1363
+ renderScreenReaderSummary() {
1364
+ const summary = this.formatSrSummary();
1365
+ return (index.h("div", { class: "screen-reader-only", role: "status", "aria-live": "polite" }, summary !== null && summary !== void 0 ? summary : this.getTranslation('code-diff.no-differences-found')));
1366
+ }
1367
+ handleKeyDown(event) {
1368
+ if (event.key !== 'ArrowUp' && event.key !== 'ArrowDown') {
1369
+ return;
1370
+ }
1371
+ event.preventDefault();
1372
+ const rows = this.getDiffRows();
1373
+ if (rows.length === 0) {
1374
+ return;
1375
+ }
1376
+ if (event.key === 'ArrowDown') {
1377
+ this.focusedRowIndex = Math.min(this.focusedRowIndex + 1, rows.length - 1);
1378
+ }
1379
+ else {
1380
+ this.focusedRowIndex = Math.max(this.focusedRowIndex - 1, 0);
1381
+ }
1382
+ this.updateRowFocus(rows);
1383
+ }
1384
+ getDiffRows() {
1385
+ var _a;
1386
+ const body = (_a = this.host.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('.diff-body');
1387
+ if (!body) {
1388
+ return [];
1389
+ }
1390
+ return [
1391
+ ...body.querySelectorAll('.diff-line:not(.diff-line--collapsed)'),
1392
+ ];
1393
+ }
1394
+ updateRowFocus(rows) {
1395
+ for (const row of rows) {
1396
+ row.removeAttribute('tabindex');
1397
+ row.classList.remove('diff-line--focused');
1398
+ }
1399
+ const target = rows[this.focusedRowIndex];
1400
+ if (target) {
1401
+ target.setAttribute('tabindex', '-1');
1402
+ target.classList.add('diff-line--focused');
1403
+ target.focus();
1404
+ this.announceLine(target);
1405
+ }
1406
+ }
1407
+ announceLine(row) {
1408
+ var _a, _b;
1409
+ let lineType = this.getTranslation('code-diff.line-context');
1410
+ if (row.classList.contains('diff-line--added')) {
1411
+ lineType = this.getTranslation('code-diff.line-added');
1412
+ }
1413
+ else if (row.classList.contains('diff-line--removed')) {
1414
+ lineType = this.getTranslation('code-diff.line-removed');
1415
+ }
1416
+ const content = (_b = (_a = row.querySelector('.line-content, .split-content')) === null || _a === void 0 ? void 0 : _a.textContent) !== null && _b !== void 0 ? _b : '';
1417
+ const trimmed = content.length > 80 ? content.slice(0, 80) + '…' : content;
1418
+ this.liveAnnouncement = `${lineType}: ${trimmed}`;
1419
+ }
1420
+ renderHeader() {
1421
+ var _a, _b;
1422
+ const oldHeading = (_a = this.oldHeading) !== null && _a !== void 0 ? _a : this.getTranslation('code-diff.old-heading');
1423
+ const newHeading = (_b = this.newHeading) !== null && _b !== void 0 ? _b : this.getTranslation('code-diff.new-heading');
1424
+ const { additions, deletions } = this.diffResult;
1425
+ const hasDiff = additions > 0 || deletions > 0;
1426
+ return (index.h("div", { class: "diff-header" }, index.h("div", { class: "diff-header__labels" }, index.h("span", { class: "diff-header__old" }, oldHeading), index.h("span", { class: "diff-header__new" }, newHeading)), index.h("div", { class: "diff-header__actions" }, index.h("div", { class: "diff-header__stats" }, additions > 0 && (index.h("span", { class: "stat stat--added" }, "+", additions)), deletions > 0 && (index.h("span", { class: "stat stat--removed" }, "-", deletions))), hasDiff && this.renderCopyButton(), deletions > 0 && this.renderSearchToggle())));
1427
+ }
1428
+ renderCopyButton() {
1429
+ const label = this.copyState === 'copied'
1430
+ ? this.getTranslation('code-diff.copied')
1431
+ : this.getTranslation('code-diff.copy-old-version');
1432
+ const icon = this.copyState === 'copied' ? 'checkmark' : 'copy';
1433
+ return (index.h("limel-icon-button", { label: label, icon: icon, onClick: () => this.copyToClipboard(this.normalizedOldText) }));
1434
+ }
1435
+ async copyToClipboard(text) {
1436
+ try {
1437
+ await navigator.clipboard.writeText(text);
1438
+ this.copyState = 'copied';
1439
+ this.liveAnnouncement = this.getTranslation('code-diff.copied-to-clipboard');
1440
+ setTimeout(() => {
1441
+ this.copyState = 'idle';
1442
+ }, 2000);
1443
+ }
1444
+ catch (_a) {
1445
+ // Clipboard API may fail in insecure contexts
1446
+ }
1447
+ }
1448
+ renderSearchToggle() {
1449
+ return (index.h("limel-icon-button", { class: { 'search-toggle--active': this.searchVisible }, label: this.getTranslation('code-diff.search'), icon: "search", onClick: () => this.toggleSearch() }));
1450
+ }
1451
+ renderSearchBar() {
1452
+ const matchInfo = this.totalSearchMatches === 0
1453
+ ? this.getTranslation('code-diff.no-matches')
1454
+ : this.getTranslation('code-diff.match-count', {
1455
+ current: this.currentMatchIndex + 1,
1456
+ total: this.totalSearchMatches,
1457
+ });
1458
+ return (index.h("div", { class: "search-bar" }, index.h("limel-input-field", { class: "search-bar__input", type: "search", placeholder: this.getTranslation('code-diff.search') + '…', value: this.searchTerm, onChange: (e) => this.onSearchInput(e), onKeyDown: (e) => this.onSearchKeyDown(e), ref: (el) => (this.searchInputEl = el) }), index.h("span", { class: "search-bar__count" }, matchInfo), index.h("limel-action-bar", { actions: this.getSearchActions(), onItemSelected: (e) => this.onSearchAction(e) })));
1459
+ }
1460
+ toggleSearch() {
1461
+ this.searchVisible = !this.searchVisible;
1462
+ if (!this.searchVisible) {
1463
+ this.searchTerm = '';
1464
+ this.currentMatchIndex = 0;
1465
+ }
1466
+ }
1467
+ onSearchInput(event) {
1468
+ this.searchTerm = event.detail;
1469
+ this.currentMatchIndex = 0;
1470
+ }
1471
+ onSearchKeyDown(event) {
1472
+ if (event.key === 'Enter') {
1473
+ event.preventDefault();
1474
+ if (event.shiftKey) {
1475
+ this.navigateSearch(-1);
1476
+ }
1477
+ else {
1478
+ this.navigateSearch(1);
1479
+ }
1480
+ }
1481
+ else if (event.key === 'Escape') {
1482
+ this.toggleSearch();
1483
+ }
1484
+ }
1485
+ computeLineNumberWidth() {
1486
+ const maxLineNumber = this.diffResult.allLines.length;
1487
+ const digits = String(maxLineNumber).length;
1488
+ return `calc(${digits}ch + 2 * var(--limel-code-diff-line-number-padding))`;
1489
+ }
1490
+ getSearchActions() {
1491
+ const noMatches = this.totalSearchMatches === 0;
1492
+ return [
1493
+ {
1494
+ text: this.getTranslation('code-diff.previous-match'),
1495
+ icon: '-lime-caret-top',
1496
+ iconOnly: true,
1497
+ disabled: noMatches,
1498
+ value: 'prev',
1499
+ },
1500
+ {
1501
+ text: this.getTranslation('code-diff.next-match'),
1502
+ icon: '-lime-caret-bottom',
1503
+ iconOnly: true,
1504
+ disabled: noMatches,
1505
+ value: 'next',
1506
+ },
1507
+ {
1508
+ text: this.getTranslation('code-diff.close-search'),
1509
+ icon: 'cancel',
1510
+ iconOnly: true,
1511
+ value: 'close',
1512
+ },
1513
+ ];
1514
+ }
1515
+ onSearchAction(event) {
1516
+ const { value } = event.detail;
1517
+ if (value === 'prev') {
1518
+ this.navigateSearch(-1);
1519
+ }
1520
+ else if (value === 'next') {
1521
+ this.navigateSearch(1);
1522
+ }
1523
+ else if (value === 'close') {
1524
+ this.toggleSearch();
1525
+ }
1526
+ }
1527
+ navigateSearch(direction) {
1528
+ this.currentMatchIndex = navigateMatchIndex(this.currentMatchIndex, direction, this.totalSearchMatches);
1529
+ }
1530
+ renderDiff() {
1531
+ const { hunks, collapsedAfter } = this.diffResult;
1532
+ if (hunks.length === 0) {
1533
+ return (index.h("div", { class: "diff-empty" }, this.getTranslation('code-diff.no-differences')));
1534
+ }
1535
+ const lineRenderer = this.layout === 'split'
1536
+ ? (hunk) => this.renderSplitHunkRows(hunk)
1537
+ : (hunk) => this.renderHunkLines(hunk);
1538
+ return this.renderHunks(hunks, collapsedAfter, lineRenderer);
1539
+ }
1540
+ renderHunks(hunks, collapsedAfter, lineRenderer) {
1541
+ const elements = [];
1542
+ for (const [i, hunk] of hunks.entries()) {
1543
+ if (hunk.collapsedBefore) {
1544
+ elements.push(this.renderCollapsedRow(hunk.collapsedBefore, i));
1545
+ }
1546
+ elements.push(...lineRenderer(hunk));
1547
+ }
1548
+ if (collapsedAfter) {
1549
+ elements.push(this.renderCollapsedAfterRow(collapsedAfter));
1550
+ }
1551
+ return elements;
1552
+ }
1553
+ renderHunkLines(hunk) {
1554
+ const elements = [];
1555
+ let i = 0;
1556
+ while (i < hunk.lines.length) {
1557
+ const line = hunk.lines[i];
1558
+ if (line.type === 'context') {
1559
+ elements.push(this.renderLine(line));
1560
+ i++;
1561
+ continue;
1562
+ }
1563
+ // Collect consecutive changed lines as a change block
1564
+ const blockLines = [];
1565
+ while (i < hunk.lines.length && hunk.lines[i].type !== 'context') {
1566
+ blockLines.push(hunk.lines[i]);
1567
+ i++;
1568
+ }
1569
+ elements.push(this.renderChangeBlock(blockLines));
1570
+ }
1571
+ return elements;
1572
+ }
1573
+ renderChangeBlock(lines) {
1574
+ const removedContent = extractRemovedContent(lines);
1575
+ return (index.h("div", { class: "change-group" }, lines.map((line) => this.renderLine(line)), removedContent && this.renderBlockCopyButton(removedContent)));
1576
+ }
1577
+ renderLine(line) {
1578
+ var _a, _b;
1579
+ const lineClass = {
1580
+ 'diff-line': true,
1581
+ [`diff-line--${line.type}`]: true,
1582
+ };
1583
+ const indicatorMap = {
1584
+ added: '+',
1585
+ removed: '-',
1586
+ context: ' ',
1587
+ };
1588
+ const indicator = indicatorMap[line.type];
1589
+ return (index.h("div", { class: lineClass, role: "row" }, index.h("span", { class: "line-number line-number--old", role: "cell", "aria-label": line.oldLineNumber
1590
+ ? this.getTranslation('code-diff.old-line', {
1591
+ number: line.oldLineNumber,
1592
+ })
1593
+ : undefined }, (_a = line.oldLineNumber) !== null && _a !== void 0 ? _a : ''), index.h("span", { class: "line-number line-number--new", role: "cell", "aria-label": line.newLineNumber
1594
+ ? this.getTranslation('code-diff.new-line', {
1595
+ number: line.newLineNumber,
1596
+ })
1597
+ : undefined }, (_b = line.newLineNumber) !== null && _b !== void 0 ? _b : ''), index.h("span", { class: "line-indicator", role: "cell" }, indicator), index.h("span", { class: "line-content", role: "cell" }, this.renderContent(line))));
1598
+ }
1599
+ renderSplitHunkRows(hunk) {
1600
+ var _a, _b, _c, _d;
1601
+ const splitRows = buildSplitLines(hunk.lines);
1602
+ const elements = [];
1603
+ let i = 0;
1604
+ while (i < splitRows.length) {
1605
+ const row = splitRows[i];
1606
+ const isContext = ((_a = row.left) === null || _a === void 0 ? void 0 : _a.type) === 'context' && ((_b = row.right) === null || _b === void 0 ? void 0 : _b.type) === 'context';
1607
+ if (isContext) {
1608
+ elements.push(this.renderSplitRow(row));
1609
+ i++;
1610
+ continue;
1611
+ }
1612
+ // Collect consecutive changed rows
1613
+ const blockRows = [];
1614
+ while (i < splitRows.length) {
1615
+ const r = splitRows[i];
1616
+ const rIsContext = ((_c = r.left) === null || _c === void 0 ? void 0 : _c.type) === 'context' && ((_d = r.right) === null || _d === void 0 ? void 0 : _d.type) === 'context';
1617
+ if (rIsContext) {
1618
+ break;
1619
+ }
1620
+ blockRows.push(r);
1621
+ i++;
1622
+ }
1623
+ elements.push(this.renderSplitChangeBlock(blockRows));
1624
+ }
1625
+ return elements;
1626
+ }
1627
+ renderSplitChangeBlock(rows) {
1628
+ const removedContent = extractRemovedContentFromSplit(rows);
1629
+ return (index.h("div", { class: "change-group" }, rows.map((row) => this.renderSplitRow(row)), removedContent && this.renderBlockCopyButton(removedContent)));
1630
+ }
1631
+ renderSplitRow(row) {
1632
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
1633
+ const leftType = (_b = (_a = row.left) === null || _a === void 0 ? void 0 : _a.type) !== null && _b !== void 0 ? _b : 'empty';
1634
+ const rightType = (_d = (_c = row.right) === null || _c === void 0 ? void 0 : _c.type) !== null && _d !== void 0 ? _d : 'empty';
1635
+ const oldLineLabel = ((_e = row.left) === null || _e === void 0 ? void 0 : _e.oldLineNumber)
1636
+ ? this.getTranslation('code-diff.old-line', {
1637
+ number: row.left.oldLineNumber,
1638
+ })
1639
+ : undefined;
1640
+ const newLineLabel = ((_f = row.right) === null || _f === void 0 ? void 0 : _f.newLineNumber)
1641
+ ? this.getTranslation('code-diff.new-line', {
1642
+ number: row.right.newLineNumber,
1643
+ })
1644
+ : undefined;
1645
+ return (index.h("div", { class: "diff-line diff-line--split", role: "row" }, index.h("span", { class: "line-number line-number--old", role: "cell", "aria-label": oldLineLabel }, (_h = (_g = row.left) === null || _g === void 0 ? void 0 : _g.oldLineNumber) !== null && _h !== void 0 ? _h : ''), index.h("span", { class: `split-content split-content--left split-content--${leftType}`, role: "cell" }, row.left ? this.renderContent(row.left) : ''), index.h("span", { class: "line-number line-number--new", role: "cell", "aria-label": newLineLabel }, (_k = (_j = row.right) === null || _j === void 0 ? void 0 : _j.newLineNumber) !== null && _k !== void 0 ? _k : ''), index.h("span", { class: `split-content split-content--right split-content--${rightType}`, role: "cell" }, row.right ? this.renderContent(row.right) : '')));
1646
+ }
1647
+ renderBlockCopyButton(removedContent) {
1648
+ return (index.h("limel-icon-button", { class: "change-group__copy", elevated: true, label: this.getTranslation('code-diff.copy-change'), icon: "copy", onClick: () => this.copyToClipboard(removedContent) }));
1649
+ }
1650
+ renderContent(line) {
1651
+ this.isRenderingRemovedLine =
1652
+ line.type === 'removed' && this.searchTerm.length > 0;
1653
+ if (!line.segments || line.segments.length === 0) {
1654
+ return this.renderSyntaxTokens(line.content);
1655
+ }
1656
+ return line.segments.map((segment) => this.renderSegment(segment, line.type));
1657
+ }
1658
+ renderSegment(segment, lineType) {
1659
+ const content = this.renderSyntaxTokens(segment.value);
1660
+ if (segment.type === 'equal') {
1661
+ return content;
1662
+ }
1663
+ const segmentClass = lineType === 'removed' ? 'segment--removed' : 'segment--added';
1664
+ return index.h("mark", { class: segmentClass }, content);
1665
+ }
1666
+ renderSyntaxTokens(text) {
1667
+ const tokens = tokenize(text, this.language);
1668
+ if (tokens.length === 1 && tokens[0].type === 'plain') {
1669
+ return this.renderSearchableText(text);
1670
+ }
1671
+ return tokens.map((token) => this.renderSyntaxToken(token));
1672
+ }
1673
+ renderSyntaxToken(token) {
1674
+ const text = this.renderSearchableText(token.value);
1675
+ if (token.type === 'plain') {
1676
+ return text;
1677
+ }
1678
+ return index.h("span", { class: `syntax--${token.type}` }, text);
1679
+ }
1680
+ renderSearchableText(text) {
1681
+ if (!this.isRenderingRemovedLine || !this.activeSearchRegex) {
1682
+ return text;
1683
+ }
1684
+ const parts = text.split(this.activeSearchRegex);
1685
+ if (parts.length === 1) {
1686
+ return text;
1687
+ }
1688
+ return parts.map((part, i) => {
1689
+ // Odd indices are the captured matches from split
1690
+ if (i % 2 === 0) {
1691
+ return part;
1692
+ }
1693
+ const matchIndex = this.searchMatchCounter++;
1694
+ const isCurrent = matchIndex === this.currentMatchIndex;
1695
+ const cls = {
1696
+ 'search-match': true,
1697
+ 'search-match--current': isCurrent,
1698
+ };
1699
+ return (index.h("mark", { key: `match-${matchIndex}`, class: cls }, part));
1700
+ });
1701
+ }
1702
+ renderCollapsedRow(count, hunkIndex) {
1703
+ return (index.h("div", { class: "diff-line diff-line--collapsed", role: "row" }, index.h("button", { class: "expand-button", type: "button", onClick: () => this.expandHunk(hunkIndex), "aria-label": this.getTranslation('code-diff.show-hidden-lines', {
1704
+ count,
1705
+ }) }, this.getTranslation('code-diff.hidden-lines', { count }))));
1706
+ }
1707
+ renderCollapsedAfterRow(count) {
1708
+ return (index.h("div", { class: "diff-line diff-line--collapsed", role: "row" }, index.h("button", { class: "expand-button", type: "button", onClick: () => this.expandAfter(), "aria-label": this.getTranslation('code-diff.show-hidden-lines', {
1709
+ count,
1710
+ }) }, this.getTranslation('code-diff.hidden-lines', { count }))));
1711
+ }
1712
+ expandHunk(hunkIndex) {
1713
+ const hunks = [...this.diffResult.hunks];
1714
+ const hunk = hunks[hunkIndex];
1715
+ const prevHunkEnd = hunkIndex > 0
1716
+ ? hunks[hunkIndex - 1].startIndex +
1717
+ hunks[hunkIndex - 1].lines.length
1718
+ : 0;
1719
+ const hiddenLines = this.diffResult.allLines.slice(prevHunkEnd, hunk.startIndex);
1720
+ hunks[hunkIndex] = Object.assign(Object.assign({}, hunk), { lines: [...hiddenLines, ...hunk.lines], collapsedBefore: undefined, startIndex: prevHunkEnd });
1721
+ this.diffResult = Object.assign(Object.assign({}, this.diffResult), { hunks });
1722
+ this.liveAnnouncement = this.getTranslation('code-diff.expanded-lines');
1723
+ }
1724
+ expandAfter() {
1725
+ const hunks = [...this.diffResult.hunks];
1726
+ const lastIndex = hunks.length - 1;
1727
+ const lastHunk = hunks[lastIndex];
1728
+ const lastHunkEnd = lastHunk.startIndex + lastHunk.lines.length;
1729
+ const hiddenLines = this.diffResult.allLines.slice(lastHunkEnd);
1730
+ hunks[lastIndex] = Object.assign(Object.assign({}, lastHunk), { lines: [...lastHunk.lines, ...hiddenLines] });
1731
+ this.diffResult = Object.assign(Object.assign({}, this.diffResult), { hunks, collapsedAfter: undefined });
1732
+ this.liveAnnouncement = this.getTranslation('code-diff.expanded-lines-end');
1733
+ }
1734
+ getTranslation(key, params) {
1735
+ return translations.translate.get(key, this.translationLanguage, params);
1736
+ }
1737
+ get host() { return index.getElement(this); }
1738
+ static get watchers() { return {
1739
+ "oldValue": [{
1740
+ "watchInputs": 0
1741
+ }],
1742
+ "newValue": [{
1743
+ "watchInputs": 0
1744
+ }],
1745
+ "contextLines": [{
1746
+ "watchInputs": 0
1747
+ }],
1748
+ "reformatJson": [{
1749
+ "watchInputs": 0
1750
+ }],
1751
+ "layout": [{
1752
+ "watchInputs": 0
1753
+ }]
1754
+ }; }
1755
+ };
1756
+ CodeDiff.style = codeDiffCss();
1757
+
1758
+ exports.limel_code_diff = CodeDiff;