punctilio 3.11.3 → 3.11.4

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.
Files changed (66) hide show
  1. package/dist/cli.d.ts +1 -12
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +4 -26
  4. package/dist/cli.js.map +1 -1
  5. package/dist/constants.d.ts +13 -61
  6. package/dist/constants.d.ts.map +1 -1
  7. package/dist/constants.js +12 -61
  8. package/dist/constants.js.map +1 -1
  9. package/dist/dashes.d.ts +0 -9
  10. package/dist/dashes.d.ts.map +1 -1
  11. package/dist/dashes.js +4 -26
  12. package/dist/dashes.js.map +1 -1
  13. package/dist/html.d.ts +1 -32
  14. package/dist/html.d.ts.map +1 -1
  15. package/dist/html.js +1 -29
  16. package/dist/html.js.map +1 -1
  17. package/dist/index.d.ts +0 -39
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +0 -39
  20. package/dist/index.js.map +1 -1
  21. package/dist/markdown.d.ts +1 -34
  22. package/dist/markdown.d.ts.map +1 -1
  23. package/dist/markdown.js +1 -34
  24. package/dist/markdown.js.map +1 -1
  25. package/dist/nbsp.d.ts +1 -68
  26. package/dist/nbsp.d.ts.map +1 -1
  27. package/dist/nbsp.js +6 -86
  28. package/dist/nbsp.js.map +1 -1
  29. package/dist/prettier-plugin.d.ts +0 -14
  30. package/dist/prettier-plugin.d.ts.map +1 -1
  31. package/dist/prettier-plugin.js +0 -19
  32. package/dist/prettier-plugin.js.map +1 -1
  33. package/dist/quotes.d.ts +0 -3
  34. package/dist/quotes.d.ts.map +1 -1
  35. package/dist/quotes.js +11 -58
  36. package/dist/quotes.js.map +1 -1
  37. package/dist/rehype.d.ts +4 -141
  38. package/dist/rehype.d.ts.map +1 -1
  39. package/dist/rehype.js +7 -144
  40. package/dist/rehype.js.map +1 -1
  41. package/dist/remark.d.ts +0 -30
  42. package/dist/remark.d.ts.map +1 -1
  43. package/dist/remark.js +0 -41
  44. package/dist/remark.js.map +1 -1
  45. package/dist/symbols.d.ts +1 -7
  46. package/dist/symbols.d.ts.map +1 -1
  47. package/dist/symbols.js +9 -53
  48. package/dist/symbols.js.map +1 -1
  49. package/dist/utils.d.ts +10 -58
  50. package/dist/utils.d.ts.map +1 -1
  51. package/dist/utils.js +10 -58
  52. package/dist/utils.js.map +1 -1
  53. package/package.json +5 -5
  54. package/src/cli.ts +5 -31
  55. package/src/constants.ts +13 -62
  56. package/src/dashes.ts +4 -27
  57. package/src/html.ts +1 -33
  58. package/src/index.ts +0 -40
  59. package/src/markdown.ts +1 -38
  60. package/src/nbsp.ts +6 -87
  61. package/src/prettier-plugin.ts +0 -20
  62. package/src/quotes.ts +11 -59
  63. package/src/rehype.ts +8 -162
  64. package/src/remark.ts +0 -42
  65. package/src/symbols.ts +9 -66
  66. package/src/utils.ts +10 -60
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "punctilio",
3
- "version": "3.11.3",
3
+ "version": "3.11.4",
4
4
  "description": "Smart typography transformations: curly quotes, em-dashes, en-dashes, and more",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -92,7 +92,7 @@
92
92
  "hastscript": "9.0.1",
93
93
  "jest": "29.7.0",
94
94
  "lint-staged": "16.4.0",
95
- "prettier": "3.8.1",
95
+ "prettier": "3.8.3",
96
96
  "recheck": "4.5.0",
97
97
  "rehype-parse": "9.0.1",
98
98
  "rehype-stringify": "10.0.1",
@@ -105,10 +105,10 @@
105
105
  "smartquotes": "2.3.2",
106
106
  "smartypants": "0.2.2",
107
107
  "tipograph": "0.7.4",
108
- "ts-jest": "29.4.9",
109
- "tsx": "4.21.0",
108
+ "ts-jest": "29.4.11",
109
+ "tsx": "4.22.3",
110
110
  "typescript": "5.9.3",
111
- "typescript-eslint": "8.59.2",
111
+ "typescript-eslint": "8.59.4",
112
112
  "typograf": "7.7.0",
113
113
  "unified": "11.0.5"
114
114
  },
