punctilio 4.1.0 → 4.1.2

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
@@ -74,11 +74,7 @@ _Note on benchmark construction: I assembled the initial cases myself. I then so
74
74
  | Input | Behavior | Why |
75
75
  | :--- | :--- | :--- |
76
76
  | `'99 but 5' clearance` | `5'` stays straight | A leading apostrophe and an opening quote are indistinguishable without semantics |
77
- | Single-quoted passage over 1,000 chars | Opener becomes an apostrophe | The opener-vs-apostrophe test scans only 1,000 characters ahead for the closing quote |
78
- | `"?"` with a distant closer | Quote stays straight | Quoted-punctuation detection looks only 50 characters ahead for the closing quote |
79
- | `word’”’”’.` (5+ nested closers) | 5th-level punctuation not moved | Punctuation placement handles at most 4 consecutive closing quotes |
80
77
 
81
- Several of these bounds (the 1,000- and 50-character lookaheads, the 4-quote nesting cap) exist to keep the quote regexes provably linear-time; they could be lifted by a single-pass quote scanner.
82
78
 
83
79
  ## Test suite
84
80
 
@@ -1 +1 @@
1
- {"version":3,"file":"quotes.d.ts","sourceRoot":"","sources":["../src/quotes.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,kBAAkB,8DAA+D,CAAA;AAC9F,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAA;AAElE,MAAM,WAAW,YAAY;IAC3B,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;CACpC;AAgSD,+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":"AAWA,eAAO,MAAM,kBAAkB,8DAA+D,CAAA;AAC9F,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAA;AAElE,MAAM,WAAW,YAAY;IAC3B,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;CACpC;AAgZD,+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
@@ -1,8 +1,5 @@
1
1
  import { cachedRegExp, DEFAULT_SEPARATOR, escapeStringRegexp, getEscapedSeparator, LATIN_LETTERS, TERMINAL_PUNCTUATION, UNICODE_SYMBOLS } from "./constants.js";
2
2
  const { EM_DASH, LEFT_DOUBLE_QUOTE, RIGHT_DOUBLE_QUOTE, LEFT_SINGLE_QUOTE, RIGHT_SINGLE_QUOTE, MODIFIER_LETTER_APOSTROPHE, } = UNICODE_SYMBOLS;
3
- const TERMINAL_PUNCTUATION_CLASS = TERMINAL_PUNCTUATION.join("");
4
- // Bounded to keep punctuation-placement regexes linear on pathological inputs.
5
- const MAX_NESTED_QUOTES = 4;
6
3
  export const PUNCTUATION_STYLES = ["american", "british", "german", "french", "none"];
7
4
  function convertSingleQuotes(text, sep) {
8
5
  const escapedSep = getEscapedSeparator({ separator: sep });
@@ -13,7 +10,7 @@ function convertSingleQuotes(text, sep) {
13
10
  text = text.replace(cachedRegExp(`(?<!${singleQuoteOrWord})''(?!${singleQuoteOrWord})`, "g"), `${LEFT_SINGLE_QUOTE}${RIGHT_SINGLE_QUOTE}`);
14
11
  text = text.replace(cachedRegExp(`(?<!${singleQuoteOrWord})'(?<ws>\\s+)'(?!${singleQuoteOrWord})`, "g"), `${LEFT_SINGLE_QUOTE}$<ws>${RIGHT_SINGLE_QUOTE}`);
15
12
  const afterEndingSinglePatterns = `\\s\\.!?;,\\)${EM_DASH}\\-\\]"`;
16
- // Full pattern with optional 's' for lookahead detection in apostropheRegex
13
+ // Ending context with optional 's', for the leading-apostrophe closer scan.
17
14
  const afterEndingSingle = `(?=${escapedSep}?(?:s${escapedSep}?)?(?:[${afterEndingSinglePatterns}]|$))`;
18
15
  // Handle 'n' abbreviation (Rock 'n' Roll). Before MLA this wasn't needed —
19
16
  // the general rules produced LSQ+n+RSQ which was fine. But MLA requires both
@@ -30,11 +27,8 @@ function convertSingleQuotes(text, sep) {
30
27
  text = text.replace(cachedRegExp(closingSingle, "gm"), RIGHT_SINGLE_QUOTE);
31
28
  const contraction = `(?<=[${LATIN_LETTERS}])['${RIGHT_SINGLE_QUOTE}${MODIFIER_LETTER_APOSTROPHE}](?=${escapedSep}?[${LATIN_LETTERS}])`;
32
29
  text = text.replace(cachedRegExp(contraction, "gm"), MODIFIER_LETTER_APOSTROPHE);
33
- const apostropheWhitelist = `(?=n${MODIFIER_LETTER_APOSTROPHE} )`;
34
30
  const endQuoteNotContraction = `(?!${contraction})[${RIGHT_SINGLE_QUOTE}${MODIFIER_LETTER_APOSTROPHE}]${afterEndingSingle}`;
35
- // Limit lookahead scan to 1000 chars to prevent catastrophic backtracking on pathological inputs
36
- const apostropheRegex = cachedRegExp(`(?<=^|[^\\w])['](?:${apostropheWhitelist}|(?![^${LEFT_SINGLE_QUOTE}'\\n]{0,1000}${endQuoteNotContraction}))`, "gm");
37
- text = text.replace(apostropheRegex, MODIFIER_LETTER_APOSTROPHE);
31
+ text = convertLeadingApostrophes(text, endQuoteNotContraction);
38
32
  const beginningSingle = `(?<beforeContext>(?:^|[\\s${LEFT_DOUBLE_QUOTE}${RIGHT_DOUBLE_QUOTE}${EM_DASH}\\-\\(])${escapedSep}?)['](?=${escapedSep}?\\S)`;
39
33
  text = text.replace(cachedRegExp(beginningSingle, "gm"), `$<beforeContext>${LEFT_SINGLE_QUOTE}`);
40
34
  text = convertUnmatchedPluralPossessives(text, sep);
@@ -63,22 +57,97 @@ function convertUnmatchedPluralPossessives(text, sep) {
63
57
  return match;
64
58
  });
65
59
  }
66
- function buildBeginningDoublePattern(escapedSep, rawEscSep) {
67
- // Consuming boundary (not a lookbehind): variable-width lookbehinds
68
- // with alternation cause ReDoS. Re-emitted via $<boundary> in the replacement.
60
+ // Classifies a leading straight quote (start of line, or after a non-word char)
61
+ // as either an apostrophe/elision (U+02BC) or an opening single quote (left as a
62
+ // straight quote for `beginningSingle` to convert). A left-to-right scan replaces
63
+ // the former distance-bounded lookahead: a leading quote is an apostrophe unless
64
+ // an unbounded forward scan finds a closing single quote (RSQ/MLA in ending
65
+ // context) before reaching a line break or another single-quote opener.
66
+ function convertLeadingApostrophes(text, endQuoteNotContraction) {
67
+ const closerAhead = cachedRegExp(endQuoteNotContraction, "y");
68
+ // `Rock 'n' Roll` already produced `n${MLA} `; a leading quote before it is an
69
+ // apostrophe even though a closing single quote may follow later in the line.
70
+ const nAbbreviationAhead = cachedRegExp(`n${MODIFIER_LETTER_APOSTROPHE} `, "y");
71
+ // High-precision decade elision: a leading quote before two digits (optionally
72
+ // followed by `s`), as in `'90s` or `'99`, is always an apostrophe.
73
+ const decadeElision = cachedRegExp(`\\d\\ds?(?![${LATIN_LETTERS}\\d])`, "y");
74
+ let result = "";
75
+ for (let i = 0; i < text.length; i++) {
76
+ const char = text[i];
77
+ if (char !== "'" || (i > 0 && /\w/.test(text[i - 1]))) {
78
+ result += char;
79
+ continue;
80
+ }
81
+ decadeElision.lastIndex = i + 1;
82
+ nAbbreviationAhead.lastIndex = i + 1;
83
+ const isApostrophe = decadeElision.test(text) ||
84
+ nAbbreviationAhead.test(text) ||
85
+ !hasClosingSingleAhead(text, i + 1, closerAhead);
86
+ result += isApostrophe ? MODIFIER_LETTER_APOSTROPHE : char;
87
+ }
88
+ return result;
89
+ }
90
+ // Scans forward from `start` for a closing single quote, stopping (no closer) at
91
+ // a line break or another single-quote opener. Separators and other characters
92
+ // are transparent. O(n) amortized: each scan halts at the next single-quote char.
93
+ function hasClosingSingleAhead(text, start, closerAhead) {
94
+ for (let position = start; position < text.length; position++) {
95
+ const char = text[position];
96
+ if (char === "\n" || char === LEFT_SINGLE_QUOTE || char === "'")
97
+ return false;
98
+ closerAhead.lastIndex = position;
99
+ if (closerAhead.test(text))
100
+ return true;
101
+ }
102
+ return false;
103
+ }
104
+ // Matches an opening-position straight double quote: a boundary (start of line,
105
+ // whitespace, bracket, dash, or separator — consumed and re-emitted, since a
106
+ // variable-width alternation lookbehind would be ReDoS-prone) and an optional
107
+ // separator before the quote.
108
+ function doubleOpenerPrefix(escapedSep) {
69
109
  const boundary = `(?<boundary>^|[\\s\\(\\/\\[\\{\\-${EM_DASH}]|${escapedSep})`;
70
110
  const beforeCapture = `(?<beforeChr>${escapedSep}?)`;
111
+ return `${boundary}${beforeCapture}["]`;
112
+ }
113
+ function buildBeginningDoublePattern(escapedSep, rawEscSep) {
71
114
  // Characters that signal an ending-quote position (not valid openers)
72
115
  const endingChars = `\\s\\)${EM_DASH},!?;:.\\}${rawEscSep}`;
73
116
  const afterConditions = [
74
117
  `(?=${escapedSep}[ .,])`,
75
118
  `(?=${escapedSep}?\\.{3}|${escapedSep}?[^${endingChars}])`,
76
- // Lookahead for a closing straight quote within 50 chars — handles
77
- // quoted punctuation like "?" and "!" where the first char after the
78
- // opening quote would otherwise look like an ending-quote context
79
- `(?=[^"]{1,50}")`,
80
119
  ];
81
- return `${boundary}${beforeCapture}["](?:${afterConditions.join("|")})`;
120
+ return `${doubleOpenerPrefix(escapedSep)}(?:${afterConditions.join("|")})`;
121
+ }
122
+ // Quoted-punctuation openers like "?" or "!", where the character right after the
123
+ // opening quote looks like an ending-quote context. A left-to-right scan replaces
124
+ // the former 50-char lookahead: a boundary-position straight double quote is an
125
+ // opener when a closing straight double quote appears anywhere ahead, with at
126
+ // least one non-quote character between them.
127
+ function convertQuotedPunctuationOpeners(text, escapedSep) {
128
+ const candidate = cachedRegExp(doubleOpenerPrefix(escapedSep), "gm");
129
+ let result = "";
130
+ let copiedUpTo = 0;
131
+ for (const match of text.matchAll(candidate)) {
132
+ // The boundary and optional separator are left in place; only the straight
133
+ // quote (the final character of the match) is rewritten to an opener.
134
+ const quoteIndex = match.index + match[0].length - 1;
135
+ if (!hasClosingDoubleAhead(text, quoteIndex + 1))
136
+ continue;
137
+ result += text.slice(copiedUpTo, quoteIndex) + LEFT_DOUBLE_QUOTE;
138
+ copiedUpTo = quoteIndex + 1;
139
+ }
140
+ return result + text.slice(copiedUpTo);
141
+ }
142
+ // Scans forward for a closing straight double quote, requiring at least one
143
+ // non-quote character between `start` and it. O(n) amortized: the scan halts at
144
+ // the next double-quote character.
145
+ function hasClosingDoubleAhead(text, start) {
146
+ for (let position = start; position < text.length; position++) {
147
+ if (text[position] === '"')
148
+ return position > start;
149
+ }
150
+ return false;
82
151
  }
83
152
  function convertDoubleQuotes(text, sep) {
84
153
  const rawEscSep = escapeStringRegexp(sep);
@@ -90,6 +159,7 @@ function convertDoubleQuotes(text, sep) {
90
159
  text = text.replace(/(?<=^|[\s([{])"(?<whitespace>\s+)"(?=$|[\s)\]}.!?,;:])/g, `${LEFT_DOUBLE_QUOTE}$<whitespace>${RIGHT_DOUBLE_QUOTE}`);
91
160
  const beginningDouble = cachedRegExp(buildBeginningDoublePattern(escapedSep, rawEscSep), "gm");
92
161
  text = text.replace(beginningDouble, `$<boundary>$<beforeChr>${LEFT_DOUBLE_QUOTE}`);
162
+ text = convertQuotedPunctuationOpeners(text, escapedSep);
93
163
  text = text.replace(cachedRegExp(`(?<=\\{)(?<sepSpace>${escapedSep}? )?["]`, "g"), `$<sepSpace>${LEFT_DOUBLE_QUOTE}`);
94
164
  const endingDouble = `(?<beforeQuote>[^\\s\\(])["](?<sepAfter>${escapedSep})?(?=${escapedSep}|[\\s/\\).,;${EM_DASH}:\\-\\}!?s]|$)`;
95
165
  text = text.replace(cachedRegExp(endingDouble, "g"), `$<beforeQuote>${RIGHT_DOUBLE_QUOTE}$<sepAfter>`);
@@ -97,32 +167,70 @@ function convertDoubleQuotes(text, sep) {
97
167
  text = text.replace(cachedRegExp(`'(?=${RIGHT_DOUBLE_QUOTE})`, "gu"), RIGHT_SINGLE_QUOTE);
98
168
  return text;
99
169
  }
100
- /**
101
- * Matches punctuation OUTSIDE consecutive closing quotes (American style).
102
- * `quotes` is bounded to MAX_NESTED_QUOTES to prevent catastrophic backtracking.
103
- */
104
- function buildOutsidePunctuationRegex(escapedSep, punctuationPattern) {
105
- const closingQuoteClass = `[${RIGHT_SINGLE_QUOTE}${RIGHT_DOUBLE_QUOTE}]`;
106
- const additionalQuotes = `(?:${escapedSep}?${closingQuoteClass}){0,${MAX_NESTED_QUOTES - 1}}`;
107
- const nonTerminalLookbehind = `(?<![${TERMINAL_PUNCTUATION_CLASS}])`;
108
- const pattern = `${nonTerminalLookbehind}` +
109
- `(?<sepBefore>${escapedSep}?)` +
110
- `(?<quotes>${closingQuoteClass}${additionalQuotes})` +
111
- `(?<sepAfter>${escapedSep}?)` +
112
- punctuationPattern;
113
- return cachedRegExp(pattern, "g");
170
+ const CLOSING_QUOTES = new Set([RIGHT_SINGLE_QUOTE, RIGHT_DOUBLE_QUOTE]);
171
+ const TERMINAL_PUNCTUATION_SET = new Set(TERMINAL_PUNCTUATION);
172
+ // Consumes a run of consecutive closing quotes (RSQ/RDQ) of arbitrary depth,
173
+ // each optionally preceded by a separator, starting at `start`. Returns the
174
+ // index just past the last closing quote, or -1 if there is no run.
175
+ function scanClosingQuoteRun(text, start, sep) {
176
+ if (!CLOSING_QUOTES.has(text[start]))
177
+ return -1;
178
+ let runEnd = start + 1;
179
+ for (;;) {
180
+ let next = runEnd;
181
+ if (sep.length > 0 && text.startsWith(sep, next))
182
+ next += sep.length;
183
+ if (!CLOSING_QUOTES.has(text[next]))
184
+ break;
185
+ runEnd = next + 1;
186
+ }
187
+ return runEnd;
188
+ }
189
+ function separatorLengthAt(text, index, sep) {
190
+ return sep.length > 0 && text.startsWith(sep, index) ? sep.length : 0;
191
+ }
192
+ // Moves a period or comma from just after a run of closing quotes to just
193
+ // before it (American style: punctuation inside the quotes). A single
194
+ // left-to-right pass collects each closing-quote run of arbitrary depth — no
195
+ // nesting cap — then relocates an adjacent period/comma, treating separators as
196
+ // transparent (re-emitted in place). The move is skipped when the character
197
+ // before the run is terminal punctuation (`"Stop!".` keeps its period outside).
198
+ function movePunctuationInside(text, sep, isMovablePunctuation) {
199
+ let result = "";
200
+ let position = 0;
201
+ while (position < text.length) {
202
+ const sepBeforeLength = separatorLengthAt(text, position, sep);
203
+ const runStart = position + sepBeforeLength;
204
+ const runEnd = scanClosingQuoteRun(text, runStart, sep);
205
+ const sepAfterLength = runEnd === -1 ? 0 : separatorLengthAt(text, runEnd, sep);
206
+ const punctuationIndex = runEnd + sepAfterLength;
207
+ const precededByTerminal = position > 0 && TERMINAL_PUNCTUATION_SET.has(text[position - 1]);
208
+ if (runEnd === -1 || precededByTerminal || !isMovablePunctuation(text, punctuationIndex)) {
209
+ result += text[position];
210
+ position++;
211
+ continue;
212
+ }
213
+ const sepBefore = text.slice(position, runStart);
214
+ const run = text.slice(runStart, runEnd);
215
+ const sepAfter = text.slice(runEnd, punctuationIndex);
216
+ result += sepBefore + text[punctuationIndex] + run + sepAfter;
217
+ position = punctuationIndex + 1;
218
+ }
219
+ return result;
220
+ }
221
+ function isMovablePeriod(text, index) {
222
+ return text[index] === "." && !text.startsWith("...", index);
114
223
  }
115
- function moveOutsideToInside(text, escapedSep, replacementChar, punctuationPattern) {
116
- const regex = buildOutsidePunctuationRegex(escapedSep, punctuationPattern);
117
- return text.replace(regex, `$<sepBefore>${replacementChar}$<quotes>$<sepAfter>`);
224
+ function isMovableComma(text, index) {
225
+ return text[index] === ",";
118
226
  }
119
227
  function applyPunctuationStyle(text, sep, style) {
120
228
  const escapedSep = getEscapedSeparator({ separator: sep });
121
229
  if (style === "american") {
122
230
  // Period outside → inside: Hello". → Hello." (and Hello'". → Hello.'")
123
- text = moveOutsideToInside(text, escapedSep, ".", `(?!\\.\\.\\.)\\.`);
231
+ text = movePunctuationInside(text, sep, isMovablePeriod);
124
232
  // Comma outside → inside: Hello", → Hello,"
125
- text = moveOutsideToInside(text, escapedSep, ",", `,`);
233
+ text = movePunctuationInside(text, sep, isMovableComma);
126
234
  }
127
235
  else {
128
236
  // Every non-"american" non-"none" style (british/german/french) places
@@ -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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "punctilio",
3
- "version": "4.1.0",
3
+ "version": "4.1.2",
4
4
  "description": "Smart typography transformations: curly quotes, em-dashes, en-dashes, and more",
5
5
  "type": "module",
6
6
  "sideEffects": false,
package/src/quotes.ts CHANGED
@@ -9,11 +9,6 @@ const {
9
9
  MODIFIER_LETTER_APOSTROPHE,
10
10
  } = UNICODE_SYMBOLS
11
11
 
12
- const TERMINAL_PUNCTUATION_CLASS = TERMINAL_PUNCTUATION.join("")
13
-
14
- // Bounded to keep punctuation-placement regexes linear on pathological inputs.
15
- const MAX_NESTED_QUOTES = 4
16
-
17
12
  export const PUNCTUATION_STYLES = ["american", "british", "german", "french", "none"] as const
18
13
  export type PunctuationStyle = (typeof PUNCTUATION_STYLES)[number]
19
14
 
@@ -35,7 +30,7 @@ function convertSingleQuotes(text: string, sep: string): string {
35
30
  text = text.replace(cachedRegExp(`(?<!${singleQuoteOrWord})'(?<ws>\\s+)'(?!${singleQuoteOrWord})`, "g"), `${LEFT_SINGLE_QUOTE}$<ws>${RIGHT_SINGLE_QUOTE}`)
36
31
 
37
32
  const afterEndingSinglePatterns = `\\s\\.!?;,\\)${EM_DASH}\\-\\]"`
38
- // Full pattern with optional 's' for lookahead detection in apostropheRegex
33
+ // Ending context with optional 's', for the leading-apostrophe closer scan.
39
34
  const afterEndingSingle = `(?=${escapedSep}?(?:s${escapedSep}?)?(?:[${afterEndingSinglePatterns}]|$))`
40
35
 
41
36
  // Handle 'n' abbreviation (Rock 'n' Roll). Before MLA this wasn't needed —
@@ -57,14 +52,8 @@ function convertSingleQuotes(text: string, sep: string): string {
57
52
  const contraction = `(?<=[${LATIN_LETTERS}])['${RIGHT_SINGLE_QUOTE}${MODIFIER_LETTER_APOSTROPHE}](?=${escapedSep}?[${LATIN_LETTERS}])`
58
53
  text = text.replace(cachedRegExp(contraction, "gm"), MODIFIER_LETTER_APOSTROPHE)
59
54
 
60
- const apostropheWhitelist = `(?=n${MODIFIER_LETTER_APOSTROPHE} )`
61
55
  const endQuoteNotContraction = `(?!${contraction})[${RIGHT_SINGLE_QUOTE}${MODIFIER_LETTER_APOSTROPHE}]${afterEndingSingle}`
62
- // Limit lookahead scan to 1000 chars to prevent catastrophic backtracking on pathological inputs
63
- const apostropheRegex = cachedRegExp(
64
- `(?<=^|[^\\w])['](?:${apostropheWhitelist}|(?![^${LEFT_SINGLE_QUOTE}'\\n]{0,1000}${endQuoteNotContraction}))`,
65
- "gm"
66
- )
67
- text = text.replace(apostropheRegex, MODIFIER_LETTER_APOSTROPHE)
56
+ text = convertLeadingApostrophes(text, endQuoteNotContraction)
68
57
 
69
58
  const beginningSingle = `(?<beforeContext>(?:^|[\\s${LEFT_DOUBLE_QUOTE}${RIGHT_DOUBLE_QUOTE}${EM_DASH}\\-\\(])${escapedSep}?)['](?=${escapedSep}?\\S)`
70
59
  text = text.replace(cachedRegExp(beginningSingle, "gm"), `$<beforeContext>${LEFT_SINGLE_QUOTE}`)
@@ -101,25 +90,102 @@ function convertUnmatchedPluralPossessives(text: string, sep: string): string {
101
90
  )
102
91
  }
103
92
 
104
- function buildBeginningDoublePattern(escapedSep: string, rawEscSep: string): string {
105
- // Consuming boundary (not a lookbehind): variable-width lookbehinds
106
- // with alternation cause ReDoS. Re-emitted via $<boundary> in the replacement.
93
+ // Classifies a leading straight quote (start of line, or after a non-word char)
94
+ // as either an apostrophe/elision (U+02BC) or an opening single quote (left as a
95
+ // straight quote for `beginningSingle` to convert). A left-to-right scan replaces
96
+ // the former distance-bounded lookahead: a leading quote is an apostrophe unless
97
+ // an unbounded forward scan finds a closing single quote (RSQ/MLA in ending
98
+ // context) before reaching a line break or another single-quote opener.
99
+ function convertLeadingApostrophes(text: string, endQuoteNotContraction: string): string {
100
+ const closerAhead = cachedRegExp(endQuoteNotContraction, "y")
101
+ // `Rock 'n' Roll` already produced `n${MLA} `; a leading quote before it is an
102
+ // apostrophe even though a closing single quote may follow later in the line.
103
+ const nAbbreviationAhead = cachedRegExp(`n${MODIFIER_LETTER_APOSTROPHE} `, "y")
104
+ // High-precision decade elision: a leading quote before two digits (optionally
105
+ // followed by `s`), as in `'90s` or `'99`, is always an apostrophe.
106
+ const decadeElision = cachedRegExp(`\\d\\ds?(?![${LATIN_LETTERS}\\d])`, "y")
107
+
108
+ let result = ""
109
+ for (let i = 0; i < text.length; i++) {
110
+ const char = text[i]
111
+ if (char !== "'" || (i > 0 && /\w/.test(text[i - 1]))) {
112
+ result += char
113
+ continue
114
+ }
115
+ decadeElision.lastIndex = i + 1
116
+ nAbbreviationAhead.lastIndex = i + 1
117
+ const isApostrophe =
118
+ decadeElision.test(text) ||
119
+ nAbbreviationAhead.test(text) ||
120
+ !hasClosingSingleAhead(text, i + 1, closerAhead)
121
+ result += isApostrophe ? MODIFIER_LETTER_APOSTROPHE : char
122
+ }
123
+ return result
124
+ }
125
+
126
+ // Scans forward from `start` for a closing single quote, stopping (no closer) at
127
+ // a line break or another single-quote opener. Separators and other characters
128
+ // are transparent. O(n) amortized: each scan halts at the next single-quote char.
129
+ function hasClosingSingleAhead(text: string, start: number, closerAhead: RegExp): boolean {
130
+ for (let position = start; position < text.length; position++) {
131
+ const char = text[position]
132
+ if (char === "\n" || char === LEFT_SINGLE_QUOTE || char === "'") return false
133
+ closerAhead.lastIndex = position
134
+ if (closerAhead.test(text)) return true
135
+ }
136
+ return false
137
+ }
138
+
139
+ // Matches an opening-position straight double quote: a boundary (start of line,
140
+ // whitespace, bracket, dash, or separator — consumed and re-emitted, since a
141
+ // variable-width alternation lookbehind would be ReDoS-prone) and an optional
142
+ // separator before the quote.
143
+ function doubleOpenerPrefix(escapedSep: string): string {
107
144
  const boundary = `(?<boundary>^|[\\s\\(\\/\\[\\{\\-${EM_DASH}]|${escapedSep})`
108
145
  const beforeCapture = `(?<beforeChr>${escapedSep}?)`
146
+ return `${boundary}${beforeCapture}["]`
147
+ }
109
148
 
149
+ function buildBeginningDoublePattern(escapedSep: string, rawEscSep: string): string {
110
150
  // Characters that signal an ending-quote position (not valid openers)
111
151
  const endingChars = `\\s\\)${EM_DASH},!?;:.\\}${rawEscSep}`
112
152
 
113
153
  const afterConditions = [
114
154
  `(?=${escapedSep}[ .,])`,
115
155
  `(?=${escapedSep}?\\.{3}|${escapedSep}?[^${endingChars}])`,
116
- // Lookahead for a closing straight quote within 50 chars — handles
117
- // quoted punctuation like "?" and "!" where the first char after the
118
- // opening quote would otherwise look like an ending-quote context
119
- `(?=[^"]{1,50}")`,
120
156
  ]
121
157
 
122
- return `${boundary}${beforeCapture}["](?:${afterConditions.join("|")})`
158
+ return `${doubleOpenerPrefix(escapedSep)}(?:${afterConditions.join("|")})`
159
+ }
160
+
161
+ // Quoted-punctuation openers like "?" or "!", where the character right after the
162
+ // opening quote looks like an ending-quote context. A left-to-right scan replaces
163
+ // the former 50-char lookahead: a boundary-position straight double quote is an
164
+ // opener when a closing straight double quote appears anywhere ahead, with at
165
+ // least one non-quote character between them.
166
+ function convertQuotedPunctuationOpeners(text: string, escapedSep: string): string {
167
+ const candidate = cachedRegExp(doubleOpenerPrefix(escapedSep), "gm")
168
+ let result = ""
169
+ let copiedUpTo = 0
170
+ for (const match of text.matchAll(candidate)) {
171
+ // The boundary and optional separator are left in place; only the straight
172
+ // quote (the final character of the match) is rewritten to an opener.
173
+ const quoteIndex = match.index + match[0].length - 1
174
+ if (!hasClosingDoubleAhead(text, quoteIndex + 1)) continue
175
+ result += text.slice(copiedUpTo, quoteIndex) + LEFT_DOUBLE_QUOTE
176
+ copiedUpTo = quoteIndex + 1
177
+ }
178
+ return result + text.slice(copiedUpTo)
179
+ }
180
+
181
+ // Scans forward for a closing straight double quote, requiring at least one
182
+ // non-quote character between `start` and it. O(n) amortized: the scan halts at
183
+ // the next double-quote character.
184
+ function hasClosingDoubleAhead(text: string, start: number): boolean {
185
+ for (let position = start; position < text.length; position++) {
186
+ if (text[position] === '"') return position > start
187
+ }
188
+ return false
123
189
  }
124
190
 
125
191
  function convertDoubleQuotes(text: string, sep: string): string {
@@ -135,6 +201,8 @@ function convertDoubleQuotes(text: string, sep: string): string {
135
201
  const beginningDouble = cachedRegExp(buildBeginningDoublePattern(escapedSep, rawEscSep), "gm")
136
202
  text = text.replace(beginningDouble, `$<boundary>$<beforeChr>${LEFT_DOUBLE_QUOTE}`)
137
203
 
204
+ text = convertQuotedPunctuationOpeners(text, escapedSep)
205
+
138
206
  text = text.replace(cachedRegExp(`(?<=\\{)(?<sepSpace>${escapedSep}? )?["]`, "g"), `$<sepSpace>${LEFT_DOUBLE_QUOTE}`)
139
207
 
140
208
  const endingDouble = `(?<beforeQuote>[^\\s\\(])["](?<sepAfter>${escapedSep})?(?=${escapedSep}|[\\s/\\).,;${EM_DASH}:\\-\\}!?s]|$)`
@@ -146,31 +214,70 @@ function convertDoubleQuotes(text: string, sep: string): string {
146
214
  return text
147
215
  }
148
216
 
149
- /**
150
- * Matches punctuation OUTSIDE consecutive closing quotes (American style).
151
- * `quotes` is bounded to MAX_NESTED_QUOTES to prevent catastrophic backtracking.
152
- */
153
- function buildOutsidePunctuationRegex(escapedSep: string, punctuationPattern: string): RegExp {
154
- const closingQuoteClass = `[${RIGHT_SINGLE_QUOTE}${RIGHT_DOUBLE_QUOTE}]`
155
- const additionalQuotes = `(?:${escapedSep}?${closingQuoteClass}){0,${MAX_NESTED_QUOTES - 1}}`
156
- const nonTerminalLookbehind = `(?<![${TERMINAL_PUNCTUATION_CLASS}])`
157
- const pattern =
158
- `${nonTerminalLookbehind}` +
159
- `(?<sepBefore>${escapedSep}?)` +
160
- `(?<quotes>${closingQuoteClass}${additionalQuotes})` +
161
- `(?<sepAfter>${escapedSep}?)` +
162
- punctuationPattern
163
- return cachedRegExp(pattern, "g")
217
+ const CLOSING_QUOTES = new Set<string>([RIGHT_SINGLE_QUOTE, RIGHT_DOUBLE_QUOTE])
218
+ const TERMINAL_PUNCTUATION_SET = new Set<string>(TERMINAL_PUNCTUATION)
219
+
220
+ // Consumes a run of consecutive closing quotes (RSQ/RDQ) of arbitrary depth,
221
+ // each optionally preceded by a separator, starting at `start`. Returns the
222
+ // index just past the last closing quote, or -1 if there is no run.
223
+ function scanClosingQuoteRun(text: string, start: number, sep: string): number {
224
+ if (!CLOSING_QUOTES.has(text[start])) return -1
225
+ let runEnd = start + 1
226
+ for (;;) {
227
+ let next = runEnd
228
+ if (sep.length > 0 && text.startsWith(sep, next)) next += sep.length
229
+ if (!CLOSING_QUOTES.has(text[next])) break
230
+ runEnd = next + 1
231
+ }
232
+ return runEnd
233
+ }
234
+
235
+ function separatorLengthAt(text: string, index: number, sep: string): number {
236
+ return sep.length > 0 && text.startsWith(sep, index) ? sep.length : 0
164
237
  }
165
238
 
166
- function moveOutsideToInside(
239
+ // Moves a period or comma from just after a run of closing quotes to just
240
+ // before it (American style: punctuation inside the quotes). A single
241
+ // left-to-right pass collects each closing-quote run of arbitrary depth — no
242
+ // nesting cap — then relocates an adjacent period/comma, treating separators as
243
+ // transparent (re-emitted in place). The move is skipped when the character
244
+ // before the run is terminal punctuation (`"Stop!".` keeps its period outside).
245
+ function movePunctuationInside(
167
246
  text: string,
168
- escapedSep: string,
169
- replacementChar: string,
170
- punctuationPattern: string,
247
+ sep: string,
248
+ isMovablePunctuation: (text: string, index: number) => boolean,
171
249
  ): string {
172
- const regex = buildOutsidePunctuationRegex(escapedSep, punctuationPattern)
173
- return text.replace(regex, `$<sepBefore>${replacementChar}$<quotes>$<sepAfter>`)
250
+ let result = ""
251
+ let position = 0
252
+ while (position < text.length) {
253
+ const sepBeforeLength = separatorLengthAt(text, position, sep)
254
+ const runStart = position + sepBeforeLength
255
+ const runEnd = scanClosingQuoteRun(text, runStart, sep)
256
+ const sepAfterLength = runEnd === -1 ? 0 : separatorLengthAt(text, runEnd, sep)
257
+ const punctuationIndex = runEnd + sepAfterLength
258
+
259
+ const precededByTerminal = position > 0 && TERMINAL_PUNCTUATION_SET.has(text[position - 1])
260
+ if (runEnd === -1 || precededByTerminal || !isMovablePunctuation(text, punctuationIndex)) {
261
+ result += text[position]
262
+ position++
263
+ continue
264
+ }
265
+
266
+ const sepBefore = text.slice(position, runStart)
267
+ const run = text.slice(runStart, runEnd)
268
+ const sepAfter = text.slice(runEnd, punctuationIndex)
269
+ result += sepBefore + text[punctuationIndex] + run + sepAfter
270
+ position = punctuationIndex + 1
271
+ }
272
+ return result
273
+ }
274
+
275
+ function isMovablePeriod(text: string, index: number): boolean {
276
+ return text[index] === "." && !text.startsWith("...", index)
277
+ }
278
+
279
+ function isMovableComma(text: string, index: number): boolean {
280
+ return text[index] === ","
174
281
  }
175
282
 
176
283
  function applyPunctuationStyle(text: string, sep: string, style: PunctuationStyle): string {
@@ -178,9 +285,9 @@ function applyPunctuationStyle(text: string, sep: string, style: PunctuationStyl
178
285
 
179
286
  if (style === "american") {
180
287
  // Period outside → inside: Hello". → Hello." (and Hello'". → Hello.'")
181
- text = moveOutsideToInside(text, escapedSep, ".", `(?!\\.\\.\\.)\\.`)
288
+ text = movePunctuationInside(text, sep, isMovablePeriod)
182
289
  // Comma outside → inside: Hello", → Hello,"
183
- text = moveOutsideToInside(text, escapedSep, ",", `,`)
290
+ text = movePunctuationInside(text, sep, isMovableComma)
184
291
  } else {
185
292
  // Every non-"american" non-"none" style (british/german/french) places
186
293
  // punctuation outside the quotes.