punctilio 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,6 +10,14 @@ Smart typography transformations for JavaScript/TypeScript. Converts ASCII punct
10
10
  - **Em dashes**: `word - word` or `word--word` → `word—word`
11
11
  - **En dashes**: `1-5` → `1–5` (number ranges), `January-March` → `January–March` (date ranges)
12
12
  - **Minus signs**: `-5` → `−5` (proper Unicode minus)
13
+ - **Ellipsis**: `...` → `…`
14
+ - **Multiplication**: `5x5` → `5×5`, `3*4` → `3×4`
15
+ - **Math symbols**: `!=` → `≠`, `+-` → `±`, `<=` → `≤`, `>=` → `≥`, `~=` → `≈`
16
+ - **Legal symbols**: `(c)` → `©`, `(r)` → `®`, `(tm)` → `™`
17
+ - **Arrows**: `->` → `→`, `<-` → `←`, `<->` → `↔`
18
+ - **Prime marks**: `5'10"` → `5′10″` (feet/inches, arcminutes/arcseconds)
19
+ - **Fractions** (optional): `1/2` → `½`, `3/4` → `¾`
20
+ - **Degrees** (optional): `20 C` → `20 °C`
13
21
  - **Handles edge cases**: contractions, possessives, nested quotes, year abbreviations ('99), "rock 'n' roll"
14
22
 
15
23
  ## Why another typography library?
@@ -41,6 +49,10 @@ import { transform, niceQuotes, hyphenReplace } from 'punctilio'
41
49
  transform('"Hello," she said - "it\'s pages 1-5."')
42
50
  // → "Hello," she said—"it's pages 1–5."
43
51
 
52
+ // Symbol transforms are included by default
53
+ transform('Wait... 5x5 != 25 (c) 2024')
54
+ // → Wait… 5×5 ≠ 25 © 2024
55
+
44
56
  // Or use individual functions
45
57
  niceQuotes('"Hello", she said.')
46
58
  // → "Hello", she said.
@@ -49,6 +61,23 @@ hyphenReplace('word - word')
49
61
  // → word—word
50
62
  ```
51
63
 
64
+ ### Transform Options
65
+
66
+ ```typescript
67
+ import { transform } from 'punctilio'
68
+
69
+ // Enable optional transforms
70
+ transform('Add 1/2 cup at 20 C', {
71
+ fractions: true, // 1/2 → ½
72
+ degrees: true // 20 C → 20 °C
73
+ })
74
+ // → Add ½ cup at 20 °C
75
+
76
+ // Disable symbol transforms if you only want quotes/dashes
77
+ transform('5x5 = 25', { symbols: false })
78
+ // → 5x5 = 25 (unchanged)
79
+ ```
80
+
52
81
  ### With HTML Element Boundaries
53
82
 
54
83
  When processing text that spans multiple HTML elements, use a separator character to mark boundaries:
@@ -71,9 +100,15 @@ For a complete implementation showing how to use this with a HAST (HTML AST) tre
71
100
 
72
101
  ### `transform(text, options?)`
73
102
 
74
- Applies all typography transformations (quotes + dashes).
103
+ Applies all typography transformations. Options:
104
+ - `separator`: Boundary marker for HTML elements (default: `"\uE000"`)
105
+ - `symbols`: Include symbol transforms (default: `true`)
106
+ - `fractions`: Convert common fractions like 1/2 → ½ (default: `false`)
107
+ - `degrees`: Convert temperature notation like 20 C → 20 °C (default: `false`)
108
+
109
+ ### Quote Functions
75
110
 
76
- ### `niceQuotes(text, options?)`
111
+ #### `niceQuotes(text, options?)`
77
112
 
78
113
  Converts straight quotes to curly quotes. Handles:
79
114
  - Opening/closing double quotes: `"` → `"` or `"`
@@ -83,7 +118,9 @@ Converts straight quotes to curly quotes. Handles:
83
118
  - Year abbreviations: `'99` → `'99`
84
119
  - Special cases: `'n'` in "rock 'n' roll"
85
120
 
86
- ### `hyphenReplace(text, options?)`
121
+ ### Dash Functions
122
+
123
+ #### `hyphenReplace(text, options?)`
87
124
 
88
125
  Converts hyphens to proper dashes. Handles:
89
126
  - Em dashes: `word - word` → `word—word`
@@ -92,18 +129,100 @@ Converts hyphens to proper dashes. Handles:
92
129
  - Minus signs: `-5` → `−5`
93
130
  - Preserves: horizontal rules (`---`), compound words (`well-known`)
94
131
 
95
- ### `enDashNumberRange(text, options?)`
132
+ #### `enDashNumberRange(text, options?)`
96
133
 
97
134
  Converts number ranges only: `pages 10-20` → `pages 10–20`
98
135
 
99
- ### `enDashDateRange(text, options?)`
136
+ #### `enDashDateRange(text, options?)`
100
137
 
101
138
  Converts month ranges only: `January-March` → `January–March`
102
139
 
103
- ### `minusReplace(text, options?)`
140
+ #### `minusReplace(text, options?)`
104
141
 
105
142
  Converts hyphens to minus signs in numerical contexts: `-5` → `−5`
106
143
 
144
+ ### Symbol Functions
145
+
146
+ #### `ellipsis(text, options?)`
147
+
148
+ Converts three periods to ellipsis: `...` → `…`
149
+
150
+ #### `multiplication(text, options?)`
151
+
152
+ Converts multiplication patterns: `5x5` → `5×5`, `3*4` → `3×4`
153
+
154
+ #### `mathSymbols(text)`
155
+
156
+ Converts math operators:
157
+ - `!=` → `≠`
158
+ - `+-` or `+/-` → `±`
159
+ - `<=` → `≤`
160
+ - `>=` → `≥`
161
+ - `~=` or `=~` → `≈`
162
+
163
+ #### `legalSymbols(text)`
164
+
165
+ Converts legal symbols:
166
+ - `(c)` → `©`
167
+ - `(r)` → `®`
168
+ - `(tm)` → `™`
169
+
170
+ #### `arrows(text, options?)`
171
+
172
+ Converts arrow patterns:
173
+ - `->` or `-->` → `→`
174
+ - `<-` or `<--` → `←`
175
+ - `<->` or `<-->` → `↔`
176
+
177
+ #### `primeMarks(text, options?)`
178
+
179
+ Converts straight quotes after numbers to prime marks:
180
+ - `5'10"` → `5′10″` (feet and inches)
181
+ - `45° 30' 15"` → `45° 30′ 15″` (coordinates)
182
+
183
+ #### `fractions(text)`
184
+
185
+ Converts common fractions: `1/2` → `½`, `1/4` → `¼`, `3/4` → `¾`, etc.
186
+
187
+ #### `degrees(text)`
188
+
189
+ Converts temperature notation: `20 C` → `20 °C`, `68 F` → `68 °F`
190
+
191
+ #### `symbolTransform(text, options?)`
192
+
193
+ Applies all symbol transforms except fractions and degrees.
194
+
195
+ ### Constants
196
+
197
+ - `DEFAULT_SEPARATOR`: The default separator character (`"\uE000"`)
198
+ - `months`: Regex-ready string of month names for date range detection
199
+
200
+ ## Character Reference
201
+
202
+ | Input | Output | Unicode | Name |
203
+ |-------|--------|---------|------|
204
+ | `"` | `"` | U+201C | Left double quotation mark |
205
+ | `"` | `"` | U+201D | Right double quotation mark |
206
+ | `'` | `'` | U+2018 | Left single quotation mark |
207
+ | `'` | `'` | U+2019 | Right single quotation mark (apostrophe) |
208
+ | `--` | `—` | U+2014 | Em dash |
209
+ | `-` (range) | `–` | U+2013 | En dash |
210
+ | `-` (negative) | `−` | U+2212 | Minus sign |
211
+ | `...` | `…` | U+2026 | Ellipsis |
212
+ | `x` (multiply) | `×` | U+00D7 | Multiplication sign |
213
+ | `!=` | `≠` | U+2260 | Not equal |
214
+ | `+-` | `±` | U+00B1 | Plus-minus |
215
+ | `<=` | `≤` | U+2264 | Less than or equal |
216
+ | `>=` | `≥` | U+2265 | Greater than or equal |
217
+ | `(c)` | `©` | U+00A9 | Copyright |
218
+ | `(r)` | `®` | U+00AE | Registered |
219
+ | `(tm)` | `™` | U+2122 | Trademark |
220
+ | `->` | `→` | U+2192 | Right arrow |
221
+ | `<-` | `←` | U+2190 | Left arrow |
222
+ | `<->` | `↔` | U+2194 | Left-right arrow |
223
+ | `'` (after digit) | `′` | U+2032 | Prime (feet, arcminutes) |
224
+ | `"` (after digit) | `″` | U+2033 | Double prime (inches, arcseconds) |
225
+
107
226
  ## License
108
227
 
109
228
  MIT © Alexander Turner
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Shared Unicode constants used throughout the punctilio package.
3
+ *
4
+ * This module provides a centralized location for all Unicode symbols
5
+ * used in typography transformations, making the codebase more maintainable
6
+ * and self-documenting.
7
+ *
8
+ * @module constants
9
+ */
10
+ /**
11
+ * Unicode symbols for typography transformations.
12
+ */
13
+ export declare const UNICODE_SYMBOLS: {
14
+ readonly ELLIPSIS: "…";
15
+ readonly MULTIPLICATION: "×";
16
+ readonly NOT_EQUAL: "≠";
17
+ readonly PLUS_MINUS: "±";
18
+ readonly COPYRIGHT: "©";
19
+ readonly REGISTERED: "®";
20
+ readonly TRADEMARK: "™";
21
+ readonly DEGREE: "°";
22
+ readonly ARROW_RIGHT: "→";
23
+ readonly ARROW_LEFT: "←";
24
+ readonly ARROW_LEFT_RIGHT: "↔";
25
+ readonly APPROXIMATE: "≈";
26
+ readonly LESS_EQUAL: "≤";
27
+ readonly GREATER_EQUAL: "≥";
28
+ readonly PRIME: "′";
29
+ readonly DOUBLE_PRIME: "″";
30
+ readonly FRACTION_1_4: "¼";
31
+ readonly FRACTION_1_2: "½";
32
+ readonly FRACTION_3_4: "¾";
33
+ readonly FRACTION_1_3: "⅓";
34
+ readonly FRACTION_2_3: "⅔";
35
+ readonly FRACTION_1_5: "⅕";
36
+ readonly FRACTION_2_5: "⅖";
37
+ readonly FRACTION_3_5: "⅗";
38
+ readonly FRACTION_4_5: "⅘";
39
+ readonly FRACTION_1_6: "⅙";
40
+ readonly FRACTION_5_6: "⅚";
41
+ readonly FRACTION_1_8: "⅛";
42
+ readonly FRACTION_3_8: "⅜";
43
+ readonly FRACTION_5_8: "⅝";
44
+ readonly FRACTION_7_8: "⅞";
45
+ readonly EM_DASH: "—";
46
+ readonly EN_DASH: "–";
47
+ readonly MINUS: "−";
48
+ readonly LEFT_DOUBLE_QUOTE: "“";
49
+ readonly RIGHT_DOUBLE_QUOTE: "”";
50
+ readonly LEFT_SINGLE_QUOTE: "‘";
51
+ readonly RIGHT_SINGLE_QUOTE: "’";
52
+ };
53
+ /**
54
+ * Default separator character for text spanning HTML elements.
55
+ * Uses Unicode Private Use Area character U+E000.
56
+ */
57
+ export declare const DEFAULT_SEPARATOR = "\uE000";
58
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;GAEG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuClB,CAAA;AAEV;;;GAGG;AACH,eAAO,MAAM,iBAAiB,WAAW,CAAA"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Shared Unicode constants used throughout the punctilio package.
3
+ *
4
+ * This module provides a centralized location for all Unicode symbols
5
+ * used in typography transformations, making the codebase more maintainable
6
+ * and self-documenting.
7
+ *
8
+ * @module constants
9
+ */
10
+ /**
11
+ * Unicode symbols for typography transformations.
12
+ */
13
+ export const UNICODE_SYMBOLS = {
14
+ ELLIPSIS: "\u2026",
15
+ MULTIPLICATION: "\u00D7",
16
+ NOT_EQUAL: "\u2260",
17
+ PLUS_MINUS: "\u00B1",
18
+ COPYRIGHT: "\u00A9",
19
+ REGISTERED: "\u00AE",
20
+ TRADEMARK: "\u2122",
21
+ DEGREE: "\u00B0",
22
+ ARROW_RIGHT: "\u2192",
23
+ ARROW_LEFT: "\u2190",
24
+ ARROW_LEFT_RIGHT: "\u2194",
25
+ APPROXIMATE: "\u2248",
26
+ LESS_EQUAL: "\u2264",
27
+ GREATER_EQUAL: "\u2265",
28
+ PRIME: "\u2032",
29
+ DOUBLE_PRIME: "\u2033",
30
+ FRACTION_1_4: "\u00BC",
31
+ FRACTION_1_2: "\u00BD",
32
+ FRACTION_3_4: "\u00BE",
33
+ FRACTION_1_3: "\u2153",
34
+ FRACTION_2_3: "\u2154",
35
+ FRACTION_1_5: "\u2155",
36
+ FRACTION_2_5: "\u2156",
37
+ FRACTION_3_5: "\u2157",
38
+ FRACTION_4_5: "\u2158",
39
+ FRACTION_1_6: "\u2159",
40
+ FRACTION_5_6: "\u215A",
41
+ FRACTION_1_8: "\u215B",
42
+ FRACTION_3_8: "\u215C",
43
+ FRACTION_5_8: "\u215D",
44
+ FRACTION_7_8: "\u215E",
45
+ EM_DASH: "\u2014",
46
+ EN_DASH: "\u2013",
47
+ MINUS: "\u2212",
48
+ LEFT_DOUBLE_QUOTE: "\u201C",
49
+ RIGHT_DOUBLE_QUOTE: "\u201D",
50
+ LEFT_SINGLE_QUOTE: "\u2018",
51
+ RIGHT_SINGLE_QUOTE: "\u2019",
52
+ };
53
+ /**
54
+ * Default separator character for text spanning HTML elements.
55
+ * Uses Unicode Private Use Area character U+E000.
56
+ */
57
+ export const DEFAULT_SEPARATOR = "\uE000";
58
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,QAAQ,EAAE,QAAQ;IAClB,cAAc,EAAE,QAAQ;IACxB,SAAS,EAAE,QAAQ;IACnB,UAAU,EAAE,QAAQ;IACpB,SAAS,EAAE,QAAQ;IACnB,UAAU,EAAE,QAAQ;IACpB,SAAS,EAAE,QAAQ;IACnB,MAAM,EAAE,QAAQ;IAChB,WAAW,EAAE,QAAQ;IACrB,UAAU,EAAE,QAAQ;IACpB,gBAAgB,EAAE,QAAQ;IAC1B,WAAW,EAAE,QAAQ;IACrB,UAAU,EAAE,QAAQ;IACpB,aAAa,EAAE,QAAQ;IACvB,KAAK,EAAE,QAAQ;IACf,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,OAAO,EAAE,QAAQ;IACjB,OAAO,EAAE,QAAQ;IACjB,KAAK,EAAE,QAAQ;IACf,iBAAiB,EAAE,QAAQ;IAC3B,kBAAkB,EAAE,QAAQ;IAC5B,iBAAiB,EAAE,QAAQ;IAC3B,kBAAkB,EAAE,QAAQ;CACpB,CAAA;AAEV;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"dashes.d.ts","sourceRoot":"","sources":["../src/dashes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,WAAW;IAC1B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAID;;GAEG;AACH,eAAO,MAAM,MAAM,QAyBR,CAAA;AAEX;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CASjF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAM/E;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAI5E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAgD7E"}
1
+ {"version":3,"file":"dashes.d.ts","sourceRoot":"","sources":["../src/dashes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,WAAW,WAAW;IAC1B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAID;;GAEG;AACH,eAAO,MAAM,MAAM,QAyBR,CAAA;AAEX;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CASjF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAM/E;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAI5E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAwC7E"}
package/dist/dashes.js CHANGED
@@ -4,7 +4,8 @@
4
4
  * Converts hyphens and dashes to typographically correct em-dashes,
5
5
  * en-dashes, and minus signs based on context.
6
6
  */
7
- const DEFAULT_SEPARATOR = "\uE000";
7
+ import { UNICODE_SYMBOLS, DEFAULT_SEPARATOR } from "./constants.js";
8
+ const { EN_DASH, EM_DASH, MINUS } = UNICODE_SYMBOLS;
8
9
  /**
9
10
  * List of month names (full and abbreviated) for date range detection
10
11
  */
@@ -59,7 +60,7 @@ export const months = [
59
60
  */
60
61
  export function enDashNumberRange(text, options = {}) {
61
62
  const chr = options.separator ?? DEFAULT_SEPARATOR;
62
- return text.replace(new RegExp(`\\b(?<![a-zA-Z.])((?:p\\.?|\\$)?\\d[\\d.,]*${chr}?)-(${chr}?\\$?\\d[\\d.,]*)(?!\\.\\d)\\b`, "g"), "$1–$2");
63
+ return text.replace(new RegExp(`\\b(?<![a-zA-Z.])((?:p\\.?|\\$)?\\d[\\d.,]*${chr}?)-(${chr}?\\$?\\d[\\d.,]*)(?!\\.\\d)\\b`, "g"), `$1${EN_DASH}$2`);
63
64
  }
64
65
  /**
65
66
  * Replaces hyphens with en-dashes in month/date ranges.
@@ -80,7 +81,7 @@ export function enDashNumberRange(text, options = {}) {
80
81
  */
81
82
  export function enDashDateRange(text, options = {}) {
82
83
  const chr = options.separator ?? DEFAULT_SEPARATOR;
83
- return text.replace(new RegExp(`\\b(${months}${chr}?)-(${chr}?(?:${months}))\\b`, "g"), "$1–$2");
84
+ return text.replace(new RegExp(`\\b(${months}${chr}?)-(${chr}?(?:${months}))\\b`, "g"), `$1${EN_DASH}$2`);
84
85
  }
85
86
  /**
86
87
  * Replaces hyphens with proper minus signs (−) in numerical contexts.
@@ -104,7 +105,7 @@ export function enDashDateRange(text, options = {}) {
104
105
  export function minusReplace(text, options = {}) {
105
106
  const chr = options.separator ?? DEFAULT_SEPARATOR;
106
107
  const minusRegex = new RegExp(`(^|[\\s\\(${chr}""])-(\\s?\\d*\\.?\\d+)`, "gm");
107
- return text.replaceAll(minusRegex, "$1−$2");
108
+ return text.replaceAll(minusRegex, `$1${MINUS}$2`);
108
109
  }
109
110
  /**
110
111
  * Comprehensive dash replacement for typographic correctness.
@@ -146,25 +147,17 @@ export function hyphenReplace(text, options = {}) {
146
147
  // Being right after chr is a sufficient condition for being an em
147
148
  // dash, as it indicates the start of a new line
148
149
  const preDash = new RegExp(`((?<markerBeforeTwo>${chr}?)[ ]+|(?<markerBeforeThree>${chr}))`);
149
- // Want eg " - " to be replaced with ""
150
- const surroundedDash = new RegExp(`(?<=[^\\s>]|^)${preDash.source}[~–—-]+[ ]*(?<markerAfter>${chr}?)([ ]+|$)`, "g");
151
- // Replace surrounded dashes with em dash
152
- text = text.replace(surroundedDash, "$<markerBeforeTwo>$<markerBeforeThree>—$<markerAfter>");
153
- // "Since--as you know" should be "Since—as you know"
154
- const multipleDashInWords = new RegExp(`(?<=[A-Za-z\\d])(?<markerBefore>${chr}?)[~–—-]{2,}(?<markerAfter>${chr}?)(?=[A-Za-z\\d ])`, "g");
155
- text = text.replace(multipleDashInWords, "$<markerBefore>—$<markerAfter>");
156
- // Handle dashes at the start of a line
157
- text = text.replace(new RegExp(`^(${chr})?[-]+ `, "gm"), "$1— ");
158
- // Create a regex for spaces around em dashes, allowing for optional spaces around the em dash
159
- const spacesAroundEM = new RegExp(`(?<markerBefore>${chr}?)[ ]*—[ ]*(?<markerAfter>${chr}?)[ ]*`, "g");
160
- // Remove spaces around em dashes
161
- text = text.replace(spacesAroundEM, "$<markerBefore>—$<markerAfter>");
162
- // Handle special case after quotation marks
150
+ const surroundedDash = new RegExp(`(?<=[^\\s>]|^)${preDash.source}[~${EN_DASH}${EM_DASH}-]+[ ]*(?<markerAfter>${chr}?)([ ]+|$)`, "g");
151
+ text = text.replace(surroundedDash, `$<markerBeforeTwo>$<markerBeforeThree>${EM_DASH}$<markerAfter>`);
152
+ const multipleDashInWords = new RegExp(`(?<=[A-Za-z\\d])(?<markerBefore>${chr}?)[~${EN_DASH}${EM_DASH}-]{2,}(?<markerAfter>${chr}?)(?=[A-Za-z\\d ])`, "g");
153
+ text = text.replace(multipleDashInWords, `$<markerBefore>${EM_DASH}$<markerAfter>`);
154
+ text = text.replace(new RegExp(`^(${chr})?[-]+ `, "gm"), `$1${EM_DASH} `);
155
+ const spacesAroundEM = new RegExp(`(?<markerBefore>${chr}?)[ ]*${EM_DASH}[ ]*(?<markerAfter>${chr}?)[ ]*`, "g");
156
+ text = text.replace(spacesAroundEM, `$<markerBefore>${EM_DASH}$<markerAfter>`);
163
157
  const postQuote = new RegExp(`(?<quote>[.!?]${chr}?['"'"]${chr}?|…)${spacesAroundEM.source}`, "g");
164
- text = text.replace(postQuote, "$<quote> $<markerBefore>—$<markerAfter> ");
165
- // Handle em dashes at the start of a line
158
+ text = text.replace(postQuote, `$<quote> $<markerBefore>${EM_DASH}$<markerAfter> `);
166
159
  const startOfLine = new RegExp(`^${spacesAroundEM.source}(?<after>[A-Z0-9])`, "gm");
167
- text = text.replace(startOfLine, "$<markerBefore>—$<markerAfter> $<after>");
160
+ text = text.replace(startOfLine, `$<markerBefore>${EM_DASH}$<markerAfter> $<after>`);
168
161
  text = enDashNumberRange(text, options);
169
162
  text = enDashDateRange(text, options);
170
163
  return text;
@@ -1 +1 @@
1
- {"version":3,"file":"dashes.js","sourceRoot":"","sources":["../src/dashes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dashes.js","sourceRoot":"","sources":["../src/dashes.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -3,12 +3,13 @@
3
3
  *
4
4
  * A library for converting plain ASCII punctuation into typographically
5
5
  * correct Unicode characters. Handles smart quotes, em-dashes, en-dashes,
6
- * minus signs, and more.
6
+ * minus signs, ellipses, multiplication signs, and more.
7
7
  *
8
8
  * @packageDocumentation
9
9
  */
10
10
  export { niceQuotes, type QuoteOptions } from "./quotes.js";
11
11
  export { hyphenReplace, enDashNumberRange, enDashDateRange, minusReplace, months, type DashOptions, } from "./dashes.js";
12
+ export { ellipsis, multiplication, mathSymbols, legalSymbols, arrows, degrees, fractions, primeMarks, symbolTransform, type SymbolOptions, } from "./symbols.js";
12
13
  export interface TransformOptions {
13
14
  /**
14
15
  * A boundary marker character used when transforming text that spans
@@ -19,12 +20,33 @@ export interface TransformOptions {
19
20
  * Default: "\uE000" (Unicode Private Use Area)
20
21
  */
21
22
  separator?: string;
23
+ /**
24
+ * Whether to include symbol transforms (ellipsis, multiplication, etc.)
25
+ * Default: true
26
+ */
27
+ symbols?: boolean;
28
+ /**
29
+ * Whether to include fraction transforms (1/2 → ½)
30
+ * Default: false (can be aggressive)
31
+ */
32
+ fractions?: boolean;
33
+ /**
34
+ * Whether to include degree symbol transforms (20 C → 20 °C)
35
+ * Default: false (can be aggressive)
36
+ */
37
+ degrees?: boolean;
22
38
  }
23
39
  /**
24
- * Applies all typography transformations: smart quotes and proper dashes.
40
+ * Applies all typography transformations: smart quotes, proper dashes,
41
+ * and symbol improvements.
25
42
  *
26
- * This is a convenience function that applies both `niceQuotes` and
27
- * `hyphenReplace` in sequence.
43
+ * This is a convenience function that applies transformations in sequence:
44
+ * 1. hyphenReplace (em-dashes, en-dashes, minus signs)
45
+ * 2. primeMarks (feet/inches, arcminutes/arcseconds)
46
+ * 3. niceQuotes (smart quotes)
47
+ * 4. symbolTransform (ellipses, multiplication, math symbols, legal symbols, arrows)
48
+ * 5. fractions (optional, disabled by default)
49
+ * 6. degrees (optional, disabled by default)
28
50
  *
29
51
  * @param text - The text to transform
30
52
  * @param options - Configuration options
@@ -32,10 +54,16 @@ export interface TransformOptions {
32
54
  *
33
55
  * @example
34
56
  * ```ts
35
- * import { transform } from '@alexander-turner/punctilio'
57
+ * import { transform } from 'punctilio'
36
58
  *
37
59
  * transform('"Hello," she said - "it\'s pages 1-5."')
38
60
  * // → '"Hello," she said—"it's pages 1–5."'
61
+ *
62
+ * transform('Wait... 5x5 != 25 (c) 2024')
63
+ * // → 'Wait… 5×5 ≠ 25 © 2024'
64
+ *
65
+ * transform('Add 1/2 cup', { fractions: true })
66
+ * // → 'Add ½ cup'
39
67
  * ```
40
68
  */
41
69
  export declare function transform(text: string, options?: TransformOptions): string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA;AAC3D,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,MAAM,EACN,KAAK,WAAW,GACjB,MAAM,aAAa,CAAA;AAEpB,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAKD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAI9E;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,WAAW,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA;AAC3D,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,MAAM,EACN,KAAK,WAAW,GACjB,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,QAAQ,EACR,cAAc,EACd,WAAW,EACX,YAAY,EACZ,MAAM,EACN,OAAO,EACP,SAAS,EACT,UAAU,EACV,eAAe,EACf,KAAK,aAAa,GACnB,MAAM,cAAc,CAAA;AAErB,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAoB9E;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,WAAW,CAAA"}
package/dist/index.js CHANGED
@@ -3,19 +3,27 @@
3
3
  *
4
4
  * A library for converting plain ASCII punctuation into typographically
5
5
  * correct Unicode characters. Handles smart quotes, em-dashes, en-dashes,
6
- * minus signs, and more.
6
+ * minus signs, ellipses, multiplication signs, and more.
7
7
  *
8
8
  * @packageDocumentation
9
9
  */
10
10
  export { niceQuotes } from "./quotes.js";
11
11
  export { hyphenReplace, enDashNumberRange, enDashDateRange, minusReplace, months, } from "./dashes.js";
12
+ export { ellipsis, multiplication, mathSymbols, legalSymbols, arrows, degrees, fractions, primeMarks, symbolTransform, } from "./symbols.js";
12
13
  import { niceQuotes } from "./quotes.js";
13
14
  import { hyphenReplace } from "./dashes.js";
15
+ import { symbolTransform, fractions as fractionsTransform, degrees as degreesTransform, primeMarks } from "./symbols.js";
14
16
  /**
15
- * Applies all typography transformations: smart quotes and proper dashes.
17
+ * Applies all typography transformations: smart quotes, proper dashes,
18
+ * and symbol improvements.
16
19
  *
17
- * This is a convenience function that applies both `niceQuotes` and
18
- * `hyphenReplace` in sequence.
20
+ * This is a convenience function that applies transformations in sequence:
21
+ * 1. hyphenReplace (em-dashes, en-dashes, minus signs)
22
+ * 2. primeMarks (feet/inches, arcminutes/arcseconds)
23
+ * 3. niceQuotes (smart quotes)
24
+ * 4. symbolTransform (ellipses, multiplication, math symbols, legal symbols, arrows)
25
+ * 5. fractions (optional, disabled by default)
26
+ * 6. degrees (optional, disabled by default)
19
27
  *
20
28
  * @param text - The text to transform
21
29
  * @param options - Configuration options
@@ -23,15 +31,32 @@ import { hyphenReplace } from "./dashes.js";
23
31
  *
24
32
  * @example
25
33
  * ```ts
26
- * import { transform } from '@alexander-turner/punctilio'
34
+ * import { transform } from 'punctilio'
27
35
  *
28
36
  * transform('"Hello," she said - "it\'s pages 1-5."')
29
37
  * // → '"Hello," she said—"it's pages 1–5."'
38
+ *
39
+ * transform('Wait... 5x5 != 25 (c) 2024')
40
+ * // → 'Wait… 5×5 ≠ 25 © 2024'
41
+ *
42
+ * transform('Add 1/2 cup', { fractions: true })
43
+ * // → 'Add ½ cup'
30
44
  * ```
31
45
  */
32
46
  export function transform(text, options = {}) {
33
- text = hyphenReplace(text, options);
34
- text = niceQuotes(text, options);
47
+ const { symbols = true, fractions = false, degrees = false, ...separatorOpts } = options;
48
+ text = hyphenReplace(text, separatorOpts);
49
+ text = primeMarks(text, separatorOpts);
50
+ text = niceQuotes(text, separatorOpts);
51
+ if (symbols) {
52
+ text = symbolTransform(text, separatorOpts);
53
+ }
54
+ if (fractions) {
55
+ text = fractionsTransform(text);
56
+ }
57
+ if (degrees) {
58
+ text = degreesTransform(text);
59
+ }
35
60
  return text;
36
61
  }
37
62
  /**
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAqB,MAAM,aAAa,CAAA;AAC3D,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,MAAM,GAEP,MAAM,aAAa,CAAA;AAcpB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,UAA4B,EAAE;IACpE,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IACnC,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IAChC,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAqB,MAAM,aAAa,CAAA;AAC3D,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,MAAM,GAEP,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,QAAQ,EACR,cAAc,EACd,WAAW,EACX,YAAY,EACZ,MAAM,EACN,OAAO,EACP,SAAS,EACT,UAAU,EACV,eAAe,GAEhB,MAAM,cAAc,CAAA;AAgCrB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,eAAe,EAAE,SAAS,IAAI,kBAAkB,EAAE,OAAO,IAAI,gBAAgB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAExH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,UAA4B,EAAE;IACpE,MAAM,EAAE,OAAO,GAAG,IAAI,EAAE,SAAS,GAAG,KAAK,EAAE,OAAO,GAAG,KAAK,EAAE,GAAG,aAAa,EAAE,GAAG,OAAO,CAAA;IAExF,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;IACzC,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;IACtC,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;IAEtC,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,GAAG,eAAe,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;IAC7C,CAAC;IAED,IAAI,SAAS,EAAE,CAAC;QACd,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAA;IACjC,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAA;IAC/B,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"quotes.d.ts","sourceRoot":"","sources":["../src/quotes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,YAAY;IAC3B;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAYD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,MAAM,CA+D3E"}
1
+ {"version":3,"file":"quotes.d.ts","sourceRoot":"","sources":["../src/quotes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAaH,MAAM,WAAW,YAAY;IAC3B;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,MAAM,CA8C3E"}
package/dist/quotes.js CHANGED
@@ -4,14 +4,8 @@
4
4
  * Converts straight quotes to typographically correct curly quotes,
5
5
  * handling contractions, possessives, and nested quotes.
6
6
  */
7
- const DEFAULT_SEPARATOR = "\uE000";
8
- // Unicode typography characters
9
- const EM_DASH = "\u2014"; // —
10
- const LEFT_DOUBLE = "\u201C"; // "
11
- const RIGHT_DOUBLE = "\u201D"; // "
12
- const LEFT_SINGLE = "\u2018"; // '
13
- const RIGHT_SINGLE = "\u2019"; // '
14
- const ELLIPSIS = "\u2026"; // …
7
+ import { UNICODE_SYMBOLS, DEFAULT_SEPARATOR } from "./constants.js";
8
+ const { EM_DASH, LEFT_DOUBLE_QUOTE, RIGHT_DOUBLE_QUOTE, LEFT_SINGLE_QUOTE, RIGHT_SINGLE_QUOTE, ELLIPSIS, } = UNICODE_SYMBOLS;
15
9
  /**
16
10
  * Converts standard quotes to typographic smart quotes.
17
11
  *
@@ -21,45 +15,28 @@ const ELLIPSIS = "\u2026"; // …
21
15
  */
22
16
  export function niceQuotes(text, options = {}) {
23
17
  const chr = options.separator ?? DEFAULT_SEPARATOR;
24
- // Single quotes //
25
- // Ending comes first so as to not mess with the open quote
26
18
  const afterEndingSinglePatterns = `\\s\\.!?;,\\)${EM_DASH}\\-\\]"`;
27
19
  const afterEndingSingle = `(?=${chr}?(?:s${chr}?)?(?:[${afterEndingSinglePatterns}]|$))`;
28
- const endingSingle = `(?<=[^\\s${LEFT_DOUBLE}'])[']${afterEndingSingle}`;
29
- text = text.replace(new RegExp(endingSingle, "gm"), RIGHT_SINGLE);
30
- // Contractions are sandwiched between two letters
31
- const contraction = `(?<=[A-Za-z])['${RIGHT_SINGLE}](?=${chr}?[a-zA-Z])`;
32
- text = text.replace(new RegExp(contraction, "gm"), RIGHT_SINGLE);
33
- // Apostrophes always point down
34
- // Whitelist for eg rock 'n' roll
35
- const apostropheWhitelist = `(?=n${RIGHT_SINGLE} )`;
36
- const endQuoteNotContraction = `(?!${contraction})${RIGHT_SINGLE}${afterEndingSingle}`;
37
- // Convert to apostrophe if not followed by an end quote
38
- // Note: The character class uses LEFT_SINGLE and ASCII straight quote (U+0027)
39
- // NOT RIGHT_SINGLE - this is intentional for the algorithm to work correctly
40
- const apostropheRegex = new RegExp(`(?<=^|[^\\w])'(${apostropheWhitelist}|(?![^${LEFT_SINGLE}'\\n]*${endQuoteNotContraction}))`, "gm");
41
- text = text.replace(apostropheRegex, RIGHT_SINGLE);
42
- // Beginning single quotes
43
- const beginningSingle = `((?:^|[\\s${LEFT_DOUBLE}${RIGHT_DOUBLE}\\-\\(])${chr}?)['](?=${chr}?\\S)`;
44
- text = text.replace(new RegExp(beginningSingle, "gm"), `$1${LEFT_SINGLE}`);
45
- // Double quotes //
20
+ const endingSingle = `(?<=[^\\s${LEFT_DOUBLE_QUOTE}'])[']${afterEndingSingle}`;
21
+ text = text.replace(new RegExp(endingSingle, "gm"), RIGHT_SINGLE_QUOTE);
22
+ const contraction = `(?<=[A-Za-z])['${RIGHT_SINGLE_QUOTE}](?=${chr}?[a-zA-Z])`;
23
+ text = text.replace(new RegExp(contraction, "gm"), RIGHT_SINGLE_QUOTE);
24
+ const apostropheWhitelist = `(?=n${RIGHT_SINGLE_QUOTE} )`;
25
+ const endQuoteNotContraction = `(?!${contraction})${RIGHT_SINGLE_QUOTE}${afterEndingSingle}`;
26
+ const apostropheRegex = new RegExp(`(?<=^|[^\\w])'(${apostropheWhitelist}|(?![^${LEFT_SINGLE_QUOTE}'\\n]*${endQuoteNotContraction}))`, "gm");
27
+ text = text.replace(apostropheRegex, RIGHT_SINGLE_QUOTE);
28
+ const beginningSingle = `((?:^|[\\s${LEFT_DOUBLE_QUOTE}${RIGHT_DOUBLE_QUOTE}\\-\\(])${chr}?)['](?=${chr}?\\S)`;
29
+ text = text.replace(new RegExp(beginningSingle, "gm"), `$1${LEFT_SINGLE_QUOTE}`);
46
30
  const beginningDouble = new RegExp(`(?<=^|[\\s\\(\\/\\[\\{\\-${EM_DASH}${chr}])(?<beforeChr>${chr}?)["](?<afterChr>(${chr}[ .,])|(?=${chr}?\\.{3}|${chr}?[^\\s\\)\\${EM_DASH},!?${chr};:.\\}]))`, "gm");
47
- text = text.replace(beginningDouble, `$<beforeChr>${LEFT_DOUBLE}$<afterChr>`);
48
- // Open quote after brace (generally in math mode)
49
- text = text.replace(new RegExp(`(?<=\\{)(${chr}? )?["]`, "g"), `$1${LEFT_DOUBLE}`);
50
- // note: Allowing 2 chrs in a row
31
+ text = text.replace(beginningDouble, `$<beforeChr>${LEFT_DOUBLE_QUOTE}$<afterChr>`);
32
+ text = text.replace(new RegExp(`(?<=\\{)(${chr}? )?["]`, "g"), `$1${LEFT_DOUBLE_QUOTE}`);
51
33
  const endingDouble = `([^\\s\\(])["](${chr}?)(?=${chr}|[\\s/\\).,;${EM_DASH}:\\-\\}!?s]|$)`;
52
- text = text.replace(new RegExp(endingDouble, "g"), `$1${RIGHT_DOUBLE}$2`);
53
- // If end of line, replace with right double quote
54
- text = text.replace(new RegExp(`["](${chr}?)$`, "g"), `${RIGHT_DOUBLE}$1`);
55
- // If single quote has a right double quote after it, replace with right single and then double
56
- text = text.replace(new RegExp(`'(?=${RIGHT_DOUBLE})`, "gu"), RIGHT_SINGLE);
57
- // Punctuation //
58
- // Periods inside quotes
59
- const periodRegex = new RegExp(`(?<![!?:\\.${ELLIPSIS}])(${chr}?)([${RIGHT_SINGLE}${RIGHT_DOUBLE}])(${chr}?)(?!\\.\\.\\.)\\.`, "g");
34
+ text = text.replace(new RegExp(endingDouble, "g"), `$1${RIGHT_DOUBLE_QUOTE}$2`);
35
+ text = text.replace(new RegExp(`["](${chr}?)$`, "g"), `${RIGHT_DOUBLE_QUOTE}$1`);
36
+ text = text.replace(new RegExp(`'(?=${RIGHT_DOUBLE_QUOTE})`, "gu"), RIGHT_SINGLE_QUOTE);
37
+ const periodRegex = new RegExp(`(?<![!?:\\.${ELLIPSIS}])(${chr}?)([${RIGHT_SINGLE_QUOTE}${RIGHT_DOUBLE_QUOTE}])(${chr}?)(?!\\.\\.\\.)\\.`, "g");
60
38
  text = text.replace(periodRegex, "$1.$2$3");
61
- // Commas outside of quotes
62
- const commaRegex = new RegExp(`(?<![!?]),(${chr}?[${RIGHT_DOUBLE}${RIGHT_SINGLE}])`, "g");
39
+ const commaRegex = new RegExp(`(?<![!?]),(${chr}?[${RIGHT_DOUBLE_QUOTE}${RIGHT_SINGLE_QUOTE}])`, "g");
63
40
  text = text.replace(commaRegex, "$1,");
64
41
  return text;
65
42
  }
@@ -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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"}
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Symbol and character transformations for common typography improvements.
3
+ *
4
+ * Handles ellipses, multiplication signs, mathematical symbols, and
5
+ * common character sequences that should use proper Unicode glyphs.
6
+ *
7
+ * @module symbols
8
+ */
9
+ export interface SymbolOptions {
10
+ /**
11
+ * Boundary marker character for text spanning HTML elements.
12
+ * Default: "\uE000" (Unicode Private Use Area)
13
+ */
14
+ separator?: string;
15
+ /**
16
+ * Whether to include arrow transformations (-> to →, etc.).
17
+ * Default: true
18
+ */
19
+ includeArrows?: boolean;
20
+ }
21
+ /**
22
+ * Converts three periods to a proper ellipsis character.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * ellipsis("Wait for it...")
27
+ * // → "Wait for it…"
28
+ * ```
29
+ */
30
+ export declare function ellipsis(text: string, options?: SymbolOptions): string;
31
+ /**
32
+ * Converts ASCII multiplication patterns to proper multiplication sign (×).
33
+ *
34
+ * Handles:
35
+ * - Dimensions: "5x5" → "5×5"
36
+ * - Trailing multiplier: "5x" → "5×" (when followed by word boundary)
37
+ * - Asterisk multiplication: "5*3" → "5×3" (when between numbers)
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * multiplication("The room is 10x12 feet")
42
+ * // → "The room is 10×12 feet"
43
+ *
44
+ * multiplication("2x speed")
45
+ * // → "2× speed"
46
+ * ```
47
+ */
48
+ export declare function multiplication(text: string, options?: SymbolOptions): string;
49
+ /**
50
+ * Converts ASCII mathematical symbols to proper Unicode equivalents.
51
+ *
52
+ * Handles:
53
+ * - "!=" → "≠"
54
+ * - "+-" or "+/-" → "±"
55
+ * - "<=" → "≤"
56
+ * - ">=" → "≥"
57
+ * - "~=" or "=~" → "≈"
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * mathSymbols("x != y and a <= b")
62
+ * // → "x ≠ y and a ≤ b"
63
+ *
64
+ * mathSymbols("The answer is +- 5%")
65
+ * // → "The answer is ± 5%"
66
+ * ```
67
+ */
68
+ export declare function mathSymbols(text: string): string;
69
+ /**
70
+ * Converts ASCII representations of copyright, registered, and trademark
71
+ * symbols to proper Unicode characters.
72
+ */
73
+ export declare function legalSymbols(text: string): string;
74
+ /**
75
+ * Converts arrow character sequences to Unicode arrows.
76
+ *
77
+ * Handles:
78
+ * - "->" or "-->" → "→"
79
+ * - "<-" or "<--" → "←"
80
+ * - "<->" or "<-->" → "↔"
81
+ *
82
+ * Note: Only converts when surrounded by spaces or at word boundaries
83
+ * to avoid false matches in code or URLs.
84
+ *
85
+ * @example
86
+ * ```ts
87
+ * arrows("A -> B -> C")
88
+ * // → "A → B → C"
89
+ *
90
+ * arrows("left <-> right")
91
+ * // → "left ↔ right"
92
+ * ```
93
+ */
94
+ export declare function arrows(text: string, options?: SymbolOptions): string;
95
+ /**
96
+ * Adds degree symbol in temperature contexts.
97
+ *
98
+ * Handles:
99
+ * - "20 C" or "20C" → "20 °C" (Celsius)
100
+ * - "68 F" or "68F" → "68 °F" (Fahrenheit)
101
+ *
102
+ * Only matches when followed by C or F (case insensitive) to avoid
103
+ * false positives.
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * degrees("The temperature is 20 C")
108
+ * // → "The temperature is 20 °C"
109
+ *
110
+ * degrees("Water boils at 212F")
111
+ * // → "Water boils at 212 °F"
112
+ * ```
113
+ */
114
+ export declare function degrees(text: string): string;
115
+ /**
116
+ * Converts straight quotes after numbers to prime marks.
117
+ *
118
+ * Prime marks are used for:
119
+ * - Feet and inches: 5'10" → 5′10″
120
+ * - Arcminutes and arcseconds: 45° 30' 15" → 45° 30′ 15″
121
+ *
122
+ * This should be called BEFORE smart quote transformations to prevent
123
+ * quotes in measurements from being curled.
124
+ *
125
+ * @example
126
+ * ```ts
127
+ * primeMarks("He's 5'10\" tall")
128
+ * // → "He's 5′10″ tall"
129
+ *
130
+ * primeMarks("Location: 45° 30' 15\"")
131
+ * // → "Location: 45° 30′ 15″"
132
+ * ```
133
+ */
134
+ export declare function primeMarks(text: string, options?: SymbolOptions): string;
135
+ /**
136
+ * Converts common fractions to Unicode fraction characters.
137
+ *
138
+ * Handles: 1/4, 1/2, 3/4, 1/3, 2/3, 1/5, 2/5, 3/5, 4/5,
139
+ * 1/6, 5/6, 1/8, 3/8, 5/8, 7/8
140
+ *
141
+ * Only converts when the fraction is surrounded by word boundaries
142
+ * to avoid breaking URLs, file paths, or dates.
143
+ *
144
+ * @example
145
+ * ```ts
146
+ * fractions("Add 1/2 cup of flour")
147
+ * // → "Add ½ cup of flour"
148
+ *
149
+ * fractions("About 3/4 complete")
150
+ * // → "About ¾ complete"
151
+ * ```
152
+ */
153
+ export declare function fractions(text: string): string;
154
+ /**
155
+ * Applies all symbol transformations.
156
+ *
157
+ * Runs in order:
158
+ * 1. ellipsis
159
+ * 2. multiplication
160
+ * 3. mathSymbols
161
+ * 4. legalSymbols
162
+ * 5. arrows
163
+ *
164
+ * Note: `degrees` and `fractions` are not included by default as they
165
+ * may be too aggressive for some use cases. Call them explicitly if needed.
166
+ *
167
+ * @example
168
+ * ```ts
169
+ * symbolTransform("Wait... 5x5 != 20 (c) 2024")
170
+ * // → "Wait… 5×5 ≠ 20 © 2024"
171
+ * ```
172
+ */
173
+ export declare function symbolTransform(text: string, options?: SymbolOptions): string;
174
+ //# sourceMappingURL=symbols.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"symbols.d.ts","sourceRoot":"","sources":["../src/symbols.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AA4BD;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAS1E;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAgBhF;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAUhD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMjD;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAaxE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO5C;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CA0B5E;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAyB9C;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CASjF"}
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Symbol and character transformations for common typography improvements.
3
+ *
4
+ * Handles ellipses, multiplication signs, mathematical symbols, and
5
+ * common character sequences that should use proper Unicode glyphs.
6
+ *
7
+ * @module symbols
8
+ */
9
+ import { UNICODE_SYMBOLS, DEFAULT_SEPARATOR } from "./constants.js";
10
+ /**
11
+ * Escapes special regex characters in a string.
12
+ */
13
+ function escapeRegex(str) {
14
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
15
+ }
16
+ const { ELLIPSIS, MULTIPLICATION, NOT_EQUAL, PLUS_MINUS, COPYRIGHT, REGISTERED, TRADEMARK, DEGREE, ARROW_RIGHT, ARROW_LEFT, ARROW_LEFT_RIGHT, APPROXIMATE, LESS_EQUAL, GREATER_EQUAL, PRIME, DOUBLE_PRIME, } = UNICODE_SYMBOLS;
17
+ /**
18
+ * Converts three periods to a proper ellipsis character.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * ellipsis("Wait for it...")
23
+ * // → "Wait for it…"
24
+ * ```
25
+ */
26
+ export function ellipsis(text, options = {}) {
27
+ const chr = escapeRegex(options.separator ?? DEFAULT_SEPARATOR);
28
+ const pattern = new RegExp(`\\.${chr}?\\.${chr}?\\.`, "g");
29
+ text = text.replace(pattern, ELLIPSIS);
30
+ text = text.replace(new RegExp(`${ELLIPSIS}(?=\\w)`, "gu"), `${ELLIPSIS} `);
31
+ return text;
32
+ }
33
+ /**
34
+ * Converts ASCII multiplication patterns to proper multiplication sign (×).
35
+ *
36
+ * Handles:
37
+ * - Dimensions: "5x5" → "5×5"
38
+ * - Trailing multiplier: "5x" → "5×" (when followed by word boundary)
39
+ * - Asterisk multiplication: "5*3" → "5×3" (when between numbers)
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * multiplication("The room is 10x12 feet")
44
+ * // → "The room is 10×12 feet"
45
+ *
46
+ * multiplication("2x speed")
47
+ * // → "2× speed"
48
+ * ```
49
+ */
50
+ export function multiplication(text, options = {}) {
51
+ const chr = escapeRegex(options.separator ?? DEFAULT_SEPARATOR);
52
+ // Dimensions with spaces: preserve spacing
53
+ const loosePattern = new RegExp(`(\\d${chr}?)\\s+[xX*]\\s+(${chr}?\\d)`, "g");
54
+ text = text.replace(loosePattern, `$1 ${MULTIPLICATION} $2`);
55
+ // Dimensions without spaces: keep tight
56
+ const tightPattern = new RegExp(`(\\d${chr}?)[xX*](${chr}?\\d)`, "g");
57
+ text = text.replace(tightPattern, `$1${MULTIPLICATION}$2`);
58
+ // Trailing multiplier: 5x (followed by space or end, not letters or numbers)
59
+ const trailingPattern = new RegExp(`(\\d${chr}?)[xX*](?=${chr}?(?:\\s|$))`, "g");
60
+ text = text.replace(trailingPattern, `$1${MULTIPLICATION}`);
61
+ return text;
62
+ }
63
+ /**
64
+ * Converts ASCII mathematical symbols to proper Unicode equivalents.
65
+ *
66
+ * Handles:
67
+ * - "!=" → "≠"
68
+ * - "+-" or "+/-" → "±"
69
+ * - "<=" → "≤"
70
+ * - ">=" → "≥"
71
+ * - "~=" or "=~" → "≈"
72
+ *
73
+ * @example
74
+ * ```ts
75
+ * mathSymbols("x != y and a <= b")
76
+ * // → "x ≠ y and a ≤ b"
77
+ *
78
+ * mathSymbols("The answer is +- 5%")
79
+ * // → "The answer is ± 5%"
80
+ * ```
81
+ */
82
+ export function mathSymbols(text) {
83
+ text = text.replace(/!=/g, NOT_EQUAL);
84
+ text = text.replace(/\+\/-/g, PLUS_MINUS);
85
+ text = text.replace(/\+-/g, PLUS_MINUS);
86
+ text = text.replace(/<=/g, LESS_EQUAL);
87
+ text = text.replace(/>=/g, GREATER_EQUAL);
88
+ text = text.replace(/~=/g, APPROXIMATE);
89
+ text = text.replace(/=~/g, APPROXIMATE);
90
+ return text;
91
+ }
92
+ /**
93
+ * Converts ASCII representations of copyright, registered, and trademark
94
+ * symbols to proper Unicode characters.
95
+ */
96
+ export function legalSymbols(text) {
97
+ text = text.replace(/\(c\)/gi, COPYRIGHT);
98
+ text = text.replace(/\(r\)/gi, REGISTERED);
99
+ text = text.replace(/\(tm\)/gi, TRADEMARK);
100
+ return text;
101
+ }
102
+ /**
103
+ * Converts arrow character sequences to Unicode arrows.
104
+ *
105
+ * Handles:
106
+ * - "->" or "-->" → "→"
107
+ * - "<-" or "<--" → "←"
108
+ * - "<->" or "<-->" → "↔"
109
+ *
110
+ * Note: Only converts when surrounded by spaces or at word boundaries
111
+ * to avoid false matches in code or URLs.
112
+ *
113
+ * @example
114
+ * ```ts
115
+ * arrows("A -> B -> C")
116
+ * // → "A → B → C"
117
+ *
118
+ * arrows("left <-> right")
119
+ * // → "left ↔ right"
120
+ * ```
121
+ */
122
+ export function arrows(text, options = {}) {
123
+ const chr = escapeRegex(options.separator ?? DEFAULT_SEPARATOR);
124
+ // Bidirectional arrow first (to avoid partial matches)
125
+ text = text.replace(new RegExp(`<-{1,2}${chr}?>`, "g"), ARROW_LEFT_RIGHT);
126
+ // Right arrow
127
+ text = text.replace(new RegExp(`(?<=[\\s${chr}]|^)-{1,2}>(?=[\\s${chr}]|$)`, "g"), ARROW_RIGHT);
128
+ // Left arrow
129
+ text = text.replace(new RegExp(`(?<=[\\s${chr}]|^)<-{1,2}(?=[\\s${chr}]|$)`, "g"), ARROW_LEFT);
130
+ return text;
131
+ }
132
+ /**
133
+ * Adds degree symbol in temperature contexts.
134
+ *
135
+ * Handles:
136
+ * - "20 C" or "20C" → "20 °C" (Celsius)
137
+ * - "68 F" or "68F" → "68 °F" (Fahrenheit)
138
+ *
139
+ * Only matches when followed by C or F (case insensitive) to avoid
140
+ * false positives.
141
+ *
142
+ * @example
143
+ * ```ts
144
+ * degrees("The temperature is 20 C")
145
+ * // → "The temperature is 20 °C"
146
+ *
147
+ * degrees("Water boils at 212F")
148
+ * // → "Water boils at 212 °F"
149
+ * ```
150
+ */
151
+ export function degrees(text) {
152
+ // Temperature with optional space before C or F
153
+ text = text.replace(/(\d+) ?([CF])\b/gi, (_, num, unit) => {
154
+ return `${num} ${DEGREE}${unit.toUpperCase()}`;
155
+ });
156
+ return text;
157
+ }
158
+ /**
159
+ * Converts straight quotes after numbers to prime marks.
160
+ *
161
+ * Prime marks are used for:
162
+ * - Feet and inches: 5'10" → 5′10″
163
+ * - Arcminutes and arcseconds: 45° 30' 15" → 45° 30′ 15″
164
+ *
165
+ * This should be called BEFORE smart quote transformations to prevent
166
+ * quotes in measurements from being curled.
167
+ *
168
+ * @example
169
+ * ```ts
170
+ * primeMarks("He's 5'10\" tall")
171
+ * // → "He's 5′10″ tall"
172
+ *
173
+ * primeMarks("Location: 45° 30' 15\"")
174
+ * // → "Location: 45° 30′ 15″"
175
+ * ```
176
+ */
177
+ export function primeMarks(text, options = {}) {
178
+ const chr = escapeRegex(options.separator ?? DEFAULT_SEPARATOR);
179
+ // Single prime: digit followed by ' and then either digit, ", or end/space/punctuation
180
+ // This handles feet (5') and arcminutes (30')
181
+ const singlePrimePattern = new RegExp(`(\\d${chr}?)'(?=${chr}?(?:\\d|"|$|[\\s.,;:!?)]))`, "g");
182
+ text = text.replace(singlePrimePattern, `$1${PRIME}`);
183
+ // Double prime: Only match when it's clearly a measurement context
184
+ // Pattern 1: Feet-inches pattern (5'10" or 5′10")
185
+ const feetInchesPattern = new RegExp(`(${PRIME}${chr}?\\d${chr}?)"`, "g");
186
+ text = text.replace(feetInchesPattern, `$1${DOUBLE_PRIME}`);
187
+ // Pattern 2: Standalone inches - match digit followed by " but NOT when it's a closing quote
188
+ // Use negative lookbehind to ensure there's no opening quote before the number
189
+ // This matches: 12" wide, but not: "Term 1"
190
+ const standaloneInchesPattern = new RegExp(`(?<!["\u201C]${chr}?[^"${chr}]{0,20})(\\d${chr}?)"(?!${chr}?[\\w])`, "g");
191
+ text = text.replace(standaloneInchesPattern, `$1${DOUBLE_PRIME}`);
192
+ return text;
193
+ }
194
+ /**
195
+ * Converts common fractions to Unicode fraction characters.
196
+ *
197
+ * Handles: 1/4, 1/2, 3/4, 1/3, 2/3, 1/5, 2/5, 3/5, 4/5,
198
+ * 1/6, 5/6, 1/8, 3/8, 5/8, 7/8
199
+ *
200
+ * Only converts when the fraction is surrounded by word boundaries
201
+ * to avoid breaking URLs, file paths, or dates.
202
+ *
203
+ * @example
204
+ * ```ts
205
+ * fractions("Add 1/2 cup of flour")
206
+ * // → "Add ½ cup of flour"
207
+ *
208
+ * fractions("About 3/4 complete")
209
+ * // → "About ¾ complete"
210
+ * ```
211
+ */
212
+ export function fractions(text) {
213
+ const fractionMap = {
214
+ "1/4": UNICODE_SYMBOLS.FRACTION_1_4,
215
+ "1/2": UNICODE_SYMBOLS.FRACTION_1_2,
216
+ "3/4": UNICODE_SYMBOLS.FRACTION_3_4,
217
+ "1/3": UNICODE_SYMBOLS.FRACTION_1_3,
218
+ "2/3": UNICODE_SYMBOLS.FRACTION_2_3,
219
+ "1/5": UNICODE_SYMBOLS.FRACTION_1_5,
220
+ "2/5": UNICODE_SYMBOLS.FRACTION_2_5,
221
+ "3/5": UNICODE_SYMBOLS.FRACTION_3_5,
222
+ "4/5": UNICODE_SYMBOLS.FRACTION_4_5,
223
+ "1/6": UNICODE_SYMBOLS.FRACTION_1_6,
224
+ "5/6": UNICODE_SYMBOLS.FRACTION_5_6,
225
+ "1/8": UNICODE_SYMBOLS.FRACTION_1_8,
226
+ "3/8": UNICODE_SYMBOLS.FRACTION_3_8,
227
+ "5/8": UNICODE_SYMBOLS.FRACTION_5_8,
228
+ "7/8": UNICODE_SYMBOLS.FRACTION_7_8,
229
+ };
230
+ for (const [ascii, unicode] of Object.entries(fractionMap)) {
231
+ const pattern = new RegExp(`(?<!\\d)${ascii.replace("/", "\\/")}(?!\\d)`, "g");
232
+ text = text.replace(pattern, unicode);
233
+ }
234
+ return text;
235
+ }
236
+ /**
237
+ * Applies all symbol transformations.
238
+ *
239
+ * Runs in order:
240
+ * 1. ellipsis
241
+ * 2. multiplication
242
+ * 3. mathSymbols
243
+ * 4. legalSymbols
244
+ * 5. arrows
245
+ *
246
+ * Note: `degrees` and `fractions` are not included by default as they
247
+ * may be too aggressive for some use cases. Call them explicitly if needed.
248
+ *
249
+ * @example
250
+ * ```ts
251
+ * symbolTransform("Wait... 5x5 != 20 (c) 2024")
252
+ * // → "Wait… 5×5 ≠ 20 © 2024"
253
+ * ```
254
+ */
255
+ export function symbolTransform(text, options = {}) {
256
+ text = ellipsis(text, options);
257
+ text = multiplication(text, options);
258
+ text = mathSymbols(text);
259
+ text = legalSymbols(text);
260
+ if (options.includeArrows !== false) {
261
+ text = arrows(text, options);
262
+ }
263
+ return text;
264
+ }
265
+ //# sourceMappingURL=symbols.js.map
@@ -0,0 +1 @@
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": "0.1.1",
3
+ "version": "0.2.1",
4
4
  "description": "Smart typography transformations: curly quotes, em-dashes, en-dashes, and more",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",