package/src/cli.ts CHANGED
@@ -1,10 +1,4 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * Command-line entry point: format Markdown and HTML files in place,
4
- * or check whether they would be reformatted (for use as a pre-commit hook).
5
- *
6
- * @packageDocumentation
7
- */
8
2
 
9
3
  import { createHash } from "node:crypto"
10
4
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"
@@ -42,11 +36,7 @@ const RULE_MARKERS = ["-", "*", "_"] as const
42
36
  const MARKDOWN_EXTENSIONS = new Set([".md", ".markdown"])
43
37
  const HTML_EXTENSIONS = new Set([".html", ".htm"])
44
38
 
45
- /**
46
- * Shape of `program.opts()` after parsing. Fields named after their CLI
47
- * flags (camelCased by commander). `commander.choices()` guarantees the
48
- * literal types at runtime; we assert them at the boundary.
49
- */
39
+ // Fields match commander's camelCased flag names; .choices() guarantees literals at runtime.
50
40
  interface ParsedFlags {
51
41
  check?: boolean
52
42
  cache?: boolean
@@ -147,8 +137,7 @@ function isGlobPattern(pattern: string): boolean {
147
137
  return /[*?[\]{}]/.test(pattern)
148
138
  }
149
139
 
150
- // Non-glob positionals pass through as literal paths so they error loudly
151
- // if missing, matching the prior behavior of `punctilio file.md`.
140
+ // Non-glob positionals pass through as literal paths so they error loudly if missing.
152
141
  async function discoverFiles(
153
142
  patterns: string[],
154
143
  cwd: string,
@@ -213,12 +202,7 @@ function saveCache(location: string, cache: Cache): void {
213
202
  writeFileSync(location, JSON.stringify(cache))
214
203
  }
215
204
 
216
- /**
217
- * Cache key for a file. Always cwd-relative so a project that moves
218
- * directories (or syncs the cache file across machines via the same
219
- * repo layout) keeps hitting the cache. Files outside cwd appear as
220
- * `../foo.md` and still hash consistently.
221
- */
205
+ // cwd-relative so the cache survives directory moves and cross-machine syncs.
222
206
  function cacheKey(filePath: string, cwd: string): string {
223
207
  return relative(cwd, filePath)
224
208
  }
@@ -249,12 +233,7 @@ async function transformContent(input: string, type: FileType, opts: CliOptions)
249
233
  return type === "md" ? transformMarkdown(input, opts) : transformHtml(input, opts)
250
234
  }
251
235
 
252
- /**
253
- * Preserves whether the original file ends with a trailing newline.
254
- * The unified pipelines for Markdown and HTML both unconditionally append
255
- * one, so without this adjustment every file lacking a trailing newline
256
- * would always appear as needing a rewrite.
257
- */
236
+ // Unified pipelines unconditionally append a trailing newline; undo if original lacked one.
258
237
  function matchTrailingNewline(original: string, formatted: string): string {
259
238
  const originalHas = original.endsWith("\n")
260
239
  const formattedHas = formatted.endsWith("\n")
@@ -282,12 +261,7 @@ async function readPackageVersion(): Promise<string> {
282
261
  }
283
262
  }
284
263
 
285
- /**
286
- * Runs the CLI with the given arguments and I/O streams.
287
- *
288
- * @returns Exit code: 0 if no changes (or all changes written),
289
- * 1 if `--check` saw a file that would change, 2 for usage errors.
290
- */
264
+ /** Returns exit code: 0 success, 1 `--check` saw changes, 2 usage error. */
291
265
  export async function runCli(args: string[], io: CliIO): Promise<number> {
292
266
  const version = await readPackageVersion()
293
267
  const program = buildProgram(version, io)
package/src/constants.ts CHANGED
@@ -1,13 +1,8 @@
1
- /**
2
- * Shared Unicode constants and regex utilities.
3
- */
4
-
5
1
  import escapeStringRegexp from "escape-string-regexp"
6
2
  import QuickLRU from "quick-lru"
7
3
 
8
- /**
9
- * Unicode symbols for typography transformations.
10
- */
4
+ export { escapeStringRegexp }
5
+
11
6
  export const UNICODE_SYMBOLS = {
12
7
  ELLIPSIS: "\u2026",
13
8
  MULTIPLICATION: "\u00D7",
@@ -82,13 +77,7 @@ export const UNICODE_SYMBOLS = {
82
77
  GREEK_QUESTION_MARK: "\u037E", // ; (visually identical to ASCII semicolon)
83
78
  } as const
84
79
 
85
- /**
86
- * All terminal punctuation characters that signal a quote is "already terminated".
87
- * Covers ASCII, ellipsis, punctuation ligatures, interrobang, CJK fullwidth,
88
- * CJK ideographic, Arabic, and Greek question mark.
89
- *
90
- * Used as a regex character class fragment in quotes.ts and as a test fixture.
91
- */
80
+ /** All terminal punctuation chars for regex character classes (ASCII through CJK/Arabic/Greek). */
92
81
  export const TERMINAL_PUNCTUATION = [
93
82
  "!", "?", ".", ",", ";", ":",
94
83
  UNICODE_SYMBOLS.ELLIPSIS,
@@ -128,13 +117,8 @@ export const DEFAULT_SEPARATOR = "\uE000\uE001"
128
117
  const ESCAPED_DEFAULT_SEPARATOR = escapeStringRegexp(DEFAULT_SEPARATOR)
129
118
 
130
119
  /**
131
- * Returns the regex-escaped separator string for the given options,
132
- * wrapped in a non-capturing group so that quantifiers like `?` and `*`
133
- * apply to the entire separator sequence (critical for multi-character
134
- * separators like the default U+E000 U+E001).
135
- *
136
- * @param options - Object with an optional `separator` field
137
- * @returns Regex-escaped separator string wrapped in `(?:...)`
120
+ * Regex-escaped separator wrapped in `(?:...)` so quantifiers apply to
121
+ * the entire multi-character sequence.
138
122
  */
139
123
  export function getEscapedSeparator(options: { separator?: string }): string {
140
124
  const escaped = options.separator
@@ -143,10 +127,7 @@ export function getEscapedSeparator(options: { separator?: string }): string {
143
127
  return `(?:${escaped})`
144
128
  }
145
129
 
146
- /**
147
- * Characters that have special meaning in regular expressions.
148
- * Used for testing that separator escaping works correctly.
149
- */
130
+ /** Regex-special characters, used for testing separator escaping. */
150
131
  export const REGEX_SPECIAL_CHARS = [".", "*", "+", "?", "^", "$", "[", "]", "\\", "|", "(", ")"] as const
151
132
 
152
133
  /**
@@ -179,45 +160,22 @@ export function wordBoundaryEnd(escapedSeparator: string): string {
179
160
  return `\\b(?!${escapedSeparator}{0,${MAX_BOUNDARY_SEPARATORS}}\\w)`
180
161
  }
181
162
 
182
- /**
183
- * Pattern string for space characters (regular space, tab, non-breaking space,
184
- * and narrow no-break space). Use inside regex character classes: `[${SPACE_CHARS}]`
185
- */
163
+ /** Space chars for regex `[...]`: regular space, tab, NBSP, NNBSP. */
186
164
  export const SPACE_CHARS = ` \t${UNICODE_SYMBOLS.NBSP}${UNICODE_SYMBOLS.NNBSP}`
187
165
 
188
- /**
189
- * Pattern string for the non-breaking space characters only (NBSP and NNBSP).
190
- * Use inside regex character classes: `[${NBSP_CHARS}]`. Used by patterns
191
- * that need to detect existing nbsp chains without also matching plain spaces.
192
- */
166
+ /** Non-breaking space chars only (NBSP, NNBSP) for regex `[...]`. */
193
167
  export const NBSP_CHARS = `${UNICODE_SYMBOLS.NBSP}${UNICODE_SYMBOLS.NNBSP}`
194
168
 
195
- /**
196
- * Maximum recursion depth used by the rehype and remark tree walkers.
197
- * Guards against stack overflow from maliciously or accidentally deep
198
- * AST nesting. Shared so both plugins behave identically.
199
- */
169
+ /** Max AST recursion depth; guards against stack overflow from deep nesting. */
200
170
  export const MAX_RECURSION_DEPTH = 1000
201
171
 
202
- /**
203
- * Canonical issue tracker URL, referenced in user-facing error messages
204
- * so there's exactly one source of truth if the repository ever moves.
205
- */
172
+ /** Single source of truth for issue tracker URL in error messages. */
206
173
  export const ISSUES_URL = "https://github.com/alexander-turner/punctilio/issues"
207
174
 
208
- /**
209
- * LRU cache for compiled RegExp objects keyed by `pattern + '\0' + flags`.
210
- * Avoids recompiling identical regexes on every function call (common
211
- * when using the default separator). Capped to prevent unbounded growth.
212
- */
213
175
  export const MAX_REGEX_CACHE_SIZE = 1000
214
176
  const regexCache = new QuickLRU<string, RegExp>({ maxSize: MAX_REGEX_CACHE_SIZE })
215
177
 
216
- /**
217
- * Returns a cached RegExp for the given pattern and flags.
218
- * Resets `lastIndex` before returning to prevent stale state when
219
- * callers use `.test()` or `.exec()` on global-flag regexes.
220
- */
178
+ /** Returns a cached RegExp, resetting `lastIndex` to prevent stale global-flag state. */
221
179
  export function cachedRegExp(pattern: string, flags: string): RegExp {
222
180
  const key = `${pattern}\0${flags}`
223
181
  let re = regexCache.get(key)
@@ -229,19 +187,12 @@ export function cachedRegExp(pattern: string, flags: string): RegExp {
229
187
  return re
230
188
  }
231
189
 
232
- /**
233
- * Returns all currently cached RegExp objects. Exported for test
234
- * introspection only (e.g. ReDoS scanning every compiled pattern).
235
- * @internal
236
- */
190
+ /** @internal */
237
191
  export function getCachedRegExps(): RegExp[] {
238
192
  return Array.from(regexCache.values())
239
193
  }
240
194
 
241
- /**
242
- * Clears the regex cache. Exported for test isolation only.
243
- * @internal
244
- */
195
+ /** @internal */
245
196
  export function clearRegexCache(): void {
246
197
  regexCache.clear()
247
198
  }
package/src/dashes.ts CHANGED
@@ -1,7 +1,3 @@
1
- /**
2
- * Dash transformation: hyphens → em-dashes, en-dashes, minus signs.
3
- */
4
-
5
1
  import { cachedRegExp, DEFAULT_SEPARATOR, getEscapedSeparator, LATIN_LETTERS, UNICODE_SYMBOLS, wordBoundaryEnd, wordBoundaryStart } from "./constants.js"
6
2
  import { namedGroups } from "./utils.js"
7
3
 
@@ -17,19 +13,10 @@ export interface DashOptions {
17
13
 
18
14
  const { EN_DASH, EM_DASH, MINUS, LEFT_DOUBLE_QUOTE, RIGHT_DOUBLE_QUOTE, LEFT_SINGLE_QUOTE, RIGHT_SINGLE_QUOTE } = UNICODE_SYMBOLS
19
15
 
20
- /**
21
- * Characters that, when preceding a number, prevent it from being
22
- * treated as the start of a number range. This prevents false positives
23
- * in model names like "Llama-2-7B" where "2-7" should not become "2–7".
24
- */
16
+ // Prevents false-positive ranges in model names like "Llama-2-7B".
25
17
  export const numberRangeDisallowedPrefixes = ["-", EN_DASH, EM_DASH, MINUS] as const
26
18
 
27
- /**
28
- * Regex character-class fragment built from {@link numberRangeDisallowedPrefixes}.
29
- * Non-ASCII dashes are escaped to `\uXXXX` form so the fragment is safe to
30
- * embed inside a `[...]` class regardless of the regex source encoding.
31
- * Computed once at module load — the inputs are `const`.
32
- */
19
+ // Non-ASCII dashes escaped to \uXXXX for safe embedding in [...] classes.
33
20
  const DISALLOWED_PREFIX_CLASS_FRAGMENT = numberRangeDisallowedPrefixes
34
21
  .map((c) => (c === "-" ? c : `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`))
35
22
  .join("")
@@ -185,10 +172,6 @@ export function minusReplace(text: string, options: DashOptions = {}): string {
185
172
  return text
186
173
  }
187
174
 
188
- /**
189
- * Convert surrounded dashes to em/en dashes.
190
- * Handles patterns like "word - word" → "word—word" (Chicago) or "word – word" (Oxford).
191
- */
192
175
  function convertParentheticalDashes(text: string, sep: string, style: DashStyle): string {
193
176
  const localizedDash = style === "british" ? EN_DASH : EM_DASH
194
177
  const maybeSpace = style === "british" ? " " : ""
@@ -239,13 +222,8 @@ function convertParentheticalDashes(text: string, sep: string, style: DashStyle)
239
222
  return text
240
223
  }
241
224
 
242
- /**
243
- * Normalize em-dash spacing for Chicago style (American).
244
- * Removes all spaces around em-dashes per Chicago Manual of Style.
245
- *
246
- * TODO: Handle interrupted-then-resumed speech within quotes, where Chicago
247
- * allows a space after the dash: "Don't inter— Hey! Who threw that?"
248
- */
225
+ // TODO: Handle interrupted-then-resumed speech within quotes, where Chicago
226
+ // allows a space after the dash: "Don't inter— Hey! Who threw that?"
249
227
  function normalizeEmDashSpacing(text: string, sep: string): string {
250
228
  const escapedSep = getEscapedSeparator({ separator: sep })
251
229
 
@@ -265,7 +243,6 @@ function normalizeEmDashSpacing(text: string, sep: string): string {
265
243
  return text
266
244
  }
267
245
 
268
- /** Full dash transformation. */
269
246
  export function hyphenReplace(text: string, options: DashOptions = {}): string {
270
247
  const sep = options.separator ?? DEFAULT_SEPARATOR
271
248
  const style = options.dashStyle ?? "american"
package/src/html.ts CHANGED
@@ -1,14 +1,3 @@
1
- /**
2
- * Convenience module for HTML-to-HTML typography transformations.
3
- *
4
- * Provides a single function that takes HTML input and returns
5
- * typographically improved HTML output.
6
- *
7
- * Requires `unified`, `rehype-parse`, and `rehype-stringify` to be installed.
8
- *
9
- * @packageDocumentation
10
- */
11
-
12
1
  import { unified } from "unified"
13
2
  import rehypeParse from "rehype-parse"
14
3
  import rehypeStringify from "rehype-stringify"
@@ -17,9 +6,6 @@ import QuickLRU from "quick-lru"
17
6
  import { rehypePunctilio, type RehypePunctilioOptions } from "./rehype.js"
18
7
  import { stableStringify } from "./utils.js"
19
8
 
20
- /**
21
- * Options for the HTML transform pipeline.
22
- */
23
9
  export interface HtmlOptions extends RehypePunctilioOptions {
24
10
  /**
25
11
  * Whether to parse the input as an HTML fragment (no implicit `<html>`,
@@ -43,29 +29,11 @@ const processorCache = new QuickLRU<string, ReturnType<typeof createProcessor>>(
43
29
  maxSize: MAX_PROCESSOR_CACHE_SIZE,
44
30
  })
45
31
 
46
- /**
47
- * Clears the processor cache. Exported for test isolation only.
48
- * @internal
49
- */
32
+ /** @internal */
50
33
  export function clearProcessorCache(): void {
51
34
  processorCache.clear()
52
35
  }
53
36
 
54
- /**
55
- * Transforms HTML text with typographic improvements.
56
- *
57
- * Parses the input as HTML, applies punctilio typography transformations,
58
- * and serializes back to HTML. The unified processor pipeline is cached
59
- * and reused across calls with identical options.
60
- *
61
- * @example
62
- * ```ts
63
- * import { transformHtml } from 'punctilio/html'
64
- *
65
- * await transformHtml('<p>"Hello" -- world</p>')
66
- * // → '<p>“Hello”—world</p>'
67
- * ```
68
- */
69
37
  export async function transformHtml(
70
38
  input: string,
71
39
  options: HtmlOptions = {}
package/src/index.ts CHANGED
@@ -1,13 +1,3 @@
1
- /**
2
- * punctilio - Smart typography transformations
3
- *
4
- * A library for converting plain ASCII punctuation into typographically
5
- * correct Unicode characters. Handles smart quotes, em-dashes, en-dashes,
6
- * minus signs, ellipses, multiplication signs, and more.
7
- *
8
- * @packageDocumentation
9
- */
10
-
11
1
  export { DEFAULT_SEPARATOR, UNICODE_SYMBOLS } from "./constants.js"
12
2
  import type { PunctuationStyle } from "./quotes.js"
13
3
  export {
@@ -194,36 +184,6 @@ const defaultOpts: Required<Omit<TransformOptions, "separator">> = {
194
184
  dashStyle: "american",
195
185
  }
196
186
 
197
- /**
198
- * Applies all typography transformations: smart quotes, proper dashes,
199
- * and symbol improvements.
200
- *
201
- * This is a convenience function that applies transformations in sequence:
202
- * 1. hyphenReplace (em-dashes, en-dashes, minus signs)
203
- * 2. primeMarks (feet/inches, arcminutes/arcseconds)
204
- * 3. niceQuotes (smart quotes)
205
- * 4. symbolTransform (ellipses, multiplication, math symbols, legal symbols, arrows)
206
- * 5. fractions (disabled by default)
207
- * 6. degrees (disabled by default)
208
- * 7. superscript (disabled by default)
209
- * 8. ligatures (disabled by default)
210
- * 9. collapseSpaces (collapses multiple spaces into one)
211
- * 10. nbsp (non-breaking spaces, enabled by default)
212
- *
213
- * @example
214
- * ```ts
215
- * import { transform } from 'punctilio'
216
- *
217
- * transform('"Hello," she said - "it\'s pages 1-5."')
218
- * // → '"Hello," she said—"it's pages 1–5."'
219
- *
220
- * transform('Wait... 5x5 != 25 (c) 2024')
221
- * // → 'Wait… 5×5 ≠ 25 © 2024'
222
- *
223
- * transform('Add 1/2 cup', { fractions: true })
224
- * // → 'Add ½ cup'
225
- * ```
226
- */
227
187
  export function transform(text: string, options: TransformOptions = {}): string {
228
188
  const separator = options.separator ?? DEFAULT_SEPARATOR
229
189
 
package/src/markdown.ts CHANGED
@@ -1,14 +1,3 @@
1
- /**
2
- * Convenience module for Markdown-to-Markdown typography transformations.
3
- *
4
- * Provides a single function that takes Markdown input and returns
5
- * typographically improved Markdown output.
6
- *
7
- * Requires `unified`, `remark-parse`, and `remark-stringify` to be installed.
8
- *
9
- * @packageDocumentation
10
- */
11
-
12
1
  import { unified } from "unified"
13
2
  import remarkParse from "remark-parse"
14
3
  import remarkGfm from "remark-gfm"
@@ -18,9 +7,6 @@ import QuickLRU from "quick-lru"
18
7
  import { remarkPunctilio, type RemarkPunctilioOptions } from "./remark.js"
19
8
  import { stableStringify } from "./utils.js"
20
9
 
21
- /**
22
- * Options for the Markdown transform pipeline.
23
- */
24
10
  export interface MarkdownOptions extends RemarkPunctilioOptions {
25
11
  /**
26
12
  * Character for emphasis (`*text*` vs `_text_`) and strong (`**text**` vs `__text__`).
@@ -41,9 +27,6 @@ export interface MarkdownOptions extends RemarkPunctilioOptions {
41
27
  ruleMarker?: "-" | "*" | "_"
42
28
  }
43
29
 
44
- /**
45
- * Creates a unified processor pipeline for Markdown typography transformations.
46
- */
47
30
  function createProcessor(options: MarkdownOptions) {
48
31
  const {
49
32
  emphasisMarker,
@@ -78,31 +61,11 @@ const processorCache = new QuickLRU<string, ReturnType<typeof createProcessor>>(
78
61
  maxSize: MAX_PROCESSOR_CACHE_SIZE,
79
62
  })
80
63
 
81
- /**
82
- * Clears the processor cache. Exported for test isolation only.
83
- * @internal
84
- */
64
+ /** @internal */
85
65
  export function clearProcessorCache(): void {
86
66
  processorCache.clear()
87
67
  }
88
68
 
89
- /**
90
- * Transforms Markdown text with typographic improvements.
91
- *
92
- * Parses the input as Markdown, applies punctilio typography transformations
93
- * (smart quotes, em-dashes, ellipses, etc.), and serializes back to Markdown.
94
- *
95
- * The unified processor pipeline is cached and reused across calls with
96
- * identical options, avoiding redundant pipeline construction.
97
- *
98
- * @example
99
- * ```ts
100
- * import { transformMarkdown } from 'punctilio/markdown'
101
- *
102
- * await transformMarkdown('"Hello" -- world')
103
- * // → '\u201CHello\u201D\u2014world'
104
- * ```
105
- */
106
69
  export async function transformMarkdown(
107
70
  input: string,
108
71
  options: MarkdownOptions = {}
package/src/nbsp.ts CHANGED
@@ -1,13 +1,3 @@
1
- /**
2
- * Non-breaking space transformations for improved typography.
3
- *
4
- * Inserts non-breaking spaces (U+00A0) in positions where line breaks
5
- * would be typographically undesirable: after short words, between
6
- * numbers and units, before orphaned last words, etc.
7
- *
8
- * @module nbsp
9
- */
10
-
11
1
  import { cachedRegExp, getEscapedSeparator, LATIN_LETTERS, NBSP_CHARS, SPACE_CHARS, UNICODE_SYMBOLS, wordBoundaryEnd } from "./constants.js"
12
2
 
13
3
  const {
@@ -26,15 +16,11 @@ export interface NbspOptions {
26
16
  separator?: string
27
17
  }
28
18
 
29
- /** Space pattern matching regular space, tab, and nbsp. */
30
19
  const SPACE = `[${SPACE_CHARS}]`
31
20
 
32
21
  const UNICODE_UPPERCASE = "\\p{Lu}"
33
22
 
34
- /**
35
- * Common units for the number-unit nbsp pattern. Only matches these specific
36
- * abbreviations after a number to avoid false positives like "chapter 3 above".
37
- */
23
+ /** Only specific abbreviations are matched to avoid false positives. */
38
24
  export const UNITS: readonly string[] = [
39
25
  // Length
40
26
  "km", "cm", "mm", "mi", "ft", "yd", "nm", "pm", "m",
@@ -111,17 +97,8 @@ const ABBREVIATION_PATTERN = REFERENCE_ABBREVIATIONS.map((a) => `${a}\\.`).join(
111
97
  const PUNCTUATION_OR_QUOTE = `[.,!?:;)(${LEFT_DOUBLE_QUOTE}${RIGHT_DOUBLE_QUOTE}\u00AB\u00BB${LEFT_SINGLE_QUOTE}${RIGHT_SINGLE_QUOTE}"]`
112
98
  const COPYRIGHT_SYMBOLS = `[${COPYRIGHT}${REGISTERED}${TRADEMARK}]`
113
99
 
114
- /**
115
- * Adds non-breaking space after short words (1-2 letters) to prevent them from
116
- * being left alone at the end of a line.
117
- *
118
- * Skips when the short word is already preceded by an NBSP from an earlier
119
- * transform, or when this match immediately follows the previous one
120
- * (back-to-back short words in the same pass). Either case would bind three
121
- * or more words into a single line-break atom — defeating widow protection.
122
- *
123
- * @example "a cat" → "a\u00A0cat", "I am" → "I\u00A0am"
124
- */
100
+ // Skips when preceded by NBSP or back-to-back with the previous match,
101
+ // preventing 3+ words from binding into a single line-break atom.
125
102
  export function nbspAfterShortWords(text: string, options: NbspOptions = {}): string {
126
103
  const sep = getEscapedSeparator(options)
127
104
  const pattern = cachedRegExp(
@@ -137,11 +114,6 @@ export function nbspAfterShortWords(text: string, options: NbspOptions = {}): st
137
114
  })
138
115
  }
139
116
 
140
- /**
141
- * Adds non-breaking space between numbers and common units.
142
- *
143
- * @example "100 km" → "100\u00A0km", "5 kg" → "5\u00A0kg"
144
- */
145
117
  export function nbspBetweenNumberAndUnit(text: string, options: NbspOptions = {}): string {
146
118
  const sep = getEscapedSeparator(options)
147
119
  const wbe = wordBoundaryEnd(sep)
@@ -152,30 +124,12 @@ export function nbspBetweenNumberAndUnit(text: string, options: NbspOptions = {}
152
124
  return text.replace(pattern, `$<digit>$<marker1>${NBSP}$<marker2>$<unit>`)
153
125
  }
154
126
 
155
- /**
156
- * Maximum length, in characters, of the "last word" that gets an NBSP
157
- * glued to its preceding space. Short enough that a typical English word
158
- * qualifies but an entire trailing URL or long token does not. Only affects
159
- * widow prevention at end-of-string and paragraph breaks.
160
- */
161
127
  const MAX_LAST_WORD_LENGTH = 10
162
128
 
163
- /**
164
- * Maximum word length, in characters, considered for the cascade check.
165
- * Bounded so the lookbehind in `nbspBeforeLastWord` stays ReDoS-safe.
166
- */
129
+ // Bounded so the lookbehind stays ReDoS-safe.
167
130
  const MAX_MIDDLE_WORD_LENGTH = 15
168
131
 
169
- /**
170
- * Adds non-breaking space before the last word to prevent widows.
171
- *
172
- * Only applies to final words of 1 to {@link MAX_LAST_WORD_LENGTH} characters,
173
- * at end of string or paragraph break (\n\n). Uses non-multiline mode so $
174
- * matches only the true end of string.
175
- *
176
- * Skips when the second-to-last word is already glued backwards via NBSP,
177
- * so the phrase doesn't become a 3-word non-breaking atom.
178
- */
132
+ // Skips when the second-to-last word is already glued backwards via NBSP.
179
133
  export function nbspBeforeLastWord(text: string, options: NbspOptions = {}): string {
180
134
  const sep = getEscapedSeparator(options)
181
135
  const cascadeBlock = `(?<![${NBSP_CHARS}][${LATIN_LETTERS}]{1,${MAX_MIDDLE_WORD_LENGTH}})`
@@ -187,12 +141,6 @@ export function nbspBeforeLastWord(text: string, options: NbspOptions = {}): str
187
141
  return text.replace(pattern, `${NBSP}$<lastWord>$<ending>`)
188
142
  }
189
143
 
190
- /**
191
- * Adds non-breaking space after reference abbreviations (Fig., Vol., p., etc.)
192
- * when followed by a number.
193
- *
194
- * @example "Fig. 1" → "Fig.\u00A01", "p. 42" → "p.\u00A042"
195
- */
196
144
  export function nbspAfterReferenceAbbreviations(text: string, options: NbspOptions = {}): string {
197
145
  const sep = getEscapedSeparator(options)
198
146
  const pattern = cachedRegExp(
@@ -202,12 +150,6 @@ export function nbspAfterReferenceAbbreviations(text: string, options: NbspOptio
202
150
  return text.replace(pattern, `$<abbrev>$<marker>${NBSP}`)
203
151
  }
204
152
 
205
- /**
206
- * Adds non-breaking space after section (§) and paragraph (¶) symbols
207
- * when followed by a number.
208
- *
209
- * @example "§ 5" → "§\u00A05"
210
- */
211
153
  export function nbspAfterSectionSymbols(text: string, options: NbspOptions = {}): string {
212
154
  const sep = getEscapedSeparator(options)
213
155
  const pattern = cachedRegExp(
@@ -217,11 +159,6 @@ export function nbspAfterSectionSymbols(text: string, options: NbspOptions = {})
217
159
  return text.replace(pattern, `$<symbol>$<marker>${NBSP}`)
218
160
  }
219
161
 
220
- /**
221
- * Adds non-breaking space after honorific titles when followed by a capitalized name.
222
- *
223
- * @example "Dr. Smith" → "Dr.\u00A0Smith", "Mr. Jones" → "Mr.\u00A0Jones"
224
- */
225
162
  export function nbspAfterHonorifics(text: string, options: NbspOptions = {}): string {
226
163
  const sep = getEscapedSeparator(options)
227
164
  const pattern = cachedRegExp(
@@ -231,12 +168,6 @@ export function nbspAfterHonorifics(text: string, options: NbspOptions = {}): st
231
168
  return text.replace(pattern, `$<honorific>$<marker>${NBSP}`)
232
169
  }
233
170
 
234
- /**
235
- * Adds non-breaking space after copyright, registered, and trademark
236
- * symbols when followed by a year or capitalized name.
237
- *
238
- * @example "© 2024" → "©\u00A02024", "® Brand" → "®\u00A0Brand"
239
- */
240
171
  export function nbspAfterCopyrightSymbols(text: string, options: NbspOptions = {}): string {
241
172
  const sep = getEscapedSeparator(options)
242
173
  const pattern = cachedRegExp(
@@ -246,11 +177,6 @@ export function nbspAfterCopyrightSymbols(text: string, options: NbspOptions = {
246
177
  return text.replace(pattern, `$<symbol>$<marker>${NBSP}`)
247
178
  }
248
179
 
249
- /**
250
- * Adds non-breaking space between initials (e.g., "J. K. Rowling").
251
- *
252
- * @example "J. K. Rowling" → "J.\u00A0K.\u00A0Rowling"
253
- */
254
180
  export function nbspBetweenInitials(text: string, options: NbspOptions = {}): string {
255
181
  const sep = getEscapedSeparator(options)
256
182
  const pattern = cachedRegExp(
@@ -262,13 +188,7 @@ export function nbspBetweenInitials(text: string, options: NbspOptions = {}): st
262
188
 
263
189
  type NbspFn = (text: string, options: NbspOptions) => string
264
190
 
265
- /**
266
- * Ordered list of nbsp transforms. Specific patterns (honorifics, abbreviations,
267
- * initials) come first so they claim their matches before the generic
268
- * `nbspAfterShortWords`. For example, "No. 5" is matched by
269
- * `nbspAfterReferenceAbbreviations` first, preventing `nbspAfterShortWords`
270
- * from also matching "No" as a 2-letter short word.
271
- */
191
+ // Specific patterns first so they claim matches before generic nbspAfterShortWords.
272
192
  const NBSP_TRANSFORMS: NbspFn[] = [
273
193
  nbspAfterHonorifics,
274
194
  nbspAfterReferenceAbbreviations,
@@ -280,7 +200,6 @@ const NBSP_TRANSFORMS: NbspFn[] = [
280
200
  nbspBeforeLastWord,
281
201
  ]
282
202
 
283
- /** Apply all non-breaking space transformations in sequence. */
284
203
  export function nbspTransform(text: string, options: NbspOptions = {}): string {
285
204
  // All nbsp patterns require a space, tab, or existing nbsp to match.
286
205
  // Short-circuit if the text contains none of these.