@limetech/lime-elements 39.5.7 → 39.7.0

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