punctilio 1.7.2 → 1.7.3

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
@@ -34,14 +34,14 @@ I tested `punctilio` 1.2.9 against [`smartypants`](https://www.npmjs.com/package
34
34
 
35
35
  My [`benchmark.mjs`](https://github.com/alexander-turner/punctilio/blob/main/benchmark.mjs) measures how well libraries handle a [wide range of scenarios](https://github.com/alexander-turner/punctilio/blob/main/benchmark_cases.json). The benchmark normalizes stylistic differences (e.g. non-breaking vs regular space, British vs American dash spacing) for fair comparison.
36
36
 
37
- | Package | Passed (of 154) |
37
+ | Package | Passed (of 159) |
38
38
  |--------:|:----------------|
39
- | `punctilio` | 149 (97%) |
40
- | `tipograph` | 88 (57%) |
41
- | `typograf` | 74 (48%) |
42
- | `smartypants` | 68 (44%) |
43
- | `smartquotes` | 67 (44%) |
44
- | `retext-smartypants` | 65 (42%) |
39
+ | `punctilio` | 154 (97%) |
40
+ | `tipograph` | 92 (58%) |
41
+ | `typograf` | 74 (47%) |
42
+ | `smartquotes` | 72 (45%) |
43
+ | `smartypants` | 68 (43%) |
44
+ | `retext-smartypants` | 65 (41%) |
45
45
 
46
46
  | Feature | Example | `punctilio` | `smartypants` | `tipograph` | `smartquotes` | `typograf` |
47
47
  |--------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|
@@ -68,8 +68,8 @@ My [`benchmark.mjs`](https://github.com/alexander-turner/punctilio/blob/main/ben
68
68
 
69
69
  | Pattern | Behavior | Notes |
70
70
  |:--------|:---------|:------|
71
- | `10' x 12'` | Second `'` not converted | Quote balancing prevents double prime conversion |
72
- | German/French quotes | Not supported | `« Bonjour »` requires language detection |
71
+ | `'Twas a 5' board` | `5'` not converted to `5′` | Leading apostrophe is indistinguishable from an opening quote without semantic understanding |
72
+ | `«Bonjour»` | Not spaced to `« Bonjour »` | French localization not supported |
73
73
 
74
74
  ## Test suite
75
75
 
@@ -1 +1 @@
1
- {"version":3,"file":"symbols.d.ts","sourceRoot":"","sources":["../src/symbols.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,MAAM,WAAW,aAAa;IAC5B,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,uDAAuD;IACvD,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AA6BD,uCAAuC;AACvC,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAe1E;AAED,gDAAgD;AAChD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAqChF;AAaD,0DAA0D;AAC1D,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKhD;AASD,yCAAyC;AACzC,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKjD;AASD,oCAAoC;AACpC,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAcxE;AAED,kFAAkF;AAClF,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAazE;AAED,sEAAsE;AACtE,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAkC5E;AAoBD,2CAA2C;AAC3C,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAoB3E;AASD,0DAA0D;AAC1D,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAkBpF;AAED,qFAAqF;AACrF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKnD;AAcD,iFAAiF;AACjF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAWtF;AAED,gFAAgF;AAChF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CASjF"}
1
+ {"version":3,"file":"symbols.d.ts","sourceRoot":"","sources":["../src/symbols.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,MAAM,WAAW,aAAa;IAC5B,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,uDAAuD;IACvD,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AA6BD,uCAAuC;AACvC,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAe1E;AAED,gDAAgD;AAChD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAqChF;AAaD,0DAA0D;AAC1D,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKhD;AASD,yCAAyC;AACzC,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKjD;AASD,oCAAoC;AACpC,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAcxE;AAED,kFAAkF;AAClF,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAazE;AAyFD,sEAAsE;AACtE,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAiB5E;AAoBD,2CAA2C;AAC3C,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAoB3E;AASD,0DAA0D;AAC1D,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAkBpF;AAED,qFAAqF;AACrF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKnD;AAcD,iFAAiF;AACjF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAWtF;AAED,gFAAgF;AAChF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CASjF"}
package/dist/symbols.js CHANGED
@@ -108,33 +108,96 @@ export function degrees(text, options = {}) {
108
108
  const wbe = wordBoundaryEnd(chr);
109
109
  return text.replace(new RegExp(`(?<num>\\d${chr}?) ?(?<unit>[CF])${wbe}`, "g"), (_, num, unit) => `${num} ${DEGREE}${unit}`);
110
110
  }
111
+ /**
112
+ * Build a regex that matches all quote characters in priority order:
113
+ * 1. Prime candidate: digit + quote + non-letter (e.g., 5', 12")
114
+ * 2. Contraction: letter + quote + letter (e.g., it's, don't, O'Brien)
115
+ * 3. Trailing apostrophe: letter + quote + non-letter (e.g., dogs')
116
+ * 4. Bare quote: anything else (typically preceded by space/start)
117
+ */
118
+ function buildQuoteClassificationPattern(escapedQuote, escapedSeparator) {
119
+ const primeCandidate = `(?<digit>\\d)(?<sep>${escapedSeparator}?)${escapedQuote}(?<afterSep>${escapedSeparator}?)(?![${LATIN_LETTERS}])`;
120
+ const contraction = `(?<=[${LATIN_LETTERS}]${escapedSeparator}?)(?<contraction>${escapedQuote})(?=${escapedSeparator}?[${LATIN_LETTERS}])`;
121
+ const trailingApostrophe = `(?<=[${LATIN_LETTERS}]${escapedSeparator}?)(?<trailing>${escapedQuote})`;
122
+ const bareQuote = escapedQuote;
123
+ return new RegExp(`${primeCandidate}|${contraction}|${trailingApostrophe}|${bareQuote}`, "g");
124
+ }
125
+ /**
126
+ * Replace callback that converts prime candidates while respecting quote balance.
127
+ * Contractions and trailing apostrophes are recognized so they don't poison the
128
+ * balance tracker. A prime candidate converts only when no unmatched opening
129
+ * quote precedes it; otherwise it acts as a closing quote.
130
+ *
131
+ * For double primes (″): since ' and " are processed in separate passes,
132
+ * 5'10" becomes 5′10" after the single-quote pass. Inside balanced double
133
+ * quotes (e.g., "He is 5′10" tall"), the balance tracker would normally treat
134
+ * the " after 10 as a closing quote. To handle this, we check whether the "
135
+ * is preceded by ′ + digits — if so, it's inches notation and converts
136
+ * regardless of balance.
137
+ */
138
+ function balancedPrimeReplacer(primeChar, escapedSeparator) {
139
+ // Pre-compile the feet-inches context pattern for the double-prime pass.
140
+ // Matches when the text before a prime candidate ends with ′ followed by
141
+ // any mix of digits and separators (e.g., "5′1" before the "0" in 5′10").
142
+ const feetInchesContext = primeChar === DOUBLE_PRIME
143
+ ? new RegExp(`${PRIME}(?:${escapedSeparator}|\\d)*$`)
144
+ : null;
145
+ let balance = 0;
146
+ return (...args) => {
147
+ const fullMatch = args[0];
148
+ const groups = args[args.length - 1];
149
+ // Contraction (letter + quote + letter): skip entirely
150
+ if (groups.contraction !== undefined) {
151
+ return fullMatch;
152
+ }
153
+ // Trailing apostrophe (letter + quote + non-letter): close if opener exists, else skip
154
+ if (groups.trailing !== undefined) {
155
+ if (balance > 0)
156
+ balance--;
157
+ return fullMatch;
158
+ }
159
+ const { digit, sep, afterSep } = groups;
160
+ if (digit !== undefined) {
161
+ // Prime candidate: convert only if no unmatched opening quote
162
+ if (balance <= 0) {
163
+ return `${digit}${sep}${primeChar}${afterSep}`;
164
+ }
165
+ // Inside balanced quotes: check if this is feet-inches notation
166
+ // (e.g., 5′10" where ″ is inches, not a closing quote)
167
+ if (feetInchesContext) {
168
+ const offset = args[args.length - 3];
169
+ const fullString = args[args.length - 2];
170
+ if (feetInchesContext.test(fullString.substring(0, offset))) {
171
+ return `${digit}${sep}${primeChar}${afterSep}`;
172
+ }
173
+ }
174
+ balance--;
175
+ return fullMatch;
176
+ }
177
+ // Bare quote (preceded by space/start): opener or closer
178
+ if (balance <= 0) {
179
+ balance = 1;
180
+ }
181
+ else {
182
+ balance--;
183
+ }
184
+ return fullMatch;
185
+ };
186
+ }
111
187
  /** Convert 5'10" to 5′10″ (prime marks). Call before smart quotes. */
112
188
  export function primeMarks(text, options = {}) {
113
- const chr = options.separator
189
+ const escapedSeparator = options.separator
114
190
  ? escapeStringRegexp(options.separator)
115
191
  : ESCAPED_DEFAULT_SEPARATOR;
116
- // Convert quotes to primes using quote balancing
117
- // Only convert if quotes are balanced (even count before) to avoid converting closing quotes
118
- // Examples: 5' → 5′ ✓, 12" → 12″ ✓, 'Term 1' → 'Term 1' ✓, "Term 1" → "Term 1" ✓
119
192
  const quotePrimePairs = [
120
193
  ["'", PRIME],
121
194
  ['"', DOUBLE_PRIME],
122
195
  ];
123
- for (const [quote, prime] of quotePrimePairs) {
124
- const pattern = new RegExp(`(?<digit>\\d)(?<sep>${chr}?)${quote}(?<afterSep>${chr}?)(?![${LATIN_LETTERS}])`, "g");
125
- const quoteCountPattern = new RegExp(escapeStringRegexp(quote), "g");
126
- text = text.replace(pattern, (match, digit, sep, afterSep, offset) => {
127
- const textBefore = text.slice(0, offset);
128
- const quoteCount = (textBefore.match(quoteCountPattern) || []).length;
129
- if (quoteCount % 2 === 0) {
130
- return `${digit}${sep}${prime}${afterSep}`;
131
- }
132
- return match;
133
- });
196
+ for (const [quote, primeChar] of quotePrimePairs) {
197
+ const escapedQuote = escapeStringRegexp(quote);
198
+ const pattern = buildQuoteClassificationPattern(escapedQuote, escapedSeparator);
199
+ text = text.replace(pattern, balancedPrimeReplacer(primeChar, escapedSeparator));
134
200
  }
135
- // Feet-inches pattern: convert " after ′ + digit (e.g., 5′10" → 5′10″)
136
- const feetInchesPattern = new RegExp(`(?<primeAndNum>${PRIME}${chr}?\\d${chr}?)"`, "g");
137
- text = text.replace(feetInchesPattern, `$<primeAndNum>${DOUBLE_PRIME}`);
138
201
  return text;
139
202
  }
140
203
  const FRACTION_MAP = {
@@ -1 +1 @@
1
- {"version":3,"file":"symbols.js","sourceRoot":"","sources":["../src/symbols.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"symbols.js","sourceRoot":"","sources":["../src/symbols.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "punctilio",
3
- "version": "1.7.2",
3
+ "version": "1.7.3",
4
4
  "description": "Smart typography transformations: curly quotes, em-dashes, en-dashes, and more",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/symbols.ts CHANGED
@@ -171,40 +171,110 @@ export function degrees(text: string, options: SymbolOptions = {}): string {
171
171
  )
172
172
  }
173
173
 
174
+ /**
175
+ * Build a regex that matches all quote characters in priority order:
176
+ * 1. Prime candidate: digit + quote + non-letter (e.g., 5', 12")
177
+ * 2. Contraction: letter + quote + letter (e.g., it's, don't, O'Brien)
178
+ * 3. Trailing apostrophe: letter + quote + non-letter (e.g., dogs')
179
+ * 4. Bare quote: anything else (typically preceded by space/start)
180
+ */
181
+ function buildQuoteClassificationPattern(
182
+ escapedQuote: string,
183
+ escapedSeparator: string
184
+ ): RegExp {
185
+ const primeCandidate = `(?<digit>\\d)(?<sep>${escapedSeparator}?)${escapedQuote}(?<afterSep>${escapedSeparator}?)(?![${LATIN_LETTERS}])`
186
+ const contraction = `(?<=[${LATIN_LETTERS}]${escapedSeparator}?)(?<contraction>${escapedQuote})(?=${escapedSeparator}?[${LATIN_LETTERS}])`
187
+ const trailingApostrophe = `(?<=[${LATIN_LETTERS}]${escapedSeparator}?)(?<trailing>${escapedQuote})`
188
+ const bareQuote = escapedQuote
189
+ return new RegExp(
190
+ `${primeCandidate}|${contraction}|${trailingApostrophe}|${bareQuote}`,
191
+ "g"
192
+ )
193
+ }
194
+
195
+ /**
196
+ * Replace callback that converts prime candidates while respecting quote balance.
197
+ * Contractions and trailing apostrophes are recognized so they don't poison the
198
+ * balance tracker. A prime candidate converts only when no unmatched opening
199
+ * quote precedes it; otherwise it acts as a closing quote.
200
+ *
201
+ * For double primes (″): since ' and " are processed in separate passes,
202
+ * 5'10" becomes 5′10" after the single-quote pass. Inside balanced double
203
+ * quotes (e.g., "He is 5′10" tall"), the balance tracker would normally treat
204
+ * the " after 10 as a closing quote. To handle this, we check whether the "
205
+ * is preceded by ′ + digits — if so, it's inches notation and converts
206
+ * regardless of balance.
207
+ */
208
+ function balancedPrimeReplacer(primeChar: string, escapedSeparator: string) {
209
+ // Pre-compile the feet-inches context pattern for the double-prime pass.
210
+ // Matches when the text before a prime candidate ends with ′ followed by
211
+ // any mix of digits and separators (e.g., "5′1" before the "0" in 5′10").
212
+ const feetInchesContext = primeChar === DOUBLE_PRIME
213
+ ? new RegExp(`${PRIME}(?:${escapedSeparator}|\\d)*$`)
214
+ : null
215
+
216
+ let balance = 0
217
+ return (...args: unknown[]) => {
218
+ const fullMatch = args[0] as string
219
+ const groups = args[args.length - 1] as Record<string, string | undefined>
220
+
221
+ // Contraction (letter + quote + letter): skip entirely
222
+ if (groups.contraction !== undefined) {
223
+ return fullMatch
224
+ }
225
+
226
+ // Trailing apostrophe (letter + quote + non-letter): close if opener exists, else skip
227
+ if (groups.trailing !== undefined) {
228
+ if (balance > 0) balance--
229
+ return fullMatch
230
+ }
231
+
232
+ const { digit, sep, afterSep } = groups
233
+ if (digit !== undefined) {
234
+ // Prime candidate: convert only if no unmatched opening quote
235
+ if (balance <= 0) {
236
+ return `${digit}${sep}${primeChar}${afterSep}`
237
+ }
238
+ // Inside balanced quotes: check if this is feet-inches notation
239
+ // (e.g., 5′10" where ″ is inches, not a closing quote)
240
+ if (feetInchesContext) {
241
+ const offset = args[args.length - 3] as number
242
+ const fullString = args[args.length - 2] as string
243
+ if (feetInchesContext.test(fullString.substring(0, offset))) {
244
+ return `${digit}${sep}${primeChar}${afterSep}`
245
+ }
246
+ }
247
+ balance--
248
+ return fullMatch
249
+ }
250
+
251
+ // Bare quote (preceded by space/start): opener or closer
252
+ if (balance <= 0) {
253
+ balance = 1
254
+ } else {
255
+ balance--
256
+ }
257
+ return fullMatch
258
+ }
259
+ }
260
+
174
261
  /** Convert 5'10" to 5′10″ (prime marks). Call before smart quotes. */
175
262
  export function primeMarks(text: string, options: SymbolOptions = {}): string {
176
- const chr = options.separator
263
+ const escapedSeparator = options.separator
177
264
  ? escapeStringRegexp(options.separator)
178
265
  : ESCAPED_DEFAULT_SEPARATOR
179
266
 
180
- // Convert quotes to primes using quote balancing
181
- // Only convert if quotes are balanced (even count before) to avoid converting closing quotes
182
- // Examples: 5' → 5′ ✓, 12" → 12″ ✓, 'Term 1' → 'Term 1' ✓, "Term 1" → "Term 1" ✓
183
- const quotePrimePairs = [
267
+ const quotePrimePairs: [string, string][] = [
184
268
  ["'", PRIME],
185
269
  ['"', DOUBLE_PRIME],
186
270
  ]
187
271
 
188
- for (const [quote, prime] of quotePrimePairs) {
189
- const pattern = new RegExp(
190
- `(?<digit>\\d)(?<sep>${chr}?)${quote}(?<afterSep>${chr}?)(?![${LATIN_LETTERS}])`,
191
- "g"
192
- )
193
- const quoteCountPattern = new RegExp(escapeStringRegexp(quote), "g")
194
- text = text.replace(pattern, (match, digit, sep, afterSep, offset) => {
195
- const textBefore = text.slice(0, offset)
196
- const quoteCount = (textBefore.match(quoteCountPattern) || []).length
197
- if (quoteCount % 2 === 0) {
198
- return `${digit}${sep}${prime}${afterSep}`
199
- }
200
- return match
201
- })
272
+ for (const [quote, primeChar] of quotePrimePairs) {
273
+ const escapedQuote = escapeStringRegexp(quote)
274
+ const pattern = buildQuoteClassificationPattern(escapedQuote, escapedSeparator)
275
+ text = text.replace(pattern, balancedPrimeReplacer(primeChar, escapedSeparator))
202
276
  }
203
277
 
204
- // Feet-inches pattern: convert " after ′ + digit (e.g., 5′10" → 5′10″)
205
- const feetInchesPattern = new RegExp(`(?<primeAndNum>${PRIME}${chr}?\\d${chr}?)"`, "g")
206
- text = text.replace(feetInchesPattern, `$<primeAndNum>${DOUBLE_PRIME}`)
207
-
208
278
  return text
209
279
  }
210
280
 
@@ -205,6 +205,19 @@ describe("primeMarks", () => {
205
205
  ["40° 44' 54\" N", `40° 44${UNICODE_SYMBOLS.PRIME} 54${UNICODE_SYMBOLS.DOUBLE_PRIME} N`],
206
206
  ['The board is 12" wide', `The board is 12${UNICODE_SYMBOLS.DOUBLE_PRIME} wide`],
207
207
  ['12" long', `12${UNICODE_SYMBOLS.DOUBLE_PRIME} long`],
208
+ // Multiple primes in one string
209
+ ["10' x 12'", `10${UNICODE_SYMBOLS.PRIME} x 12${UNICODE_SYMBOLS.PRIME}`],
210
+ ["The room is 10' x 12' x 8' tall", `The room is 10${UNICODE_SYMBOLS.PRIME} x 12${UNICODE_SYMBOLS.PRIME} x 8${UNICODE_SYMBOLS.PRIME} tall`],
211
+ ['10" x 12"', `10${UNICODE_SYMBOLS.DOUBLE_PRIME} x 12${UNICODE_SYMBOLS.DOUBLE_PRIME}`],
212
+ [`5' and 8' boards`, `5${UNICODE_SYMBOLS.PRIME} and 8${UNICODE_SYMBOLS.PRIME} boards`],
213
+ // Contractions before primes
214
+ ["it's 5' long", `it's 5${UNICODE_SYMBOLS.PRIME} long`],
215
+ ["don't measure 8'", `don't measure 8${UNICODE_SYMBOLS.PRIME}`],
216
+ ["she's 5'10\"", `she's 5${UNICODE_SYMBOLS.PRIME}10${UNICODE_SYMBOLS.DOUBLE_PRIME}`],
217
+ ["O'Brien's 6' fence", `O'Brien's 6${UNICODE_SYMBOLS.PRIME} fence`],
218
+ // Possessive plurals before primes
219
+ ["the dogs' 5' leashes", `the dogs' 5${UNICODE_SYMBOLS.PRIME} leashes`],
220
+ ["the cats' and dogs' 5' run", `the cats' and dogs' 5${UNICODE_SYMBOLS.PRIME} run`],
208
221
  ])('converts "%s" to "%s"', (input, expected) => {
209
222
  expect(primeMarks(input)).toBe(expected)
210
223
  })
@@ -226,12 +239,34 @@ describe("primeMarks", () => {
226
239
  expect(primeMarks(input)).toBe(expected)
227
240
  })
228
241
 
242
+ // Feet-inches inside balanced quotes: the balance tracker detects ′ + digits
243
+ // before a " prime candidate and converts it to ″ regardless of quote balance
244
+ it.each([
245
+ ['"He is 5\'10" tall"', `"He is 5${UNICODE_SYMBOLS.PRIME}10${UNICODE_SYMBOLS.DOUBLE_PRIME} tall"`],
246
+ ['"The shelf is 5\'11" wide"', `"The shelf is 5${UNICODE_SYMBOLS.PRIME}11${UNICODE_SYMBOLS.DOUBLE_PRIME} wide"`],
247
+ ])('feet-inches inside balanced quotes converts "%s"', (input, expected) => {
248
+ expect(primeMarks(input)).toBe(expected)
249
+ })
250
+
229
251
  it("handles separator characters", () => {
230
252
  const sep = "\uE000"
231
253
  expect(primeMarks(`5${sep}'${sep}10${sep}"`, { separator: sep })).toBe(
232
254
  `5${sep}${UNICODE_SYMBOLS.PRIME}${sep}10${sep}${UNICODE_SYMBOLS.DOUBLE_PRIME}`
233
255
  )
234
256
  })
257
+
258
+ // Separator-aware contractions: the quote classification pattern must recognize
259
+ // contractions even when separators split the word across HTML element boundaries
260
+ it.each([
261
+ // Contraction with separator before the apostrophe: it<sep>'s
262
+ [`it${"\uE000"}'${"\uE000"}s 5'`, `it${"\uE000"}'${"\uE000"}s 5${UNICODE_SYMBOLS.PRIME}`],
263
+ // Contraction with separator after the apostrophe: don't
264
+ [`don${"\uE000"}'t measure 8'`, `don${"\uE000"}'t measure 8${UNICODE_SYMBOLS.PRIME}`],
265
+ // Trailing apostrophe with separator: dogs<sep>'
266
+ [`the dogs${"\uE000"}' 5' leashes`, `the dogs${"\uE000"}' 5${UNICODE_SYMBOLS.PRIME} leashes`],
267
+ ])('separator-aware contraction/trailing in "%s"', (input, expected) => {
268
+ expect(primeMarks(input, { separator: "\uE000" })).toBe(expected)
269
+ })
235
270
  })
236
271
 
237
272
  describe("fractions", () => {
@@ -658,7 +693,7 @@ describe("prime marks edge cases", () => {
658
693
  ['100\'50"', `100${UNICODE_SYMBOLS.PRIME}50${UNICODE_SYMBOLS.DOUBLE_PRIME}`],
659
694
  ["5' boards", `5${UNICODE_SYMBOLS.PRIME} boards`],
660
695
  ['12" pipe', `12${UNICODE_SYMBOLS.DOUBLE_PRIME} pipe`],
661
- ["5', 10'", `5${UNICODE_SYMBOLS.PRIME}, 10'`],
696
+ ["5', 10'", `5${UNICODE_SYMBOLS.PRIME}, 10${UNICODE_SYMBOLS.PRIME}`],
662
697
  ])('handles prime mark edge: "%s"', (input, expected) => {
663
698
  expect(primeMarks(input)).toBe(expected)
664
699
  })