punctilio 3.0.10 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  Pretty good at making your text pretty. The most feature-complete and reliable English typography package. `punctilio` transforms plain ASCII into typographically correct Unicode, even across HTML element boundaries.
8
8
 
9
- **Smart quotes** · **Em/en dashes** · **Ellipses** · **Math symbols** · **Legal symbols** · **Arrows** · **Primes** · **Fractions** · **Superscripts** · **Ligatures** · **Non-breaking spaces** · **HTML-aware** · **Bri’ish localisation support**
9
+ **Smart quotes** · **Em/en dashes** · **Ellipses** · **Math symbols** · **Legal symbols** · **Arrows** · **Primes** · **Fractions** · **Superscripts** · **Ligatures** · **Non-breaking spaces** · **HTML-aware** · **Bri’ish, German, and French localisation support**
10
10
 
11
11
  ```typescript
12
12
  import { transform } from 'punctilio'
@@ -39,10 +39,10 @@ My [`benchmark.mjs`](https://github.com/alexander-turner/punctilio/blob/main/ben
39
39
 
40
40
  | Package | Passed (of 157) |
41
41
  |--------:|:----------------|
42
- | `punctilio` | 152 (97%) |
43
- | `tipograph` | 92 (58%) |
42
+ | `punctilio` | 155 (99%) |
43
+ | `tipograph` | 91 (58%) |
44
44
  | `typograf` | 74 (47%) |
45
- | `smartquotes` | 72 (45%) |
45
+ | `smartquotes` | 72 (46%) |
46
46
  | `smartypants` | 68 (43%) |
47
47
  | `retext-smartypants` | 65 (41%) |
48
48
 
@@ -64,7 +64,7 @@ My [`benchmark.mjs`](https://github.com/alexander-turner/punctilio/blob/main/ben
64
64
  | Superscripts | <span class="no-formatting">2nd → 2ⁿᵈ</span> | ✓ | ✗ | ✗ | ✗ | ✗ |
65
65
  | English localization | <span class="no-formatting">American / British</span> | ✓ | ✗ | ✗ | ✗ | ✗ |
66
66
  | Ligatures | <span class="no-formatting">?? → ⁇</span> | ✓ | ✗ | ✓ | ✗ | ✗ |
67
- | Non-English quotes | <span class="no-formatting">„Hallo”</span> | ✗ | ✗ | ✓ | ✗ | ◐ |
67
+ | Non-English quotes | <span class=”no-formatting”>„Hallo”</span> | ✓ | ✗ | ✓ | ✗ | ◐ |
68
68
  | Non-breaking spaces | <span class="no-formatting">Chapter 1</span> | ✓ | ✗ | ✗ | ✗ | ✓ |
69
69
 
70
70
  ### Known limitations of `punctilio`
@@ -72,11 +72,10 @@ My [`benchmark.mjs`](https://github.com/alexander-turner/punctilio/blob/main/ben
72
72
  | Pattern | Behavior | Notes |
73
73
  |:--------|:---------|:------|
74
74
  | `'99 but 5' clearance` | `5'` not converted to `5′` | Leading apostrophe is indistinguishable from an opening quote without semantic understanding |
75
- | `«Bonjour»` | Not spaced to `« Bonjour »` | French localization not supported |
76
75
 
77
76
  ## Test suite
78
77
 
