punctilio 3.3.7 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -1
- package/dist/constants.d.ts +3 -2
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +3 -2
- package/dist/constants.js.map +1 -1
- package/dist/markdown.d.ts +8 -0
- package/dist/markdown.d.ts.map +1 -1
- package/dist/markdown.js +44 -18
- package/dist/markdown.js.map +1 -1
- package/dist/nbsp.d.ts.map +1 -1
- package/dist/nbsp.js +10 -0
- package/dist/nbsp.js.map +1 -1
- package/dist/rehype.d.ts.map +1 -1
- package/dist/rehype.js +26 -11
- package/dist/rehype.js.map +1 -1
- package/package.json +2 -1
- package/src/constants.ts +3 -2
- package/src/markdown.ts +54 -21
- package/src/nbsp.ts +10 -0
- package/src/rehype.ts +35 -13
- package/src/tests/index.test.ts +1 -1
- package/src/tests/markdown.test.ts +42 -1
- package/src/tests/quotes.test.ts +4 -0
- package/src/tests/rehype.test.ts +10 -0
package/README.md
CHANGED
|
@@ -79,7 +79,7 @@ Setting aside the benchmark, `punctilio`’s test suite includes 1,550+ tests at
|
|
|
79
79
|
|
|
80
80
|
## Works with HTML DOMs via separation boundaries
|
|
81
81
|
|
|
82
|
-
Perhaps the most innovative feature of the library is that it properly handles DOMs!
|
|
82
|
+
Perhaps the most innovative feature of the library is that it properly handles DOMs! For Markdown, use the built-in `remarkPunctilio` or `transformMarkdown` plugins instead of converting to HTML and back.
|
|
83
83
|
|
|
84
84
|
Other typography libraries take one of two approaches, both with drawbacks.
|
|
85
85
|
|
|
@@ -119,6 +119,15 @@ For Markdown ASTs via `remark`, use `remarkPunctilio` which applies the same sep
|
|
|
119
119
|
|
|
120
120
|
For manual DOM walking or custom transforms, use `transformElement` from `punctilio/rehype`.
|
|
121
121
|
|
|
122
|
+
The rehype plugin accepts additional options. Elements matching any `skipTags` tag name or carrying any `skipClasses` class are left untransformed (values shown are the defaults for `skipTags`):
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
rehypePunctilio({
|
|
126
|
+
skipTags: ["code", "pre", "script", "style", "kbd", "var", "samp"],
|
|
127
|
+
skipClasses: ["no-formatting"],
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
122
131
|
## Options
|
|
123
132
|
|
|
124
133
|
`punctilio` doesn’t enable all transformations by default. Fractions and degrees tend to match too aggressively (perfectly applying the degree transformation requires semantic meaning). Superscript letters and punctuation ligatures have spotty font support. Furthermore, `ligatures = true` can change the meaning of text by collapsing question and exclamation marks.
|
package/dist/constants.d.ts
CHANGED
|
@@ -93,10 +93,11 @@ export declare const TERMINAL_PUNCTUATION: readonly ["!", "?", ".", ",", ";", ":
|
|
|
93
93
|
* - Latin-1 Supplement: À-Ö, Ø-ö, ø-ÿ (excludes × and ÷)
|
|
94
94
|
* - Latin Extended-A: Ā-ſ (U+0100-017F)
|
|
95
95
|
* - Latin Extended-B: ƀ-ɏ (U+0180-024F)
|
|
96
|
+
* - Latin Extended Additional: Ḁ-ỿ (U+1E00-1EFF) — Vietnamese, Welsh, medievalist
|
|
96
97
|
*
|
|
97
|
-
* Examples of covered characters: é, ñ, ü, ø, ą, ł,
|
|
98
|
+
* Examples of covered characters: é, ñ, ü, ø, ą, ł, ș, ả, ầ, ẁ, ẃ
|
|
98
99
|
*/
|
|
99
|
-
export declare const LATIN_LETTERS = "A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u00FF\\u0100-\\u017F\\u0180-\\u024F";
|
|
100
|
+
export declare const LATIN_LETTERS = "A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u00FF\\u0100-\\u017F\\u0180-\\u024F\\u1E00-\\u1EFF";
|
|
100
101
|
/**
|
|
101
102
|
* Default separator for text spanning HTML elements.
|
|
102
103
|
* Uses a two-character sentinel from the Unicode Private Use Area
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH;;GAEG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuElB,CAAA;AAEV;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,8HAYvB,CAAA;AAEV
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH;;GAEG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuElB,CAAA;AAEV;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,8HAYvB,CAAA;AAEV;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,aAAa,qGAAqG,CAAA;AAE/H;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,iBAAiB,CAAA;AAG/C;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAK3E;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,wEAAyE,CAAA;AAEzG;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED;;;GAGG;AACH,eAAO,MAAM,WAAW,QAA6B,CAAA;AAErD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,OAAO,CAAA;AAGxC;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CASnE;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}
|
package/dist/constants.js
CHANGED
|
@@ -113,10 +113,11 @@ export const TERMINAL_PUNCTUATION = [
|
|
|
113
113
|
* - Latin-1 Supplement: À-Ö, Ø-ö, ø-ÿ (excludes × and ÷)
|
|
114
114
|
* - Latin Extended-A: Ā-ſ (U+0100-017F)
|
|
115
115
|
* - Latin Extended-B: ƀ-ɏ (U+0180-024F)
|
|
116
|
+
* - Latin Extended Additional: Ḁ-ỿ (U+1E00-1EFF) — Vietnamese, Welsh, medievalist
|
|
116
117
|
*
|
|
117
|
-
* Examples of covered characters: é, ñ, ü, ø, ą, ł,
|
|
118
|
+
* Examples of covered characters: é, ñ, ü, ø, ą, ł, ș, ả, ầ, ẁ, ẃ
|
|
118
119
|
*/
|
|
119
|
-
export const LATIN_LETTERS = "A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u00FF\\u0100-\\u017F\\u0180-\\u024F";
|
|
120
|
+
export const LATIN_LETTERS = "A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u00FF\\u0100-\\u017F\\u0180-\\u024F\\u1E00-\\u1EFF";
|
|
120
121
|
/**
|
|
121
122
|
* Default separator for text spanning HTML elements.
|
|
122
123
|
* Uses a two-character sentinel from the Unicode Private Use Area
|
package/dist/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
|
package/dist/markdown.d.ts
CHANGED
|
@@ -28,12 +28,20 @@ export interface MarkdownOptions extends RemarkPunctilioOptions {
|
|
|
28
28
|
/** Thematic break marker. Default: "-" */
|
|
29
29
|
ruleMarker?: "-" | "*" | "_";
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Clears the processor cache. Exported for test isolation only.
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
35
|
+
export declare function clearProcessorCache(): void;
|
|
31
36
|
/**
|
|
32
37
|
* Transforms Markdown text with typographic improvements.
|
|
33
38
|
*
|
|
34
39
|
* Parses the input as Markdown, applies punctilio typography transformations
|
|
35
40
|
* (smart quotes, em-dashes, ellipses, etc.), and serializes back to Markdown.
|
|
36
41
|
*
|
|
42
|
+
* The unified processor pipeline is cached and reused across calls with
|
|
43
|
+
* identical options, avoiding redundant pipeline construction.
|
|
44
|
+
*
|
|
37
45
|
* @param input - The Markdown text to transform
|
|
38
46
|
* @param options - Configuration options for both the transform and serializer
|
|
39
47
|
* @returns The typographically improved Markdown text
|
package/dist/markdown.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH,OAAO,EAAmB,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAE1E;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,sBAAsB;IAC7D;;;OAGG;IACH,cAAc,CAAC,EAAE,GAAG,GAAG,GAAG,CAAA;IAE1B;;;OAGG;IACH,YAAY,CAAC,EAAE,GAAG,GAAG,GAAG,CAAA;IAExB,yDAAyD;IACzD,YAAY,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;IAE9B,0CAA0C;IAC1C,UAAU,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;CAC7B;AAuCD;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAajB"}
|
package/dist/markdown.js
CHANGED
|
@@ -12,28 +12,14 @@ import { unified } from "unified";
|
|
|
12
12
|
import remarkParse from "remark-parse";
|
|
13
13
|
import remarkGfm from "remark-gfm";
|
|
14
14
|
import remarkStringify from "remark-stringify";
|
|
15
|
+
import QuickLRU from "quick-lru";
|
|
15
16
|
import { remarkPunctilio } from "./remark.js";
|
|
16
17
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* Parses the input as Markdown, applies punctilio typography transformations
|
|
20
|
-
* (smart quotes, em-dashes, ellipses, etc.), and serializes back to Markdown.
|
|
21
|
-
*
|
|
22
|
-
* @param input - The Markdown text to transform
|
|
23
|
-
* @param options - Configuration options for both the transform and serializer
|
|
24
|
-
* @returns The typographically improved Markdown text
|
|
25
|
-
*
|
|
26
|
-
* @example
|
|
27
|
-
* ```ts
|
|
28
|
-
* import { transformMarkdown } from 'punctilio/markdown'
|
|
29
|
-
*
|
|
30
|
-
* await transformMarkdown('"Hello" -- world')
|
|
31
|
-
* // → '\u201CHello\u201D\u2014world'
|
|
32
|
-
* ```
|
|
18
|
+
* Creates a unified processor pipeline for Markdown typography transformations.
|
|
33
19
|
*/
|
|
34
|
-
|
|
20
|
+
function createProcessor(options) {
|
|
35
21
|
const { emphasisMarker, strongMarker, bulletMarker, ruleMarker, ...punctilioOptions } = options;
|
|
36
|
-
|
|
22
|
+
return unified()
|
|
37
23
|
.use(remarkParse)
|
|
38
24
|
.use(remarkGfm)
|
|
39
25
|
.use(remarkPunctilio, punctilioOptions)
|
|
@@ -50,6 +36,46 @@ export async function transformMarkdown(input, options = {}) {
|
|
|
50
36
|
// output is re-parsed by markdown renderers.
|
|
51
37
|
unsafe: [{ character: "]", inConstruct: "phrasing" }],
|
|
52
38
|
});
|
|
39
|
+
}
|
|
40
|
+
const MAX_PROCESSOR_CACHE_SIZE = 8;
|
|
41
|
+
const processorCache = new QuickLRU({
|
|
42
|
+
maxSize: MAX_PROCESSOR_CACHE_SIZE,
|
|
43
|
+
});
|
|
44
|
+
/**
|
|
45
|
+
* Clears the processor cache. Exported for test isolation only.
|
|
46
|
+
* @internal
|
|
47
|
+
*/
|
|
48
|
+
export function clearProcessorCache() {
|
|
49
|
+
processorCache.clear();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Transforms Markdown text with typographic improvements.
|
|
53
|
+
*
|
|
54
|
+
* Parses the input as Markdown, applies punctilio typography transformations
|
|
55
|
+
* (smart quotes, em-dashes, ellipses, etc.), and serializes back to Markdown.
|
|
56
|
+
*
|
|
57
|
+
* The unified processor pipeline is cached and reused across calls with
|
|
58
|
+
* identical options, avoiding redundant pipeline construction.
|
|
59
|
+
*
|
|
60
|
+
* @param input - The Markdown text to transform
|
|
61
|
+
* @param options - Configuration options for both the transform and serializer
|
|
62
|
+
* @returns The typographically improved Markdown text
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* import { transformMarkdown } from 'punctilio/markdown'
|
|
67
|
+
*
|
|
68
|
+
* await transformMarkdown('"Hello" -- world')
|
|
69
|
+
* // → '\u201CHello\u201D\u2014world'
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export async function transformMarkdown(input, options = {}) {
|
|
73
|
+
const optionsKey = JSON.stringify(Object.entries(options).sort(([a], [b]) => a.localeCompare(b)));
|
|
74
|
+
let processor = processorCache.get(optionsKey);
|
|
75
|
+
if (!processor) {
|
|
76
|
+
processor = createProcessor(options);
|
|
77
|
+
processorCache.set(optionsKey, processor);
|
|
78
|
+
}
|
|
53
79
|
const result = await processor.process(input);
|
|
54
80
|
return String(result);
|
|
55
81
|
}
|
package/dist/markdown.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,WAAW,MAAM,cAAc,CAAA;AACtC,OAAO,SAAS,MAAM,YAAY,CAAA;AAClC,OAAO,eAAe,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,WAAW,MAAM,cAAc,CAAA;AACtC,OAAO,SAAS,MAAM,YAAY,CAAA;AAClC,OAAO,eAAe,MAAM,kBAAkB,CAAA;AAC9C,OAAO,QAAQ,MAAM,WAAW,CAAA;AAEhC,OAAO,EAAE,eAAe,EAA+B,MAAM,aAAa,CAAA;AAyB1E;;GAEG;AACH,SAAS,eAAe,CAAC,OAAwB;IAC/C,MAAM,EACJ,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,GAAG,gBAAgB,EACpB,GAAG,OAAO,CAAA;IAEX,OAAO,OAAO,EAAE;SACb,GAAG,CAAC,WAAW,CAAC;SAChB,GAAG,CAAC,SAAS,CAAC;SACd,GAAG,CAAC,eAAe,EAAE,gBAAgB,CAAC;SACtC,GAAG,CAAC,eAAe,EAAE;QACpB,QAAQ,EAAE,cAAc,IAAI,GAAG;QAC/B,MAAM,EAAE,YAAY,IAAI,GAAG;QAC3B,MAAM,EAAE,YAAY,IAAI,GAAG;QAC3B,IAAI,EAAE,UAAU,IAAI,GAAG;QACvB,kEAAkE;QAClE,uDAAuD;QACvD,GAAG,CAAC,UAAU,KAAK,GAAG,IAAI,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChF,sEAAsE;QACtE,sEAAsE;QACtE,6CAA6C;QAC7C,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC;KACtD,CAAC,CAAA;AACN,CAAC;AAED,MAAM,wBAAwB,GAAG,CAAC,CAAA;AAElC,MAAM,cAAc,GAAG,IAAI,QAAQ,CAA6C;IAC9E,OAAO,EAAE,wBAAwB;CAClC,CAAC,CAAA;AAEF;;;GAGG;AACH,MAAM,UAAU,mBAAmB;IACjC,cAAc,CAAC,KAAK,EAAE,CAAA;AACxB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAAa,EACb,UAA2B,EAAE;IAE7B,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAC/B,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAC/D,CAAA;IAED,IAAI,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;IAC9C,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,SAAS,GAAG,eAAe,CAAC,OAAO,CAAC,CAAA;QACpC,cAAc,CAAC,GAAG,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;IAC3C,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IAC7C,OAAO,MAAM,CAAC,MAAM,CAAC,CAAA;AACvB,CAAC"}
|
package/dist/nbsp.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nbsp.d.ts","sourceRoot":"","sources":["../src/nbsp.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAajD,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,CAAA;AAO1D;;;GAGG;AACH,eAAO,MAAM,KAAK,
|
|
1
|
+
{"version":3,"file":"nbsp.d.ts","sourceRoot":"","sources":["../src/nbsp.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAajD,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,CAAA;AAO1D;;;GAGG;AACH,eAAO,MAAM,KAAK,UAqCjB,CAAA;AAED,eAAO,MAAM,UAAU,UActB,CAAA;AAED,eAAO,MAAM,uBAAuB,UASnC,CAAA;AASD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAOnF;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAQxF;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAQlF;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAO/F;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAOvF;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAOnF;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAOzF;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAOnF;AAsBD,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAS7E"}
|
package/dist/nbsp.js
CHANGED
|
@@ -43,6 +43,16 @@ export const UNITS = [
|
|
|
43
43
|
"MM", "M", "B", "T",
|
|
44
44
|
// Misc
|
|
45
45
|
"kcal", "mol", "cal", "dB",
|
|
46
|
+
// Speed
|
|
47
|
+
"mph", "kph", "fps",
|
|
48
|
+
// Pressure
|
|
49
|
+
"atm", "mbar",
|
|
50
|
+
// Battery / charge
|
|
51
|
+
"mAh", "Ah",
|
|
52
|
+
// Torque
|
|
53
|
+
"Nm",
|
|
54
|
+
// Light
|
|
55
|
+
"lm",
|
|
46
56
|
];
|
|
47
57
|
export const HONORIFICS = [
|
|
48
58
|
// English
|
package/dist/nbsp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nbsp.js","sourceRoot":"","sources":["../src/nbsp.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAGhI,MAAM,EACJ,IAAI,EACJ,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,SAAS,EACT,UAAU,EACV,SAAS,GACV,GAAG,eAAe,CAAA;AAInB,2DAA2D;AAC3D,MAAM,KAAK,GAAG,QAAQ,IAAI,GAAG,CAAA;AAE7B,MAAM,iBAAiB,GAAG,SAAS,CAAA;AAEnC;;;GAGG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,SAAS;IACT,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG;IACnD,OAAO;IACP,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG;IACvC,SAAS;IACT,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG;IACjC,OAAO;IACP,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG;IAClC,oBAAoB;IACpB,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI;IACvC,UAAU;IACV,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IACtE,iBAAiB;IACjB,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG;IAC1D,cAAc;IACd,GAAG;IACH,aAAa;IACb,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG;IAC1B,kBAAkB;IAClB,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI;IAC/B,mBAAmB;IACnB,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAC1C,UAAU;IACV,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;IACnB,OAAO;IACP,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI;
|
|
1
|
+
{"version":3,"file":"nbsp.js","sourceRoot":"","sources":["../src/nbsp.ts"],"names":[],"mappings":"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"}
|
package/dist/rehype.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rehype.d.ts","sourceRoot":"","sources":["../src/rehype.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,MAAM,CAAA;AACpF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAI1C,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAI7D,8FAA8F;AAC9F,KAAK,gBAAgB,GAAG,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAA;AAElD,gFAAgF;AAChF,KAAK,eAAe,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;AAEhD;;GAEG;AACH,MAAM,WAAW,sBAAuB,SAAQ,gBAAgB;IAC9D;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IAEnB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CACvB;AAwCD;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,OAAO,GAAG,cAAc,EAC9B,UAAU,EAAE,gBAAgB,EAC5B,KAAK,GAAE,MAAU,GAChB,IAAI,EAAE,CAkBR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,OAAO,EACb,UAAU,GAAE,gBAA8B,GACzC,MAAM,CAIR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,GAAG,WAAW,EAC1B,KAAK,GAAE,MAAU,GAChB,IAAI,GAAG,IAAI,CAeb;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAuB1D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,OAAO,EACb,WAAW,EAAE,eAAe,EAC5B,UAAU,EAAE,gBAAgB,EAC5B,SAAS,EAAE,MAAM,EACjB,eAAe,GAAE,OAAe,GAC/B,IAAI,CAiCN;
|
|
1
|
+
{"version":3,"file":"rehype.d.ts","sourceRoot":"","sources":["../src/rehype.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,MAAM,CAAA;AACpF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAI1C,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAI7D,8FAA8F;AAC9F,KAAK,gBAAgB,GAAG,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAA;AAElD,gFAAgF;AAChF,KAAK,eAAe,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;AAEhD;;GAEG;AACH,MAAM,WAAW,sBAAuB,SAAQ,gBAAgB;IAC9D;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IAEnB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CACvB;AAwCD;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,OAAO,GAAG,cAAc,EAC9B,UAAU,EAAE,gBAAgB,EAC5B,KAAK,GAAE,MAAU,GAChB,IAAI,EAAE,CAkBR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,OAAO,EACb,UAAU,GAAE,gBAA8B,GACzC,MAAM,CAIR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,GAAG,WAAW,EAC1B,KAAK,GAAE,MAAU,GAChB,IAAI,GAAG,IAAI,CAeb;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAuB1D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,OAAO,EACb,WAAW,EAAE,eAAe,EAC5B,UAAU,EAAE,gBAAgB,EAC5B,SAAS,EAAE,MAAM,EACjB,eAAe,GAAE,OAAe,GAC/B,IAAI,CAiCN;AAwGD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,OAAO,EACb,UAAU,EAAE,gBAAgB,EAC5B,KAAK,GAAE,MAAU,GAChB,OAAO,EAAE,CAsCX;AAqBD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,eAAe,CAC7B,OAAO,GAAE,sBAA2B,GACnC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CA+DzB;AAED,eAAe,eAAe,CAAA"}
|
package/dist/rehype.js
CHANGED
|
@@ -64,7 +64,7 @@ export function flattenTextNodes(node, shouldSkip, depth = 0) {
|
|
|
64
64
|
if (node.type === "text") {
|
|
65
65
|
return [node];
|
|
66
66
|
}
|
|
67
|
-
if (node.type === "element"
|
|
67
|
+
if (node.type === "element") {
|
|
68
68
|
return node.children.flatMap((child) => flattenTextNodes(child, shouldSkip, depth + 1));
|
|
69
69
|
}
|
|
70
70
|
return [];
|
|
@@ -287,6 +287,26 @@ const TRANSFORMABLE_ELEMENTS = new Set([
|
|
|
287
287
|
"rt",
|
|
288
288
|
"rp",
|
|
289
289
|
]);
|
|
290
|
+
/**
|
|
291
|
+
* Checks whether an element has any text node descendants (skipping elements
|
|
292
|
+
* matched by shouldSkip). Returns as soon as one is found — avoids allocating
|
|
293
|
+
* an array of all text nodes just to check existence.
|
|
294
|
+
*/
|
|
295
|
+
function hasTextDescendant(node, shouldSkip, depth = 0) {
|
|
296
|
+
if (depth > MAX_RECURSION_DEPTH) {
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
if (node.type === "element" && shouldSkip(node)) {
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
if (node.type === "text") {
|
|
303
|
+
return true;
|
|
304
|
+
}
|
|
305
|
+
if (node.type === "element") {
|
|
306
|
+
return node.children.some((child) => hasTextDescendant(child, shouldSkip, depth + 1));
|
|
307
|
+
}
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
290
310
|
/**
|
|
291
311
|
* Collects elements that should have text transformations applied.
|
|
292
312
|
*
|
|
@@ -318,7 +338,7 @@ export function collectTransformableElements(node, shouldSkip, depth = 0) {
|
|
|
318
338
|
// (short-circuit avoids unnecessary tree traversal)
|
|
319
339
|
const hasBlockChildren = !hasDirectText && node.children.some((child) => child.type === "element" && BLOCK_ELEMENTS.has(child.tagName));
|
|
320
340
|
const hasTextDescendants = !hasDirectText && !hasBlockChildren &&
|
|
321
|
-
|
|
341
|
+
hasTextDescendant(node, shouldSkip);
|
|
322
342
|
if (TRANSFORMABLE_ELEMENTS.has(node.tagName) &&
|
|
323
343
|
(hasDirectText || hasTextDescendants)) {
|
|
324
344
|
results.push(node);
|
|
@@ -406,25 +426,20 @@ export function rehypePunctilio(options = {}) {
|
|
|
406
426
|
return (tree) => {
|
|
407
427
|
// Track transformed elements to avoid double-processing
|
|
408
428
|
const transformed = new Set();
|
|
409
|
-
visitParents(tree, (node, ancestors) => {
|
|
410
|
-
// Only process element nodes
|
|
411
|
-
if (node.type !== "element") {
|
|
412
|
-
return;
|
|
413
|
-
}
|
|
414
|
-
const element = node;
|
|
429
|
+
visitParents(tree, "element", (node, ancestors) => {
|
|
415
430
|
// Skip if already transformed
|
|
416
|
-
if (transformed.has(
|
|
431
|
+
if (transformed.has(node)) {
|
|
417
432
|
return;
|
|
418
433
|
}
|
|
419
434
|
// Check if this node or any ancestor should be skipped
|
|
420
|
-
if (shouldSkip(
|
|
435
|
+
if (shouldSkip(node)) {
|
|
421
436
|
return;
|
|
422
437
|
}
|
|
423
438
|
if (hasAncestor(ancestors, shouldSkip)) {
|
|
424
439
|
return;
|
|
425
440
|
}
|
|
426
441
|
// Collect and transform elements with text content
|
|
427
|
-
const elementsToTransform = collectTransformableElements(
|
|
442
|
+
const elementsToTransform = collectTransformableElements(node, shouldSkip);
|
|
428
443
|
for (const elt of elementsToTransform) {
|
|
429
444
|
if (!transformed.has(elt)) {
|
|
430
445
|
transformElement(elt, transformFn, shouldSkip, separator);
|
package/dist/rehype.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rehype.js","sourceRoot":"","sources":["../src/rehype.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAEvD,OAAO,EAAE,SAAS,EAAyB,MAAM,YAAY,CAAA;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAClD,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AA8BlE,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAA;AAElF;;;GAGG;AACH,MAAM,mBAAmB,GAAG,IAAI,CAAA;AAEhC;;GAEG;AACH,SAAS,QAAQ,CAAC,IAAa,EAAE,SAAiB;IAChD,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,SAAS,CAAA;IAC7C,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9B,OAAO,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;IACvC,CAAC;IACD,iGAAiG;IACjG,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE,CAAC;QACnC,OAAO,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;IACpD,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAClB,SAAmB,EACnB,SAA2B;IAE3B,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;QACjC,IAAI,QAAQ,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAChC,OAAO,SAAS,CAAC,QAAmB,CAAC,CAAA;QACvC,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,gBAAgB,CAC9B,IAA8B,EAC9B,UAA4B,EAC5B,QAAgB,CAAC;IAEjB,IAAI,KAAK,GAAG,mBAAmB,EAAE,CAAC;QAChC,OAAO,EAAE,CAAA;IACX,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,OAAO,EAAE,CAAA;IACX,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC,CAAA;IACf,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,
|
|
1
|
+
{"version":3,"file":"rehype.js","sourceRoot":"","sources":["../src/rehype.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "punctilio",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.0",
|
|
4
4
|
"description": "Smart typography transformations: curly quotes, em-dashes, en-dashes, and more",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
6
7
|
"main": "./dist/index.js",
|
|
7
8
|
"types": "./dist/index.d.ts",
|
|
8
9
|
"exports": {
|
package/src/constants.ts
CHANGED
|
@@ -117,10 +117,11 @@ export const TERMINAL_PUNCTUATION = [
|
|
|
117
117
|
* - Latin-1 Supplement: À-Ö, Ø-ö, ø-ÿ (excludes × and ÷)
|
|
118
118
|
* - Latin Extended-A: Ā-ſ (U+0100-017F)
|
|
119
119
|
* - Latin Extended-B: ƀ-ɏ (U+0180-024F)
|
|
120
|
+
* - Latin Extended Additional: Ḁ-ỿ (U+1E00-1EFF) — Vietnamese, Welsh, medievalist
|
|
120
121
|
*
|
|
121
|
-
* Examples of covered characters: é, ñ, ü, ø, ą, ł,
|
|
122
|
+
* Examples of covered characters: é, ñ, ü, ø, ą, ł, ș, ả, ầ, ẁ, ẃ
|
|
122
123
|
*/
|
|
123
|
-
export const LATIN_LETTERS = "A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u00FF\\u0100-\\u017F\\u0180-\\u024F"
|
|
124
|
+
export const LATIN_LETTERS = "A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u00FF\\u0100-\\u017F\\u0180-\\u024F\\u1E00-\\u1EFF"
|
|
124
125
|
|
|
125
126
|
/**
|
|
126
127
|
* Default separator for text spanning HTML elements.
|
package/src/markdown.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { unified } from "unified"
|
|
|
13
13
|
import remarkParse from "remark-parse"
|
|
14
14
|
import remarkGfm from "remark-gfm"
|
|
15
15
|
import remarkStringify from "remark-stringify"
|
|
16
|
+
import QuickLRU from "quick-lru"
|
|
16
17
|
|
|
17
18
|
import { remarkPunctilio, type RemarkPunctilioOptions } from "./remark.js"
|
|
18
19
|
|
|
@@ -40,27 +41,9 @@ export interface MarkdownOptions extends RemarkPunctilioOptions {
|
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* Parses the input as Markdown, applies punctilio typography transformations
|
|
46
|
-
* (smart quotes, em-dashes, ellipses, etc.), and serializes back to Markdown.
|
|
47
|
-
*
|
|
48
|
-
* @param input - The Markdown text to transform
|
|
49
|
-
* @param options - Configuration options for both the transform and serializer
|
|
50
|
-
* @returns The typographically improved Markdown text
|
|
51
|
-
*
|
|
52
|
-
* @example
|
|
53
|
-
* ```ts
|
|
54
|
-
* import { transformMarkdown } from 'punctilio/markdown'
|
|
55
|
-
*
|
|
56
|
-
* await transformMarkdown('"Hello" -- world')
|
|
57
|
-
* // → '\u201CHello\u201D\u2014world'
|
|
58
|
-
* ```
|
|
44
|
+
* Creates a unified processor pipeline for Markdown typography transformations.
|
|
59
45
|
*/
|
|
60
|
-
|
|
61
|
-
input: string,
|
|
62
|
-
options: MarkdownOptions = {}
|
|
63
|
-
): Promise<string> {
|
|
46
|
+
function createProcessor(options: MarkdownOptions) {
|
|
64
47
|
const {
|
|
65
48
|
emphasisMarker,
|
|
66
49
|
strongMarker,
|
|
@@ -69,7 +52,7 @@ export async function transformMarkdown(
|
|
|
69
52
|
...punctilioOptions
|
|
70
53
|
} = options
|
|
71
54
|
|
|
72
|
-
|
|
55
|
+
return unified()
|
|
73
56
|
.use(remarkParse)
|
|
74
57
|
.use(remarkGfm)
|
|
75
58
|
.use(remarkPunctilio, punctilioOptions)
|
|
@@ -86,6 +69,56 @@ export async function transformMarkdown(
|
|
|
86
69
|
// output is re-parsed by markdown renderers.
|
|
87
70
|
unsafe: [{ character: "]", inConstruct: "phrasing" }],
|
|
88
71
|
})
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const MAX_PROCESSOR_CACHE_SIZE = 8
|
|
75
|
+
|
|
76
|
+
const processorCache = new QuickLRU<string, ReturnType<typeof createProcessor>>({
|
|
77
|
+
maxSize: MAX_PROCESSOR_CACHE_SIZE,
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Clears the processor cache. Exported for test isolation only.
|
|
82
|
+
* @internal
|
|
83
|
+
*/
|
|
84
|
+
export function clearProcessorCache(): void {
|
|
85
|
+
processorCache.clear()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Transforms Markdown text with typographic improvements.
|
|
90
|
+
*
|
|
91
|
+
* Parses the input as Markdown, applies punctilio typography transformations
|
|
92
|
+
* (smart quotes, em-dashes, ellipses, etc.), and serializes back to Markdown.
|
|
93
|
+
*
|
|
94
|
+
* The unified processor pipeline is cached and reused across calls with
|
|
95
|
+
* identical options, avoiding redundant pipeline construction.
|
|
96
|
+
*
|
|
97
|
+
* @param input - The Markdown text to transform
|
|
98
|
+
* @param options - Configuration options for both the transform and serializer
|
|
99
|
+
* @returns The typographically improved Markdown text
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* import { transformMarkdown } from 'punctilio/markdown'
|
|
104
|
+
*
|
|
105
|
+
* await transformMarkdown('"Hello" -- world')
|
|
106
|
+
* // → '\u201CHello\u201D\u2014world'
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export async function transformMarkdown(
|
|
110
|
+
input: string,
|
|
111
|
+
options: MarkdownOptions = {}
|
|
112
|
+
): Promise<string> {
|
|
113
|
+
const optionsKey = JSON.stringify(
|
|
114
|
+
Object.entries(options).sort(([a], [b]) => a.localeCompare(b))
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
let processor = processorCache.get(optionsKey)
|
|
118
|
+
if (!processor) {
|
|
119
|
+
processor = createProcessor(options)
|
|
120
|
+
processorCache.set(optionsKey, processor)
|
|
121
|
+
}
|
|
89
122
|
|
|
90
123
|
const result = await processor.process(input)
|
|
91
124
|
return String(result)
|
package/src/nbsp.ts
CHANGED
|
@@ -60,6 +60,16 @@ export const UNITS = [
|
|
|
60
60
|
"MM", "M", "B", "T",
|
|
61
61
|
// Misc
|
|
62
62
|
"kcal", "mol", "cal", "dB",
|
|
63
|
+
// Speed
|
|
64
|
+
"mph", "kph", "fps",
|
|
65
|
+
// Pressure
|
|
66
|
+
"atm", "mbar",
|
|
67
|
+
// Battery / charge
|
|
68
|
+
"mAh", "Ah",
|
|
69
|
+
// Torque
|
|
70
|
+
"Nm",
|
|
71
|
+
// Light
|
|
72
|
+
"lm",
|
|
63
73
|
]
|
|
64
74
|
|
|
65
75
|
export const HONORIFICS = [
|
package/src/rehype.ts
CHANGED
|
@@ -112,7 +112,7 @@ export function flattenTextNodes(
|
|
|
112
112
|
return [node]
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
if (node.type === "element"
|
|
115
|
+
if (node.type === "element") {
|
|
116
116
|
return node.children.flatMap((child) => flattenTextNodes(child, shouldSkip, depth + 1))
|
|
117
117
|
}
|
|
118
118
|
|
|
@@ -363,6 +363,35 @@ const TRANSFORMABLE_ELEMENTS = new Set([
|
|
|
363
363
|
"rp",
|
|
364
364
|
])
|
|
365
365
|
|
|
366
|
+
/**
|
|
367
|
+
* Checks whether an element has any text node descendants (skipping elements
|
|
368
|
+
* matched by shouldSkip). Returns as soon as one is found — avoids allocating
|
|
369
|
+
* an array of all text nodes just to check existence.
|
|
370
|
+
*/
|
|
371
|
+
function hasTextDescendant(
|
|
372
|
+
node: Element | ElementContent,
|
|
373
|
+
shouldSkip: ElementPredicate,
|
|
374
|
+
depth: number = 0
|
|
375
|
+
): boolean {
|
|
376
|
+
if (depth > MAX_RECURSION_DEPTH) {
|
|
377
|
+
return false
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
if (node.type === "element" && shouldSkip(node)) {
|
|
381
|
+
return false
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
if (node.type === "text") {
|
|
385
|
+
return true
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
if (node.type === "element") {
|
|
389
|
+
return node.children.some((child) => hasTextDescendant(child, shouldSkip, depth + 1))
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
return false
|
|
393
|
+
}
|
|
394
|
+
|
|
366
395
|
/**
|
|
367
396
|
* Collects elements that should have text transformations applied.
|
|
368
397
|
*
|
|
@@ -403,7 +432,7 @@ export function collectTransformableElements(
|
|
|
403
432
|
(child) => child.type === "element" && BLOCK_ELEMENTS.has(child.tagName)
|
|
404
433
|
)
|
|
405
434
|
const hasTextDescendants = !hasDirectText && !hasBlockChildren &&
|
|
406
|
-
|
|
435
|
+
hasTextDescendant(node, shouldSkip)
|
|
407
436
|
|
|
408
437
|
if (
|
|
409
438
|
TRANSFORMABLE_ELEMENTS.has(node.tagName) &&
|
|
@@ -509,21 +538,14 @@ export function rehypePunctilio(
|
|
|
509
538
|
// Track transformed elements to avoid double-processing
|
|
510
539
|
const transformed = new Set<Element>()
|
|
511
540
|
|
|
512
|
-
visitParents(tree, (node, ancestors) => {
|
|
513
|
-
// Only process element nodes
|
|
514
|
-
if (node.type !== "element") {
|
|
515
|
-
return
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
const element = node as Element
|
|
519
|
-
|
|
541
|
+
visitParents(tree, "element", (node, ancestors) => {
|
|
520
542
|
// Skip if already transformed
|
|
521
|
-
if (transformed.has(
|
|
543
|
+
if (transformed.has(node)) {
|
|
522
544
|
return
|
|
523
545
|
}
|
|
524
546
|
|
|
525
547
|
// Check if this node or any ancestor should be skipped
|
|
526
|
-
if (shouldSkip(
|
|
548
|
+
if (shouldSkip(node)) {
|
|
527
549
|
return
|
|
528
550
|
}
|
|
529
551
|
if (hasAncestor(ancestors as Parent[], shouldSkip)) {
|
|
@@ -531,7 +553,7 @@ export function rehypePunctilio(
|
|
|
531
553
|
}
|
|
532
554
|
|
|
533
555
|
// Collect and transform elements with text content
|
|
534
|
-
const elementsToTransform = collectTransformableElements(
|
|
556
|
+
const elementsToTransform = collectTransformableElements(node, shouldSkip)
|
|
535
557
|
for (const elt of elementsToTransform) {
|
|
536
558
|
if (!transformed.has(elt)) {
|
|
537
559
|
transformElement(elt, transformFn, shouldSkip, separator)
|
package/src/tests/index.test.ts
CHANGED
|
@@ -356,7 +356,7 @@ describe("transform", () => {
|
|
|
356
356
|
})
|
|
357
357
|
})
|
|
358
358
|
|
|
359
|
-
describe("Unicode
|
|
359
|
+
describe("Unicode control characters", () => {
|
|
360
360
|
it.each([
|
|
361
361
|
['"test\u200Bword"', `${LEFT_DOUBLE_QUOTE}test\u200Bword${RIGHT_DOUBLE_QUOTE}`],
|
|
362
362
|
['"test\u200Fword"', `${LEFT_DOUBLE_QUOTE}test\u200Fword${RIGHT_DOUBLE_QUOTE}`],
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from "fs"
|
|
2
2
|
import { resolve } from "path"
|
|
3
3
|
import { fileURLToPath } from "url"
|
|
4
|
-
import { transformMarkdown } from "../markdown.js"
|
|
4
|
+
import { transformMarkdown, clearProcessorCache } from "../markdown.js"
|
|
5
5
|
import { transform } from "../index.js"
|
|
6
6
|
import { UNICODE_SYMBOLS } from "../constants.js"
|
|
7
7
|
|
|
@@ -16,6 +16,10 @@ const {
|
|
|
16
16
|
} = UNICODE_SYMBOLS
|
|
17
17
|
|
|
18
18
|
describe("transformMarkdown", () => {
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
clearProcessorCache()
|
|
21
|
+
})
|
|
22
|
+
|
|
19
23
|
it("transforms basic typography", async () => {
|
|
20
24
|
const result = await transformMarkdown('"Hello," she said.', { nbsp: false })
|
|
21
25
|
expect(result.trimEnd()).toEqual(`${LDQ}Hello,${RDQ} she said.`)
|
|
@@ -92,6 +96,43 @@ describe("transformMarkdown", () => {
|
|
|
92
96
|
expect(result).toContain(LDQ)
|
|
93
97
|
})
|
|
94
98
|
|
|
99
|
+
it("reuses cached processor for identical options", async () => {
|
|
100
|
+
const opts = { punctuationStyle: "british" as const, nbsp: false }
|
|
101
|
+
const first = await transformMarkdown('"Hello."', opts)
|
|
102
|
+
const second = await transformMarkdown('"World."', opts)
|
|
103
|
+
expect(first.trimEnd()).toEqual(`${LDQ}Hello${RDQ}.`)
|
|
104
|
+
expect(second.trimEnd()).toEqual(`${LDQ}World${RDQ}.`)
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it("invalidates cache when options change", async () => {
|
|
108
|
+
const american = await transformMarkdown('"Hello."', { punctuationStyle: "american", nbsp: false })
|
|
109
|
+
const british = await transformMarkdown('"Hello."', { punctuationStyle: "british", nbsp: false })
|
|
110
|
+
expect(american.trimEnd()).toEqual(`${LDQ}Hello.${RDQ}`)
|
|
111
|
+
expect(british.trimEnd()).toEqual(`${LDQ}Hello${RDQ}.`)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it("LRU cache retains multiple option sets simultaneously", async () => {
|
|
115
|
+
const american = { punctuationStyle: "american" as const, nbsp: false }
|
|
116
|
+
const british = { punctuationStyle: "british" as const, nbsp: false }
|
|
117
|
+
// Populate both cache entries
|
|
118
|
+
await transformMarkdown('"A."', american)
|
|
119
|
+
await transformMarkdown('"B."', british)
|
|
120
|
+
// Both should still be cached (not evicted)
|
|
121
|
+
const a2 = await transformMarkdown('"C."', american)
|
|
122
|
+
const b2 = await transformMarkdown('"D."', british)
|
|
123
|
+
expect(a2.trimEnd()).toEqual(`${LDQ}C.${RDQ}`)
|
|
124
|
+
expect(b2.trimEnd()).toEqual(`${LDQ}D${RDQ}.`)
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
it("distinguishes explicit undefined from absent options in cache key", async () => {
|
|
128
|
+
// { nbsp: undefined } overrides the default (true), disabling nbsp.
|
|
129
|
+
// The cache must not conflate this with {} which uses the default.
|
|
130
|
+
const withDefault = await transformMarkdown("Dr. Smith")
|
|
131
|
+
const withUndefined = await transformMarkdown("Dr. Smith", { nbsp: undefined })
|
|
132
|
+
expect(withDefault).toContain("\u00A0")
|
|
133
|
+
expect(withUndefined).not.toContain("\u00A0")
|
|
134
|
+
})
|
|
135
|
+
|
|
95
136
|
it("README.md prose is already typographically correct", () => {
|
|
96
137
|
const readme = readFileSync(resolve(__dirname, "../../README.md"), "utf-8")
|
|
97
138
|
const lines = readme.split("\n")
|
package/src/tests/quotes.test.ts
CHANGED
|
@@ -135,6 +135,10 @@ describe("niceQuotes", () => {
|
|
|
135
135
|
["Привет's", `Привет${MODIFIER_LETTER_APOSTROPHE}s`],
|
|
136
136
|
// Closing RSQ then opening LDQ
|
|
137
137
|
[`'hello' "world"`, `${LEFT_SINGLE_QUOTE}hello${RIGHT_SINGLE_QUOTE} ${LEFT_DOUBLE_QUOTE}world${RIGHT_DOUBLE_QUOTE}`],
|
|
138
|
+
// Latin Extended Additional: Vietnamese contraction-like patterns
|
|
139
|
+
["l'\u1EA3nh", `l${MODIFIER_LETTER_APOSTROPHE}\u1EA3nh`],
|
|
140
|
+
// Latin Extended Additional: Welsh w-acute (U+1E83, in U+1E00-1EFF range)
|
|
141
|
+
["l'\u1E83r", `l${MODIFIER_LETTER_APOSTROPHE}\u1E83r`],
|
|
138
142
|
])('should handle single quotes/apostrophes in "%s"', (input, expected) => {
|
|
139
143
|
expect(classifyApostrophes(input)).toBe(expected)
|
|
140
144
|
})
|
package/src/tests/rehype.test.ts
CHANGED
|
@@ -446,6 +446,16 @@ describe("rehypePunctilio", () => {
|
|
|
446
446
|
expect(collectTransformableElements(tree, ignoreCode)).toHaveLength(0)
|
|
447
447
|
})
|
|
448
448
|
|
|
449
|
+
it("returns empty when only non-text, non-element children exist", () => {
|
|
450
|
+
const tree: Element = {
|
|
451
|
+
type: "element",
|
|
452
|
+
tagName: "p",
|
|
453
|
+
properties: {},
|
|
454
|
+
children: [{ type: "comment", value: "a comment" } as unknown as ElementContent],
|
|
455
|
+
}
|
|
456
|
+
expect(collectTransformableElements(tree, ignoreNone)).toHaveLength(0)
|
|
457
|
+
})
|
|
458
|
+
|
|
449
459
|
it("stops at max recursion depth", () => {
|
|
450
460
|
let deep: Element = h("p", "deep") as Element
|
|
451
461
|
for (let i = 0; i < 1100; i++) deep = h("div", [deep]) as Element
|