punctilio 1.7.14 → 1.8.0

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
@@ -109,7 +109,7 @@ For manual DOM walking or custom transforms, use `transformElement` from `puncti
109
109
 
110
110
  ## Options
111
111
 
112
- `punctilio` doesn’t enable all transformations by default. Fractions and degrees tend to match too aggressively (perfectly applying the degree transformation requires semantic meaning). Superscript letters and punctuation ligatures have spotty font support. Furthermore, `ligatures = true` can change the meaning of text by collapsing question and exclamation marks. Non-breaking spaces are also opt-in since they alter whitespace throughout the text.
112
+ `punctilio` doesn't enable all transformations by default. Fractions and degrees tend to match too aggressively (perfectly applying the degree transformation requires semantic meaning). Superscript letters and punctuation ligatures have spotty font support. Furthermore, `ligatures = true` can change the meaning of text by collapsing question and exclamation marks.
113
113
 
114
114
  ```typescript
115
115
  transform(text, {
@@ -122,7 +122,7 @@ transform(text, {
122
122
  degrees: false, // 20 C → 20 °C
123
123
  superscript: false, // 1st → 1ˢᵗ
124
124
  ligatures: false, // ??? → ⁇, ?! → ⁈, !? → ⁉, !!! → !
125
- nbsp: false, // non-breaking spaces (after honorifics, between numbers and units, etc.)
125
+ nbsp: true, // non-breaking spaces (after honorifics, between numbers and units, etc.)
126
126
  checkIdempotency: true, // verify transform(transform(x)) === transform(x)
127
127
  })
128
128
  ```
package/dist/index.d.ts CHANGED
@@ -86,7 +86,7 @@ export interface TransformOptions {
86
86
  * Whether to insert non-breaking spaces in typographically appropriate
87
87
  * locations (after short words, between numbers and units, before
88
88
  * last words to prevent widows, after honorifics, etc.).
89
- * Default: false
89
+ * Default: true
90
90
  */
91
91
  nbsp?: boolean;
92
92
  /**
package/dist/index.js CHANGED
@@ -32,8 +32,8 @@ export { DEFAULT_SEPARATOR } from "./constants.js";
32
32
  * 6. degrees (disabled by default)
33
33
  * 7. superscript (disabled by default)
34
34
  * 8. ligatures (disabled by default)
35
- * 9. nbsp (non-breaking spaces, disabled by default)
36
- * 10. collapseSpaces (collapses multiple spaces into one)
35
+ * 9. collapseSpaces (collapses multiple spaces into one)
36
+ * 10. nbsp (non-breaking spaces, enabled by default)
37
37
  *
38
38
  * @param text - The text to transform
39
39
  * @param options - Configuration options
@@ -59,7 +59,7 @@ const defaultOpts = {
59
59
  degrees: false,
60
60
  superscript: false,
61
61
  ligatures: false,
62
- nbsp: false,
62
+ nbsp: true,
63
63
  collapseSpaces: true,
64
64
  checkIdempotency: true,
65
65
  punctuationStyle: "american",
@@ -94,12 +94,12 @@ export function transform(text, options = {}) {
94
94
  if (ligatures) {
95
95
  text = ligaturesTransform(text, separatorOpts);
96
96
  }
97
- if (nbsp) {
98
- text = nbspTransformFn(text, separatorOpts);
99
- }
100
97
  if (collapseSpaces) {
101
98
  text = collapseSpacesTransform(text);
102
99
  }
100
+ if (nbsp) {
101
+ text = nbspTransformFn(text, separatorOpts);
102
+ }
103
103
  assertSeparatorCountPreserved(original, text, separator, "transform");
104
104
  if (checkIdempotency) {
105
105
  const secondPass = transform(text, { ...options, checkIdempotency: false });
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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "punctilio",
3
- "version": "1.7.14",
3
+ "version": "1.8.0",
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/index.ts CHANGED
@@ -134,7 +134,7 @@ export interface TransformOptions {
134
134
  * Whether to insert non-breaking spaces in typographically appropriate
135
135
  * locations (after short words, between numbers and units, before
136
136
  * last words to prevent widows, after honorifics, etc.).
137
- * Default: false
137
+ * Default: true
138
138
  */
139
139
  nbsp?: boolean
140
140
 
@@ -171,8 +171,8 @@ export { DEFAULT_SEPARATOR } from "./constants.js"
171
171
  * 6. degrees (disabled by default)
172
172
  * 7. superscript (disabled by default)
173
173
  * 8. ligatures (disabled by default)
174
- * 9. nbsp (non-breaking spaces, disabled by default)
175
- * 10. collapseSpaces (collapses multiple spaces into one)
174
+ * 9. collapseSpaces (collapses multiple spaces into one)
175
+ * 10. nbsp (non-breaking spaces, enabled by default)
176
176
  *
177
177
  * @param text - The text to transform
178
178
  * @param options - Configuration options
@@ -198,7 +198,7 @@ const defaultOpts: Required<Omit<TransformOptions, "separator">> = {
198
198
  degrees: false,
199
199
  superscript: false,
200
200
  ligatures: false,
201
- nbsp: false,
201
+ nbsp: true,
202
202
  collapseSpaces: true,
203
203
  checkIdempotency: true,
204
204
  punctuationStyle: "american",
@@ -245,14 +245,14 @@ export function transform(text: string, options: TransformOptions = {}): string
245
245
  text = ligaturesTransform(text, separatorOpts)
246
246
  }
247
247
 
248
- if (nbsp) {
249
- text = nbspTransformFn(text, separatorOpts)
250
- }
251
-
252
248
  if (collapseSpaces) {
253
249
  text = collapseSpacesTransform(text)
254
250
  }
255
251
 
252
+ if (nbsp) {
253
+ text = nbspTransformFn(text, separatorOpts)
254
+ }
255
+
256
256
  assertSeparatorCountPreserved(original, text, separator, "transform")
257
257
 
258
258
  if (checkIdempotency) {
@@ -26,43 +26,43 @@ describe("transform", () => {
26
26
  it("applies both quote and dash transformations", () => {
27
27
  const input = '"Hello," she said - "it\'s pages 1-5."'
28
28
  const expected = `${LEFT_DOUBLE_QUOTE}Hello,${RIGHT_DOUBLE_QUOTE} she said${EM_DASH}${LEFT_DOUBLE_QUOTE}it${RIGHT_SINGLE_QUOTE}s pages 1${EN_DASH}5.${RIGHT_DOUBLE_QUOTE}`
29
- expect(transform(input)).toBe(expected)
29
+ expect(transform(input, { nbsp: false })).toBe(expected)
30
30
  })
31
31
 
32
32
  it("handles complex mixed content", () => {
33
33
  const input = 'I was born in \'99 - "the best year" - and pages 10-20 are my favorite.'
34
34
  const expected = `I was born in ${RIGHT_SINGLE_QUOTE}99${EM_DASH}${LEFT_DOUBLE_QUOTE}the best year${RIGHT_DOUBLE_QUOTE}${EM_DASH}and pages 10${EN_DASH}20 are my favorite.`
35
- expect(transform(input)).toBe(expected)
35
+ expect(transform(input, { nbsp: false })).toBe(expected)
36
36
  })
37
37
 
38
38
  it("preserves separator character", () => {
39
39
  const sep = DEFAULT_SEPARATOR
40
40
  const input = `"Hello${sep}" - test`
41
- expect(transform(input, { separator: sep })).toBe(`${LEFT_DOUBLE_QUOTE}Hello${sep}${RIGHT_DOUBLE_QUOTE}${EM_DASH}test`)
41
+ expect(transform(input, { separator: sep, nbsp: false })).toBe(`${LEFT_DOUBLE_QUOTE}Hello${sep}${RIGHT_DOUBLE_QUOTE}${EM_DASH}test`)
42
42
  })
43
43
 
44
44
  describe("symbol transforms", () => {
45
45
  it("applies symbol transforms by default", () => {
46
- expect(transform('Wait... 5x5 != 25 (c) 2024')).toBe(`Wait${ELLIPSIS} 5${MULTIPLICATION}5 ${NOT_EQUAL} 25 ${COPYRIGHT} 2024`)
46
+ expect(transform('Wait... 5x5 != 25 (c) 2024', { nbsp: false })).toBe(`Wait${ELLIPSIS} 5${MULTIPLICATION}5 ${NOT_EQUAL} 25 ${COPYRIGHT} 2024`)
47
47
  })
48
48
 
49
49
  it("can disable symbol transforms", () => {
50
- expect(transform('Wait... 5x5 != 25', { symbols: false })).toBe('Wait... 5x5 != 25')
50
+ expect(transform('Wait... 5x5 != 25', { symbols: false, nbsp: false })).toBe('Wait... 5x5 != 25')
51
51
  })
52
52
  })
53
53
 
54
54
  describe("optional transforms", () => {
55
55
  it.each([
56
- ["fractions disabled", "1/2", {}, "1/2"],
57
- ["fractions enabled", "1/2", { fractions: true }, UNICODE_SYMBOLS.FRACTION_1_2],
58
- ["degrees disabled", "20 C", {}, "20 C"],
59
- ["degrees enabled", "20 C", { degrees: true }, `20 ${UNICODE_SYMBOLS.DEGREE}C`],
60
- ["superscript disabled", "1st", {}, "1st"],
61
- ["superscript enabled", "1st", { superscript: true }, `1${UNICODE_SYMBOLS.SUPERSCRIPT_ST}`],
62
- ["ligatures disabled", "??", {}, "??"],
63
- ["ligatures enabled", "??", { ligatures: true }, UNICODE_SYMBOLS.DOUBLE_QUESTION],
64
- ["nbsp disabled", "Dr. Smith", {}, "Dr. Smith"],
65
- ["nbsp enabled", "Dr. Smith", { nbsp: true }, `Dr.${NBSP}Smith`],
56
+ ["fractions disabled", "1/2", { nbsp: false }, "1/2"],
57
+ ["fractions enabled", "1/2", { fractions: true, nbsp: false }, UNICODE_SYMBOLS.FRACTION_1_2],
58
+ ["degrees disabled", "20 C", { nbsp: false }, "20 C"],
59
+ ["degrees enabled", "20 C", { degrees: true, nbsp: false }, `20 ${UNICODE_SYMBOLS.DEGREE}C`],
60
+ ["superscript disabled", "1st", { nbsp: false }, "1st"],
61
+ ["superscript enabled", "1st", { superscript: true, nbsp: false }, `1${UNICODE_SYMBOLS.SUPERSCRIPT_ST}`],
62
+ ["ligatures disabled", "??", { nbsp: false }, "??"],
63
+ ["ligatures enabled", "??", { ligatures: true, nbsp: false }, UNICODE_SYMBOLS.DOUBLE_QUESTION],
64
+ ["nbsp enabled (default)", "Dr. Smith", {}, `Dr.${NBSP}Smith`],
65
+ ["nbsp disabled", "Dr. Smith", { nbsp: false }, "Dr. Smith"],
66
66
  ] as const)("%s: %s → %s", (_desc, input, options, expected) => {
67
67
  expect(transform(input, options)).toBe(expected)
68
68
  })
@@ -77,7 +77,7 @@ describe("transform", () => {
77
77
  ['"Hello."', "british", periodOutside, "british"],
78
78
  ['"Hello".', "none", periodOutside, "none"],
79
79
  ] as const)("handles %s with %s style", (input, style, expected) => {
80
- expect(transform(input, style ? { punctuationStyle: style } : {})).toBe(expected)
80
+ expect(transform(input, { ...(style ? { punctuationStyle: style } : {}), nbsp: false })).toBe(expected)
81
81
  })
82
82
  })
83
83
 
@@ -88,14 +88,14 @@ describe("transform", () => {
88
88
  [`a ${NBSP}b`, `a${NBSP}b`, "mixed spaces prefer nbsp"],
89
89
  [`a${NBSP} b`, `a${NBSP}b`, "mixed spaces prefer nbsp"],
90
90
  ])("collapses %s by default", (input, expected) => {
91
- expect(transform(input)).toBe(expected)
91
+ expect(transform(input, { nbsp: false })).toBe(expected)
92
92
  })
93
93
 
94
94
  it.each([
95
95
  ["hello world", "hello world", "multiple spaces"],
96
96
  [`foo${NBSP}${NBSP}bar`, `foo${NBSP}${NBSP}bar`, "multiple nbsp"],
97
97
  ])("preserves %s when disabled", (input, expected) => {
98
- expect(transform(input, { collapseSpaces: false })).toBe(expected)
98
+ expect(transform(input, { collapseSpaces: false, nbsp: false })).toBe(expected)
99
99
  })
100
100
  })
101
101
 
@@ -130,8 +130,8 @@ describe("transform", () => {
130
130
  [`"Hello${DEFAULT_SEPARATOR}" - ${DEFAULT_SEPARATOR}she${DEFAULT_SEPARATOR} said`, 3],
131
131
  [`.${DEFAULT_SEPARATOR}.${DEFAULT_SEPARATOR}.`, 2],
132
132
  ])('preserves %i separators in "%s"', (input, expectedCount) => {
133
- expect(() => transform(input, { separator: DEFAULT_SEPARATOR })).not.toThrow()
134
- expect(countSeparators(transform(input, { separator: DEFAULT_SEPARATOR }), DEFAULT_SEPARATOR)).toBe(expectedCount)
133
+ expect(() => transform(input, { separator: DEFAULT_SEPARATOR, nbsp: false })).not.toThrow()
134
+ expect(countSeparators(transform(input, { separator: DEFAULT_SEPARATOR, nbsp: false }), DEFAULT_SEPARATOR)).toBe(expectedCount)
135
135
  })
136
136
 
137
137
  it("preserves separator in ellipsis", () => {
@@ -142,7 +142,7 @@ describe("transform", () => {
142
142
 
143
143
  it("preserves consecutive separators", () => {
144
144
  const input = `a${DEFAULT_SEPARATOR}${DEFAULT_SEPARATOR}${DEFAULT_SEPARATOR}b`
145
- expect(transform(input)).toBe(input)
145
+ expect(transform(input, { nbsp: false })).toBe(input)
146
146
  })
147
147
  })
148
148
 
@@ -154,7 +154,7 @@ describe("transform", () => {
154
154
  '"שלום"',
155
155
  "a\u200Bb",
156
156
  ])('preserves content in "%s"', (input) => {
157
- expect(transform(input)).toBe(transform(input)) // idempotent
157
+ expect(transform(input, { nbsp: false })).toBe(transform(input, { nbsp: false })) // idempotent
158
158
  })
159
159
  })
160
160
 
@@ -181,7 +181,7 @@ describe("transform", () => {
181
181
  ['5\'10"', `5′10″`],
182
182
  ['He is 6\'2" tall', `He is 6′2″ tall`],
183
183
  ])('correctly transforms: "%s"', (input, expected) => {
184
- expect(transform(input, { symbols: true, degrees: true })).toBe(expected)
184
+ expect(transform(input, { symbols: true, degrees: true, nbsp: false })).toBe(expected)
185
185
  })
186
186
  })
187
187
 
@@ -194,7 +194,7 @@ describe("transform", () => {
194
194
  "self-aware",
195
195
  "high-quality",
196
196
  ])('preserves compound word: "%s"', (input) => {
197
- expect(transform(input)).toBe(input)
197
+ expect(transform(input, { nbsp: false })).toBe(input)
198
198
  })
199
199
  })
200
200
 
@@ -207,7 +207,7 @@ describe("transform", () => {
207
207
  "Claude-3-Opus",
208
208
  "Qwen1.5-1.8B",
209
209
  ])('preserves model name: "%s"', (input) => {
210
- expect(transform(input)).toBe(input)
210
+ expect(transform(input, { nbsp: false })).toBe(input)
211
211
  })
212
212
  })
213
213
  })
@@ -216,25 +216,25 @@ describe("transform", () => {
216
216
  it("handles dialogue with dashes and quotes", () => {
217
217
  const input = '"Wait," she said -- "I don\'t think that\'s right."'
218
218
  const expected = `${LEFT_DOUBLE_QUOTE}Wait,${RIGHT_DOUBLE_QUOTE} she said${EM_DASH}${LEFT_DOUBLE_QUOTE}I don${RIGHT_SINGLE_QUOTE}t think that${RIGHT_SINGLE_QUOTE}s right.${RIGHT_DOUBLE_QUOTE}`
219
- expect(transform(input)).toEqual(expected)
219
+ expect(transform(input, { nbsp: false })).toEqual(expected)
220
220
  })
221
221
 
222
222
  it("handles technical documentation", () => {
223
223
  const input = 'The API returns x != y when a <= b and c >= d. Error tolerance: +-5%.'
224
224
  const expected = `The API returns x ${NOT_EQUAL} y when a ≤ b and c ≥ d. Error tolerance: ±5%.`
225
- expect(transform(input)).toBe(expected)
225
+ expect(transform(input, { nbsp: false })).toBe(expected)
226
226
  })
227
227
 
228
228
  it("handles measurement text", () => {
229
229
  const input = 'He is 6\'2" tall.'
230
230
  const expected = `He is 6${PRIME}2${DOUBLE_PRIME} tall.`
231
- expect(transform(input, { symbols: true })).toEqual(expected)
231
+ expect(transform(input, { symbols: true, nbsp: false })).toEqual(expected)
232
232
  })
233
233
 
234
234
  it("handles copyright notices", () => {
235
235
  const input = '(c) 2024 Company(tm). All rights reserved(r).'
236
236
  const expected = `${COPYRIGHT} 2024 Company${TRADEMARK}. All rights reserved${REGISTERED}.`
237
- expect(transform(input)).toEqual(expected)
237
+ expect(transform(input, { nbsp: false })).toEqual(expected)
238
238
  })
239
239
  })
240
240
 
@@ -244,7 +244,7 @@ describe("transform", () => {
244
244
  // When there's an open quote before a number, the quote after should close
245
245
  // not become a prime mark
246
246
  const input = '"Number 5"'
247
- const result = transform(input)
247
+ const result = transform(input, { nbsp: false })
248
248
  // The 5" should be a closing quote, not a prime
249
249
  expect(result).toBe(`${LEFT_DOUBLE_QUOTE}Number 5${RIGHT_DOUBLE_QUOTE}`)
250
250
  })
@@ -261,7 +261,7 @@ describe("transform", () => {
261
261
  `${COPYRIGHT} 2024${EM_DASH}Room is 10×12, set to 72 °F`,
262
262
  ],
263
263
  ])('handles complex transform: "%s"', (input, expected) => {
264
- expect(transform(input, { degrees: true })).toBe(expected)
264
+ expect(transform(input, { degrees: true, nbsp: false })).toBe(expected)
265
265
  })
266
266
  })
267
267
 
@@ -273,7 +273,7 @@ describe("transform", () => {
273
273
  ["\t", "\t"],
274
274
  [" ", " "],
275
275
  ])('handles empty/whitespace: "%s"', (input, expected) => {
276
- expect(transform(input)).toBe(expected)
276
+ expect(transform(input, { nbsp: false })).toBe(expected)
277
277
  })
278
278
  })
279
279
 
@@ -281,19 +281,19 @@ describe("transform", () => {
281
281
  it("handles long repeated patterns", () => {
282
282
  const input = '"Hello" '.repeat(100)
283
283
  const expected = `${LEFT_DOUBLE_QUOTE}Hello${RIGHT_DOUBLE_QUOTE} `.repeat(100)
284
- expect(transform(input)).toEqual(expected)
284
+ expect(transform(input, { nbsp: false })).toEqual(expected)
285
285
  })
286
286
 
287
287
  it("handles long continuous text", () => {
288
288
  const input = "word ".repeat(1000)
289
- const result = transform(input)
289
+ const result = transform(input, { nbsp: false })
290
290
  expect(result).toBe(input.trim() + " ")
291
291
  })
292
292
 
293
293
  it("converts ALL quote pairs in repeated pattern", () => {
294
294
  const count = 50
295
295
  const input = '"Hello" '.repeat(count)
296
- const result = transform(input)
296
+ const result = transform(input, { nbsp: false })
297
297
  const leftCount = (result.match(new RegExp(LEFT_DOUBLE_QUOTE, "g")) || []).length
298
298
  const rightCount = (result.match(new RegExp(RIGHT_DOUBLE_QUOTE, "g")) || []).length
299
299
  expect(leftCount).toBe(count)
@@ -303,7 +303,7 @@ describe("transform", () => {
303
303
  it("converts ALL dashes in repeated pattern", () => {
304
304
  const count = 50
305
305
  const input = "pages 1-5 ".repeat(count)
306
- const result = transform(input)
306
+ const result = transform(input, { nbsp: false })
307
307
  const enDashCount = (result.match(/–/g) || []).length
308
308
  expect(enDashCount).toBe(count)
309
309
  })
@@ -311,7 +311,7 @@ describe("transform", () => {
311
311
  it("converts ALL ellipses in repeated pattern", () => {
312
312
  const count = 50
313
313
  const input = "Wait... ".repeat(count)
314
- const result = transform(input)
314
+ const result = transform(input, { nbsp: false })
315
315
  const ellipsisCount = (result.match(/…/g) || []).length
316
316
  expect(ellipsisCount).toBe(count)
317
317
  })
@@ -323,7 +323,7 @@ describe("transform", () => {
323
323
  ['"test\u200Fword"', `${LEFT_DOUBLE_QUOTE}test\u200Fword${RIGHT_DOUBLE_QUOTE}`],
324
324
  ['"caf\u0065\u0301"', `${LEFT_DOUBLE_QUOTE}caf\u0065\u0301${RIGHT_DOUBLE_QUOTE}`],
325
325
  ])('handles Unicode edge case', (input, expected) => {
326
- expect(transform(input)).toBe(expected)
326
+ expect(transform(input, { nbsp: false })).toBe(expected)
327
327
  })
328
328
  })
329
329
 
@@ -336,6 +336,7 @@ describe("transform", () => {
336
336
  degrees: true,
337
337
  superscript: true,
338
338
  ligatures: true,
339
+ nbsp: false,
339
340
  })).toEqual(expected)
340
341
  })
341
342
 
@@ -345,6 +346,7 @@ describe("transform", () => {
345
346
  expect(transform(input, {
346
347
  fractions: true,
347
348
  degrees: false,
349
+ nbsp: false,
348
350
  })).toEqual(expected)
349
351
  })
350
352
  })
@@ -357,19 +359,19 @@ describe("transform", () => {
357
359
  [`"test${sep}word"`, `${LEFT_DOUBLE_QUOTE}test${sep}word${RIGHT_DOUBLE_QUOTE}`],
358
360
  [`${sep}${sep}"test"${sep}${sep}`, `${sep}${sep}${LEFT_DOUBLE_QUOTE}test${RIGHT_DOUBLE_QUOTE}${sep}${sep}`],
359
361
  ])('handles separator in quotes', (input, expected) => {
360
- expect(transform(input, { separator: sep })).toBe(expected)
362
+ expect(transform(input, { separator: sep, nbsp: false })).toBe(expected)
361
363
  })
362
364
 
363
365
  it.each([
364
366
  [`word${sep} - ${sep}word`, `word${sep}${EM_DASH}${sep}word`],
365
367
  [`1${sep}-${sep}5`, `1${sep}–${sep}5`],
366
368
  ])('handles separator in dashes', (input, expected) => {
367
- expect(transform(input, { separator: sep })).toBe(expected)
369
+ expect(transform(input, { separator: sep, nbsp: false })).toBe(expected)
368
370
  })
369
371
 
370
372
  it("preserves exact separator count through transform", () => {
371
373
  const input = `${sep}text${sep}more${sep}text${sep}`
372
- const result = transform(input, { separator: sep })
374
+ const result = transform(input, { separator: sep, nbsp: false })
373
375
  const inputCount = (input.match(new RegExp(sep, "g")) || []).length
374
376
  const resultCount = (result.match(new RegExp(sep, "g")) || []).length
375
377
  expect(resultCount).toBe(inputCount)
@@ -377,7 +379,7 @@ describe("transform", () => {
377
379
 
378
380
  it("handles input containing separator character", () => {
379
381
  const input = `Text with ${sep} in it`
380
- expect(() => transform(input, { separator: sep })).not.toThrow()
382
+ expect(() => transform(input, { separator: sep, nbsp: false })).not.toThrow()
381
383
  })
382
384
  })
383
385
 
@@ -399,8 +401,8 @@ describe("transform", () => {
399
401
  `1–5`,
400
402
  `Wait…`,
401
403
  `5×5`,
402
- `20 °C`,
403
- `${COPYRIGHT} 2024`,
404
+ `20${NBSP}°C`,
405
+ `${COPYRIGHT}${NBSP}2024`,
404
406
  ])('stable for: "%s"', (input) => {
405
407
  expect(transform(input)).toBe(input)
406
408
  })
@@ -410,19 +412,19 @@ describe("transform", () => {
410
412
  it("applies American conventions throughout", () => {
411
413
  const input = '"Hello." - word - "World."'
412
414
  const expected = `${LEFT_DOUBLE_QUOTE}Hello.${RIGHT_DOUBLE_QUOTE}${EM_DASH}word${EM_DASH}${LEFT_DOUBLE_QUOTE}World.${RIGHT_DOUBLE_QUOTE}`
413
- expect(transform(input, { punctuationStyle: "american", dashStyle: "american" })).toEqual(expected)
415
+ expect(transform(input, { punctuationStyle: "american", dashStyle: "american", nbsp: false })).toEqual(expected)
414
416
  })
415
417
 
416
418
  it("applies British conventions throughout", () => {
417
419
  const input = '"Hello." - word - "World."'
418
420
  const expected = `${LEFT_DOUBLE_QUOTE}Hello${RIGHT_DOUBLE_QUOTE}. ${EN_DASH} word ${EN_DASH} ${LEFT_DOUBLE_QUOTE}World${RIGHT_DOUBLE_QUOTE}.`
419
- expect(transform(input, { punctuationStyle: "british", dashStyle: "british" })).toEqual(expected)
421
+ expect(transform(input, { punctuationStyle: "british", dashStyle: "british", nbsp: false })).toEqual(expected)
420
422
  })
421
423
 
422
424
  it("applies American punctuation with British dashes", () => {
423
425
  const input = '"Hello." - word'
424
426
  const expected = `${LEFT_DOUBLE_QUOTE}Hello.${RIGHT_DOUBLE_QUOTE} ${EN_DASH} word`
425
- expect(transform(input, { punctuationStyle: "american", dashStyle: "british" })).toEqual(expected)
427
+ expect(transform(input, { punctuationStyle: "american", dashStyle: "british", nbsp: false })).toEqual(expected)
426
428
  })
427
429
  })
428
430
 
@@ -470,7 +472,7 @@ describe("transform", () => {
470
472
  ['"test .dot"', `${LEFT_DOUBLE_QUOTE}test .dot${RIGHT_DOUBLE_QUOTE}`],
471
473
  ['"test |pipe"', `${LEFT_DOUBLE_QUOTE}test |pipe${RIGHT_DOUBLE_QUOTE}`],
472
474
  ])('handles regex special chars: "%s"', (input, expected) => {
473
- expect(transform(input)).toBe(expected)
475
+ expect(transform(input, { nbsp: false })).toBe(expected)
474
476
  })
475
477
  })
476
478
 
@@ -485,7 +487,7 @@ describe("transform", () => {
485
487
  ["end...", `end…`],
486
488
  ["5x", `5×`],
487
489
  ])('handles boundary: "%s"', (input, expected) => {
488
- expect(transform(input)).toBe(expected)
490
+ expect(transform(input, { nbsp: false })).toBe(expected)
489
491
  })
490
492
  })
491
493
 
@@ -497,7 +499,7 @@ describe("transform", () => {
497
499
  ] as const
498
500
 
499
501
  it.each(invalidSeparators)("rejects %s separator (%s)", (sep) => {
500
- expect(() => transform('"Hello"', { separator: sep })).toThrow(
502
+ expect(() => transform('"Hello"', { separator: sep, nbsp: false })).toThrow(
501
503
  /Invalid separator.*must be a single character/
502
504
  )
503
505
  })
@@ -505,13 +507,13 @@ describe("transform", () => {
505
507
  const validSeparators = ["\uE000", "|", "\u2603"] // Default, pipe, snowman
506
508
 
507
509
  it.each(validSeparators)("accepts '%s' as separator", (sep) => {
508
- expect(() => transform('"Hello"', { separator: sep })).not.toThrow()
510
+ expect(() => transform('"Hello"', { separator: sep, nbsp: false })).not.toThrow()
509
511
  })
510
512
  })
511
513
 
512
514
  describe("regex-special separator characters", () => {
513
515
  it.each(REGEX_SPECIAL_CHARS)("handles '%s' as separator", (sep) => {
514
- expect(transform('"Hello"', { separator: sep })).toEqual(
516
+ expect(transform('"Hello"', { separator: sep, nbsp: false })).toEqual(
515
517
  `${LEFT_DOUBLE_QUOTE}Hello${RIGHT_DOUBLE_QUOTE}`
516
518
  )
517
519
  })
@@ -523,7 +525,7 @@ describe("transform", () => {
523
525
  ["RTL text", '"שלום"', `${LEFT_DOUBLE_QUOTE}שלום${RIGHT_DOUBLE_QUOTE}`],
524
526
  ["zero-width space", '"Hello\u200BWorld"', `${LEFT_DOUBLE_QUOTE}Hello\u200BWorld${RIGHT_DOUBLE_QUOTE}`],
525
527
  ] as const)("preserves %s in input", (_, input, expected) => {
526
- expect(transform(input)).toEqual(expected)
528
+ expect(transform(input, { nbsp: false })).toEqual(expected)
527
529
  })
528
530
  })
529
531
 
@@ -49,7 +49,7 @@ describe("rehypePunctilio", () => {
49
49
  ["math symbols", "<p>x != y</p>", `<p>x ${NOT_EQUAL} y</p>`],
50
50
  ["legal symbols", "<p>(c) 2024</p>", `<p>${COPYRIGHT} 2024</p>`],
51
51
  ])("transforms %s", async (_name, html, expected) => {
52
- expect(await processHtml(html)).toEqual(expected)
52
+ expect(await processHtml(html, { nbsp: false })).toEqual(expected)
53
53
  })
54
54
  })
55
55
 
@@ -60,7 +60,7 @@ describe("rehypePunctilio", () => {
60
60
  ["deeply nested", '<div><p><span><strong>"Hello"</strong></span></p></div>', `<div><p><span><strong>${LDQ}Hello${RDQ}</strong></span></p></div>`],
61
61
  ["attributes", '<p class="intro" id="first">"Hello"</p>', `<p class="intro" id="first">${LDQ}Hello${RDQ}</p>`],
62
62
  ])("preserves %s", async (_name, html, expected) => {
63
- expect(await processHtml(html)).toEqual(expected)
63
+ expect(await processHtml(html, { nbsp: false })).toEqual(expected)
64
64
  })
65
65
  })
66
66
 
@@ -71,7 +71,7 @@ describe("rehypePunctilio", () => {
71
71
  ["simple range still converts", "<p>pages <em>1</em>-5</p>", `<p>pages <em>1</em>${EN_DASH}5</p>`],
72
72
  ["genuine negative at element start", "<p><em>-5</em> degrees</p>", "<p><em>\u22125</em> degrees</p>"],
73
73
  ])("%s", async (_name, html, expected) => {
74
- expect(await processHtml(html)).toEqual(expected)
74
+ expect(await processHtml(html, { nbsp: false })).toEqual(expected)
75
75
  })
76
76
  })
77
77
 
@@ -108,15 +108,15 @@ describe("rehypePunctilio", () => {
108
108
 
109
109
  describe("transform options passthrough", () => {
110
110
  it.each([
111
- ["punctuationStyle american", '<p>"Hello."</p>', { punctuationStyle: "american" as const }, `<p>${LDQ}Hello.${RDQ}</p>`],
112
- ["punctuationStyle british", '<p>"Hello."</p>', { punctuationStyle: "british" as const }, `<p>${LDQ}Hello${RDQ}.</p>`],
113
- ["dashStyle american", "<p>word - word</p>", { dashStyle: "american" as const }, `<p>word${EM_DASH}word</p>`],
114
- ["dashStyle british", "<p>word - word</p>", { dashStyle: "british" as const }, `<p>word ${EN_DASH} word</p>`],
115
- ["symbols enabled", "<p>5x5</p>", { symbols: true }, `<p>5${MULTIPLICATION}5</p>`],
116
- ["symbols disabled", "<p>5x5</p>", { symbols: false }, "<p>5x5</p>"],
117
- ["fractions enabled", "<p>1/2 cup</p>", { fractions: true }, `<p>${FRACTION_1_2} cup</p>`],
118
- ["fractions disabled", "<p>1/2 cup</p>", { fractions: false }, "<p>1/2 cup</p>"],
119
- ["custom separator", '<p>"Hello"</p>', { separator: "\uE001" }, `<p>${LDQ}Hello${RDQ}</p>`],
111
+ ["punctuationStyle american", '<p>"Hello."</p>', { punctuationStyle: "american" as const, nbsp: false as const }, `<p>${LDQ}Hello.${RDQ}</p>`],
112
+ ["punctuationStyle british", '<p>"Hello."</p>', { punctuationStyle: "british" as const, nbsp: false as const }, `<p>${LDQ}Hello${RDQ}.</p>`],
113
+ ["dashStyle american", "<p>word - word</p>", { dashStyle: "american" as const, nbsp: false as const }, `<p>word${EM_DASH}word</p>`],
114
+ ["dashStyle british", "<p>word - word</p>", { dashStyle: "british" as const, nbsp: false as const }, `<p>word ${EN_DASH} word</p>`],
115
+ ["symbols enabled", "<p>5x5</p>", { symbols: true, nbsp: false as const }, `<p>5${MULTIPLICATION}5</p>`],
116
+ ["symbols disabled", "<p>5x5</p>", { symbols: false, nbsp: false as const }, "<p>5x5</p>"],
117
+ ["fractions enabled", "<p>1/2 cup</p>", { fractions: true, nbsp: false as const }, `<p>${FRACTION_1_2} cup</p>`],
118
+ ["fractions disabled", "<p>1/2 cup</p>", { fractions: false, nbsp: false as const }, "<p>1/2 cup</p>"],
119
+ ["custom separator", '<p>"Hello"</p>', { separator: "\uE001", nbsp: false as const }, `<p>${LDQ}Hello${RDQ}</p>`],
120
120
  ])("respects %s", async (_name, html, options, expected) => {
121
121
  expect(await processHtml(html, options)).toEqual(expected)
122
122
  })
@@ -145,7 +145,7 @@ describe("rehypePunctilio", () => {
145
145
  `<ul><li>${LDQ}First${RDQ}${EM_DASH}important</li><li>Pages 1${EN_DASH}5</li></ul>`,
146
146
  ],
147
147
  ])("handles %s", async (_name, html, expected) => {
148
- expect(await processHtml(html)).toEqual(expected)
148
+ expect(await processHtml(html, { nbsp: false })).toEqual(expected)
149
149
  })
150
150
  })
151
151
 
@@ -157,7 +157,7 @@ describe("rehypePunctilio", () => {
157
157
  ["emoji", '<p>"Hello 👋"</p>', `<p>${LDQ}Hello 👋${RDQ}</p>`],
158
158
  ["links", '<p><a href="https://example.com">"Link"</a></p>', `<p><a href="https://example.com">${LDQ}Link${RDQ}</a></p>`],
159
159
  ])("handles %s", async (_name, html, expected) => {
160
- expect(await processHtml(html)).toEqual(expected)
160
+ expect(await processHtml(html, { nbsp: false })).toEqual(expected)
161
161
  })
162
162
 
163
163
  it("is idempotent", async () => {
@@ -417,8 +417,14 @@ describe("rehypePunctilio", () => {
417
417
  expect(result).toContain(`5${NBSP}kg`)
418
418
  })
419
419
 
420
- it("does not insert nbsp when option disabled (default)", async () => {
420
+ it("inserts nbsp by default", async () => {
421
421
  const result = await processHtml('<p>Dr. Smith has 5 kg of items.</p>')
422
+ expect(result).toContain(`Dr.${NBSP}Smith`)
423
+ expect(result).toContain(`5${NBSP}kg`)
424
+ })
425
+
426
+ it("does not insert nbsp when option disabled", async () => {
427
+ const result = await processHtml('<p>Dr. Smith has 5 kg of items.</p>', { nbsp: false })
422
428
  expect(result).not.toContain(NBSP)
423
429
  })
424
430
 
@@ -443,13 +449,13 @@ describe("rehypePunctilio", () => {
443
449
  })
444
450
 
445
451
  it("handles skipped child within non-skipped parent", async () => {
446
- expect(await processHtml('<div>"Before" <code>"Inside"</code> "After"</div>')).toEqual(
452
+ expect(await processHtml('<div>"Before" <code>"Inside"</code> "After"</div>', { nbsp: false })).toEqual(
447
453
  `<div>${LDQ}Before${RDQ} <code>"Inside"</code> ${LDQ}After${RDQ}</div>`
448
454
  )
449
455
  })
450
456
 
451
457
  it("handles mixed skip and non-skip siblings", async () => {
452
- expect(await processHtml('<article><p>"Hello"</p><pre>"Code"</pre><p>"World"</p></article>')).toEqual(
458
+ expect(await processHtml('<article><p>"Hello"</p><pre>"Code"</pre><p>"World"</p></article>', { nbsp: false })).toEqual(
453
459
  `<article><p>${LDQ}Hello${RDQ}</p><pre>"Code"</pre><p>${LDQ}World${RDQ}</p></article>`
454
460
  )
455
461
  })