79
- Setting aside the benchmark, `punctilio`’s test suite includes 1,400+ tests at 100% branch coverage, including edge cases derived from competitor libraries ([`smartquotes`](https://github.com/kellym/smartquotes.js), [`retext-smartypants`](https://github.com/retextjs/retext-smartypants), [`typograf`](https://github.com/typograf/typograf)) and the [Standard Ebooks typography manual](https://standardebooks.org/manual/). I also verify that all transformations are stable when applied multiple times.
78
+ Setting aside the benchmark, `punctilio`’s test suite includes 1,450+ tests at 100% branch coverage, including edge cases derived from competitor libraries ([`smartquotes`](https://github.com/kellym/smartquotes.js), [`retext-smartypants`](https://github.com/retextjs/retext-smartypants), [`typograf`](https://github.com/typograf/typograf)) and the [Standard Ebooks typography manual](https://standardebooks.org/manual/). I also verify that all transformations are stable when applied multiple times.
80
79
 
81
80
  ## Works with HTML DOMs via separation boundaries
82
81
 
@@ -126,7 +125,7 @@ For manual DOM walking or custom transforms, use `transformElement` from `puncti
126
125
 
127
126
  ```typescript
128
127
  transform(text, {
129
- punctuationStyle: 'american' | 'british' | 'none', // default: 'american'
128
+ punctuationStyle: 'american' | 'british' | 'german' | 'french' | 'none', // default: 'american'
130
129
  dashStyle: 'american' | 'british' | 'none', // default: 'american'
131
130
 
132
131
  symbols: true, // ellipsis, math, legal, arrows
@@ -147,6 +146,11 @@ transform(text, {
147
146
  - The `british` style follows [Oxford style](https://www.ox.ac.uk/sites/files/oxford/Style%20Guide%20quick%20reference%20A-Z.pdf):
148
147
  - Periods and commas go outside quotation marks (“Hello”, she said.)
149
148
  - Spaced en-dashes between words (word – word)
149
+ - The `german` style uses low-9 quotes: „double” (U+201E/U+201C) and ‚single' (U+201A/U+2018).
150
+ - Punctuation outside quotes
151
+ - The `french` style uses guillemets with non-breaking space padding: «\u00A0Bonjour\u00A0».
152
+ - Single quotes remain as curly quotes
153
+ - Punctuation outside quotes
150
154
  - Setting either style to `none` skips the entire transform category: `punctuationStyle: 'none'` preserves straight quotes, apostrophes, and prime marks; `dashStyle: 'none'` preserves all hyphens, number ranges, date ranges, and minus signs.
151
155
  - `punctilio` is idempotent by design: `transform(transform(text))` always equals `transform(text)`. This is verified automatically by default (`checkIdempotency: true`). Set `checkIdempotency: false` to disable the check.
152
156
  - Use `classifyApostrophes(text)` to distinguish apostrophes from closing single quotes. It returns text with apostrophes as U+02BC (MODIFIER LETTER APOSTROPHE) and closing quotes as U+2019 (RIGHT SINGLE QUOTATION MARK). Per the [Unicode Standard](https://www.unicode.org/versions/Unicode16.0.0/core-spec/chapter-6/#G30602), `transform()` and `niceQuotes()` use U+2019 for both in their output.
@@ -51,6 +51,10 @@ export declare const UNICODE_SYMBOLS: {
51
51
  readonly RIGHT_SINGLE_QUOTE: "’";
52
52
  readonly MODIFIER_LETTER_APOSTROPHE: "ʼ";
53
53
  readonly NBSP: " ";
54
+ readonly DOUBLE_LOW_9_QUOTE: "„";
55
+ readonly SINGLE_LOW_9_QUOTE: "‚";
56
+ readonly LEFT_GUILLEMET: "«";
57
+ readonly RIGHT_GUILLEMET: "»";
54
58
  readonly SUPERSCRIPT_ST: "ˢᵗ";
55
59
  readonly SUPERSCRIPT_ND: "ⁿᵈ";
56
60
  readonly SUPERSCRIPT_RD: "ʳᵈ";
@@ -94,17 +98,21 @@ export declare const TERMINAL_PUNCTUATION: readonly ["!", "?", ".", ",", ";", ":
94
98
  */
95
99
  export declare const LATIN_LETTERS = "A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u00FF\\u0100-\\u017F\\u0180-\\u024F";
96
100
  /**
97
- * Default separator character for text spanning HTML elements.
98
- * Uses Unicode Private Use Area character U+E000.
101
+ * Default separator for text spanning HTML elements.
102
+ * Uses a two-character sentinel from the Unicode Private Use Area
103
+ * (U+E000 U+E001) to avoid collisions with CJK fonts, Apple emoji
104
+ * internals, PDF-to-text output, and icon fonts that repurpose U+E000.
99
105
  */
100
- export declare const DEFAULT_SEPARATOR = "\uE000";
106
+ export declare const DEFAULT_SEPARATOR = "\uE000\uE001";
101
107
  export declare const ESCAPED_DEFAULT_SEPARATOR: string;
102
108
  /**
103
- * Returns the regex-escaped separator string for the given options.
104
- * Centralizes the common pattern of falling back to the pre-escaped default.
109
+ * Returns the regex-escaped separator string for the given options,
110
+ * wrapped in a non-capturing group so that quantifiers like `?` and `*`
111
+ * apply to the entire separator sequence (critical for multi-character
112
+ * separators like the default U+E000 U+E001).
105
113
  *
106
114
  * @param options - Object with an optional `separator` field
107
- * @returns Regex-escaped separator string
115
+ * @returns Regex-escaped separator string wrapped in `(?:...)`
108
116
  */
109
117
  export declare function getEscapedSeparator(options: {
110
118
  separator?: string;
@@ -157,16 +165,22 @@ export declare const SPACE_CHARS: string;
157
165
  * Creates a lookbehind pattern that matches after whitespace, separator, or start of string.
158
166
  * Used for arrow patterns and other constructs that should appear at word boundaries.
159
167
  *
160
- * @param escapedSeparator - Regex-escaped separator string
161
- * @returns Pattern string: `(?<=[\\s${sep}]|^)`
168
+ * Uses alternation instead of a character class so that multi-character
169
+ * separators are matched as a sequence, not as individual characters.
170
+ *
171
+ * @param escapedSeparator - Regex-escaped separator string (may be grouped)
172
+ * @returns Pattern string: `(?<=\\s|${sep}|^)`
162
173
  */
163
174
  export declare function spaceBoundaryStart(escapedSeparator: string): string;
164
175
  /**
165
176
  * Creates a lookahead pattern that matches before whitespace, separator, or end of string.
166
177
  * Used for arrow patterns and other constructs that should appear at word boundaries.
167
178
  *
168
- * @param escapedSeparator - Regex-escaped separator string
169
- * @returns Pattern string: `(?=[\\s${sep}]|$)`
179
+ * Uses alternation instead of a character class so that multi-character
180
+ * separators are matched as a sequence, not as individual characters.
181
+ *
182
+ * @param escapedSeparator - Regex-escaped separator string (may be grouped)
183
+ * @returns Pattern string: `(?=\\s|${sep}|$)`
170
184
  */
171
185
  export declare function spaceBoundaryEnd(escapedSeparator: string): string;
172
186
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;GAEG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmElB,CAAA;AAEV;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,8HAYvB,CAAA;AAEV;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,sFAAsF,CAAA;AAEhH;;;GAGG;AACH,eAAO,MAAM,iBAAiB,WAAW,CAAA;AACzC,eAAO,MAAM,yBAAyB,QAAwC,CAAA;AAE9E;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAI3E;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,wEAAyE,CAAA;AAEzG;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED;;;GAGG;AACH,eAAO,MAAM,WAAW,QAA6B,CAAA;AAErD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAEjE;AAUD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAcnE"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;GAEG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuElB,CAAA;AAEV;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,8HAYvB,CAAA;AAEV;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,sFAAsF,CAAA;AAEhH;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,iBAAiB,CAAA;AAC/C,eAAO,MAAM,yBAAyB,QAAwC,CAAA;AAE9E;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAK3E;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,wEAAyE,CAAA;AAEzG;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED;;;GAGG;AACH,eAAO,MAAM,WAAW,QAA6B,CAAA;AAErD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAEjE;AAUD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAcnE"}
package/dist/constants.js CHANGED
@@ -52,6 +52,10 @@ export const UNICODE_SYMBOLS = {
52
52
  RIGHT_SINGLE_QUOTE: "\u2019",
53
53
  MODIFIER_LETTER_APOSTROPHE: "\u02BC",
54
54
  NBSP: "\u00A0",
55
+ DOUBLE_LOW_9_QUOTE: "\u201E", // „
56
+ SINGLE_LOW_9_QUOTE: "\u201A", // ‚
57
+ LEFT_GUILLEMET: "\u00AB", // «
58
+ RIGHT_GUILLEMET: "\u00BB", // »
55
59
  // Superscript ordinal suffixes
56
60
  SUPERSCRIPT_ST: "\u02E2\u1D57", // ˢᵗ
57
61
  SUPERSCRIPT_ND: "\u207F\u1D48", // ⁿᵈ
@@ -113,22 +117,27 @@ export const TERMINAL_PUNCTUATION = [
113
117
  */
114
118
  export const LATIN_LETTERS = "A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u00FF\\u0100-\\u017F\\u0180-\\u024F";
115
119
  /**
116
- * Default separator character for text spanning HTML elements.
117
- * Uses Unicode Private Use Area character U+E000.
120
+ * Default separator for text spanning HTML elements.
121
+ * Uses a two-character sentinel from the Unicode Private Use Area
122
+ * (U+E000 U+E001) to avoid collisions with CJK fonts, Apple emoji
123
+ * internals, PDF-to-text output, and icon fonts that repurpose U+E000.
118
124
  */
119
- export const DEFAULT_SEPARATOR = "\uE000";
125
+ export const DEFAULT_SEPARATOR = "\uE000\uE001";
120
126
  export const ESCAPED_DEFAULT_SEPARATOR = escapeStringRegexp(DEFAULT_SEPARATOR);
121
127
  /**
122
- * Returns the regex-escaped separator string for the given options.
123
- * Centralizes the common pattern of falling back to the pre-escaped default.
128
+ * Returns the regex-escaped separator string for the given options,
129
+ * wrapped in a non-capturing group so that quantifiers like `?` and `*`
130
+ * apply to the entire separator sequence (critical for multi-character
131
+ * separators like the default U+E000 U+E001).
124
132
  *
125
133
  * @param options - Object with an optional `separator` field
126
- * @returns Regex-escaped separator string
134
+ * @returns Regex-escaped separator string wrapped in `(?:...)`
127
135
  */
128
136
  export function getEscapedSeparator(options) {
129
- return options.separator
137
+ const escaped = options.separator
130
138
  ? escapeStringRegexp(options.separator)
131
139
  : ESCAPED_DEFAULT_SEPARATOR;
140
+ return `(?:${escaped})`;
132
141
  }
133
142
  /**
134
143
  * Characters that have special meaning in regular expressions.
@@ -182,21 +191,27 @@ export const SPACE_CHARS = ` ${UNICODE_SYMBOLS.NBSP}`;
182
191
  * Creates a lookbehind pattern that matches after whitespace, separator, or start of string.
183
192
  * Used for arrow patterns and other constructs that should appear at word boundaries.
184
193
  *
185
- * @param escapedSeparator - Regex-escaped separator string
186
- * @returns Pattern string: `(?<=[\\s${sep}]|^)`
194
+ * Uses alternation instead of a character class so that multi-character
195
+ * separators are matched as a sequence, not as individual characters.
196
+ *
197
+ * @param escapedSeparator - Regex-escaped separator string (may be grouped)
198
+ * @returns Pattern string: `(?<=\\s|${sep}|^)`
187
199
  */
188
200
  export function spaceBoundaryStart(escapedSeparator) {
189
- return `(?<=[\\s${escapedSeparator}]|^)`;
201
+ return `(?<=\\s|${escapedSeparator}|^)`;
190
202
  }
191
203
  /**
192
204
  * Creates a lookahead pattern that matches before whitespace, separator, or end of string.
193
205
  * Used for arrow patterns and other constructs that should appear at word boundaries.
194
206
  *
195
- * @param escapedSeparator - Regex-escaped separator string
196
- * @returns Pattern string: `(?=[\\s${sep}]|$)`
207
+ * Uses alternation instead of a character class so that multi-character
208
+ * separators are matched as a sequence, not as individual characters.
209
+ *
210
+ * @param escapedSeparator - Regex-escaped separator string (may be grouped)
211
+ * @returns Pattern string: `(?=\\s|${sep}|$)`
197
212
  */
198
213
  export function spaceBoundaryEnd(escapedSeparator) {
199
- return `(?=[\\s${escapedSeparator}]|$)`;
214
+ return `(?=\\s|${escapedSeparator}|$)`;
200
215
  }
201
216
  /**
202
217
  * Cache for compiled RegExp objects keyed by `pattern + '\0' + flags`.
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"dashes.d.ts","sourceRoot":"","sources":["../src/dashes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,CAAA;AAEvD,MAAM,WAAW,WAAW;IAC1B,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mFAAmF;IACnF,SAAS,CAAC,EAAE,SAAS,CAAA;CACtB;AAID;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,+BAA0C,CAAA;AAEpF,eAAO,MAAM,MAAM,QAKR,CAAA;AAEX,8DAA8D;AAC9D,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAuDjF;AAED,iFAAiF;AACjF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAe/E;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAkC5E;AA0ED,gCAAgC;AAChC,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAU7E"}
1
+ {"version":3,"file":"dashes.d.ts","sourceRoot":"","sources":["../src/dashes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,CAAA;AAEvD,MAAM,WAAW,WAAW;IAC1B,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mFAAmF;IACnF,SAAS,CAAC,EAAE,SAAS,CAAA;CACtB;AAID;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,+BAA0C,CAAA;AAEpF,eAAO,MAAM,MAAM,QAKR,CAAA;AAEX,8DAA8D;AAC9D,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAuDjF;AAED,iFAAiF;AACjF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAe/E;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAkC5E;AA0ED,gCAAgC;AAChC,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAU7E"}
package/dist/dashes.js CHANGED
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * Dash transformation: hyphens → em-dashes, en-dashes, minus signs.
3
3
  */
4
- import escapeStringRegexp from "escape-string-regexp";
5
4
  import { UNICODE_SYMBOLS, DEFAULT_SEPARATOR, LATIN_LETTERS, wordBoundaryStart, wordBoundaryEnd, getEscapedSeparator, cachedRegExp } from "./constants.js";
6
5
  const { EN_DASH, EM_DASH, MINUS, LEFT_DOUBLE_QUOTE, RIGHT_DOUBLE_QUOTE, LEFT_SINGLE_QUOTE, RIGHT_SINGLE_QUOTE } = UNICODE_SYMBOLS;
7
6
  /**
@@ -102,7 +101,7 @@ export function minusReplace(text, options = {}) {
102
101
  function convertParentheticalDashes(text, sep, style) {
103
102
  const localizedDash = style === "british" ? EN_DASH : EM_DASH;
104
103
  const maybeSpace = style === "british" ? " " : "";
105
- const escapedSep = escapeStringRegexp(sep);
104
+ const escapedSep = getEscapedSeparator({ separator: sep });
106
105
  // Convert spaced dashes: "word - word" or "word — word"
107
106
  // When a separator follows the dash, preserve trailing spaces (they belong to the next text segment).
108
107
  // A single plain hyphen directly before a word character (through optional separators) is a
@@ -137,7 +136,7 @@ function convertParentheticalDashes(text, sep, style) {
137
136
  * allows a space after the dash: "Don't inter— Hey! Who threw that?"
138
137
  */
139
138
  function normalizeEmDashSpacing(text, sep) {
140
- const escapedSep = escapeStringRegexp(sep);
139
+ const escapedSep = getEscapedSeparator({ separator: sep });
141
140
  // Remove all spaces around em-dashes
142
141
  text = text.replace(cachedRegExp(`(?<before>${escapedSep}?)[ ]*${EM_DASH}[ ]*(?<after>${escapedSep}?)`, "g"), `$<before>${EM_DASH}$<after>`);
143
142
  // Preserve space after em-dash at start of line (e.g., attribution)
@@ -1 +1 @@
1
- {"version":3,"file":"dashes.js","sourceRoot":"","sources":["../src/dashes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dashes.js","sourceRoot":"","sources":["../src/dashes.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -47,6 +47,10 @@ export interface TransformOptions {
47
47
  * - `"british"`: Oxford style. Converts straight quotes to smart quotes,
48
48
  * converts prime marks, and places periods/commas outside quotes.
49
49
  * Example: "Hello". and "Hello",
50
+ * - `"german"`: German style. Uses low-9 quote characters: „..." and ‚...'
51
+ * (U+201E/U+201C double, U+201A/U+2018 single). Punctuation outside quotes.
52
+ * - `"french"`: French style. Uses guillemets with NBSP padding: «\u00A0...\u00A0»
53
+ * Single quotes remain as curly quotes. Punctuation outside quotes.
50
54
  * - `"none"`: Skip all quote and punctuation transforms entirely.
51
55
  * Straight quotes, apostrophes, and prime marks are left unmodified.
52
56
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,KAAK,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAA;AACvG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,MAAM,EACN,6BAA6B,EAC7B,KAAK,WAAW,EAChB,KAAK,SAAS,GACf,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EACL,QAAQ,EACR,cAAc,EACd,WAAW,EACX,YAAY,EACZ,MAAM,EACN,OAAO,EACP,SAAS,EACT,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,KAAK,aAAa,GACnB,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,kBAAkB,EAClB,+BAA+B,EAC/B,uBAAuB,EACvB,mBAAmB,EACnB,yBAAyB,EACzB,mBAAmB,EACnB,aAAa,EACb,KAAK,EACL,UAAU,EACV,uBAAuB,EACvB,KAAK,WAAW,GACjB,MAAM,WAAW,CAAA;AAElB,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IAExB;;;;;;;;;;;;;OAaG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IAEnC;;;;;;;;;;;;;OAaG;IACH,SAAS,CAAC,EAAE,SAAS,CAAA;IAErB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IAErB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;IAEd;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAE3B;AASD,OAAO,EAAE,qBAAqB,EAAE,6BAA6B,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAClG,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AACnE,eAAO,MAAM,0BAA0B,KAA6C,CAAA;AAiDpF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAmE9E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,KAAK,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAA;AACvG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,MAAM,EACN,6BAA6B,EAC7B,KAAK,WAAW,EAChB,KAAK,SAAS,GACf,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EACL,QAAQ,EACR,cAAc,EACd,WAAW,EACX,YAAY,EACZ,MAAM,EACN,OAAO,EACP,SAAS,EACT,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,KAAK,aAAa,GACnB,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,kBAAkB,EAClB,+BAA+B,EAC/B,uBAAuB,EACvB,mBAAmB,EACnB,yBAAyB,EACzB,mBAAmB,EACnB,aAAa,EACb,KAAK,EACL,UAAU,EACV,uBAAuB,EACvB,KAAK,WAAW,GACjB,MAAM,WAAW,CAAA;AAElB,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IAExB;;;;;;;;;;;;;;;;;OAiBG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IAEnC;;;;;;;;;;;;;OAaG;IACH,SAAS,CAAC,EAAE,SAAS,CAAA;IAErB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IAErB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;IAEd;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAE3B;AASD,OAAO,EAAE,qBAAqB,EAAE,6BAA6B,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAClG,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AACnE,eAAO,MAAM,0BAA0B,KAA6C,CAAA;AAiDpF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAwE9E"}
package/dist/index.js CHANGED
@@ -68,12 +68,17 @@ const defaultOpts = {
68
68
  };
69
69
  export function transform(text, options = {}) {
70
70
  const separator = options.separator ?? DEFAULT_SEPARATOR;
71
- // Validate separator: must be a single UTF-16 code unit (BMP character)
72
- // Multi-codepoint characters (surrogate pairs like emoji) cause issues with regex patterns
73
- if (separator.length !== 1) {
74
- throw new Error(`Invalid separator: must be a single character. ` +
75
- `Received "${separator}" (length: ${separator.length}). ` +
76
- `Use a single-codepoint character like the default "\\uE000".`);
71
+ // Validate separator: must be non-empty and contain only BMP characters.
72
+ // for...of iterates by code point; surrogate pairs (non-BMP) yield a
73
+ // two-UTF16-unit string, so ch.length > 1 detects them.
74
+ if (separator.length === 0) {
75
+ throw new Error("Invalid separator: must not be empty.");
76
+ }
77
+ for (const ch of separator) {
78
+ if (ch.length > 1) {
79
+ throw new Error(`Invalid separator: must contain only BMP characters (no characters outside the Basic Multilingual Plane). ` +
80
+ `Received "${separator}" which contains a non-BMP character.`);
81
+ }
77
82
  }
78
83
  const original = text;
79
84
  const { symbols, fractions, degrees, superscript, ligatures, nbsp, collapseSpaces, checkIdempotency, ...separatorOpts } = { ...defaultOpts, ...options };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"nbsp.d.ts","sourceRoot":"","sources":["../src/nbsp.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAajD,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,CAAA;AAO1D;;;GAGG;AACH,eAAO,MAAM,KAAK,UA2BjB,CAAA;AAED,eAAO,MAAM,UAAU,UActB,CAAA;AAED,eAAO,MAAM,uBAAuB,UASnC,CAAA;AASD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAOnF;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAQxF;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAOlF;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAO/F;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAOvF;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAOnF;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAOzF;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAOnF;AAsBD,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAK7E"}
1
+ {"version":3,"file":"nbsp.d.ts","sourceRoot":"","sources":["../src/nbsp.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAajD,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,CAAA;AAO1D;;;GAGG;AACH,eAAO,MAAM,KAAK,UA2BjB,CAAA;AAED,eAAO,MAAM,UAAU,UActB,CAAA;AAED,eAAO,MAAM,uBAAuB,UASnC,CAAA;AASD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAOnF;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAQxF;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAQlF;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAO/F;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAOvF;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAOnF;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAOzF;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAOnF;AAsBD,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAK7E"}
package/dist/nbsp.js CHANGED
@@ -106,7 +106,8 @@ export function nbspBetweenNumberAndUnit(text, options = {}) {
106
106
  */
107
107
  export function nbspBeforeLastWord(text, options = {}) {
108
108
  const sep = getEscapedSeparator(options);
109
- const pattern = cachedRegExp(`(?<=[\\w${sep}])${SPACE}(?<lastWord>[^\\s${sep}]{1,10})(?<ending>${sep}?(?:\\n\\n|$))`, "g");
109
+ // Use alternation instead of character classes for multi-char separator support
110
+ const pattern = cachedRegExp(`(?<=\\w|${sep})${SPACE}(?<lastWord>(?:(?!\\s)(?!${sep}).){1,10})(?<ending>${sep}?(?:\\n\\n|$))`, "g");
110
111
  return text.replace(pattern, `${NBSP}$<lastWord>$<ending>`);
111
112
  }
112
113
  /**
package/dist/nbsp.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"nbsp.js","sourceRoot":"","sources":["../src/nbsp.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"nbsp.js","sourceRoot":"","sources":["../src/nbsp.ts"],"names":[],"mappings":"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"}
package/dist/quotes.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Smart quote transformation: straight quotes → curly quotes.
3
3
  */
4
- export type PunctuationStyle = "american" | "british" | "none";
4
+ export type PunctuationStyle = "american" | "british" | "german" | "french" | "none";
5
5
  export interface QuoteOptions {
6
6
  /** Boundary marker for HTML element boundaries. Default: "\uE000" */
7
7
  separator?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"quotes.d.ts","sourceRoot":"","sources":["../src/quotes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAiBH,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,CAAA;AAE9D,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;CACpC;AA8JD,+CAA+C;AAC/C,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,MAAM,CAK3E;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,MAAM,CAEpF"}
1
+ {"version":3,"file":"quotes.d.ts","sourceRoot":"","sources":["../src/quotes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAiBH,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAA;AAEpF,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;CACpC;AAqOD,+CAA+C;AAC/C,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,MAAM,CAK3E;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,MAAM,CAEpF"}
package/dist/quotes.js CHANGED
@@ -2,13 +2,13 @@
2
2
  * Smart quote transformation: straight quotes → curly quotes.
3
3
  */
4
4
  import escapeStringRegexp from "escape-string-regexp";
5
- import { UNICODE_SYMBOLS, DEFAULT_SEPARATOR, LATIN_LETTERS, TERMINAL_PUNCTUATION, cachedRegExp } from "./constants.js";
5
+ import { UNICODE_SYMBOLS, DEFAULT_SEPARATOR, LATIN_LETTERS, TERMINAL_PUNCTUATION, getEscapedSeparator, cachedRegExp } from "./constants.js";
6
6
  const { EM_DASH, LEFT_DOUBLE_QUOTE, RIGHT_DOUBLE_QUOTE, LEFT_SINGLE_QUOTE, RIGHT_SINGLE_QUOTE, MODIFIER_LETTER_APOSTROPHE, } = UNICODE_SYMBOLS;
7
7
  /** Joined string of all terminal punctuation characters for use in regex character classes. */
8
8
  const TERMINAL_PUNCTUATION_CLASS = TERMINAL_PUNCTUATION.join("");
9
9
  /** Convert straight single quotes to curly quotes and apostrophes */
10
10
  function convertSingleQuotes(text, sep) {
11
- const escapedSep = escapeStringRegexp(sep);
11
+ const escapedSep = getEscapedSeparator({ separator: sep });
12
12
  // Handle empty single quotes '' and whitespace-only quotes ' ' first
13
13
  // Only match straight quotes, not already-converted curly quotes
14
14
  const singleQuoteChars = `'${LEFT_SINGLE_QUOTE}${RIGHT_SINGLE_QUOTE}${MODIFIER_LETTER_APOSTROPHE}`;
@@ -60,8 +60,9 @@ function convertUnmatchedPluralPossessives(text, sep) {
60
60
  return match;
61
61
  }
62
62
  let i = offset - 1;
63
- while (i >= 0 && text[i] === sep)
64
- i--;
63
+ while (i >= sep.length - 1 && text.startsWith(sep, i - sep.length + 1)) {
64
+ i -= sep.length;
65
+ }
65
66
  if (i >= 0 && (text[i] === "s" || text[i] === "S")) {
66
67
  return MODIFIER_LETTER_APOSTROPHE;
67
68
  }
@@ -70,13 +71,14 @@ function convertUnmatchedPluralPossessives(text, sep) {
70
71
  }
71
72
  /** Convert straight double quotes to curly quotes */
72
73
  function convertDoubleQuotes(text, sep) {
73
- const escapedSep = escapeStringRegexp(sep);
74
+ const rawEscSep = escapeStringRegexp(sep);
75
+ const escapedSep = getEscapedSeparator({ separator: sep });
74
76
  // Handle empty quotes "" first - match only when not part of adjacent quotes
75
77
  // Require word boundary or start/end of string on at least one side
76
78
  text = text.replace(/(?<=^|[\s([{])""(?=$|[\s)\]}.!?,;:])/g, `${LEFT_DOUBLE_QUOTE}${RIGHT_DOUBLE_QUOTE}`);
77
79
  // Handle whitespace-only quotes " " - require non-quote chars on both sides
78
80
  text = text.replace(/(?<=^|[\s([{])"(?<whitespace>\s+)"(?=$|[\s)\]}.!?,;:])/g, `${LEFT_DOUBLE_QUOTE}$<whitespace>${RIGHT_DOUBLE_QUOTE}`);
79
- const beginningDouble = cachedRegExp(`(?<=^|[\\s\\(\\/\\[\\{\\-${EM_DASH}${escapedSep}])(?<beforeChr>${escapedSep}?)["](?<afterChr>(?<sepWithPunct>${escapedSep}[ .,])|(?=${escapedSep}?\\.{3}|${escapedSep}?[^\\s\\)\\${EM_DASH},!?${escapedSep};:.\\}]))`, "gm");
81
+ const beginningDouble = cachedRegExp(`(?<=^|[\\s\\(\\/\\[\\{\\-${EM_DASH}]|${escapedSep})(?<beforeChr>${escapedSep}?)["](?<afterChr>(?<sepWithPunct>${escapedSep}[ .,])|(?=${escapedSep}?\\.{3}|${escapedSep}?[^\\s\\)${EM_DASH},!?;:.\\}${rawEscSep}]))`, "gm");
80
82
  text = text.replace(beginningDouble, `$<beforeChr>${LEFT_DOUBLE_QUOTE}$<afterChr>`);
81
83
  text = text.replace(cachedRegExp(`(?<=\\{)(?<sepSpace>${escapedSep}? )?["]`, "g"), `$<sepSpace>${LEFT_DOUBLE_QUOTE}`);
82
84
  const endingDouble = `(?<beforeQuote>[^\\s\\(])["]((?<sepAfter>${escapedSep})?)(?=${escapedSep}|[\\s/\\).,;${EM_DASH}:\\-\\}!?s]|$)`;
@@ -87,7 +89,7 @@ function convertDoubleQuotes(text, sep) {
87
89
  }
88
90
  /** Apply American or British punctuation style */
89
91
  function applyPunctuationStyle(text, sep, style) {
90
- const escapedSep = escapeStringRegexp(sep);
92
+ const escapedSep = getEscapedSeparator({ separator: sep });
91
93
  if (style === "american") {
92
94
  // Period outside → inside: "Hello". → "Hello."
93
95
  const periodOutsideRegex = cachedRegExp(`(?<![${TERMINAL_PUNCTUATION_CLASS}])(?<sepBefore>${escapedSep}?)(?<quote>[${RIGHT_SINGLE_QUOTE}${RIGHT_DOUBLE_QUOTE}])(?<sepAfter>${escapedSep}?)(?!\\.\\.\\.)\\.`, "g");
@@ -96,7 +98,7 @@ function applyPunctuationStyle(text, sep, style) {
96
98
  const commaOutsideRegex = cachedRegExp(`(?<![${TERMINAL_PUNCTUATION_CLASS}])(?<sepBefore>${escapedSep}?)(?<quote>[${RIGHT_SINGLE_QUOTE}${RIGHT_DOUBLE_QUOTE}])(?<sepAfter>${escapedSep}?),`, "g");
97
99
  text = text.replace(commaOutsideRegex, "$<sepBefore>,$<quote>$<sepAfter>");
98
100
  }
99
- else if (style === "british") {
101
+ else if (style === "british" || style === "german" || style === "french") {
100
102
  // Period inside → outside: "Hello." → "Hello".
101
103
  // No terminal punctuation guard — "Stop!." inside is always wrong; move the period out.
102
104
  const periodInsideRegex = cachedRegExp(`(?<sepBefore>${escapedSep}?)\\.(?<sepMiddle>${escapedSep}?)(?<quote>[${RIGHT_SINGLE_QUOTE}${RIGHT_DOUBLE_QUOTE}])`, "g");
@@ -107,15 +109,79 @@ function applyPunctuationStyle(text, sep, style) {
107
109
  }
108
110
  return text;
109
111
  }
112
+ /**
113
+ * Normalize German quotes back to American for idempotent re-processing.
114
+ * Tracks „..." (U+201E/U+201C) and ‚...' (U+201A/U+2018) pairs so that
115
+ * the ambiguous closer characters are mapped to the correct American equivalents.
116
+ */
117
+ function normalizeGermanQuotes(text) {
118
+ const DLQ = UNICODE_SYMBOLS.DOUBLE_LOW_9_QUOTE;
119
+ const SLQ = UNICODE_SYMBOLS.SINGLE_LOW_9_QUOTE;
120
+ let result = "";
121
+ let doubleDepth = 0;
122
+ let singleDepth = 0;
123
+ for (const ch of text) {
124
+ if (ch === DLQ) {
125
+ result += LEFT_DOUBLE_QUOTE;
126
+ doubleDepth++;
127
+ }
128
+ else if (ch === LEFT_DOUBLE_QUOTE && doubleDepth > 0) {
129
+ result += RIGHT_DOUBLE_QUOTE;
130
+ doubleDepth--;
131
+ }
132
+ else if (ch === SLQ) {
133
+ result += LEFT_SINGLE_QUOTE;
134
+ singleDepth++;
135
+ }
136
+ else if (ch === LEFT_SINGLE_QUOTE && singleDepth > 0) {
137
+ result += RIGHT_SINGLE_QUOTE;
138
+ singleDepth--;
139
+ }
140
+ else {
141
+ result += ch;
142
+ }
143
+ }
144
+ return result;
145
+ }
146
+ /** Remap American curly quotes to German low-9 style. Safe because apostrophes are still MLA at this stage. */
147
+ function applyGermanQuotes(text) {
148
+ return text
149
+ .replaceAll(LEFT_DOUBLE_QUOTE, UNICODE_SYMBOLS.DOUBLE_LOW_9_QUOTE)
150
+ .replaceAll(RIGHT_DOUBLE_QUOTE, LEFT_DOUBLE_QUOTE)
151
+ .replaceAll(LEFT_SINGLE_QUOTE, UNICODE_SYMBOLS.SINGLE_LOW_9_QUOTE)
152
+ .replaceAll(RIGHT_SINGLE_QUOTE, LEFT_SINGLE_QUOTE);
153
+ }
154
+ /** Normalize French guillemets back to American for idempotent re-processing. */
155
+ function normalizeFrenchQuotes(text) {
156
+ return text
157
+ .replace(cachedRegExp(`${UNICODE_SYMBOLS.LEFT_GUILLEMET}${UNICODE_SYMBOLS.NBSP}?`, "g"), LEFT_DOUBLE_QUOTE)
158
+ .replace(cachedRegExp(`${UNICODE_SYMBOLS.NBSP}?${UNICODE_SYMBOLS.RIGHT_GUILLEMET}`, "g"), RIGHT_DOUBLE_QUOTE);
159
+ }
160
+ /** Remap American curly double quotes to French guillemets with NBSP padding. */
161
+ function applyFrenchQuotes(text) {
162
+ return text
163
+ .replaceAll(LEFT_DOUBLE_QUOTE, `${UNICODE_SYMBOLS.LEFT_GUILLEMET}${UNICODE_SYMBOLS.NBSP}`)
164
+ .replaceAll(RIGHT_DOUBLE_QUOTE, `${UNICODE_SYMBOLS.NBSP}${UNICODE_SYMBOLS.RIGHT_GUILLEMET}`);
165
+ }
166
+ /** Locale-specific normalize (pre-pipeline) and apply (post-pipeline) functions. */
167
+ const localeQuoteTransforms = {
168
+ german: { normalize: normalizeGermanQuotes, apply: applyGermanQuotes },
169
+ french: { normalize: normalizeFrenchQuotes, apply: applyFrenchQuotes },
170
+ };
110
171
  /** Shared quote-processing pipeline. Returns text with MLA for apostrophes. */
111
172
  function processQuotes(text, options) {
112
173
  const sep = options.separator ?? DEFAULT_SEPARATOR;
113
174
  const punctuationStyle = options.punctuationStyle ?? "american";
114
175
  if (punctuationStyle === "none")
115
176
  return text;
177
+ const locale = localeQuoteTransforms[punctuationStyle];
178
+ if (locale)
179
+ text = locale.normalize(text);
116
180
  text = convertSingleQuotes(text, sep);
117
181
  text = convertDoubleQuotes(text, sep);
118
182
  text = applyPunctuationStyle(text, sep, punctuationStyle);
183
+ if (locale)
184
+ text = locale.apply(text);
119
185
  return text;
120
186
  }
121
187
  /** Convert straight quotes to smart quotes. */
@@ -1 +1 @@
1
- {"version":3,"file":"quotes.js","sourceRoot":"","sources":["../src/quotes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"quotes.js","sourceRoot":"","sources":["../src/quotes.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAkBxE;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAWnF;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE,MAA0B,GAAG,MAAM,CAM3F;AAED;;;;;;;;;GASG;AACH,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,SAAS,GAAE,MAA0B,EACrC,aAAa,GAAE,MAAoB,GAClC,IAAI,CAUN"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAkBxE;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAanF;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE,MAA0B,GAAG,MAAM,CAQ3F;AAED;;;;;;;;;GASG;AACH,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,SAAS,GAAE,MAA0B,EACrC,aAAa,GAAE,MAAoB,GAClC,IAAI,CAUN"}
package/dist/utils.js CHANGED
@@ -41,17 +41,20 @@ export function assertSeparatorAbsent(textValues, separator) {
41
41
  for (const value of textValues) {
42
42
  if (!value.includes(separator))
43
43
  continue;
44
- const codePoint = `U+${separator.codePointAt(0).toString(16).toUpperCase().padStart(4, "0")}`;
45
- throw new Error(`Text contains the separator character ${codePoint} which is used internally by punctilio ` +
46
- `to track element boundaries. Pass a different character via the "separator" option.\n` +
44
+ const codePoints = [...separator]
45
+ .map(ch => `U+${ch.codePointAt(0).toString(16).toUpperCase().padStart(4, "0")}`)
46
+ .join(" ");
47
+ throw new Error(`Text contains the separator sequence ${codePoints} which is used internally by punctilio ` +
48
+ `to track element boundaries. Pass a different separator via the "separator" option.\n` +
47
49
  `Text: ${formatErrorString(value, "input")}`);
48
50
  }
49
51
  }
50
52
  export function countSeparators(text, separator = DEFAULT_SEPARATOR) {
51
53
  let count = 0;
52
- for (const char of text) {
53
- if (char === separator)
54
- count++;
54
+ let index = 0;
55
+ while ((index = text.indexOf(separator, index)) !== -1) {
56
+ count++;
57
+ index += separator.length;
55
58
  }
56
59
  return count;
57
60
  }
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAElD,qEAAqE;AACrE,MAAM,sBAAsB,GAAG,IAAI,CAAA;AAEnC;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe,EAAE,KAAa;IAC9D,IAAI,OAAO,CAAC,MAAM,IAAI,sBAAsB,EAAE,CAAC;QAC7C,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;IAChC,CAAC;IAED,yDAAyD;IACzD,IAAI,CAAC;QACH,IAAI,OAAO,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,KAAK,UAAU,EAAE,CAAC;YAC5D,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAC7B,gBAAgB,KAAK,kBAAkB,OAAO,CAAC,MAAM,cAAc,OAAO,MAAM,CACjF,CAAA;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,gDAAgD;IAClD,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,sBAAsB,CAAC,CAAA;IAC1D,OAAO,IAAI,KAAK,KAAK,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,OAAO,CAAC,MAAM,gBAAgB,CAAA;AACtF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,UAAoB,EAAE,SAAiB;IAC3E,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;QAC/B,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC;YAAE,SAAQ;QAExC,MAAM,SAAS,GAAG,KAAK,SAAS,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAA;QAC9F,MAAM,IAAI,KAAK,CACb,yCAAyC,SAAS,yCAAyC;YAC3F,uFAAuF;YACvF,SAAS,iBAAiB,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAC7C,CAAA;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,YAAoB,iBAAiB;IACjF,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;QACxB,IAAI,IAAI,KAAK,SAAS;YAAE,KAAK,EAAE,CAAA;IACjC,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,6BAA6B,CAC3C,QAAgB,EAChB,WAAmB,EACnB,YAAoB,iBAAiB,EACrC,gBAAwB,WAAW;IAEnC,MAAM,aAAa,GAAG,eAAe,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;IAC1D,MAAM,gBAAgB,GAAG,eAAe,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;IAChE,IAAI,aAAa,KAAK,gBAAgB,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CACb,GAAG,aAAa,sCAAsC,aAAa,SAAS,gBAAgB,KAAK;YACjG,4GAA4G;YAC5G,gDAAgD,CACjD,CAAA;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAElD,qEAAqE;AACrE,MAAM,sBAAsB,GAAG,IAAI,CAAA;AAEnC;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe,EAAE,KAAa;IAC9D,IAAI,OAAO,CAAC,MAAM,IAAI,sBAAsB,EAAE,CAAC;QAC7C,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;IAChC,CAAC;IAED,yDAAyD;IACzD,IAAI,CAAC;QACH,IAAI,OAAO,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,KAAK,UAAU,EAAE,CAAC;YAC5D,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAC7B,gBAAgB,KAAK,kBAAkB,OAAO,CAAC,MAAM,cAAc,OAAO,MAAM,CACjF,CAAA;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,gDAAgD;IAClD,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,sBAAsB,CAAC,CAAA;IAC1D,OAAO,IAAI,KAAK,KAAK,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,OAAO,CAAC,MAAM,gBAAgB,CAAA;AACtF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,UAAoB,EAAE,SAAiB;IAC3E,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;QAC/B,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC;YAAE,SAAQ;QAExC,MAAM,UAAU,GAAG,CAAC,GAAG,SAAS,CAAC;aAC9B,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;aAChF,IAAI,CAAC,GAAG,CAAC,CAAA;QACZ,MAAM,IAAI,KAAK,CACb,wCAAwC,UAAU,yCAAyC;YAC3F,uFAAuF;YACvF,SAAS,iBAAiB,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAC7C,CAAA;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,YAAoB,iBAAiB;IACjF,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QACvD,KAAK,EAAE,CAAA;QACP,KAAK,IAAI,SAAS,CAAC,MAAM,CAAA;IAC3B,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,6BAA6B,CAC3C,QAAgB,EAChB,WAAmB,EACnB,YAAoB,iBAAiB,EACrC,gBAAwB,WAAW;IAEnC,MAAM,aAAa,GAAG,eAAe,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;IAC1D,MAAM,gBAAgB,GAAG,eAAe,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;IAChE,IAAI,aAAa,KAAK,gBAAgB,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CACb,GAAG,aAAa,sCAAsC,aAAa,SAAS,gBAAgB,KAAK;YACjG,4GAA4G;YAC5G,gDAAgD,CACjD,CAAA;IACH,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "punctilio",
3
- "version": "3.0.10",
3
+ "version": "3.1.1",
4
4
  "description": "Smart typography transformations: curly quotes, em-dashes, en-dashes, and more",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -68,6 +68,7 @@
68
68
  "eslint-plugin-regexp": "^3.0.0",
69
69
  "hastscript": "9.0.1",
70
70
  "jest": "^29.7.0",
71
+ "lint-staged": "16.3.2",
71
72
  "rehype-parse": "9.0.1",
72
73
  "rehype-stringify": "10.0.1",
73
74
  "remark-gfm": "^4.0.1",
@@ -104,6 +105,9 @@
104
105
  "escape-string-regexp": "5.0.0",
105
106
  "unist-util-visit-parents": "^6.0.1"
106
107
  },
108
+ "lint-staged": {
109
+ "*.{ts,js,mjs}": "eslint --fix"
110
+ },
107
111
  "scripts": {
108
112
  "build": "tsc",
109
113
  "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
package/src/constants.ts CHANGED
@@ -54,6 +54,10 @@ export const UNICODE_SYMBOLS = {
54
54
  RIGHT_SINGLE_QUOTE: "\u2019",
55
55
  MODIFIER_LETTER_APOSTROPHE: "\u02BC",
56
56
  NBSP: "\u00A0",
57
+ DOUBLE_LOW_9_QUOTE: "\u201E", // „
58
+ SINGLE_LOW_9_QUOTE: "\u201A", // ‚
59
+ LEFT_GUILLEMET: "\u00AB", // «
60
+ RIGHT_GUILLEMET: "\u00BB", // »
57
61
  // Superscript ordinal suffixes
58
62
  SUPERSCRIPT_ST: "\u02E2\u1D57", // ˢᵗ
59
63
  SUPERSCRIPT_ND: "\u207F\u1D48", // ⁿᵈ
@@ -118,23 +122,28 @@ export const TERMINAL_PUNCTUATION = [
118
122
  export const LATIN_LETTERS = "A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u00FF\\u0100-\\u017F\\u0180-\\u024F"
119
123
 
120
124
  /**
121
- * Default separator character for text spanning HTML elements.
122
- * Uses Unicode Private Use Area character U+E000.
125
+ * Default separator for text spanning HTML elements.
126
+ * Uses a two-character sentinel from the Unicode Private Use Area
127
+ * (U+E000 U+E001) to avoid collisions with CJK fonts, Apple emoji
128
+ * internals, PDF-to-text output, and icon fonts that repurpose U+E000.
123
129
  */
124
- export const DEFAULT_SEPARATOR = "\uE000"
130
+ export const DEFAULT_SEPARATOR = "\uE000\uE001"
125
131
  export const ESCAPED_DEFAULT_SEPARATOR = escapeStringRegexp(DEFAULT_SEPARATOR)
126
132
 
127
133
  /**
128
- * Returns the regex-escaped separator string for the given options.
129
- * Centralizes the common pattern of falling back to the pre-escaped default.
134
+ * Returns the regex-escaped separator string for the given options,
135
+ * wrapped in a non-capturing group so that quantifiers like `?` and `*`
136
+ * apply to the entire separator sequence (critical for multi-character
137
+ * separators like the default U+E000 U+E001).
130
138
  *
131
139
  * @param options - Object with an optional `separator` field
132
- * @returns Regex-escaped separator string
140
+ * @returns Regex-escaped separator string wrapped in `(?:...)`
133
141
  */
134
142
  export function getEscapedSeparator(options: { separator?: string }): string {
135
- return options.separator
143
+ const escaped = options.separator
136
144
  ? escapeStringRegexp(options.separator)
137
145
  : ESCAPED_DEFAULT_SEPARATOR
146
+ return `(?:${escaped})`
138
147
  }
139
148
 
140
149
  /**
@@ -193,22 +202,28 @@ export const SPACE_CHARS = ` ${UNICODE_SYMBOLS.NBSP}`
193
202
  * Creates a lookbehind pattern that matches after whitespace, separator, or start of string.
194
203
  * Used for arrow patterns and other constructs that should appear at word boundaries.
195
204
  *
196
- * @param escapedSeparator - Regex-escaped separator string
197
- * @returns Pattern string: `(?<=[\\s${sep}]|^)`
205
+ * Uses alternation instead of a character class so that multi-character
206
+ * separators are matched as a sequence, not as individual characters.
207
+ *
208
+ * @param escapedSeparator - Regex-escaped separator string (may be grouped)
209
+ * @returns Pattern string: `(?<=\\s|${sep}|^)`
198
210
  */
199
211
  export function spaceBoundaryStart(escapedSeparator: string): string {
200
- return `(?<=[\\s${escapedSeparator}]|^)`
212
+ return `(?<=\\s|${escapedSeparator}|^)`
201
213
  }
202
214
 
203
215
  /**
204
216
  * Creates a lookahead pattern that matches before whitespace, separator, or end of string.
205
217
  * Used for arrow patterns and other constructs that should appear at word boundaries.
206
218
  *
207
- * @param escapedSeparator - Regex-escaped separator string
208
- * @returns Pattern string: `(?=[\\s${sep}]|$)`
219
+ * Uses alternation instead of a character class so that multi-character
220
+ * separators are matched as a sequence, not as individual characters.
221
+ *
222
+ * @param escapedSeparator - Regex-escaped separator string (may be grouped)
223
+ * @returns Pattern string: `(?=\\s|${sep}|$)`
209
224
  */
210
225
  export function spaceBoundaryEnd(escapedSeparator: string): string {
211
- return `(?=[\\s${escapedSeparator}]|$)`
226
+ return `(?=\\s|${escapedSeparator}|$)`
212
227
  }
213
228
 
214
229
  /**
package/src/dashes.ts CHANGED
@@ -2,7 +2,6 @@
2
2
  * Dash transformation: hyphens → em-dashes, en-dashes, minus signs.
3
3
  */
4
4
 
5
- import escapeStringRegexp from "escape-string-regexp"
6
5
  import { UNICODE_SYMBOLS, DEFAULT_SEPARATOR, LATIN_LETTERS, wordBoundaryStart, wordBoundaryEnd, getEscapedSeparator, cachedRegExp } from "./constants.js"
7
6
 
8
7
  export type DashStyle = "american" | "british" | "none"
@@ -150,7 +149,7 @@ export function minusReplace(text: string, options: DashOptions = {}): string {
150
149
  function convertParentheticalDashes(text: string, sep: string, style: DashStyle): string {
151
150
  const localizedDash = style === "british" ? EN_DASH : EM_DASH
152
151
  const maybeSpace = style === "british" ? " " : ""
153
- const escapedSep = escapeStringRegexp(sep)
152
+ const escapedSep = getEscapedSeparator({ separator: sep })
154
153
 
155
154
  // Convert spaced dashes: "word - word" or "word — word"
156
155
  // When a separator follows the dash, preserve trailing spaces (they belong to the next text segment).
@@ -198,7 +197,7 @@ function convertParentheticalDashes(text: string, sep: string, style: DashStyle)
198
197
  * allows a space after the dash: "Don't inter— Hey! Who threw that?"
199
198
  */
200
199
  function normalizeEmDashSpacing(text: string, sep: string): string {
201
- const escapedSep = escapeStringRegexp(sep)
200
+ const escapedSep = getEscapedSeparator({ separator: sep })
202
201
 
203
202
  // Remove all spaces around em-dashes
204
203
  text = text.replace(
package/src/index.ts CHANGED
@@ -89,6 +89,10 @@ export interface TransformOptions {
89
89
  * - `"british"`: Oxford style. Converts straight quotes to smart quotes,
90
90
  * converts prime marks, and places periods/commas outside quotes.
91
91
  * Example: "Hello". and "Hello",
92
+ * - `"german"`: German style. Uses low-9 quote characters: „..." and ‚...'
93
+ * (U+201E/U+201C double, U+201A/U+2018 single). Punctuation outside quotes.
94
+ * - `"french"`: French style. Uses guillemets with NBSP padding: «\u00A0...\u00A0»
95
+ * Single quotes remain as curly quotes. Punctuation outside quotes.
92
96
  * - `"none"`: Skip all quote and punctuation transforms entirely.
93
97
  * Straight quotes, apostrophes, and prime marks are left unmodified.
94
98
  *
@@ -218,14 +222,19 @@ const defaultOpts: Required<Omit<TransformOptions, "separator">> = {
218
222
  export function transform(text: string, options: TransformOptions = {}): string {
219
223
  const separator = options.separator ?? DEFAULT_SEPARATOR
220
224
 
221
- // Validate separator: must be a single UTF-16 code unit (BMP character)
222
- // Multi-codepoint characters (surrogate pairs like emoji) cause issues with regex patterns
223
- if (separator.length !== 1) {
224
- throw new Error(
225
- `Invalid separator: must be a single character. ` +
226
- `Received "${separator}" (length: ${separator.length}). ` +
227
- `Use a single-codepoint character like the default "\\uE000".`
228
- )
225
+ // Validate separator: must be non-empty and contain only BMP characters.
226
+ // for...of iterates by code point; surrogate pairs (non-BMP) yield a
227
+ // two-UTF16-unit string, so ch.length > 1 detects them.
228
+ if (separator.length === 0) {
229
+ throw new Error("Invalid separator: must not be empty.")
230
+ }
231
+ for (const ch of separator) {
232
+ if (ch.length > 1) {
233
+ throw new Error(
234
+ `Invalid separator: must contain only BMP characters (no characters outside the Basic Multilingual Plane). ` +
235
+ `Received "${separator}" which contains a non-BMP character.`
236
+ )
237
+ }
229
238
  }
230
239
 
231
240
  const original = text
package/src/nbsp.ts CHANGED
@@ -135,8 +135,9 @@ export function nbspBetweenNumberAndUnit(text: string, options: NbspOptions = {}
135
135
  */
136
136
  export function nbspBeforeLastWord(text: string, options: NbspOptions = {}): string {
137
137
  const sep = getEscapedSeparator(options)
138
+ // Use alternation instead of character classes for multi-char separator support
138
139
  const pattern = cachedRegExp(
139
- `(?<=[\\w${sep}])${SPACE}(?<lastWord>[^\\s${sep}]{1,10})(?<ending>${sep}?(?:\\n\\n|$))`,
140
+ `(?<=\\w|${sep})${SPACE}(?<lastWord>(?:(?!\\s)(?!${sep}).){1,10})(?<ending>${sep}?(?:\\n\\n|$))`,
140
141
  "g"
141
142
  )
142
143
  return text.replace(pattern, `${NBSP}$<lastWord>$<ending>`)
package/src/quotes.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  import escapeStringRegexp from "escape-string-regexp"
6
- import { UNICODE_SYMBOLS, DEFAULT_SEPARATOR, LATIN_LETTERS, TERMINAL_PUNCTUATION, cachedRegExp } from "./constants.js"
6
+ import { UNICODE_SYMBOLS, DEFAULT_SEPARATOR, LATIN_LETTERS, TERMINAL_PUNCTUATION, getEscapedSeparator, cachedRegExp } from "./constants.js"
7
7
 
8
8
  const {
9
9
  EM_DASH,
@@ -17,7 +17,7 @@ const {
17
17
  /** Joined string of all terminal punctuation characters for use in regex character classes. */
18
18
  const TERMINAL_PUNCTUATION_CLASS = TERMINAL_PUNCTUATION.join("")
19
19
 
20
- export type PunctuationStyle = "american" | "british" | "none"
20
+ export type PunctuationStyle = "american" | "british" | "german" | "french" | "none"
21
21
 
22
22
  export interface QuoteOptions {
23
23
  /** Boundary marker for HTML element boundaries. Default: "\uE000" */
@@ -28,7 +28,7 @@ export interface QuoteOptions {
28
28
 
29
29
  /** Convert straight single quotes to curly quotes and apostrophes */
30
30
  function convertSingleQuotes(text: string, sep: string): string {
31
- const escapedSep = escapeStringRegexp(sep)
31
+ const escapedSep = getEscapedSeparator({ separator: sep })
32
32
 
33
33
  // Handle empty single quotes '' and whitespace-only quotes ' ' first
34
34
  // Only match straight quotes, not already-converted curly quotes
@@ -96,7 +96,9 @@ function convertUnmatchedPluralPossessives(text: string, sep: string): string {
96
96
  return match
97
97
  }
98
98
  let i = offset - 1
99
- while (i >= 0 && text[i] === sep) i--
99
+ while (i >= sep.length - 1 && text.startsWith(sep, i - sep.length + 1)) {
100
+ i -= sep.length
101
+ }
100
102
  if (i >= 0 && (text[i] === "s" || text[i] === "S")) {
101
103
  return MODIFIER_LETTER_APOSTROPHE
102
104
  }
@@ -107,7 +109,8 @@ function convertUnmatchedPluralPossessives(text: string, sep: string): string {
107
109
 
108
110
  /** Convert straight double quotes to curly quotes */
109
111
  function convertDoubleQuotes(text: string, sep: string): string {
110
- const escapedSep = escapeStringRegexp(sep)
112
+ const rawEscSep = escapeStringRegexp(sep)
113
+ const escapedSep = getEscapedSeparator({ separator: sep })
111
114
 
112
115
  // Handle empty quotes "" first - match only when not part of adjacent quotes
113
116
  // Require word boundary or start/end of string on at least one side
@@ -116,7 +119,7 @@ function convertDoubleQuotes(text: string, sep: string): string {
116
119
  text = text.replace(/(?<=^|[\s([{])"(?<whitespace>\s+)"(?=$|[\s)\]}.!?,;:])/g, `${LEFT_DOUBLE_QUOTE}$<whitespace>${RIGHT_DOUBLE_QUOTE}`)
117
120
 
118
121
  const beginningDouble = cachedRegExp(
119
- `(?<=^|[\\s\\(\\/\\[\\{\\-${EM_DASH}${escapedSep}])(?<beforeChr>${escapedSep}?)["](?<afterChr>(?<sepWithPunct>${escapedSep}[ .,])|(?=${escapedSep}?\\.{3}|${escapedSep}?[^\\s\\)\\${EM_DASH},!?${escapedSep};:.\\}]))`,
122
+ `(?<=^|[\\s\\(\\/\\[\\{\\-${EM_DASH}]|${escapedSep})(?<beforeChr>${escapedSep}?)["](?<afterChr>(?<sepWithPunct>${escapedSep}[ .,])|(?=${escapedSep}?\\.{3}|${escapedSep}?[^\\s\\)${EM_DASH},!?;:.\\}${rawEscSep}]))`,
120
123
  "gm"
121
124
  )
122
125
  text = text.replace(beginningDouble, `$<beforeChr>${LEFT_DOUBLE_QUOTE}$<afterChr>`)
@@ -134,7 +137,7 @@ function convertDoubleQuotes(text: string, sep: string): string {
134
137
 
135
138
  /** Apply American or British punctuation style */
136
139
  function applyPunctuationStyle(text: string, sep: string, style: PunctuationStyle): string {
137
- const escapedSep = escapeStringRegexp(sep)
140
+ const escapedSep = getEscapedSeparator({ separator: sep })
138
141
 
139
142
  if (style === "american") {
140
143
  // Period outside → inside: "Hello". → "Hello."
@@ -150,7 +153,7 @@ function applyPunctuationStyle(text: string, sep: string, style: PunctuationStyl
150
153
  "g"
151
154
  )
152
155
  text = text.replace(commaOutsideRegex, "$<sepBefore>,$<quote>$<sepAfter>")
153
- } else if (style === "british") {
156
+ } else if (style === "british" || style === "german" || style === "french") {
154
157
  // Period inside → outside: "Hello." → "Hello".
155
158
  // No terminal punctuation guard — "Stop!." inside is always wrong; move the period out.
156
159
  const periodInsideRegex = cachedRegExp(
@@ -169,16 +172,84 @@ function applyPunctuationStyle(text: string, sep: string, style: PunctuationStyl
169
172
  return text
170
173
  }
171
174
 
175
+ /**
176
+ * Normalize German quotes back to American for idempotent re-processing.
177
+ * Tracks „..." (U+201E/U+201C) and ‚...' (U+201A/U+2018) pairs so that
178
+ * the ambiguous closer characters are mapped to the correct American equivalents.
179
+ */
180
+ function normalizeGermanQuotes(text: string): string {
181
+ const DLQ = UNICODE_SYMBOLS.DOUBLE_LOW_9_QUOTE
182
+ const SLQ = UNICODE_SYMBOLS.SINGLE_LOW_9_QUOTE
183
+
184
+ let result = ""
185
+ let doubleDepth = 0
186
+ let singleDepth = 0
187
+
188
+ for (const ch of text) {
189
+ if (ch === DLQ) {
190
+ result += LEFT_DOUBLE_QUOTE
191
+ doubleDepth++
192
+ } else if (ch === LEFT_DOUBLE_QUOTE && doubleDepth > 0) {
193
+ result += RIGHT_DOUBLE_QUOTE
194
+ doubleDepth--
195
+ } else if (ch === SLQ) {
196
+ result += LEFT_SINGLE_QUOTE
197
+ singleDepth++
198
+ } else if (ch === LEFT_SINGLE_QUOTE && singleDepth > 0) {
199
+ result += RIGHT_SINGLE_QUOTE
200
+ singleDepth--
201
+ } else {
202
+ result += ch
203
+ }
204
+ }
205
+
206
+ return result
207
+ }
208
+
209
+ /** Remap American curly quotes to German low-9 style. Safe because apostrophes are still MLA at this stage. */
210
+ function applyGermanQuotes(text: string): string {
211
+ return text
212
+ .replaceAll(LEFT_DOUBLE_QUOTE, UNICODE_SYMBOLS.DOUBLE_LOW_9_QUOTE)
213
+ .replaceAll(RIGHT_DOUBLE_QUOTE, LEFT_DOUBLE_QUOTE)
214
+ .replaceAll(LEFT_SINGLE_QUOTE, UNICODE_SYMBOLS.SINGLE_LOW_9_QUOTE)
215
+ .replaceAll(RIGHT_SINGLE_QUOTE, LEFT_SINGLE_QUOTE)
216
+ }
217
+
218
+ /** Normalize French guillemets back to American for idempotent re-processing. */
219
+ function normalizeFrenchQuotes(text: string): string {
220
+ return text
221
+ .replace(cachedRegExp(`${UNICODE_SYMBOLS.LEFT_GUILLEMET}${UNICODE_SYMBOLS.NBSP}?`, "g"), LEFT_DOUBLE_QUOTE)
222
+ .replace(cachedRegExp(`${UNICODE_SYMBOLS.NBSP}?${UNICODE_SYMBOLS.RIGHT_GUILLEMET}`, "g"), RIGHT_DOUBLE_QUOTE)
223
+ }
224
+
225
+ /** Remap American curly double quotes to French guillemets with NBSP padding. */
226
+ function applyFrenchQuotes(text: string): string {
227
+ return text
228
+ .replaceAll(LEFT_DOUBLE_QUOTE, `${UNICODE_SYMBOLS.LEFT_GUILLEMET}${UNICODE_SYMBOLS.NBSP}`)
229
+ .replaceAll(RIGHT_DOUBLE_QUOTE, `${UNICODE_SYMBOLS.NBSP}${UNICODE_SYMBOLS.RIGHT_GUILLEMET}`)
230
+ }
231
+
232
+ /** Locale-specific normalize (pre-pipeline) and apply (post-pipeline) functions. */
233
+ const localeQuoteTransforms: Partial<Record<PunctuationStyle, { normalize: (t: string) => string; apply: (t: string) => string }>> = {
234
+ german: { normalize: normalizeGermanQuotes, apply: applyGermanQuotes },
235
+ french: { normalize: normalizeFrenchQuotes, apply: applyFrenchQuotes },
236
+ }
237
+
172
238
  /** Shared quote-processing pipeline. Returns text with MLA for apostrophes. */
173
239
  function processQuotes(text: string, options: QuoteOptions): string {
174
240
  const sep = options.separator ?? DEFAULT_SEPARATOR
175
241
  const punctuationStyle = options.punctuationStyle ?? "american"
176
242
  if (punctuationStyle === "none") return text
177
243
 
244
+ const locale = localeQuoteTransforms[punctuationStyle]
245
+ if (locale) text = locale.normalize(text)
246
+
178
247
  text = convertSingleQuotes(text, sep)
179
248
  text = convertDoubleQuotes(text, sep)
180
249
  text = applyPunctuationStyle(text, sep, punctuationStyle)
181
250
 
251
+ if (locale) text = locale.apply(text)
252
+
182
253
  return text
183
254
  }
184
255
 
@@ -93,6 +93,31 @@ describe("transform", () => {
93
93
  })
94
94
  })
95
95
 
96
+ describe("german and french locale styles", () => {
97
+ it.each([
98
+ ['"Guten Tag"', `${UNICODE_SYMBOLS.DOUBLE_LOW_9_QUOTE}Guten Tag${LEFT_DOUBLE_QUOTE}`, { punctuationStyle: "german" as const, nbsp: false }],
99
+ ['"Bonjour"', `${UNICODE_SYMBOLS.LEFT_GUILLEMET}${NBSP}Bonjour${NBSP}${UNICODE_SYMBOLS.RIGHT_GUILLEMET}`, { punctuationStyle: "french" as const, nbsp: false }],
100
+ ["it's", `it${RIGHT_SINGLE_QUOTE}s`, { punctuationStyle: "german" as const, nbsp: false }],
101
+ ["l'homme", `l${RIGHT_SINGLE_QUOTE}homme`, { punctuationStyle: "french" as const, nbsp: false }],
102
+ ])('transforms "%s" with locale style', (input, expected, options) => {
103
+ expect(transform(input, options)).toBe(expected)
104
+ })
105
+
106
+ it("german style is idempotent", () => {
107
+ const input = '"Guten Tag"'
108
+ const first = transform(input, { punctuationStyle: "german", nbsp: false })
109
+ const second = transform(first, { punctuationStyle: "german", nbsp: false })
110
+ expect(second).toBe(first)
111
+ })
112
+
113
+ it("french style is idempotent", () => {
114
+ const input = '"Bonjour"'
115
+ const first = transform(input, { punctuationStyle: "french", nbsp: false })
116
+ const second = transform(first, { punctuationStyle: "french", nbsp: false })
117
+ expect(second).toBe(first)
118
+ })
119
+ })
120
+
96
121
  describe("collapseSpaces option", () => {
97
122
  it.each([
98
123
  ["hello world", "hello world", "multiple spaces"],
@@ -533,18 +558,17 @@ describe("transform", () => {
533
558
 
534
559
  describe("separator validation", () => {
535
560
  const invalidSeparators = [
536
- ["🎉", "emoji (multi-codepoint)"],
537
- ["ab", "multi-character"],
561
+ ["🎉", "emoji (non-BMP)"],
538
562
  ["", "empty string"],
539
563
  ] as const
540
564
 
541
565
  it.each(invalidSeparators)("rejects %s separator (%s)", (sep) => {
542
566
  expect(() => transform('"Hello"', { separator: sep, nbsp: false })).toThrow(
543
- /Invalid separator.*must be a single character/
567
+ /Invalid separator/
544
568
  )
545
569
  })
546
570
 
547
- const validSeparators = ["\uE000", "|", "\u2603"] // Default, pipe, snowman
571
+ const validSeparators = ["\uE000\uE001", "\uE000", "|", "\u2603", "ab"] // Default, single PUA, pipe, snowman, multi-char
548
572
 
549
573
  it.each(validSeparators)("accepts '%s' as separator", (sep) => {
550
574
  expect(() => transform('"Hello"', { separator: sep, nbsp: false })).not.toThrow()
@@ -559,6 +583,25 @@ describe("transform", () => {
559
583
  })
560
584
  })
561
585
 
586
+ describe("multi-character separator behavior", () => {
587
+ const sep = "\uE000\uE001"
588
+
589
+ it.each([
590
+ ["quotes with separator at boundary", `${sep}"Hello"`, `${sep}${LEFT_DOUBLE_QUOTE}Hello${RIGHT_DOUBLE_QUOTE}`],
591
+ ["em-dash with adjacent separators", `word${sep} - ${sep}word`, `word${sep}${EM_DASH}${sep}word`],
592
+ ["ellipsis with separator between dots", `a.${sep}.${sep}.`, `a\u2026${sep}${sep}`],
593
+ ["nbsp before last word with trailing separator", `Hello world${sep}`, `Hello${NBSP}world${sep}`],
594
+ ])("%s", (_desc, input, expected) => {
595
+ expect(transform(input, { separator: sep, nbsp: true })).toBe(expected)
596
+ })
597
+
598
+ it("preserves separator count through transform", () => {
599
+ const input = `${sep}"Hello"${sep} -- ${sep}world${sep}`
600
+ const result = transform(input, { separator: sep })
601
+ expect(countSeparators(result, sep)).toBe(countSeparators(input, sep))
602
+ })
603
+ })
604
+
562
605
  describe("Unicode preservation", () => {
563
606
  it.each([
564
607
  ["emoji", '"Hello 👋 World"', `${LEFT_DOUBLE_QUOTE}Hello 👋 World${RIGHT_DOUBLE_QUOTE}`],
@@ -9,6 +9,11 @@ const {
9
9
  MODIFIER_LETTER_APOSTROPHE,
10
10
  EM_DASH,
11
11
  ELLIPSIS,
12
+ DOUBLE_LOW_9_QUOTE,
13
+ SINGLE_LOW_9_QUOTE,
14
+ LEFT_GUILLEMET,
15
+ RIGHT_GUILLEMET,
16
+ NBSP,
12
17
  } = UNICODE_SYMBOLS
13
18
 
14
19
  describe("niceQuotes", () => {
@@ -631,6 +636,38 @@ describe("niceQuotes", () => {
631
636
  })
632
637
  })
633
638
 
639
+ describe("locale quotes", () => {
640
+ describe.each([
641
+ // German double quotes
642
+ ['"Guten Tag"', `${DOUBLE_LOW_9_QUOTE}Guten Tag${LEFT_DOUBLE_QUOTE}`, { punctuationStyle: "german" as const }],
643
+ ['"Hello," she said.', `${DOUBLE_LOW_9_QUOTE}Hello${LEFT_DOUBLE_QUOTE}, she said.`, { punctuationStyle: "german" as const }],
644
+ // German single quotes
645
+ ["'Hallo'", `${SINGLE_LOW_9_QUOTE}Hallo${LEFT_SINGLE_QUOTE}`, { punctuationStyle: "german" as const }],
646
+ // German apostrophes stay as RSQ (after MLA→RSQ conversion in niceQuotes)
647
+ ["it's", `it${RIGHT_SINGLE_QUOTE}s`, { punctuationStyle: "german" as const }],
648
+ // French double quotes
649
+ ['"Bonjour"', `${LEFT_GUILLEMET}${NBSP}Bonjour${NBSP}${RIGHT_GUILLEMET}`, { punctuationStyle: "french" as const }],
650
+ // French apostrophes stay as RSQ
651
+ ["l'homme", `l${RIGHT_SINGLE_QUOTE}homme`, { punctuationStyle: "french" as const }],
652
+ // Nested quotes in German
653
+ [`"She said 'hello'"`, `${DOUBLE_LOW_9_QUOTE}She said ${SINGLE_LOW_9_QUOTE}hello${LEFT_SINGLE_QUOTE}${LEFT_DOUBLE_QUOTE}`, { punctuationStyle: "german" as const }],
654
+ // French punctuation placement
655
+ ['"Bonjour," dit-il.', `${LEFT_GUILLEMET}${NBSP}Bonjour${NBSP}${RIGHT_GUILLEMET}, dit-il.`, { punctuationStyle: "french" as const }],
656
+ ])("locale quotes: %s → %s", (input, expected, options) => {
657
+ it("transforms correctly", () => {
658
+ expect(niceQuotes(input, options)).toBe(expected)
659
+ })
660
+ })
661
+
662
+ it.each([
663
+ [`${DOUBLE_LOW_9_QUOTE}Guten Tag${LEFT_DOUBLE_QUOTE}`, { punctuationStyle: "german" as const }],
664
+ [`${SINGLE_LOW_9_QUOTE}Hallo${LEFT_SINGLE_QUOTE}`, { punctuationStyle: "german" as const }],
665
+ [`${LEFT_GUILLEMET}${NBSP}Bonjour${NBSP}${RIGHT_GUILLEMET}`, { punctuationStyle: "french" as const }],
666
+ ])("locale output is idempotent: %s", (input, options) => {
667
+ expect(niceQuotes(input, options)).toBe(input)
668
+ })
669
+ })
670
+
634
671
  describe("pathological inputs", () => {
635
672
  it("handles 1500-char input without closing quote", () => {
636
673
  const input = `'${"a".repeat(1500)}`
@@ -10,9 +10,9 @@ describe("assertSeparatorAbsent", () => {
10
10
  })
11
11
 
12
12
  it.each([
13
- ["default separator", [`hello${DEFAULT_SEPARATOR}world`], DEFAULT_SEPARATOR, /U\+E000/],
13
+ ["default separator", [`hello${DEFAULT_SEPARATOR}world`], DEFAULT_SEPARATOR, /U\+E000 U\+E001/],
14
14
  ["custom separator", ["hello|world"], "|", /U\+007C/],
15
- ["separator in middle element", ["clean", `has${DEFAULT_SEPARATOR}sep`, "also clean"], DEFAULT_SEPARATOR, /separator character/],
15
+ ["separator in middle element", ["clean", `has${DEFAULT_SEPARATOR}sep`, "also clean"], DEFAULT_SEPARATOR, /separator sequence/],
16
16
  ])("throws: %s", (_desc, values, separator, expectedPattern) => {
17
17
  expect(() => assertSeparatorAbsent(values, separator)).toThrow(expectedPattern)
18
18
  })
package/src/utils.ts CHANGED
@@ -48,10 +48,12 @@ export function assertSeparatorAbsent(textValues: string[], separator: string):
48
48
  for (const value of textValues) {
49
49
  if (!value.includes(separator)) continue
50
50
 
51
- const codePoint = `U+${separator.codePointAt(0)!.toString(16).toUpperCase().padStart(4, "0")}`
51
+ const codePoints = [...separator]
52
+ .map(ch => `U+${ch.codePointAt(0)!.toString(16).toUpperCase().padStart(4, "0")}`)
53
+ .join(" ")
52
54
  throw new Error(
53
- `Text contains the separator character ${codePoint} which is used internally by punctilio ` +
54
- `to track element boundaries. Pass a different character via the "separator" option.\n` +
55
+ `Text contains the separator sequence ${codePoints} which is used internally by punctilio ` +
56
+ `to track element boundaries. Pass a different separator via the "separator" option.\n` +
55
57
  `Text: ${formatErrorString(value, "input")}`
56
58
  )
57
59
  }
@@ -59,8 +61,10 @@ export function assertSeparatorAbsent(textValues: string[], separator: string):
59
61
 
60
62
  export function countSeparators(text: string, separator: string = DEFAULT_SEPARATOR): number {
61
63
  let count = 0
62
- for (const char of text) {
63
- if (char === separator) count++
64
+ let index = 0
65
+ while ((index = text.indexOf(separator, index)) !== -1) {
66
+ count++
67
+ index += separator.length
64
68
  }
65
69
  return count
66
70
  }