Skip to content

Commit 2717fd8

Browse files
Fix diffSentences for old Safari versions (#616)
* Fix diffSentences for old Safari versions Resolves #615 * Add release notes
1 parent d3f3bf5 commit 2717fd8

File tree

2 files changed

+51
-2
lines changed

2 files changed

+51
-2
lines changed

release-notes.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Release Notes
22

3+
## 8.0.2
4+
5+
- [#616](https://github.com/kpdecker/jsdiff/pull/616) **Restored compatibility of `diffSentences` with old Safari versions.** This was broken in 8.0.0 by the introduction of a regex with a [lookbehind assertion](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Lookbehind_assertion); these weren't supported in Safari prior to version 16.4.
6+
- [#612](https://github.com/kpdecker/jsdiff/pull/612) **Improved tree shakeability** by marking the built CJS and ESM packages with `sideEffects: false`.
7+
38
## 8.0.1
49

510
- [#610](https://github.com/kpdecker/jsdiff/pull/610) **Fixes types for `diffJson` which were broken by 8.0.0**. The new bundled types in 8.0.0 only allowed `diffJson` to be passed string arguments, but it should've been possible to pass either strings or objects (and now is). Thanks to Josh Kelley for the fix.

src/diff/sentence.ts

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,53 @@
11
import Diff from './base.js';
2-
import type { ChangeObject, CallbackOptionAbortable, CallbackOptionNonabortable, DiffCallbackNonabortable, DiffSentencesOptionsAbortable, DiffSentencesOptionsNonabortable} from '../types.js';
2+
import type {
3+
ChangeObject,
4+
CallbackOptionAbortable,
5+
CallbackOptionNonabortable,
6+
DiffCallbackNonabortable,
7+
DiffSentencesOptionsAbortable,
8+
DiffSentencesOptionsNonabortable
9+
} from '../types.js';
10+
11+
function isSentenceEndPunct(char: string) {
12+
return char == '.' || char == '!' || char == '?';
13+
}
314

415
class SentenceDiff extends Diff<string, string> {
516
tokenize(value: string) {
6-
return value.split(/(?<=[.!?])(\s+|$)/);
17+
// If in future we drop support for environments that don't support lookbehinds, we can replace
18+
// this entire function with:
19+
// return value.split(/(?<=[.!?])(\s+|$)/);
20+
// but until then, for similar reasons to the trailingWs function in string.ts, we are forced
21+
// to do this verbosely "by hand" instead of using a regex.
22+
const result = [];
23+
let tokenStartI = 0;
24+
for (let i = 0; i < value.length; i++) {
25+
if (i == value.length - 1) {
26+
result.push(value.slice(tokenStartI));
27+
break;
28+
}
29+
30+
if (isSentenceEndPunct(value[i]) && value[i + 1].match(/\s/)) {
31+
// We've hit a sentence break - i.e. a punctuation mark followed by whitespace.
32+
// We now want to push TWO tokens to the result:
33+
// 1. the sentence
34+
result.push(value.slice(tokenStartI, i + 1));
35+
36+
// 2. the whitespace
37+
i = tokenStartI = i + 1;
38+
while (value[i + 1]?.match(/\s/)) {
39+
i++;
40+
}
41+
result.push(value.slice(tokenStartI, i + 1));
42+
43+
// Then the next token (a sentence) starts on the character after the whitespace.
44+
// (It's okay if this is off the end of the string - then the outer loop will terminate
45+
// here anyway.)
46+
tokenStartI = i + 1;
47+
}
48+
}
49+
50+
return result;
751
}
852
}
953

0 commit comments

Comments
 (0)