punctilio 0.1.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/LICENSE +21 -0
- package/README.md +109 -0
- package/dist/dashes.d.ts +118 -0
- package/dist/dashes.d.ts.map +1 -0
- package/dist/dashes.js +172 -0
- package/dist/dashes.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/dist/quotes.d.ts +27 -0
- package/dist/quotes.d.ts.map +1 -0
- package/dist/quotes.js +66 -0
- package/dist/quotes.js.map +1 -0
- package/package.json +53 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Alexander Turner
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# punctilio
|
|
2
|
+
|
|
3
|
+
> *punctilio* (n.): a fine point of conduct or procedure
|
|
4
|
+
|
|
5
|
+
Smart typography transformations for JavaScript/TypeScript. Converts ASCII punctuation to typographically correct Unicode characters. Originally built for [my personal website](https://turntrout.com/design).
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Smart quotes**: `"straight"` → `"curly"` and `'apostrophes'` → `'apostrophes'`
|
|
10
|
+
- **Em dashes**: `word - word` or `word--word` → `word—word`
|
|
11
|
+
- **En dashes**: `1-5` → `1–5` (number ranges), `January-March` → `January–March` (date ranges)
|
|
12
|
+
- **Minus signs**: `-5` → `−5` (proper Unicode minus)
|
|
13
|
+
- **Handles edge cases**: contractions, possessives, nested quotes, year abbreviations ('99), "rock 'n' roll"
|
|
14
|
+
|
|
15
|
+
## Why another typography library?
|
|
16
|
+
|
|
17
|
+
Existing solutions like [SmartyPants](https://daringfireball.net/projects/smartypants/) struggle with:
|
|
18
|
+
|
|
19
|
+
- **Apostrophe ambiguity**: Is `'Twas` an opening quote or apostrophe? (It's an apostrophe)
|
|
20
|
+
- **Cross-element text**: When quotes span `<em>"Hello</em> world"`, most libraries fail
|
|
21
|
+
- **Context sensitivity**: `'99` (year) vs `'hello'` (quoted) vs `don't` (contraction)
|
|
22
|
+
|
|
23
|
+
`punctilio` handles these through thorough regex patterns and an optional separator character for processing text that spans HTML elements.
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install punctilio
|
|
29
|
+
# or
|
|
30
|
+
pnpm add punctilio
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
### Basic
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import { transform, niceQuotes, hyphenReplace } from 'punctilio'
|
|
39
|
+
|
|
40
|
+
// Apply all transformations
|
|
41
|
+
transform('"Hello," she said - "it\'s pages 1-5."')
|
|
42
|
+
// → "Hello," she said—"it's pages 1–5."
|
|
43
|
+
|
|
44
|
+
// Or use individual functions
|
|
45
|
+
niceQuotes('"Hello", she said.')
|
|
46
|
+
// → "Hello", she said.
|
|
47
|
+
|
|
48
|
+
hyphenReplace('word - word')
|
|
49
|
+
// → word—word
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### With HTML Element Boundaries
|
|
53
|
+
|
|
54
|
+
When processing text that spans multiple HTML elements, use a separator character to mark boundaries:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { transform, DEFAULT_SEPARATOR } from 'punctilio'
|
|
58
|
+
|
|
59
|
+
// Your HTML: <p>"Hello <em>world</em>"</p>
|
|
60
|
+
// Extract text with separator between elements:
|
|
61
|
+
const text = `"Hello ${DEFAULT_SEPARATOR}world${DEFAULT_SEPARATOR}"`
|
|
62
|
+
|
|
63
|
+
const result = transform(text, { separator: DEFAULT_SEPARATOR })
|
|
64
|
+
// → "Hello \uE000world\uE000"
|
|
65
|
+
// The separator is preserved; split on it to restore to your elements
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
For a complete implementation showing how to use this with a HAST (HTML AST) tree, see the [`transformElement` function in TurnTrout.com](https://github.com/alexander-turner/TurnTrout.com/blob/main/quartz/plugins/transformers/formatting_improvement_html.ts). I explain the philosophy behind this algorithm.
|
|
69
|
+
|
|
70
|
+
## API
|
|
71
|
+
|
|
72
|
+
### `transform(text, options?)`
|
|
73
|
+
|
|
74
|
+
Applies all typography transformations (quotes + dashes).
|
|
75
|
+
|
|
76
|
+
### `niceQuotes(text, options?)`
|
|
77
|
+
|
|
78
|
+
Converts straight quotes to curly quotes. Handles:
|
|
79
|
+
- Opening/closing double quotes: `"` → `"` or `"`
|
|
80
|
+
- Opening/closing single quotes: `'` → `'` or `'`
|
|
81
|
+
- Contractions: `don't` → `don't`
|
|
82
|
+
- Possessives: `dog's` → `dog's`
|
|
83
|
+
- Year abbreviations: `'99` → `'99`
|
|
84
|
+
- Special cases: `'n'` in "rock 'n' roll"
|
|
85
|
+
|
|
86
|
+
### `hyphenReplace(text, options?)`
|
|
87
|
+
|
|
88
|
+
Converts hyphens to proper dashes. Handles:
|
|
89
|
+
- Em dashes: `word - word` → `word—word`
|
|
90
|
+
- En dashes for number ranges: `1-5` → `1–5`
|
|
91
|
+
- En dashes for date ranges: `Jan-Mar` → `Jan–Mar`
|
|
92
|
+
- Minus signs: `-5` → `−5`
|
|
93
|
+
- Preserves: horizontal rules (`---`), compound words (`well-known`)
|
|
94
|
+
|
|
95
|
+
### `enDashNumberRange(text, options?)`
|
|
96
|
+
|
|
97
|
+
Converts number ranges only: `pages 10-20` → `pages 10–20`
|
|
98
|
+
|
|
99
|
+
### `enDashDateRange(text, options?)`
|
|
100
|
+
|
|
101
|
+
Converts month ranges only: `January-March` → `January–March`
|
|
102
|
+
|
|
103
|
+
### `minusReplace(text, options?)`
|
|
104
|
+
|
|
105
|
+
Converts hyphens to minus signs in numerical contexts: `-5` → `−5`
|
|
106
|
+
|
|
107
|
+
## License
|
|
108
|
+
|
|
109
|
+
MIT © Alexander Turner
|
package/dist/dashes.d.ts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dash and hyphen transformation
|
|
3
|
+
*
|
|
4
|
+
* Converts hyphens and dashes to typographically correct em-dashes,
|
|
5
|
+
* en-dashes, and minus signs based on context.
|
|
6
|
+
*/
|
|
7
|
+
export interface DashOptions {
|
|
8
|
+
/**
|
|
9
|
+
* A boundary marker character used when transforming text that spans
|
|
10
|
+
* multiple HTML elements. This character is treated as "transparent"
|
|
11
|
+
* in the regex patterns.
|
|
12
|
+
*
|
|
13
|
+
* Should be a character that doesn't appear in your text.
|
|
14
|
+
* Default: "\uE000" (Unicode Private Use Area)
|
|
15
|
+
*/
|
|
16
|
+
separator?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* List of month names (full and abbreviated) for date range detection
|
|
20
|
+
*/
|
|
21
|
+
export declare const months: string;
|
|
22
|
+
/**
|
|
23
|
+
* Replaces hyphens with en-dashes in number ranges.
|
|
24
|
+
*
|
|
25
|
+
* Handles:
|
|
26
|
+
* - Simple ranges: "1-5" → "1–5"
|
|
27
|
+
* - Page numbers: "p.206-207" → "p.206–207"
|
|
28
|
+
* - Dollar amounts: "$100-$200" → "$100–$200"
|
|
29
|
+
* - Comma-formatted numbers: "1,000-2,000" → "1,000–2,000"
|
|
30
|
+
*
|
|
31
|
+
* Does NOT replace:
|
|
32
|
+
* - Spaced ranges: "1 - 5" (ambiguous, could be subtraction)
|
|
33
|
+
* - Version numbers with decimals: "1.5-1.8"
|
|
34
|
+
*
|
|
35
|
+
* @param text - The text to transform
|
|
36
|
+
* @param options - Configuration options
|
|
37
|
+
* @returns The text with en-dashes in number ranges
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* enDashNumberRange("pages 10-15")
|
|
42
|
+
* // → "pages 10–15"
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare function enDashNumberRange(text: string, options?: DashOptions): string;
|
|
46
|
+
/**
|
|
47
|
+
* Replaces hyphens with en-dashes in month/date ranges.
|
|
48
|
+
*
|
|
49
|
+
* Handles full and abbreviated month names:
|
|
50
|
+
* - "January-March" → "January–March"
|
|
51
|
+
* - "Jan-Mar" → "Jan–Mar"
|
|
52
|
+
*
|
|
53
|
+
* @param text - The text to transform
|
|
54
|
+
* @param options - Configuration options
|
|
55
|
+
* @returns The text with en-dashes in date ranges
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* enDashDateRange("January-March 2024")
|
|
60
|
+
* // → "January–March 2024"
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export declare function enDashDateRange(text: string, options?: DashOptions): string;
|
|
64
|
+
/**
|
|
65
|
+
* Replaces hyphens with proper minus signs (−) in numerical contexts.
|
|
66
|
+
*
|
|
67
|
+
* Handles negative numbers at:
|
|
68
|
+
* - Start of string/line
|
|
69
|
+
* - After whitespace
|
|
70
|
+
* - After opening parenthesis
|
|
71
|
+
* - After opening quote
|
|
72
|
+
*
|
|
73
|
+
* @param text - The text to transform
|
|
74
|
+
* @param options - Configuration options
|
|
75
|
+
* @returns The text with minus signs
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* minusReplace("The temperature was -5 degrees")
|
|
80
|
+
* // → "The temperature was −5 degrees"
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export declare function minusReplace(text: string, options?: DashOptions): string;
|
|
84
|
+
/**
|
|
85
|
+
* Comprehensive dash replacement for typographic correctness.
|
|
86
|
+
*
|
|
87
|
+
* Applies multiple transformations:
|
|
88
|
+
* 1. Converts hyphens to minus signs in numerical contexts
|
|
89
|
+
* 2. Converts surrounded dashes (- or --) to em-dashes (—)
|
|
90
|
+
* 3. Removes spaces around em-dashes (per modern style)
|
|
91
|
+
* 4. Preserves space after em-dash at start of line
|
|
92
|
+
* 5. Adds space after em-dash following quotation marks
|
|
93
|
+
* 6. Converts number ranges to en-dashes (1-5 → 1–5)
|
|
94
|
+
* 7. Converts date ranges to en-dashes (Jan-Mar → Jan–Mar)
|
|
95
|
+
*
|
|
96
|
+
* Does NOT modify:
|
|
97
|
+
* - Horizontal rules (---)
|
|
98
|
+
* - Compound modifiers (well-known, browser-specific)
|
|
99
|
+
* - Hyphens in quoted blockquotes ("> - item")
|
|
100
|
+
*
|
|
101
|
+
* @param text - The text to transform
|
|
102
|
+
* @param options - Configuration options
|
|
103
|
+
* @returns The text with proper dashes
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```ts
|
|
107
|
+
* hyphenReplace("This is a - test")
|
|
108
|
+
* // → "This is a—test"
|
|
109
|
+
*
|
|
110
|
+
* hyphenReplace("Since--as you know")
|
|
111
|
+
* // → "Since—as you know"
|
|
112
|
+
*
|
|
113
|
+
* hyphenReplace("Pages 1-5")
|
|
114
|
+
* // → "Pages 1–5"
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
export declare function hyphenReplace(text: string, options?: DashOptions): string;
|
|
118
|
+
//# sourceMappingURL=dashes.d.ts.map
|
|
@@ -0,0 +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"}
|
package/dist/dashes.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dash and hyphen transformation
|
|
3
|
+
*
|
|
4
|
+
* Converts hyphens and dashes to typographically correct em-dashes,
|
|
5
|
+
* en-dashes, and minus signs based on context.
|
|
6
|
+
*/
|
|
7
|
+
const DEFAULT_SEPARATOR = "\uE000";
|
|
8
|
+
/**
|
|
9
|
+
* List of month names (full and abbreviated) for date range detection
|
|
10
|
+
*/
|
|
11
|
+
export const months = [
|
|
12
|
+
"January",
|
|
13
|
+
"February",
|
|
14
|
+
"March",
|
|
15
|
+
"April",
|
|
16
|
+
"May",
|
|
17
|
+
"June",
|
|
18
|
+
"July",
|
|
19
|
+
"August",
|
|
20
|
+
"September",
|
|
21
|
+
"October",
|
|
22
|
+
"November",
|
|
23
|
+
"December",
|
|
24
|
+
"Jan",
|
|
25
|
+
"Feb",
|
|
26
|
+
"Mar",
|
|
27
|
+
"Apr",
|
|
28
|
+
"May",
|
|
29
|
+
"Jun",
|
|
30
|
+
"Jul",
|
|
31
|
+
"Aug",
|
|
32
|
+
"Sep",
|
|
33
|
+
"Oct",
|
|
34
|
+
"Nov",
|
|
35
|
+
"Dec",
|
|
36
|
+
].join("|");
|
|
37
|
+
/**
|
|
38
|
+
* Replaces hyphens with en-dashes in number ranges.
|
|
39
|
+
*
|
|
40
|
+
* Handles:
|
|
41
|
+
* - Simple ranges: "1-5" → "1–5"
|
|
42
|
+
* - Page numbers: "p.206-207" → "p.206–207"
|
|
43
|
+
* - Dollar amounts: "$100-$200" → "$100–$200"
|
|
44
|
+
* - Comma-formatted numbers: "1,000-2,000" → "1,000–2,000"
|
|
45
|
+
*
|
|
46
|
+
* Does NOT replace:
|
|
47
|
+
* - Spaced ranges: "1 - 5" (ambiguous, could be subtraction)
|
|
48
|
+
* - Version numbers with decimals: "1.5-1.8"
|
|
49
|
+
*
|
|
50
|
+
* @param text - The text to transform
|
|
51
|
+
* @param options - Configuration options
|
|
52
|
+
* @returns The text with en-dashes in number ranges
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* enDashNumberRange("pages 10-15")
|
|
57
|
+
* // → "pages 10–15"
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export function enDashNumberRange(text, options = {}) {
|
|
61
|
+
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
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Replaces hyphens with en-dashes in month/date ranges.
|
|
66
|
+
*
|
|
67
|
+
* Handles full and abbreviated month names:
|
|
68
|
+
* - "January-March" → "January–March"
|
|
69
|
+
* - "Jan-Mar" → "Jan–Mar"
|
|
70
|
+
*
|
|
71
|
+
* @param text - The text to transform
|
|
72
|
+
* @param options - Configuration options
|
|
73
|
+
* @returns The text with en-dashes in date ranges
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* enDashDateRange("January-March 2024")
|
|
78
|
+
* // → "January–March 2024"
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export function enDashDateRange(text, options = {}) {
|
|
82
|
+
const chr = options.separator ?? DEFAULT_SEPARATOR;
|
|
83
|
+
return text.replace(new RegExp(`\\b(${months}${chr}?)-(${chr}?(?:${months}))\\b`, "g"), "$1–$2");
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Replaces hyphens with proper minus signs (−) in numerical contexts.
|
|
87
|
+
*
|
|
88
|
+
* Handles negative numbers at:
|
|
89
|
+
* - Start of string/line
|
|
90
|
+
* - After whitespace
|
|
91
|
+
* - After opening parenthesis
|
|
92
|
+
* - After opening quote
|
|
93
|
+
*
|
|
94
|
+
* @param text - The text to transform
|
|
95
|
+
* @param options - Configuration options
|
|
96
|
+
* @returns The text with minus signs
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```ts
|
|
100
|
+
* minusReplace("The temperature was -5 degrees")
|
|
101
|
+
* // → "The temperature was −5 degrees"
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
export function minusReplace(text, options = {}) {
|
|
105
|
+
const chr = options.separator ?? DEFAULT_SEPARATOR;
|
|
106
|
+
const minusRegex = new RegExp(`(^|[\\s\\(${chr}""])-(\\s?\\d*\\.?\\d+)`, "gm");
|
|
107
|
+
return text.replaceAll(minusRegex, "$1−$2");
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Comprehensive dash replacement for typographic correctness.
|
|
111
|
+
*
|
|
112
|
+
* Applies multiple transformations:
|
|
113
|
+
* 1. Converts hyphens to minus signs in numerical contexts
|
|
114
|
+
* 2. Converts surrounded dashes (- or --) to em-dashes (—)
|
|
115
|
+
* 3. Removes spaces around em-dashes (per modern style)
|
|
116
|
+
* 4. Preserves space after em-dash at start of line
|
|
117
|
+
* 5. Adds space after em-dash following quotation marks
|
|
118
|
+
* 6. Converts number ranges to en-dashes (1-5 → 1–5)
|
|
119
|
+
* 7. Converts date ranges to en-dashes (Jan-Mar → Jan–Mar)
|
|
120
|
+
*
|
|
121
|
+
* Does NOT modify:
|
|
122
|
+
* - Horizontal rules (---)
|
|
123
|
+
* - Compound modifiers (well-known, browser-specific)
|
|
124
|
+
* - Hyphens in quoted blockquotes ("> - item")
|
|
125
|
+
*
|
|
126
|
+
* @param text - The text to transform
|
|
127
|
+
* @param options - Configuration options
|
|
128
|
+
* @returns The text with proper dashes
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```ts
|
|
132
|
+
* hyphenReplace("This is a - test")
|
|
133
|
+
* // → "This is a—test"
|
|
134
|
+
*
|
|
135
|
+
* hyphenReplace("Since--as you know")
|
|
136
|
+
* // → "Since—as you know"
|
|
137
|
+
*
|
|
138
|
+
* hyphenReplace("Pages 1-5")
|
|
139
|
+
* // → "Pages 1–5"
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
export function hyphenReplace(text, options = {}) {
|
|
143
|
+
const chr = options.separator ?? DEFAULT_SEPARATOR;
|
|
144
|
+
text = minusReplace(text, options);
|
|
145
|
+
// Handle dashes with potential spaces and optional marker character
|
|
146
|
+
// Being right after chr is a sufficient condition for being an em
|
|
147
|
+
// dash, as it indicates the start of a new line
|
|
148
|
+
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
|
|
163
|
+
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
|
|
166
|
+
const startOfLine = new RegExp(`^${spacesAroundEM.source}(?<after>[A-Z0-9])`, "gm");
|
|
167
|
+
text = text.replace(startOfLine, "$<markerBefore>—$<markerAfter> $<after>");
|
|
168
|
+
text = enDashNumberRange(text, options);
|
|
169
|
+
text = enDashDateRange(text, options);
|
|
170
|
+
return text;
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=dashes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashes.js","sourceRoot":"","sources":["../src/dashes.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
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, and more.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
export { niceQuotes, type QuoteOptions } from "./quotes.js";
|
|
11
|
+
export { hyphenReplace, enDashNumberRange, enDashDateRange, minusReplace, months, type DashOptions, } from "./dashes.js";
|
|
12
|
+
export interface TransformOptions {
|
|
13
|
+
/**
|
|
14
|
+
* A boundary marker character used when transforming text that spans
|
|
15
|
+
* multiple HTML elements. This character is treated as "transparent"
|
|
16
|
+
* in the regex patterns.
|
|
17
|
+
*
|
|
18
|
+
* Should be a character that doesn't appear in your text.
|
|
19
|
+
* Default: "\uE000" (Unicode Private Use Area)
|
|
20
|
+
*/
|
|
21
|
+
separator?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Applies all typography transformations: smart quotes and proper dashes.
|
|
25
|
+
*
|
|
26
|
+
* This is a convenience function that applies both `niceQuotes` and
|
|
27
|
+
* `hyphenReplace` in sequence.
|
|
28
|
+
*
|
|
29
|
+
* @param text - The text to transform
|
|
30
|
+
* @param options - Configuration options
|
|
31
|
+
* @returns The text with all typography improvements applied
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* import { transform } from '@alexander-turner/punctilio'
|
|
36
|
+
*
|
|
37
|
+
* transform('"Hello," she said - "it\'s pages 1-5."')
|
|
38
|
+
* // → '"Hello," she said—"it's pages 1–5."'
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare function transform(text: string, options?: TransformOptions): string;
|
|
42
|
+
/**
|
|
43
|
+
* Default separator character for boundary marking.
|
|
44
|
+
* Uses Unicode Private Use Area character U+E000.
|
|
45
|
+
*/
|
|
46
|
+
export declare const DEFAULT_SEPARATOR = "\uE000";
|
|
47
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
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, and more.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
export { niceQuotes } from "./quotes.js";
|
|
11
|
+
export { hyphenReplace, enDashNumberRange, enDashDateRange, minusReplace, months, } from "./dashes.js";
|
|
12
|
+
import { niceQuotes } from "./quotes.js";
|
|
13
|
+
import { hyphenReplace } from "./dashes.js";
|
|
14
|
+
/**
|
|
15
|
+
* Applies all typography transformations: smart quotes and proper dashes.
|
|
16
|
+
*
|
|
17
|
+
* This is a convenience function that applies both `niceQuotes` and
|
|
18
|
+
* `hyphenReplace` in sequence.
|
|
19
|
+
*
|
|
20
|
+
* @param text - The text to transform
|
|
21
|
+
* @param options - Configuration options
|
|
22
|
+
* @returns The text with all typography improvements applied
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { transform } from '@alexander-turner/punctilio'
|
|
27
|
+
*
|
|
28
|
+
* transform('"Hello," she said - "it\'s pages 1-5."')
|
|
29
|
+
* // → '"Hello," she said—"it's pages 1–5."'
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export function transform(text, options = {}) {
|
|
33
|
+
text = hyphenReplace(text, options);
|
|
34
|
+
text = niceQuotes(text, options);
|
|
35
|
+
return text;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Default separator character for boundary marking.
|
|
39
|
+
* Uses Unicode Private Use Area character U+E000.
|
|
40
|
+
*/
|
|
41
|
+
export const DEFAULT_SEPARATOR = "\uE000";
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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"}
|
package/dist/quotes.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart quote transformation
|
|
3
|
+
*
|
|
4
|
+
* Converts straight quotes to typographically correct curly quotes,
|
|
5
|
+
* handling contractions, possessives, and nested quotes.
|
|
6
|
+
*/
|
|
7
|
+
export interface QuoteOptions {
|
|
8
|
+
/**
|
|
9
|
+
* A boundary marker character used when transforming text that spans
|
|
10
|
+
* multiple HTML elements. This character is treated as "transparent"
|
|
11
|
+
* in the regex patterns - it won't affect quote matching but allows
|
|
12
|
+
* the algorithm to work across element boundaries.
|
|
13
|
+
*
|
|
14
|
+
* Should be a character that doesn't appear in your text.
|
|
15
|
+
* Default: "\uE000" (Unicode Private Use Area)
|
|
16
|
+
*/
|
|
17
|
+
separator?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Converts standard quotes to typographic smart quotes.
|
|
21
|
+
*
|
|
22
|
+
* @param text - The text to transform
|
|
23
|
+
* @param options - Configuration options
|
|
24
|
+
* @returns The text with smart quotes
|
|
25
|
+
*/
|
|
26
|
+
export declare function niceQuotes(text: string, options?: QuoteOptions): string;
|
|
27
|
+
//# sourceMappingURL=quotes.d.ts.map
|
|
@@ -0,0 +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"}
|
package/dist/quotes.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart quote transformation
|
|
3
|
+
*
|
|
4
|
+
* Converts straight quotes to typographically correct curly quotes,
|
|
5
|
+
* handling contractions, possessives, and nested quotes.
|
|
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"; // …
|
|
15
|
+
/**
|
|
16
|
+
* Converts standard quotes to typographic smart quotes.
|
|
17
|
+
*
|
|
18
|
+
* @param text - The text to transform
|
|
19
|
+
* @param options - Configuration options
|
|
20
|
+
* @returns The text with smart quotes
|
|
21
|
+
*/
|
|
22
|
+
export function niceQuotes(text, options = {}) {
|
|
23
|
+
const chr = options.separator ?? DEFAULT_SEPARATOR;
|
|
24
|
+
// Single quotes //
|
|
25
|
+
// Ending comes first so as to not mess with the open quote
|
|
26
|
+
const afterEndingSinglePatterns = `\\s\\.!?;,\\)${EM_DASH}\\-\\]"`;
|
|
27
|
+
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 //
|
|
46
|
+
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
|
|
51
|
+
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");
|
|
60
|
+
text = text.replace(periodRegex, "$1.$2$3");
|
|
61
|
+
// Commas outside of quotes
|
|
62
|
+
const commaRegex = new RegExp(`(?<![!?]),(${chr}?[${RIGHT_DOUBLE}${RIGHT_SINGLE}])`, "g");
|
|
63
|
+
text = text.replace(commaRegex, "$1,");
|
|
64
|
+
return text;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=quotes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quotes.js","sourceRoot":"","sources":["../src/quotes.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "punctilio",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Smart typography transformations: curly quotes, em-dashes, en-dashes, and more",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"keywords": [
|
|
18
|
+
"typography",
|
|
19
|
+
"smart-quotes",
|
|
20
|
+
"curly-quotes",
|
|
21
|
+
"em-dash",
|
|
22
|
+
"en-dash",
|
|
23
|
+
"typesetting",
|
|
24
|
+
"punctuation",
|
|
25
|
+
"text-formatting"
|
|
26
|
+
],
|
|
27
|
+
"author": "Alexander Turner",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/alexander-turner/punctilio.git"
|
|
32
|
+
},
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/alexander-turner/punctilio/issues"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://github.com/alexander-turner/punctilio#readme",
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=18.0.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/jest": "^29.5.12",
|
|
42
|
+
"@types/node": "^20.11.0",
|
|
43
|
+
"jest": "^29.7.0",
|
|
44
|
+
"ts-jest": "^29.1.2",
|
|
45
|
+
"typescript": "^5.3.3"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsc",
|
|
49
|
+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
|
50
|
+
"postinstall": "bash scripts/install-hooks.sh || true",
|
|
51
|
+
"install-hooks": "bash scripts/install-hooks.sh"
|
|
52
|
+
}
|
|
53
|
+
}
|