市场夺宝奇兵
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

866 lines
30 KiB

  1. (function() {
  2. "use strict";
  3. /**
  4. * @license
  5. * Copyright 2019 Google LLC
  6. * SPDX-License-Identifier: Apache-2.0
  7. */
  8. const proxyMarker = Symbol("Comlink.proxy");
  9. const createEndpoint = Symbol("Comlink.endpoint");
  10. const releaseProxy = Symbol("Comlink.releaseProxy");
  11. const finalizer = Symbol("Comlink.finalizer");
  12. const throwMarker = Symbol("Comlink.thrown");
  13. const isObject = (val) => typeof val === "object" && val !== null || typeof val === "function";
  14. /**
  15. * Internal transfer handle to handle objects marked to proxy.
  16. */
  17. const proxyTransferHandler = {
  18. canHandle: (val) => isObject(val) && val[proxyMarker],
  19. serialize(obj) {
  20. const { port1, port2 } = new MessageChannel();
  21. expose(obj, port1);
  22. return [port2, [port2]];
  23. },
  24. deserialize(port) {
  25. port.start();
  26. return wrap(port);
  27. }
  28. };
  29. /**
  30. * Internal transfer handler to handle thrown exceptions.
  31. */
  32. const throwTransferHandler = {
  33. canHandle: (value) => isObject(value) && throwMarker in value,
  34. serialize({ value }) {
  35. let serialized;
  36. if (value instanceof Error) serialized = {
  37. isError: true,
  38. value: {
  39. message: value.message,
  40. name: value.name,
  41. stack: value.stack
  42. }
  43. };
  44. else serialized = {
  45. isError: false,
  46. value
  47. };
  48. return [serialized, []];
  49. },
  50. deserialize(serialized) {
  51. if (serialized.isError) throw Object.assign(new Error(serialized.value.message), serialized.value);
  52. throw serialized.value;
  53. }
  54. };
  55. /**
  56. * Allows customizing the serialization of certain values.
  57. */
  58. const transferHandlers = new Map([["proxy", proxyTransferHandler], ["throw", throwTransferHandler]]);
  59. function isAllowedOrigin(allowedOrigins, origin) {
  60. for (const allowedOrigin of allowedOrigins) {
  61. if (origin === allowedOrigin || allowedOrigin === "*") return true;
  62. if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) return true;
  63. }
  64. return false;
  65. }
  66. function expose(obj, ep = globalThis, allowedOrigins = ["*"]) {
  67. ep.addEventListener("message", function callback(ev) {
  68. if (!ev || !ev.data) return;
  69. if (!isAllowedOrigin(allowedOrigins, ev.origin)) {
  70. console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);
  71. return;
  72. }
  73. const { id, type, path } = Object.assign({ path: [] }, ev.data);
  74. const argumentList = (ev.data.argumentList || []).map(fromWireValue);
  75. let returnValue;
  76. try {
  77. const parent = path.slice(0, -1).reduce((obj$1, prop) => obj$1[prop], obj);
  78. const rawValue = path.reduce((obj$1, prop) => obj$1[prop], obj);
  79. switch (type) {
  80. case "GET":
  81. returnValue = rawValue;
  82. break;
  83. case "SET":
  84. {
  85. parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);
  86. returnValue = true;
  87. }
  88. break;
  89. case "APPLY":
  90. returnValue = rawValue.apply(parent, argumentList);
  91. break;
  92. case "CONSTRUCT":
  93. {
  94. const value = new rawValue(...argumentList);
  95. returnValue = proxy(value);
  96. }
  97. break;
  98. case "ENDPOINT":
  99. {
  100. const { port1, port2 } = new MessageChannel();
  101. expose(obj, port2);
  102. returnValue = transfer(port1, [port1]);
  103. }
  104. break;
  105. case "RELEASE":
  106. returnValue = void 0;
  107. break;
  108. default: return;
  109. }
  110. } catch (value) {
  111. returnValue = {
  112. value,
  113. [throwMarker]: 0
  114. };
  115. }
  116. Promise.resolve(returnValue).catch((value) => {
  117. return {
  118. value,
  119. [throwMarker]: 0
  120. };
  121. }).then((returnValue$1) => {
  122. const [wireValue, transferables] = toWireValue(returnValue$1);
  123. ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);
  124. if (type === "RELEASE") {
  125. ep.removeEventListener("message", callback);
  126. closeEndPoint(ep);
  127. if (finalizer in obj && typeof obj[finalizer] === "function") obj[finalizer]();
  128. }
  129. }).catch((error) => {
  130. const [wireValue, transferables] = toWireValue({
  131. value: new TypeError("Unserializable return value"),
  132. [throwMarker]: 0
  133. });
  134. ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);
  135. });
  136. });
  137. if (ep.start) ep.start();
  138. }
  139. function isMessagePort(endpoint) {
  140. return endpoint.constructor.name === "MessagePort";
  141. }
  142. function closeEndPoint(endpoint) {
  143. if (isMessagePort(endpoint)) endpoint.close();
  144. }
  145. function wrap(ep, target) {
  146. const pendingListeners = new Map();
  147. ep.addEventListener("message", function handleMessage(ev) {
  148. const { data } = ev;
  149. if (!data || !data.id) return;
  150. const resolver = pendingListeners.get(data.id);
  151. if (!resolver) return;
  152. try {
  153. resolver(data);
  154. } finally {
  155. pendingListeners.delete(data.id);
  156. }
  157. });
  158. return createProxy(ep, pendingListeners, [], target);
  159. }
  160. function throwIfProxyReleased(isReleased) {
  161. if (isReleased) throw new Error("Proxy has been released and is not useable");
  162. }
  163. function releaseEndpoint(ep) {
  164. return requestResponseMessage(ep, new Map(), { type: "RELEASE" }).then(() => {
  165. closeEndPoint(ep);
  166. });
  167. }
  168. const proxyCounter = new WeakMap();
  169. const proxyFinalizers = "FinalizationRegistry" in globalThis && new FinalizationRegistry((ep) => {
  170. const newCount = (proxyCounter.get(ep) || 0) - 1;
  171. proxyCounter.set(ep, newCount);
  172. if (newCount === 0) releaseEndpoint(ep);
  173. });
  174. function registerProxy(proxy$1, ep) {
  175. const newCount = (proxyCounter.get(ep) || 0) + 1;
  176. proxyCounter.set(ep, newCount);
  177. if (proxyFinalizers) proxyFinalizers.register(proxy$1, ep, proxy$1);
  178. }
  179. function unregisterProxy(proxy$1) {
  180. if (proxyFinalizers) proxyFinalizers.unregister(proxy$1);
  181. }
  182. function createProxy(ep, pendingListeners, path = [], target = function() {}) {
  183. let isProxyReleased = false;
  184. const proxy$1 = new Proxy(target, {
  185. get(_target, prop) {
  186. throwIfProxyReleased(isProxyReleased);
  187. if (prop === releaseProxy) return () => {
  188. unregisterProxy(proxy$1);
  189. releaseEndpoint(ep);
  190. pendingListeners.clear();
  191. isProxyReleased = true;
  192. };
  193. if (prop === "then") {
  194. if (path.length === 0) return { then: () => proxy$1 };
  195. const r = requestResponseMessage(ep, pendingListeners, {
  196. type: "GET",
  197. path: path.map((p) => p.toString())
  198. }).then(fromWireValue);
  199. return r.then.bind(r);
  200. }
  201. return createProxy(ep, pendingListeners, [...path, prop]);
  202. },
  203. set(_target, prop, rawValue) {
  204. throwIfProxyReleased(isProxyReleased);
  205. const [value, transferables] = toWireValue(rawValue);
  206. return requestResponseMessage(ep, pendingListeners, {
  207. type: "SET",
  208. path: [...path, prop].map((p) => p.toString()),
  209. value
  210. }, transferables).then(fromWireValue);
  211. },
  212. apply(_target, _thisArg, rawArgumentList) {
  213. throwIfProxyReleased(isProxyReleased);
  214. const last = path[path.length - 1];
  215. if (last === createEndpoint) return requestResponseMessage(ep, pendingListeners, { type: "ENDPOINT" }).then(fromWireValue);
  216. if (last === "bind") return createProxy(ep, pendingListeners, path.slice(0, -1));
  217. const [argumentList, transferables] = processArguments(rawArgumentList);
  218. return requestResponseMessage(ep, pendingListeners, {
  219. type: "APPLY",
  220. path: path.map((p) => p.toString()),
  221. argumentList
  222. }, transferables).then(fromWireValue);
  223. },
  224. construct(_target, rawArgumentList) {
  225. throwIfProxyReleased(isProxyReleased);
  226. const [argumentList, transferables] = processArguments(rawArgumentList);
  227. return requestResponseMessage(ep, pendingListeners, {
  228. type: "CONSTRUCT",
  229. path: path.map((p) => p.toString()),
  230. argumentList
  231. }, transferables).then(fromWireValue);
  232. }
  233. });
  234. registerProxy(proxy$1, ep);
  235. return proxy$1;
  236. }
  237. function myFlat(arr) {
  238. return Array.prototype.concat.apply([], arr);
  239. }
  240. function processArguments(argumentList) {
  241. const processed = argumentList.map(toWireValue);
  242. return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];
  243. }
  244. const transferCache = new WeakMap();
  245. function transfer(obj, transfers) {
  246. transferCache.set(obj, transfers);
  247. return obj;
  248. }
  249. function proxy(obj) {
  250. return Object.assign(obj, { [proxyMarker]: true });
  251. }
  252. function toWireValue(value) {
  253. for (const [name, handler] of transferHandlers) if (handler.canHandle(value)) {
  254. const [serializedValue, transferables] = handler.serialize(value);
  255. return [{
  256. type: "HANDLER",
  257. name,
  258. value: serializedValue
  259. }, transferables];
  260. }
  261. return [{
  262. type: "RAW",
  263. value
  264. }, transferCache.get(value) || []];
  265. }
  266. function fromWireValue(value) {
  267. switch (value.type) {
  268. case "HANDLER": return transferHandlers.get(value.name).deserialize(value.value);
  269. case "RAW": return value.value;
  270. }
  271. }
  272. function requestResponseMessage(ep, pendingListeners, msg, transfers) {
  273. return new Promise((resolve) => {
  274. const id = generateUUID();
  275. pendingListeners.set(id, resolve);
  276. if (ep.start) ep.start();
  277. ep.postMessage(Object.assign({ id }, msg), transfers);
  278. });
  279. }
  280. function generateUUID() {
  281. return new Array(4).fill(0).map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16)).join("-");
  282. }
  283. const defaultOptions = /* @__PURE__ */ Object.freeze({
  284. diffTimeout: 1,
  285. diffEditCost: 4,
  286. matchThreshold: .5,
  287. matchDistance: 1e3,
  288. patchDeleteThreshold: .5,
  289. patchMargin: 4,
  290. matchMaxBits: 32
  291. });
  292. function resolveOptions(options) {
  293. if (options?.__resolved) return options;
  294. const resolved = {
  295. ...defaultOptions,
  296. ...options
  297. };
  298. Object.defineProperty(resolved, "__resolved", {
  299. value: true,
  300. enumerable: false
  301. });
  302. return resolved;
  303. }
  304. const DIFF_DELETE = -1;
  305. const DIFF_INSERT = 1;
  306. const DIFF_EQUAL = 0;
  307. function createDiff(op, text) {
  308. return [op, text];
  309. }
  310. function diffMain(text1, text2, options, opt_checklines = true, opt_deadline) {
  311. const resolved = resolveOptions(options);
  312. if (typeof opt_deadline == "undefined") if (resolved.diffTimeout <= 0) opt_deadline = Number.MAX_VALUE;
  313. else opt_deadline = (/* @__PURE__ */ new Date()).getTime() + resolved.diffTimeout * 1e3;
  314. const deadline = opt_deadline;
  315. if (text1 == null || text2 == null) throw new Error("Null input. (diff_main)");
  316. if (text1 === text2) {
  317. if (text1) return [createDiff(DIFF_EQUAL, text1)];
  318. return [];
  319. }
  320. const checklines = opt_checklines;
  321. let commonlength = diffCommonPrefix(text1, text2);
  322. const commonprefix = text1.substring(0, commonlength);
  323. text1 = text1.substring(commonlength);
  324. text2 = text2.substring(commonlength);
  325. commonlength = diffCommonSuffix(text1, text2);
  326. const commonsuffix = text1.substring(text1.length - commonlength);
  327. text1 = text1.substring(0, text1.length - commonlength);
  328. text2 = text2.substring(0, text2.length - commonlength);
  329. const diffs = diffCompute(text1, text2, resolved, checklines, deadline);
  330. if (commonprefix) diffs.unshift(createDiff(DIFF_EQUAL, commonprefix));
  331. if (commonsuffix) diffs.push(createDiff(DIFF_EQUAL, commonsuffix));
  332. diffCleanupMerge(diffs);
  333. return diffs;
  334. }
  335. function diffCompute(text1, text2, options, checklines, deadline) {
  336. let diffs;
  337. if (!text1) return [createDiff(DIFF_INSERT, text2)];
  338. if (!text2) return [createDiff(DIFF_DELETE, text1)];
  339. const longtext = text1.length > text2.length ? text1 : text2;
  340. const shorttext = text1.length > text2.length ? text2 : text1;
  341. const i = longtext.indexOf(shorttext);
  342. if (i !== -1) {
  343. diffs = [
  344. createDiff(DIFF_INSERT, longtext.substring(0, i)),
  345. createDiff(DIFF_EQUAL, shorttext),
  346. createDiff(DIFF_INSERT, longtext.substring(i + shorttext.length))
  347. ];
  348. if (text1.length > text2.length) diffs[0][0] = diffs[2][0] = DIFF_DELETE;
  349. return diffs;
  350. }
  351. if (shorttext.length === 1) return [createDiff(DIFF_DELETE, text1), createDiff(DIFF_INSERT, text2)];
  352. const hm = diffHalfMatch(text1, text2, options);
  353. if (hm) {
  354. const text1_a = hm[0];
  355. const text1_b = hm[1];
  356. const text2_a = hm[2];
  357. const text2_b = hm[3];
  358. const mid_common = hm[4];
  359. const diffs_a = diffMain(text1_a, text2_a, options, checklines, deadline);
  360. const diffs_b = diffMain(text1_b, text2_b, options, checklines, deadline);
  361. return diffs_a.concat([createDiff(DIFF_EQUAL, mid_common)], diffs_b);
  362. }
  363. if (checklines && text1.length > 100 && text2.length > 100) return diffLineMode(text1, text2, options, deadline);
  364. return diffBisect(text1, text2, options, deadline);
  365. }
  366. function diffLineMode(text1, text2, options, deadline) {
  367. const a = diffLinesToChars(text1, text2);
  368. text1 = a.chars1;
  369. text2 = a.chars2;
  370. const linearray = a.lineArray;
  371. const diffs = diffMain(text1, text2, options, false, deadline);
  372. diffCharsToLines(diffs, linearray);
  373. diffCleanupSemantic(diffs);
  374. diffs.push(createDiff(DIFF_EQUAL, ""));
  375. let pointer = 0;
  376. let count_delete = 0;
  377. let count_insert = 0;
  378. let text_delete = "";
  379. let text_insert = "";
  380. while (pointer < diffs.length) {
  381. switch (diffs[pointer][0]) {
  382. case DIFF_INSERT:
  383. count_insert++;
  384. text_insert += diffs[pointer][1];
  385. break;
  386. case DIFF_DELETE:
  387. count_delete++;
  388. text_delete += diffs[pointer][1];
  389. break;
  390. case DIFF_EQUAL:
  391. if (count_delete >= 1 && count_insert >= 1) {
  392. diffs.splice(pointer - count_delete - count_insert, count_delete + count_insert);
  393. pointer = pointer - count_delete - count_insert;
  394. const subDiff = diffMain(text_delete, text_insert, options, false, deadline);
  395. for (let j = subDiff.length - 1; j >= 0; j--) diffs.splice(pointer, 0, subDiff[j]);
  396. pointer = pointer + subDiff.length;
  397. }
  398. count_insert = 0;
  399. count_delete = 0;
  400. text_delete = "";
  401. text_insert = "";
  402. break;
  403. }
  404. pointer++;
  405. }
  406. diffs.pop();
  407. return diffs;
  408. }
  409. function diffBisect(text1, text2, options, deadline) {
  410. const text1_length = text1.length;
  411. const text2_length = text2.length;
  412. const max_d = Math.ceil((text1_length + text2_length) / 2);
  413. const v_offset = max_d;
  414. const v_length = 2 * max_d;
  415. const v1 = new Array(v_length);
  416. const v2 = new Array(v_length);
  417. for (let x = 0; x < v_length; x++) {
  418. v1[x] = -1;
  419. v2[x] = -1;
  420. }
  421. v1[v_offset + 1] = 0;
  422. v2[v_offset + 1] = 0;
  423. const delta = text1_length - text2_length;
  424. const front = delta % 2 !== 0;
  425. let k1start = 0;
  426. let k1end = 0;
  427. let k2start = 0;
  428. let k2end = 0;
  429. for (let d = 0; d < max_d; d++) {
  430. if ((/* @__PURE__ */ new Date()).getTime() > deadline) break;
  431. for (let k1 = -d + k1start; k1 <= d - k1end; k1 += 2) {
  432. const k1_offset = v_offset + k1;
  433. let x1;
  434. if (k1 === -d || k1 !== d && v1[k1_offset - 1] < v1[k1_offset + 1]) x1 = v1[k1_offset + 1];
  435. else x1 = v1[k1_offset - 1] + 1;
  436. let y1 = x1 - k1;
  437. while (x1 < text1_length && y1 < text2_length && text1.charAt(x1) === text2.charAt(y1)) {
  438. x1++;
  439. y1++;
  440. }
  441. v1[k1_offset] = x1;
  442. if (x1 > text1_length) k1end += 2;
  443. else if (y1 > text2_length) k1start += 2;
  444. else if (front) {
  445. const k2_offset = v_offset + delta - k1;
  446. if (k2_offset >= 0 && k2_offset < v_length && v2[k2_offset] !== -1) {
  447. const x2 = text1_length - v2[k2_offset];
  448. if (x1 >= x2) return diffBisectSplit(text1, text2, options, x1, y1, deadline);
  449. }
  450. }
  451. }
  452. for (let k2 = -d + k2start; k2 <= d - k2end; k2 += 2) {
  453. const k2_offset = v_offset + k2;
  454. let x2;
  455. if (k2 === -d || k2 !== d && v2[k2_offset - 1] < v2[k2_offset + 1]) x2 = v2[k2_offset + 1];
  456. else x2 = v2[k2_offset - 1] + 1;
  457. let y2 = x2 - k2;
  458. while (x2 < text1_length && y2 < text2_length && text1.charAt(text1_length - x2 - 1) === text2.charAt(text2_length - y2 - 1)) {
  459. x2++;
  460. y2++;
  461. }
  462. v2[k2_offset] = x2;
  463. if (x2 > text1_length) k2end += 2;
  464. else if (y2 > text2_length) k2start += 2;
  465. else if (!front) {
  466. const k1_offset = v_offset + delta - k2;
  467. if (k1_offset >= 0 && k1_offset < v_length && v1[k1_offset] !== -1) {
  468. const x1 = v1[k1_offset];
  469. const y1 = v_offset + x1 - k1_offset;
  470. x2 = text1_length - x2;
  471. if (x1 >= x2) return diffBisectSplit(text1, text2, options, x1, y1, deadline);
  472. }
  473. }
  474. }
  475. }
  476. return [createDiff(DIFF_DELETE, text1), createDiff(DIFF_INSERT, text2)];
  477. }
  478. function diffBisectSplit(text1, text2, options, x, y, deadline) {
  479. const text1a = text1.substring(0, x);
  480. const text2a = text2.substring(0, y);
  481. const text1b = text1.substring(x);
  482. const text2b = text2.substring(y);
  483. const diffs = diffMain(text1a, text2a, options, false, deadline);
  484. const diffsb = diffMain(text1b, text2b, options, false, deadline);
  485. return diffs.concat(diffsb);
  486. }
  487. function diffLinesToChars(text1, text2) {
  488. const lineArray = [];
  489. const lineHash = {};
  490. let maxLines = 4e4;
  491. lineArray[0] = "";
  492. function diffLinesToCharsMunge(text) {
  493. let chars = "";
  494. let lineStart = 0;
  495. let lineEnd = -1;
  496. let lineArrayLength = lineArray.length;
  497. while (lineEnd < text.length - 1) {
  498. lineEnd = text.indexOf("\n", lineStart);
  499. if (lineEnd === -1) lineEnd = text.length - 1;
  500. let line = text.substring(lineStart, lineEnd + 1);
  501. if (lineHash.hasOwnProperty ? Object.prototype.hasOwnProperty.call(lineHash, line) : lineHash[line] !== void 0) chars += String.fromCharCode(lineHash[line]);
  502. else {
  503. if (lineArrayLength === maxLines) {
  504. line = text.substring(lineStart);
  505. lineEnd = text.length;
  506. }
  507. chars += String.fromCharCode(lineArrayLength);
  508. lineHash[line] = lineArrayLength;
  509. lineArray[lineArrayLength++] = line;
  510. }
  511. lineStart = lineEnd + 1;
  512. }
  513. return chars;
  514. }
  515. const chars1 = diffLinesToCharsMunge(text1);
  516. maxLines = 65535;
  517. const chars2 = diffLinesToCharsMunge(text2);
  518. return {
  519. chars1,
  520. chars2,
  521. lineArray
  522. };
  523. }
  524. function diffCharsToLines(diffs, lineArray) {
  525. for (let i = 0; i < diffs.length; i++) {
  526. const chars = diffs[i][1];
  527. const text = [];
  528. for (let j = 0; j < chars.length; j++) text[j] = lineArray[chars.charCodeAt(j)];
  529. diffs[i][1] = text.join("");
  530. }
  531. }
  532. function diffCommonPrefix(text1, text2) {
  533. if (!text1 || !text2 || text1.charAt(0) !== text2.charAt(0)) return 0;
  534. let pointermin = 0;
  535. let pointermax = Math.min(text1.length, text2.length);
  536. let pointermid = pointermax;
  537. let pointerstart = 0;
  538. while (pointermin < pointermid) {
  539. if (text1.substring(pointerstart, pointermid) === text2.substring(pointerstart, pointermid)) {
  540. pointermin = pointermid;
  541. pointerstart = pointermin;
  542. } else pointermax = pointermid;
  543. pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
  544. }
  545. return pointermid;
  546. }
  547. function diffCommonSuffix(text1, text2) {
  548. if (!text1 || !text2 || text1.charAt(text1.length - 1) !== text2.charAt(text2.length - 1)) return 0;
  549. let pointermin = 0;
  550. let pointermax = Math.min(text1.length, text2.length);
  551. let pointermid = pointermax;
  552. let pointerend = 0;
  553. while (pointermin < pointermid) {
  554. if (text1.substring(text1.length - pointermid, text1.length - pointerend) === text2.substring(text2.length - pointermid, text2.length - pointerend)) {
  555. pointermin = pointermid;
  556. pointerend = pointermin;
  557. } else pointermax = pointermid;
  558. pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
  559. }
  560. return pointermid;
  561. }
  562. function diffCommonOverlap(text1, text2) {
  563. const text1_length = text1.length;
  564. const text2_length = text2.length;
  565. if (text1_length === 0 || text2_length === 0) return 0;
  566. if (text1_length > text2_length) text1 = text1.substring(text1_length - text2_length);
  567. else if (text1_length < text2_length) text2 = text2.substring(0, text1_length);
  568. const text_length = Math.min(text1_length, text2_length);
  569. if (text1 === text2) return text_length;
  570. let best = 0;
  571. let length = 1;
  572. while (true) {
  573. const pattern = text1.substring(text_length - length);
  574. const found = text2.indexOf(pattern);
  575. if (found === -1) return best;
  576. length += found;
  577. if (found === 0 || text1.substring(text_length - length) === text2.substring(0, length)) {
  578. best = length;
  579. length++;
  580. }
  581. }
  582. }
  583. function diffHalfMatch(text1, text2, options) {
  584. if (options.diffTimeout <= 0) return null;
  585. const longtext = text1.length > text2.length ? text1 : text2;
  586. const shorttext = text1.length > text2.length ? text2 : text1;
  587. if (longtext.length < 4 || shorttext.length * 2 < longtext.length) return null;
  588. function diffHalfMatchI(longtext2, shorttext2, i) {
  589. const seed = longtext2.substring(i, i + Math.floor(longtext2.length / 4));
  590. let j = -1;
  591. let best_common = "";
  592. let best_longtext_a, best_longtext_b, best_shorttext_a, best_shorttext_b;
  593. while ((j = shorttext2.indexOf(seed, j + 1)) !== -1) {
  594. const prefixLength = diffCommonPrefix(longtext2.substring(i), shorttext2.substring(j));
  595. const suffixLength = diffCommonSuffix(longtext2.substring(0, i), shorttext2.substring(0, j));
  596. if (best_common.length < suffixLength + prefixLength) {
  597. best_common = shorttext2.substring(j - suffixLength, j) + shorttext2.substring(j, j + prefixLength);
  598. best_longtext_a = longtext2.substring(0, i - suffixLength);
  599. best_longtext_b = longtext2.substring(i + prefixLength);
  600. best_shorttext_a = shorttext2.substring(0, j - suffixLength);
  601. best_shorttext_b = shorttext2.substring(j + prefixLength);
  602. }
  603. }
  604. if (best_common.length * 2 >= longtext2.length) return [
  605. best_longtext_a,
  606. best_longtext_b,
  607. best_shorttext_a,
  608. best_shorttext_b,
  609. best_common
  610. ];
  611. else return null;
  612. }
  613. const hm1 = diffHalfMatchI(longtext, shorttext, Math.ceil(longtext.length / 4));
  614. const hm2 = diffHalfMatchI(longtext, shorttext, Math.ceil(longtext.length / 2));
  615. let hm;
  616. if (!hm1 && !hm2) return null;
  617. else if (!hm2) hm = hm1;
  618. else if (!hm1) hm = hm2;
  619. else hm = hm1[4].length > hm2[4].length ? hm1 : hm2;
  620. let text1_a, text1_b, text2_a, text2_b;
  621. if (text1.length > text2.length) {
  622. text1_a = hm[0];
  623. text1_b = hm[1];
  624. text2_a = hm[2];
  625. text2_b = hm[3];
  626. } else {
  627. text2_a = hm[0];
  628. text2_b = hm[1];
  629. text1_a = hm[2];
  630. text1_b = hm[3];
  631. }
  632. const mid_common = hm[4];
  633. return [
  634. text1_a,
  635. text1_b,
  636. text2_a,
  637. text2_b,
  638. mid_common
  639. ];
  640. }
  641. function diffCleanupSemantic(diffs) {
  642. let changes = false;
  643. const equalities = [];
  644. let equalitiesLength = 0;
  645. let lastEquality = null;
  646. let pointer = 0;
  647. let length_insertions1 = 0;
  648. let length_deletions1 = 0;
  649. let length_insertions2 = 0;
  650. let length_deletions2 = 0;
  651. while (pointer < diffs.length) {
  652. if (diffs[pointer][0] === DIFF_EQUAL) {
  653. equalities[equalitiesLength++] = pointer;
  654. length_insertions1 = length_insertions2;
  655. length_deletions1 = length_deletions2;
  656. length_insertions2 = 0;
  657. length_deletions2 = 0;
  658. lastEquality = diffs[pointer][1];
  659. } else {
  660. if (diffs[pointer][0] === DIFF_INSERT) length_insertions2 += diffs[pointer][1].length;
  661. else length_deletions2 += diffs[pointer][1].length;
  662. if (lastEquality && lastEquality.length <= Math.max(length_insertions1, length_deletions1) && lastEquality.length <= Math.max(length_insertions2, length_deletions2)) {
  663. diffs.splice(equalities[equalitiesLength - 1], 0, createDiff(DIFF_DELETE, lastEquality));
  664. diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT;
  665. equalitiesLength--;
  666. equalitiesLength--;
  667. pointer = equalitiesLength > 0 ? equalities[equalitiesLength - 1] : -1;
  668. length_insertions1 = 0;
  669. length_deletions1 = 0;
  670. length_insertions2 = 0;
  671. length_deletions2 = 0;
  672. lastEquality = null;
  673. changes = true;
  674. }
  675. }
  676. pointer++;
  677. }
  678. if (changes) diffCleanupMerge(diffs);
  679. diffCleanupSemanticLossless(diffs);
  680. pointer = 1;
  681. while (pointer < diffs.length) {
  682. if (diffs[pointer - 1][0] === DIFF_DELETE && diffs[pointer][0] === DIFF_INSERT) {
  683. const deletion = diffs[pointer - 1][1];
  684. const insertion = diffs[pointer][1];
  685. const overlap_length1 = diffCommonOverlap(deletion, insertion);
  686. const overlap_length2 = diffCommonOverlap(insertion, deletion);
  687. if (overlap_length1 >= overlap_length2) {
  688. if (overlap_length1 >= deletion.length / 2 || overlap_length1 >= insertion.length / 2) {
  689. diffs.splice(pointer, 0, createDiff(DIFF_EQUAL, insertion.substring(0, overlap_length1)));
  690. diffs[pointer - 1][1] = deletion.substring(0, deletion.length - overlap_length1);
  691. diffs[pointer + 1][1] = insertion.substring(overlap_length1);
  692. pointer++;
  693. }
  694. } else if (overlap_length2 >= deletion.length / 2 || overlap_length2 >= insertion.length / 2) {
  695. diffs.splice(pointer, 0, createDiff(DIFF_EQUAL, deletion.substring(0, overlap_length2)));
  696. diffs[pointer - 1][0] = DIFF_INSERT;
  697. diffs[pointer - 1][1] = insertion.substring(0, insertion.length - overlap_length2);
  698. diffs[pointer + 1][0] = DIFF_DELETE;
  699. diffs[pointer + 1][1] = deletion.substring(overlap_length2);
  700. pointer++;
  701. }
  702. pointer++;
  703. }
  704. pointer++;
  705. }
  706. }
  707. const nonAlphaNumericRegex_ = /[^a-z0-9]/i;
  708. const whitespaceRegex_ = /\s/;
  709. const linebreakRegex_ = /[\r\n]/;
  710. const blanklineEndRegex_ = /\n\r?\n$/;
  711. const blanklineStartRegex_ = /^\r?\n\r?\n/;
  712. function diffCleanupSemanticLossless(diffs) {
  713. function diffCleanupSemanticScore(one, two) {
  714. if (!one || !two) return 6;
  715. const char1 = one.charAt(one.length - 1);
  716. const char2 = two.charAt(0);
  717. const nonAlphaNumeric1 = char1.match(nonAlphaNumericRegex_);
  718. const nonAlphaNumeric2 = char2.match(nonAlphaNumericRegex_);
  719. const whitespace1 = nonAlphaNumeric1 && char1.match(whitespaceRegex_);
  720. const whitespace2 = nonAlphaNumeric2 && char2.match(whitespaceRegex_);
  721. const lineBreak1 = whitespace1 && char1.match(linebreakRegex_);
  722. const lineBreak2 = whitespace2 && char2.match(linebreakRegex_);
  723. const blankLine1 = lineBreak1 && one.match(blanklineEndRegex_);
  724. const blankLine2 = lineBreak2 && two.match(blanklineStartRegex_);
  725. if (blankLine1 || blankLine2) return 5;
  726. else if (lineBreak1 || lineBreak2) return 4;
  727. else if (nonAlphaNumeric1 && !whitespace1 && whitespace2) return 3;
  728. else if (whitespace1 || whitespace2) return 2;
  729. else if (nonAlphaNumeric1 || nonAlphaNumeric2) return 1;
  730. return 0;
  731. }
  732. let pointer = 1;
  733. while (pointer < diffs.length - 1) {
  734. if (diffs[pointer - 1][0] === DIFF_EQUAL && diffs[pointer + 1][0] === DIFF_EQUAL) {
  735. let equality1 = diffs[pointer - 1][1];
  736. let edit = diffs[pointer][1];
  737. let equality2 = diffs[pointer + 1][1];
  738. const commonOffset = diffCommonSuffix(equality1, edit);
  739. if (commonOffset) {
  740. const commonString = edit.substring(edit.length - commonOffset);
  741. equality1 = equality1.substring(0, equality1.length - commonOffset);
  742. edit = commonString + edit.substring(0, edit.length - commonOffset);
  743. equality2 = commonString + equality2;
  744. }
  745. let bestEquality1 = equality1;
  746. let bestEdit = edit;
  747. let bestEquality2 = equality2;
  748. let bestScore = diffCleanupSemanticScore(equality1, edit) + diffCleanupSemanticScore(edit, equality2);
  749. while (edit.charAt(0) === equality2.charAt(0)) {
  750. equality1 += edit.charAt(0);
  751. edit = edit.substring(1) + equality2.charAt(0);
  752. equality2 = equality2.substring(1);
  753. const score = diffCleanupSemanticScore(equality1, edit) + diffCleanupSemanticScore(edit, equality2);
  754. if (score >= bestScore) {
  755. bestScore = score;
  756. bestEquality1 = equality1;
  757. bestEdit = edit;
  758. bestEquality2 = equality2;
  759. }
  760. }
  761. if (diffs[pointer - 1][1] !== bestEquality1) {
  762. if (bestEquality1) diffs[pointer - 1][1] = bestEquality1;
  763. else {
  764. diffs.splice(pointer - 1, 1);
  765. pointer--;
  766. }
  767. diffs[pointer][1] = bestEdit;
  768. if (bestEquality2) diffs[pointer + 1][1] = bestEquality2;
  769. else {
  770. diffs.splice(pointer + 1, 1);
  771. pointer--;
  772. }
  773. }
  774. }
  775. pointer++;
  776. }
  777. }
  778. function diffCleanupMerge(diffs) {
  779. diffs.push(createDiff(DIFF_EQUAL, ""));
  780. let pointer = 0;
  781. let count_delete = 0;
  782. let count_insert = 0;
  783. let text_delete = "";
  784. let text_insert = "";
  785. let commonlength;
  786. while (pointer < diffs.length) switch (diffs[pointer][0]) {
  787. case DIFF_INSERT:
  788. count_insert++;
  789. text_insert += diffs[pointer][1];
  790. pointer++;
  791. break;
  792. case DIFF_DELETE:
  793. count_delete++;
  794. text_delete += diffs[pointer][1];
  795. pointer++;
  796. break;
  797. case DIFF_EQUAL:
  798. if (count_delete + count_insert > 1) {
  799. if (count_delete !== 0 && count_insert !== 0) {
  800. commonlength = diffCommonPrefix(text_insert, text_delete);
  801. if (commonlength !== 0) {
  802. if (pointer - count_delete - count_insert > 0 && diffs[pointer - count_delete - count_insert - 1][0] === DIFF_EQUAL) diffs[pointer - count_delete - count_insert - 1][1] += text_insert.substring(0, commonlength);
  803. else {
  804. diffs.splice(0, 0, createDiff(DIFF_EQUAL, text_insert.substring(0, commonlength)));
  805. pointer++;
  806. }
  807. text_insert = text_insert.substring(commonlength);
  808. text_delete = text_delete.substring(commonlength);
  809. }
  810. commonlength = diffCommonSuffix(text_insert, text_delete);
  811. if (commonlength !== 0) {
  812. diffs[pointer][1] = text_insert.substring(text_insert.length - commonlength) + diffs[pointer][1];
  813. text_insert = text_insert.substring(0, text_insert.length - commonlength);
  814. text_delete = text_delete.substring(0, text_delete.length - commonlength);
  815. }
  816. }
  817. pointer -= count_delete + count_insert;
  818. diffs.splice(pointer, count_delete + count_insert);
  819. if (text_delete.length) {
  820. diffs.splice(pointer, 0, createDiff(DIFF_DELETE, text_delete));
  821. pointer++;
  822. }
  823. if (text_insert.length) {
  824. diffs.splice(pointer, 0, createDiff(DIFF_INSERT, text_insert));
  825. pointer++;
  826. }
  827. pointer++;
  828. } else if (pointer !== 0 && diffs[pointer - 1][0] === DIFF_EQUAL) {
  829. diffs[pointer - 1][1] += diffs[pointer][1];
  830. diffs.splice(pointer, 1);
  831. } else pointer++;
  832. count_insert = 0;
  833. count_delete = 0;
  834. text_delete = "";
  835. text_insert = "";
  836. break;
  837. }
  838. if (diffs[diffs.length - 1][1] === "") diffs.pop();
  839. let changes = false;
  840. pointer = 1;
  841. while (pointer < diffs.length - 1) {
  842. if (diffs[pointer - 1][0] === DIFF_EQUAL && diffs[pointer + 1][0] === DIFF_EQUAL) {
  843. if (diffs[pointer][1].substring(diffs[pointer][1].length - diffs[pointer - 1][1].length) === diffs[pointer - 1][1]) {
  844. diffs[pointer][1] = diffs[pointer - 1][1] + diffs[pointer][1].substring(0, diffs[pointer][1].length - diffs[pointer - 1][1].length);
  845. diffs[pointer + 1][1] = diffs[pointer - 1][1] + diffs[pointer + 1][1];
  846. diffs.splice(pointer - 1, 1);
  847. changes = true;
  848. } else if (diffs[pointer][1].substring(0, diffs[pointer + 1][1].length) === diffs[pointer + 1][1]) {
  849. diffs[pointer - 1][1] += diffs[pointer + 1][1];
  850. diffs[pointer][1] = diffs[pointer][1].substring(diffs[pointer + 1][1].length) + diffs[pointer + 1][1];
  851. diffs.splice(pointer + 1, 1);
  852. changes = true;
  853. }
  854. }
  855. pointer++;
  856. }
  857. if (changes) diffCleanupMerge(diffs);
  858. }
  859. function calculateDiff(left, right) {
  860. const changes = diffMain(left.replace(/\r\n/g, "\n"), right.replace(/\r\n/g, "\n"));
  861. diffCleanupSemantic(changes);
  862. return changes;
  863. }
  864. const exports$1 = { calculateDiff };
  865. expose(exports$1);
  866. })();