punctilio 3.2.2 → 3.3.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 +3 -3
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +1 -1
- package/dist/constants.js.map +1 -1
- package/dist/nbsp.d.ts.map +1 -1
- package/dist/nbsp.js +5 -1
- package/dist/nbsp.js.map +1 -1
- package/dist/symbols.d.ts +1 -1
- package/dist/symbols.d.ts.map +1 -1
- package/dist/symbols.js +39 -29
- package/dist/symbols.js.map +1 -1
- package/dist/tests/test-helpers.d.ts +30 -0
- package/dist/tests/test-helpers.d.ts.map +1 -0
- package/dist/tests/test-helpers.js +91 -0
- package/dist/tests/test-helpers.js.map +1 -0
- package/package.json +3 -1
- package/src/constants.ts +1 -1
- package/src/nbsp.ts +5 -1
- package/src/symbols.ts +47 -32
- package/src/tests/dashes.test.ts +11 -0
- package/src/tests/index.test.ts +85 -44
- package/src/tests/markdown.test.ts +24 -0
- package/src/tests/nbsp.test.ts +12 -0
- package/src/tests/quotes.test.ts +24 -12
- package/src/tests/rehype.test.ts +45 -0
- package/src/tests/remark.test.ts +27 -0
- package/src/tests/symbols.test.ts +16 -5
- package/src/tests/test-helpers.ts +102 -0
package/README.md
CHANGED
|
@@ -75,11 +75,11 @@ My [`benchmark.mjs`](https://github.com/alexander-turner/punctilio/blob/main/ben
|
|
|
75
75
|
|
|
76
76
|
## Test suite
|
|
77
77
|
|
|
78
|
-
Setting aside the benchmark, `punctilio`’s test suite includes 1,450+ tests at 100% branch coverage, including edge cases derived from competitor libraries ([`smartquotes`](https://github.com/kellym/smartquotes.js), [`retext-smartypants`](https://github.com/retextjs/retext-smartypants), [`typograf`](https://github.com/typograf/typograf)) and the [Standard Ebooks typography manual](https://standardebooks.org/manual/). I also verify that all transformations are stable when applied multiple times.
|
|
78
|
+
Setting aside the benchmark, `punctilio`’s test suite includes 1,450+ tests at 100% branch coverage, including edge cases derived from competitor libraries ([`smartquotes`](https://github.com/kellym/smartquotes.js), [`retext-smartypants`](https://github.com/retextjs/retext-smartypants), [`typograf`](https://github.com/typograf/typograf)) and the [Standard Ebooks typography manual](https://standardebooks.org/manual/). I also verify that all transformations are stable when applied multiple times. All transforms run in linear time, with scaling tests that guard against quadratic RegEx backtracking.
|
|
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! (This means it
|
|
82
|
+
Perhaps the most innovative feature of the library is that it properly handles DOMs! (This means it’ll also work on Markdown: [convert to HTML](https://github.com/remarkjs/remark), transform with `punctilio`, [convert back to Markdown](https://github.com/JohannesKaufmann/html-to-markdown).)
|
|
83
83
|
|
|
84
84
|
Other typography libraries take one of two approaches, both with drawbacks.
|
|
85
85
|
|
|
@@ -121,7 +121,7 @@ For manual DOM walking or custom transforms, use `transformElement` from `puncti
|
|
|
121
121
|
|
|
122
122
|
## Options
|
|
123
123
|
|
|
124
|
-
`punctilio` doesn
|
|
124
|
+
`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.
|
|
125
125
|
|
|
126
126
|
```typescript
|
|
127
127
|
transform(text, {
|
package/dist/constants.d.ts
CHANGED
|
@@ -183,6 +183,7 @@ export declare function spaceBoundaryStart(escapedSeparator: string): string;
|
|
|
183
183
|
* @returns Pattern string: `(?=\\s|${sep}|$)`
|
|
184
184
|
*/
|
|
185
185
|
export declare function spaceBoundaryEnd(escapedSeparator: string): string;
|
|
186
|
+
export declare const MAX_REGEX_CACHE_SIZE = 1000;
|
|
186
187
|
/**
|
|
187
188
|
* Returns a cached RegExp for the given pattern and flags.
|
|
188
189
|
* Resets `lastIndex` before returning to prevent stale state when
|
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;AAIH;;GAEG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuElB,CAAA;AAEV;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,8HAYvB,CAAA;AAEV;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,sFAAsF,CAAA;AAEhH;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,iBAAiB,CAAA;AAC/C,eAAO,MAAM,yBAAyB,QAAwC,CAAA;AAE9E;;;;;;;;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;
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;GAEG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuElB,CAAA;AAEV;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,8HAYvB,CAAA;AAEV;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,sFAAsF,CAAA;AAEhH;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,iBAAiB,CAAA;AAC/C,eAAO,MAAM,yBAAyB,QAAwC,CAAA;AAE9E;;;;;;;;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;AAQD,eAAO,MAAM,oBAAoB,OAAO,CAAA;AAExC;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAcnE"}
|
package/dist/constants.js
CHANGED
|
@@ -219,7 +219,7 @@ export function spaceBoundaryEnd(escapedSeparator) {
|
|
|
219
219
|
* when using the default separator). Capped to prevent unbounded growth.
|
|
220
220
|
*/
|
|
221
221
|
const regexCache = new Map();
|
|
222
|
-
const MAX_REGEX_CACHE_SIZE = 1000;
|
|
222
|
+
export const MAX_REGEX_CACHE_SIZE = 1000;
|
|
223
223
|
/**
|
|
224
224
|
* Returns a cached RegExp for the given pattern and flags.
|
|
225
225
|
* Resets `lastIndex` before returning to prevent stale state when
|
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/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,UA2BjB,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,
|
|
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,UA2BjB,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
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @module nbsp
|
|
9
9
|
*/
|
|
10
|
-
import { UNICODE_SYMBOLS, LATIN_LETTERS, wordBoundaryEnd, getEscapedSeparator, cachedRegExp } from "./constants.js";
|
|
10
|
+
import { UNICODE_SYMBOLS, LATIN_LETTERS, SPACE_CHARS, wordBoundaryEnd, getEscapedSeparator, cachedRegExp } from "./constants.js";
|
|
11
11
|
const { NBSP, LEFT_DOUBLE_QUOTE, RIGHT_DOUBLE_QUOTE, LEFT_SINGLE_QUOTE, RIGHT_SINGLE_QUOTE, COPYRIGHT, REGISTERED, TRADEMARK, } = UNICODE_SYMBOLS;
|
|
12
12
|
/** Space pattern matching regular space, tab, and nbsp. */
|
|
13
13
|
const SPACE = `[ \\t${NBSP}]`;
|
|
@@ -182,6 +182,10 @@ const NBSP_TRANSFORMS = [
|
|
|
182
182
|
];
|
|
183
183
|
/** Apply all non-breaking space transformations in sequence. */
|
|
184
184
|
export function nbspTransform(text, options = {}) {
|
|
185
|
+
// All nbsp patterns require a space, tab, or existing nbsp to match.
|
|
186
|
+
// Short-circuit if the text contains none of these.
|
|
187
|
+
if (!cachedRegExp(`[${SPACE_CHARS}\\t]`, "").test(text))
|
|
188
|
+
return text;
|
|
185
189
|
for (const fn of NBSP_TRANSFORMS) {
|
|
186
190
|
text = fn(text, options);
|
|
187
191
|
}
|
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,eAAe,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"nbsp.js","sourceRoot":"","sources":["../src/nbsp.ts"],"names":[],"mappings":"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"}
|
package/dist/symbols.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ export declare function arrows(text: string, options?: SymbolOptions): string;
|
|
|
21
21
|
export declare function degrees(text: string, options?: SymbolOptions): string;
|
|
22
22
|
/** Convert 5'10" to 5′10″ (prime marks). Call before smart quotes. */
|
|
23
23
|
export declare function primeMarks(text: string, options?: SymbolOptions): string;
|
|
24
|
-
/** Convert 1/2, 1/4, etc. to ½, ¼, etc. */
|
|
24
|
+
/** Convert 1/2, 1/4, etc. to ½, ¼, etc. Single-pass using alternation. */
|
|
25
25
|
export declare function fractions(text: string, options?: SymbolOptions): string;
|
|
26
26
|
/** Convert 1st, 2nd, 3rd, 4th to superscript ordinals. */
|
|
27
27
|
export declare function superscriptOrdinal(text: string, options?: SymbolOptions): string;
|
package/dist/symbols.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"symbols.d.ts","sourceRoot":"","sources":["../src/symbols.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,WAAW,aAAa;IAC5B,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,uDAAuD;IACvD,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AA6BD,uCAAuC;AACvC,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAa1E;AAED,gDAAgD;AAChD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAmChF;AAgBD,0DAA0D;AAC1D,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAQ7E;AAmBD,yCAAyC;AACzC,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAejD;AASD,oCAAoC;AACpC,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAYxE;AAED,kFAAkF;AAClF,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAWzE;AAyFD,sEAAsE;AACtE,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAe5E;
|
|
1
|
+
{"version":3,"file":"symbols.d.ts","sourceRoot":"","sources":["../src/symbols.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,WAAW,aAAa;IAC5B,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,uDAAuD;IACvD,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AA6BD,uCAAuC;AACvC,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAa1E;AAED,gDAAgD;AAChD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAmChF;AAgBD,0DAA0D;AAC1D,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAQ7E;AAmBD,yCAAyC;AACzC,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAejD;AASD,oCAAoC;AACpC,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAYxE;AAED,kFAAkF;AAClF,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAWzE;AAyFD,sEAAsE;AACtE,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAe5E;AA0BD,0EAA0E;AAC1E,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CA2B3E;AASD,0DAA0D;AAC1D,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAgBpF;AAED,qFAAqF;AACrF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKnD;AAcD,iFAAiF;AACjF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAStF;AAED,gFAAgF;AAChF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CASjF"}
|
package/dist/symbols.js
CHANGED
|
@@ -202,37 +202,47 @@ export function primeMarks(text, options = {}) {
|
|
|
202
202
|
}
|
|
203
203
|
return text;
|
|
204
204
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
"
|
|
211
|
-
"1
|
|
212
|
-
"
|
|
213
|
-
"3
|
|
214
|
-
"
|
|
215
|
-
"1
|
|
216
|
-
"5
|
|
217
|
-
"
|
|
218
|
-
"
|
|
219
|
-
"
|
|
220
|
-
"
|
|
221
|
-
|
|
222
|
-
|
|
205
|
+
/**
|
|
206
|
+
* Supported Unicode fractions: [numerator, denominator, unicode character].
|
|
207
|
+
* The regex alternation and lookup map are both derived from this list.
|
|
208
|
+
*/
|
|
209
|
+
const FRACTION_TUPLES = [
|
|
210
|
+
["1", "4", UNICODE_SYMBOLS.FRACTION_1_4],
|
|
211
|
+
["1", "2", UNICODE_SYMBOLS.FRACTION_1_2],
|
|
212
|
+
["3", "4", UNICODE_SYMBOLS.FRACTION_3_4],
|
|
213
|
+
["1", "3", UNICODE_SYMBOLS.FRACTION_1_3],
|
|
214
|
+
["2", "3", UNICODE_SYMBOLS.FRACTION_2_3],
|
|
215
|
+
["1", "5", UNICODE_SYMBOLS.FRACTION_1_5],
|
|
216
|
+
["2", "5", UNICODE_SYMBOLS.FRACTION_2_5],
|
|
217
|
+
["3", "5", UNICODE_SYMBOLS.FRACTION_3_5],
|
|
218
|
+
["4", "5", UNICODE_SYMBOLS.FRACTION_4_5],
|
|
219
|
+
["1", "6", UNICODE_SYMBOLS.FRACTION_1_6],
|
|
220
|
+
["5", "6", UNICODE_SYMBOLS.FRACTION_5_6],
|
|
221
|
+
["1", "8", UNICODE_SYMBOLS.FRACTION_1_8],
|
|
222
|
+
["3", "8", UNICODE_SYMBOLS.FRACTION_3_8],
|
|
223
|
+
["5", "8", UNICODE_SYMBOLS.FRACTION_5_8],
|
|
224
|
+
["7", "8", UNICODE_SYMBOLS.FRACTION_7_8],
|
|
225
|
+
];
|
|
226
|
+
const FRACTION_MAP = Object.fromEntries(FRACTION_TUPLES.map(([n, d, u]) => [`${n}/${d}`, u]));
|
|
227
|
+
/** Convert 1/2, 1/4, etc. to ½, ¼, etc. Single-pass using alternation. */
|
|
223
228
|
export function fractions(text, options = {}) {
|
|
224
229
|
const chr = getEscapedSeparator(options);
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
230
|
+
// Build alternation of exact valid pairs: `1${sep}?/${sep}?4|1${sep}?/${sep}?2|...`
|
|
231
|
+
// Only exact pairs from FRACTION_TUPLES match — no cross-product.
|
|
232
|
+
const pairAlternation = FRACTION_TUPLES.map(([n, d]) => `${n}${chr}?/${chr}?${d}`).join("|");
|
|
233
|
+
// - (?<![/.\d]) prevents matching after slashes, dots, or digits
|
|
234
|
+
// - (?![/\d]|\.\d) prevents matching before slashes, digits, or decimal points
|
|
235
|
+
const pattern = cachedRegExp(`(?<![/\\.\\d])(?:${pairAlternation})(?![/\\d]|\\.\\d)`, "g");
|
|
236
|
+
const sepPattern = cachedRegExp(chr, "g");
|
|
237
|
+
return text.replace(pattern, (match) => {
|
|
238
|
+
// Split on separator to isolate the raw fraction and preserve markers.
|
|
239
|
+
// e.g. "1\uE000/\uE0002" → parts ["1", "/", "2"], separators ["\uE000", "\uE000"]
|
|
240
|
+
const parts = match.split(sepPattern);
|
|
241
|
+
const raw = parts.join("");
|
|
242
|
+
const separators = match.match(sepPattern) ?? [];
|
|
243
|
+
// Distribute separators: first goes before the unicode char, second after
|
|
244
|
+
return `${separators[0] ?? ""}${FRACTION_MAP[raw]}${separators[1] ?? ""}`;
|
|
245
|
+
});
|
|
236
246
|
}
|
|
237
247
|
const ORDINAL_MAP = {
|
|
238
248
|
st: SUPERSCRIPT_ST,
|
package/dist/symbols.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"symbols.js","sourceRoot":"","sources":["../src/symbols.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"symbols.js","sourceRoot":"","sources":["../src/symbols.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared test utilities for punctilio test suites.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Builds a deterministic pseudo-random string of approximately `charCount`
|
|
6
|
+
* characters by randomly sampling from FRAGMENTS using a seeded PRNG.
|
|
7
|
+
*
|
|
8
|
+
* @param charCount - Approximate desired character count
|
|
9
|
+
* @param seed - PRNG seed (default: "42")
|
|
10
|
+
*/
|
|
11
|
+
export declare function buildMixedContent(charCount: number, seed?: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Asserts that a function scales linearly (not quadratically) with input size.
|
|
14
|
+
*
|
|
15
|
+
* Measures ms/char at 4 input sizes (1x, 2x, 4x, 8x) after a JIT warmup pass.
|
|
16
|
+
* Compares the two largest sizes (4x vs 8x) which have the best signal-to-noise
|
|
17
|
+
* ratio. For a linear algorithm, doubling input keeps ms/char constant (ratio ~1).
|
|
18
|
+
* For a quadratic one, doubling input doubles ms/char (ratio ~2).
|
|
19
|
+
*
|
|
20
|
+
* Default startingN of 5000 produces inputs from ~5K to ~40K chars, which is
|
|
21
|
+
* past V8's string allocation overhead inflection point where ms/char stabilizes.
|
|
22
|
+
*
|
|
23
|
+
* Uses min 3 iterations and min 20ms per size to get stable averages.
|
|
24
|
+
*
|
|
25
|
+
* @param fn - The function to benchmark
|
|
26
|
+
* @param buildInput - Builds an input string of approximately `n` units
|
|
27
|
+
* @param startingN - Size parameter for the smallest input (default: 5000)
|
|
28
|
+
*/
|
|
29
|
+
export declare function assertLinearScaling(fn: (input: string) => unknown, buildInput: (n: number) => string, startingN?: number): void;
|
|
30
|
+
//# sourceMappingURL=test-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-helpers.d.ts","sourceRoot":"","sources":["../../src/tests/test-helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAgCH;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,GAAE,MAAa,GAAG,MAAM,CAQhF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,EAC9B,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EACjC,SAAS,GAAE,MAAa,GACvB,IAAI,CA6BN"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared test utilities for punctilio test suites.
|
|
3
|
+
*/
|
|
4
|
+
import seedrandom from "seedrandom";
|
|
5
|
+
/**
|
|
6
|
+
* Fragments covering every transform type: quotes, dashes, apostrophes,
|
|
7
|
+
* ellipses, multiplication, math symbols, legal symbols, arrows, primes,
|
|
8
|
+
* fractions, degrees, ordinals, nbsp-triggering short words, and plain text.
|
|
9
|
+
*/
|
|
10
|
+
const FRAGMENTS = [
|
|
11
|
+
`"Hello," she said. `,
|
|
12
|
+
`It's a beautiful day -- isn't it? `,
|
|
13
|
+
`Wait... `,
|
|
14
|
+
`The temperature was 20 C. `,
|
|
15
|
+
`5x5 != 25. `,
|
|
16
|
+
`Add 1/2 cup. `,
|
|
17
|
+
`He's 5'10" tall. `,
|
|
18
|
+
`(c) 2024 Acme Corp. `,
|
|
19
|
+
`See p. 42 for details. `,
|
|
20
|
+
`Dr. Smith arrived. `,
|
|
21
|
+
`The 1st place winner. `,
|
|
22
|
+
`Go -> click -> done. `,
|
|
23
|
+
`Really?! No way!! `,
|
|
24
|
+
`A B C D E F G H. `,
|
|
25
|
+
`Pages 10-20 contain important info. `,
|
|
26
|
+
`January-March was cold. `,
|
|
27
|
+
`The value is -5. `,
|
|
28
|
+
`"Don't stop," he said, "keep going." `,
|
|
29
|
+
`J. K. Rowling wrote it. `,
|
|
30
|
+
`100 km in 2 hrs. `,
|
|
31
|
+
];
|
|
32
|
+
/**
|
|
33
|
+
* Builds a deterministic pseudo-random string of approximately `charCount`
|
|
34
|
+
* characters by randomly sampling from FRAGMENTS using a seeded PRNG.
|
|
35
|
+
*
|
|
36
|
+
* @param charCount - Approximate desired character count
|
|
37
|
+
* @param seed - PRNG seed (default: "42")
|
|
38
|
+
*/
|
|
39
|
+
export function buildMixedContent(charCount, seed = "42") {
|
|
40
|
+
const random = seedrandom(seed);
|
|
41
|
+
let result = "";
|
|
42
|
+
while (result.length < charCount) {
|
|
43
|
+
const index = Math.floor(random() * FRAGMENTS.length);
|
|
44
|
+
result += FRAGMENTS[index];
|
|
45
|
+
}
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Asserts that a function scales linearly (not quadratically) with input size.
|
|
50
|
+
*
|
|
51
|
+
* Measures ms/char at 4 input sizes (1x, 2x, 4x, 8x) after a JIT warmup pass.
|
|
52
|
+
* Compares the two largest sizes (4x vs 8x) which have the best signal-to-noise
|
|
53
|
+
* ratio. For a linear algorithm, doubling input keeps ms/char constant (ratio ~1).
|
|
54
|
+
* For a quadratic one, doubling input doubles ms/char (ratio ~2).
|
|
55
|
+
*
|
|
56
|
+
* Default startingN of 5000 produces inputs from ~5K to ~40K chars, which is
|
|
57
|
+
* past V8's string allocation overhead inflection point where ms/char stabilizes.
|
|
58
|
+
*
|
|
59
|
+
* Uses min 3 iterations and min 20ms per size to get stable averages.
|
|
60
|
+
*
|
|
61
|
+
* @param fn - The function to benchmark
|
|
62
|
+
* @param buildInput - Builds an input string of approximately `n` units
|
|
63
|
+
* @param startingN - Size parameter for the smallest input (default: 5000)
|
|
64
|
+
*/
|
|
65
|
+
export function assertLinearScaling(fn, buildInput, startingN = 5000) {
|
|
66
|
+
const multipliers = [1, 2, 4, 8];
|
|
67
|
+
// Warmup with the largest input so JIT compiles all code paths before timing.
|
|
68
|
+
fn(buildInput(startingN * multipliers[multipliers.length - 1]));
|
|
69
|
+
function measureMsPerChar(mult) {
|
|
70
|
+
const input = buildInput(startingN * mult);
|
|
71
|
+
const minIterations = 3;
|
|
72
|
+
const minElapsedMs = 20;
|
|
73
|
+
let totalElapsed = 0;
|
|
74
|
+
let iterations = 0;
|
|
75
|
+
while (iterations < minIterations || totalElapsed < minElapsedMs) {
|
|
76
|
+
const start = performance.now();
|
|
77
|
+
fn(input);
|
|
78
|
+
totalElapsed += performance.now() - start;
|
|
79
|
+
iterations++;
|
|
80
|
+
}
|
|
81
|
+
return totalElapsed / iterations / input.length;
|
|
82
|
+
}
|
|
83
|
+
// Measure all sizes (exercises the function at various scales)
|
|
84
|
+
const msPerChar = multipliers.map(measureMsPerChar);
|
|
85
|
+
// Compare the two largest inputs (best SNR, per-call overhead is negligible).
|
|
86
|
+
// For linear: rate_8x / rate_4x ≈ 1. For quadratic: ≈ 2.
|
|
87
|
+
const rate4x = msPerChar[2];
|
|
88
|
+
const rate8x = msPerChar[3];
|
|
89
|
+
expect(rate8x / rate4x).toBeLessThan(1.5);
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=test-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-helpers.js","sourceRoot":"","sources":["../../src/tests/test-helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,UAAU,MAAM,YAAY,CAAA;AAEnC;;;;GAIG;AACH,MAAM,SAAS,GAAG;IAChB,qBAAqB;IACrB,oCAAoC;IACpC,UAAU;IACV,4BAA4B;IAC5B,aAAa;IACb,eAAe;IACf,mBAAmB;IACnB,sBAAsB;IACtB,yBAAyB;IACzB,qBAAqB;IACrB,wBAAwB;IACxB,uBAAuB;IACvB,oBAAoB;IACpB,mBAAmB;IACnB,sCAAsC;IACtC,0BAA0B;IAC1B,mBAAmB;IACnB,uCAAuC;IACvC,0BAA0B;IAC1B,mBAAmB;CACpB,CAAA;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,SAAiB,EAAE,OAAe,IAAI;IACtE,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAA;IAC/B,IAAI,MAAM,GAAG,EAAE,CAAA;IACf,OAAO,MAAM,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,CAAA;QACrD,MAAM,IAAI,SAAS,CAAC,KAAK,CAAC,CAAA;IAC5B,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,mBAAmB,CACjC,EAA8B,EAC9B,UAAiC,EACjC,YAAoB,IAAI;IAExB,MAAM,WAAW,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IAEhC,8EAA8E;IAC9E,EAAE,CAAC,UAAU,CAAC,SAAS,GAAG,WAAW,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;IAE/D,SAAS,gBAAgB,CAAC,IAAY;QACpC,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,GAAG,IAAI,CAAC,CAAA;QAC1C,MAAM,aAAa,GAAG,CAAC,CAAA;QACvB,MAAM,YAAY,GAAG,EAAE,CAAA;QACvB,IAAI,YAAY,GAAG,CAAC,CAAA;QACpB,IAAI,UAAU,GAAG,CAAC,CAAA;QAClB,OAAO,UAAU,GAAG,aAAa,IAAI,YAAY,GAAG,YAAY,EAAE,CAAC;YACjE,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;YAC/B,EAAE,CAAC,KAAK,CAAC,CAAA;YACT,YAAY,IAAI,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAA;YACzC,UAAU,EAAE,CAAA;QACd,CAAC;QACD,OAAO,YAAY,GAAG,UAAU,GAAG,KAAK,CAAC,MAAM,CAAA;IACjD,CAAC;IAED,+DAA+D;IAC/D,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAA;IAEnD,8EAA8E;IAC9E,yDAAyD;IACzD,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;IAC3B,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;IAC3B,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAA;AAC3C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "punctilio",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "Smart typography transformations: curly quotes, em-dashes, en-dashes, and more",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
"@types/jest": "^29.5.12",
|
|
65
65
|
"@types/mdast": "4.0.4",
|
|
66
66
|
"@types/node": "^20.11.0",
|
|
67
|
+
"@types/seedrandom": "3.0.8",
|
|
67
68
|
"eslint": "^9.39.2",
|
|
68
69
|
"eslint-plugin-regexp": "^3.0.0",
|
|
69
70
|
"hastscript": "9.0.1",
|
|
@@ -76,6 +77,7 @@
|
|
|
76
77
|
"remark-stringify": "11.0.0",
|
|
77
78
|
"retext": "9.0.0",
|
|
78
79
|
"retext-smartypants": "6.2.0",
|
|
80
|
+
"seedrandom": "3.0.5",
|
|
79
81
|
"smartquotes": "2.3.2",
|
|
80
82
|
"smartypants": "0.2.2",
|
|
81
83
|
"tipograph": "0.7.4",
|
package/src/constants.ts
CHANGED
|
@@ -232,7 +232,7 @@ export function spaceBoundaryEnd(escapedSeparator: string): string {
|
|
|
232
232
|
* when using the default separator). Capped to prevent unbounded growth.
|
|
233
233
|
*/
|
|
234
234
|
const regexCache = new Map<string, RegExp>()
|
|
235
|
-
const MAX_REGEX_CACHE_SIZE = 1000
|
|
235
|
+
export const MAX_REGEX_CACHE_SIZE = 1000
|
|
236
236
|
|
|
237
237
|
/**
|
|
238
238
|
* Returns a cached RegExp for the given pattern and flags.
|
package/src/nbsp.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* @module nbsp
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { UNICODE_SYMBOLS, LATIN_LETTERS, wordBoundaryEnd, getEscapedSeparator, cachedRegExp } from "./constants.js"
|
|
11
|
+
import { UNICODE_SYMBOLS, LATIN_LETTERS, SPACE_CHARS, wordBoundaryEnd, getEscapedSeparator, cachedRegExp } from "./constants.js"
|
|
12
12
|
import type { SymbolOptions } from "./symbols.js"
|
|
13
13
|
|
|
14
14
|
const {
|
|
@@ -238,6 +238,10 @@ const NBSP_TRANSFORMS: NbspFn[] = [
|
|
|
238
238
|
|
|
239
239
|
/** Apply all non-breaking space transformations in sequence. */
|
|
240
240
|
export function nbspTransform(text: string, options: NbspOptions = {}): string {
|
|
241
|
+
// All nbsp patterns require a space, tab, or existing nbsp to match.
|
|
242
|
+
// Short-circuit if the text contains none of these.
|
|
243
|
+
if (!cachedRegExp(`[${SPACE_CHARS}\\t]`, "").test(text)) return text
|
|
244
|
+
|
|
241
245
|
for (const fn of NBSP_TRANSFORMS) {
|
|
242
246
|
text = fn(text, options)
|
|
243
247
|
}
|
package/src/symbols.ts
CHANGED
|
@@ -293,43 +293,58 @@ export function primeMarks(text: string, options: SymbolOptions = {}): string {
|
|
|
293
293
|
return text
|
|
294
294
|
}
|
|
295
295
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
"
|
|
302
|
-
"1
|
|
303
|
-
"
|
|
304
|
-
"3
|
|
305
|
-
"
|
|
306
|
-
"1
|
|
307
|
-
"5
|
|
308
|
-
"
|
|
309
|
-
"
|
|
310
|
-
"
|
|
311
|
-
"
|
|
312
|
-
|
|
296
|
+
/**
|
|
297
|
+
* Supported Unicode fractions: [numerator, denominator, unicode character].
|
|
298
|
+
* The regex alternation and lookup map are both derived from this list.
|
|
299
|
+
*/
|
|
300
|
+
const FRACTION_TUPLES: [string, string, string][] = [
|
|
301
|
+
["1", "4", UNICODE_SYMBOLS.FRACTION_1_4],
|
|
302
|
+
["1", "2", UNICODE_SYMBOLS.FRACTION_1_2],
|
|
303
|
+
["3", "4", UNICODE_SYMBOLS.FRACTION_3_4],
|
|
304
|
+
["1", "3", UNICODE_SYMBOLS.FRACTION_1_3],
|
|
305
|
+
["2", "3", UNICODE_SYMBOLS.FRACTION_2_3],
|
|
306
|
+
["1", "5", UNICODE_SYMBOLS.FRACTION_1_5],
|
|
307
|
+
["2", "5", UNICODE_SYMBOLS.FRACTION_2_5],
|
|
308
|
+
["3", "5", UNICODE_SYMBOLS.FRACTION_3_5],
|
|
309
|
+
["4", "5", UNICODE_SYMBOLS.FRACTION_4_5],
|
|
310
|
+
["1", "6", UNICODE_SYMBOLS.FRACTION_1_6],
|
|
311
|
+
["5", "6", UNICODE_SYMBOLS.FRACTION_5_6],
|
|
312
|
+
["1", "8", UNICODE_SYMBOLS.FRACTION_1_8],
|
|
313
|
+
["3", "8", UNICODE_SYMBOLS.FRACTION_3_8],
|
|
314
|
+
["5", "8", UNICODE_SYMBOLS.FRACTION_5_8],
|
|
315
|
+
["7", "8", UNICODE_SYMBOLS.FRACTION_7_8],
|
|
316
|
+
]
|
|
313
317
|
|
|
314
|
-
|
|
318
|
+
const FRACTION_MAP = Object.fromEntries(FRACTION_TUPLES.map(([n, d, u]) => [`${n}/${d}`, u]))
|
|
319
|
+
|
|
320
|
+
/** Convert 1/2, 1/4, etc. to ½, ¼, etc. Single-pass using alternation. */
|
|
315
321
|
export function fractions(text: string, options: SymbolOptions = {}): string {
|
|
316
322
|
const chr = getEscapedSeparator(options)
|
|
317
323
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
const [numerator, denominator] = ascii.split("/")
|
|
324
|
-
const pattern = cachedRegExp(
|
|
325
|
-
`(?<![/\\.\\d])${numerator}(?<sepBefore>${chr}?)/(?<sepAfter>${chr}?)${denominator}(?![/\\d]|\\.\\d)`,
|
|
326
|
-
"g"
|
|
327
|
-
)
|
|
328
|
-
// Preserve separators around the fraction Unicode character
|
|
329
|
-
text = text.replace(pattern, `$<sepBefore>${unicode}$<sepAfter>`)
|
|
330
|
-
}
|
|
324
|
+
// Build alternation of exact valid pairs: `1${sep}?/${sep}?4|1${sep}?/${sep}?2|...`
|
|
325
|
+
// Only exact pairs from FRACTION_TUPLES match — no cross-product.
|
|
326
|
+
const pairAlternation = FRACTION_TUPLES.map(([n, d]) =>
|
|
327
|
+
`${n}${chr}?/${chr}?${d}`
|
|
328
|
+
).join("|")
|
|
331
329
|
|
|
332
|
-
|
|
330
|
+
// - (?<![/.\d]) prevents matching after slashes, dots, or digits
|
|
331
|
+
// - (?![/\d]|\.\d) prevents matching before slashes, digits, or decimal points
|
|
332
|
+
const pattern = cachedRegExp(
|
|
333
|
+
`(?<![/\\.\\d])(?:${pairAlternation})(?![/\\d]|\\.\\d)`,
|
|
334
|
+
"g"
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
const sepPattern = cachedRegExp(chr, "g")
|
|
338
|
+
|
|
339
|
+
return text.replace(pattern, (match) => {
|
|
340
|
+
// Split on separator to isolate the raw fraction and preserve markers.
|
|
341
|
+
// e.g. "1\uE000/\uE0002" → parts ["1", "/", "2"], separators ["\uE000", "\uE000"]
|
|
342
|
+
const parts = match.split(sepPattern)
|
|
343
|
+
const raw = parts.join("")
|
|
344
|
+
const separators = match.match(sepPattern) ?? []
|
|
345
|
+
// Distribute separators: first goes before the unicode char, second after
|
|
346
|
+
return `${separators[0] ?? ""}${FRACTION_MAP[raw]}${separators[1] ?? ""}`
|
|
347
|
+
})
|
|
333
348
|
}
|
|
334
349
|
|
|
335
350
|
const ORDINAL_MAP: Record<string, string> = {
|
package/src/tests/dashes.test.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { hyphenReplace, enDashNumberRange, enDashDateRange, minusReplace, numberRangeDisallowedPrefixes } from "../dashes.js"
|
|
2
2
|
import { DEFAULT_SEPARATOR, UNICODE_SYMBOLS } from "../constants.js"
|
|
3
|
+
import { assertLinearScaling } from "./test-helpers.js"
|
|
3
4
|
|
|
4
5
|
const {
|
|
5
6
|
LEFT_DOUBLE_QUOTE,
|
|
@@ -709,3 +710,13 @@ describe("hyphenReplace preserves multi-segment numbers across separators", () =
|
|
|
709
710
|
expect(hyphenReplace(input, { separator: sep })).toBe(input)
|
|
710
711
|
})
|
|
711
712
|
})
|
|
713
|
+
|
|
714
|
+
describe("dash stress tests", () => {
|
|
715
|
+
it("scales linearly for parenthetical dashes", () => {
|
|
716
|
+
assertLinearScaling(hyphenReplace, (n) => "word - word ".repeat(n))
|
|
717
|
+
})
|
|
718
|
+
|
|
719
|
+
it("scales linearly for number ranges", () => {
|
|
720
|
+
assertLinearScaling(hyphenReplace, (n) => "pages 1-2 ".repeat(n))
|
|
721
|
+
})
|
|
722
|
+
})
|
package/src/tests/index.test.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { transform, DEFAULT_SEPARATOR, countSeparators } from "../index.js"
|
|
2
2
|
import { ellipsis } from "../symbols.js"
|
|
3
|
-
import { UNICODE_SYMBOLS, REGEX_SPECIAL_CHARS } from "../constants.js"
|
|
3
|
+
import { UNICODE_SYMBOLS, REGEX_SPECIAL_CHARS, MAX_REGEX_CACHE_SIZE } from "../constants.js"
|
|
4
|
+
import { assertLinearScaling, buildMixedContent } from "./test-helpers.js"
|
|
4
5
|
|
|
5
6
|
const {
|
|
6
7
|
LEFT_DOUBLE_QUOTE,
|
|
@@ -507,36 +508,16 @@ describe("transform", () => {
|
|
|
507
508
|
})
|
|
508
509
|
|
|
509
510
|
describe("regex performance", () => {
|
|
510
|
-
it("
|
|
511
|
-
|
|
512
|
-
const start = Date.now()
|
|
513
|
-
transform(input)
|
|
514
|
-
const duration = Date.now() - start
|
|
515
|
-
expect(duration).toBeLessThan(1000)
|
|
511
|
+
it("scales linearly for pathological quote patterns", () => {
|
|
512
|
+
assertLinearScaling(transform, (n) => '"a"'.repeat(n) + "'")
|
|
516
513
|
})
|
|
517
514
|
|
|
518
|
-
it("
|
|
519
|
-
|
|
520
|
-
const start = Date.now()
|
|
521
|
-
transform(input)
|
|
522
|
-
const duration = Date.now() - start
|
|
523
|
-
expect(duration).toBeLessThan(1000)
|
|
515
|
+
it("scales linearly for pathological dash patterns", () => {
|
|
516
|
+
assertLinearScaling(transform, (n) => "1" + "-1".repeat(n))
|
|
524
517
|
})
|
|
525
518
|
|
|
526
|
-
it("
|
|
527
|
-
|
|
528
|
-
const start = performance.now()
|
|
529
|
-
transform(input)
|
|
530
|
-
const duration = performance.now() - start
|
|
531
|
-
expect(duration).toBeLessThan(500)
|
|
532
|
-
})
|
|
533
|
-
|
|
534
|
-
it("handles 500 chained number patterns efficiently", () => {
|
|
535
|
-
const input = "1" + "-1".repeat(500)
|
|
536
|
-
const start = performance.now()
|
|
537
|
-
transform(input)
|
|
538
|
-
const duration = performance.now() - start
|
|
539
|
-
expect(duration).toBeLessThan(500)
|
|
519
|
+
it("scales linearly for unbalanced single quotes", () => {
|
|
520
|
+
assertLinearScaling(transform, (n) => "'".repeat(n) + "a")
|
|
540
521
|
})
|
|
541
522
|
})
|
|
542
523
|
|
|
@@ -626,28 +607,88 @@ describe("transform", () => {
|
|
|
626
607
|
})
|
|
627
608
|
|
|
628
609
|
describe("large input handling", () => {
|
|
629
|
-
it("
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
610
|
+
it("scales linearly on seeded mixed content", () => {
|
|
611
|
+
assertLinearScaling(transform, (n) => buildMixedContent(n * 100), 50)
|
|
612
|
+
})
|
|
613
|
+
|
|
614
|
+
it("scales linearly with all features enabled", () => {
|
|
615
|
+
const allFeatures = { fractions: true, degrees: true, superscript: true, ligatures: true }
|
|
616
|
+
assertLinearScaling((input) => transform(input, allFeatures), (n) => buildMixedContent(n * 100), 50)
|
|
634
617
|
})
|
|
635
618
|
})
|
|
636
619
|
|
|
637
|
-
describe("
|
|
638
|
-
const
|
|
620
|
+
describe("idempotency across punctuation styles", () => {
|
|
621
|
+
const mixedInput = `"Hello," she said -- "it's pages 1-5." Wait... 5x5 != 25. He's 5'10" tall.`
|
|
622
|
+
|
|
623
|
+
it.each([
|
|
624
|
+
["american"],
|
|
625
|
+
["british"],
|
|
626
|
+
["german"],
|
|
627
|
+
["french"],
|
|
628
|
+
] as const)("idempotent with %s style", (style) => {
|
|
629
|
+
const opts = { punctuationStyle: style, checkIdempotency: false, nbsp: false } as const
|
|
630
|
+
const first = transform(mixedInput, opts)
|
|
631
|
+
const second = transform(first, opts)
|
|
632
|
+
expect(second).toBe(first)
|
|
633
|
+
})
|
|
634
|
+
})
|
|
639
635
|
|
|
636
|
+
describe("edge case inputs", () => {
|
|
637
|
+
it.each([
|
|
638
|
+
["empty string", "", ""],
|
|
639
|
+
["single space", " ", " "],
|
|
640
|
+
["newlines only", "\n\n\n", "\n\n\n"],
|
|
641
|
+
["tab only", "\t", "\t"],
|
|
642
|
+
["nbsp only", NBSP, NBSP],
|
|
643
|
+
])("handles %s", (_desc, input, expected) => {
|
|
644
|
+
expect(transform(input)).toBe(expected)
|
|
645
|
+
})
|
|
646
|
+
})
|
|
647
|
+
|
|
648
|
+
describe("separator collision", () => {
|
|
649
|
+
it("preserves default separator in plain transform", () => {
|
|
650
|
+
// transform() itself uses the separator internally but tolerates it in input
|
|
651
|
+
// The assertSeparatorAbsent check is in the rehype/remark plugins
|
|
652
|
+
const input = `text${DEFAULT_SEPARATOR}more`
|
|
653
|
+
const result = transform(input)
|
|
654
|
+
expect(countSeparators(result, DEFAULT_SEPARATOR)).toBe(1)
|
|
655
|
+
})
|
|
656
|
+
|
|
657
|
+
it("does not throw for single char of multi-char default separator", () => {
|
|
658
|
+
expect(() => transform(`text${DEFAULT_SEPARATOR[0]}more`)).not.toThrow()
|
|
659
|
+
})
|
|
660
|
+
})
|
|
661
|
+
|
|
662
|
+
describe("regex cache thrashing", () => {
|
|
663
|
+
it("produces correct results after exceeding cache capacity", () => {
|
|
664
|
+
const input = `"Hello," she said.`
|
|
665
|
+
const separatorCount = MAX_REGEX_CACHE_SIZE + 200
|
|
666
|
+
for (let i = 0; i < separatorCount; i++) {
|
|
667
|
+
const sep = String.fromCharCode(0xE100 + i)
|
|
668
|
+
const result = transform(input, { separator: sep, nbsp: false })
|
|
669
|
+
expect(result).toContain(LEFT_DOUBLE_QUOTE)
|
|
670
|
+
expect(result).toContain(RIGHT_DOUBLE_QUOTE)
|
|
671
|
+
}
|
|
672
|
+
})
|
|
673
|
+
})
|
|
674
|
+
|
|
675
|
+
describe("ReDoS resistance", () => {
|
|
640
676
|
it.each([
|
|
641
|
-
["
|
|
642
|
-
["
|
|
643
|
-
["
|
|
644
|
-
["
|
|
645
|
-
["alternating digits/hyphens", "1-2-3-4-5-6-7-8-9-0".repeat(
|
|
646
|
-
["
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
677
|
+
["single quotes", (n: number) => "'".repeat(n)],
|
|
678
|
+
["double quotes", (n: number) => '"'.repeat(n)],
|
|
679
|
+
["unbalanced quotes", (n: number) => '"Hello '.repeat(n)],
|
|
680
|
+
["hyphens", (n: number) => "-".repeat(n)],
|
|
681
|
+
["alternating digits/hyphens", (n: number) => "1-2-3-4-5-6-7-8-9-0".repeat(n / 10)],
|
|
682
|
+
["dots", (n: number) => ".".repeat(n)],
|
|
683
|
+
["fraction-like patterns", (n: number) => "1/2 ".repeat(n)],
|
|
684
|
+
["short words (nbsp)", (n: number) => "a b c d e f ".repeat(n)],
|
|
685
|
+
["math symbol patterns", (n: number) => "!= ".repeat(n)],
|
|
686
|
+
] as const)("scales linearly for %s", (_, buildInput) => {
|
|
687
|
+
assertLinearScaling(transform, buildInput)
|
|
688
|
+
})
|
|
689
|
+
|
|
690
|
+
it("scales linearly on seeded mixed content", () => {
|
|
691
|
+
assertLinearScaling(transform, (n) => buildMixedContent(n * 10))
|
|
651
692
|
})
|
|
652
693
|
})
|
|
653
694
|
})
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
import { readFileSync } from "fs"
|
|
2
|
+
import { resolve } from "path"
|
|
3
|
+
import { fileURLToPath } from "url"
|
|
1
4
|
import { transformMarkdown } from "../markdown.js"
|
|
5
|
+
import { transform } from "../index.js"
|
|
2
6
|
import { UNICODE_SYMBOLS } from "../constants.js"
|
|
3
7
|
|
|
8
|
+
const __dirname = fileURLToPath(new URL(".", import.meta.url))
|
|
9
|
+
|
|
4
10
|
const {
|
|
5
11
|
LEFT_DOUBLE_QUOTE: LDQ,
|
|
6
12
|
RIGHT_DOUBLE_QUOTE: RDQ,
|
|
@@ -75,4 +81,22 @@ describe("transformMarkdown", () => {
|
|
|
75
81
|
})
|
|
76
82
|
expect(result.trimEnd()).toEqual("See references \\[1\\]\\[4\\]\\[5\\]\\[6\\] for details.")
|
|
77
83
|
})
|
|
84
|
+
|
|
85
|
+
it("README.md prose is already typographically correct", () => {
|
|
86
|
+
const readme = readFileSync(resolve(__dirname, "../../README.md"), "utf-8")
|
|
87
|
+
const lines = readme.split("\n")
|
|
88
|
+
let inCodeBlock = false
|
|
89
|
+
|
|
90
|
+
for (const line of lines) {
|
|
91
|
+
if (line.startsWith("```")) { inCodeBlock = !inCodeBlock; continue }
|
|
92
|
+
if (inCodeBlock) continue
|
|
93
|
+
// Skip non-prose: tables, badges, HTML, footnotes, headings, list items (including indented)
|
|
94
|
+
if (/^[|#>\d]|^\s*-\s|^\s*\d+\.\s|^\[[\^!]|<span/.test(line)) continue
|
|
95
|
+
if (line.trim() === "") continue
|
|
96
|
+
|
|
97
|
+
// collapseSpaces: false because Markdown uses double-space for formatting
|
|
98
|
+
const transformed = transform(line, { nbsp: false, collapseSpaces: false, checkIdempotency: false })
|
|
99
|
+
expect(transformed).toBe(line)
|
|
100
|
+
}
|
|
101
|
+
})
|
|
78
102
|
})
|
package/src/tests/nbsp.test.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
type NbspOptions,
|
|
15
15
|
} from "../nbsp.js"
|
|
16
16
|
import { UNICODE_SYMBOLS, DEFAULT_SEPARATOR } from "../constants.js"
|
|
17
|
+
import { assertLinearScaling } from "./test-helpers.js"
|
|
17
18
|
|
|
18
19
|
const { NBSP, COPYRIGHT, REGISTERED, TRADEMARK } = UNICODE_SYMBOLS
|
|
19
20
|
const SEP = DEFAULT_SEPARATOR
|
|
@@ -252,4 +253,15 @@ describe("nbspTransform", () => {
|
|
|
252
253
|
expect(nbspTransform("St. Anne had 5 kg")).toBe(`St.${NBSP}Anne had 5${NBSP}kg`)
|
|
253
254
|
})
|
|
254
255
|
})
|
|
256
|
+
|
|
257
|
+
describe("stress tests", () => {
|
|
258
|
+
it("scales linearly for short words", () => {
|
|
259
|
+
assertLinearScaling(nbspTransform, (n) => "a b c d e f ".repeat(n))
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
it("early-exits on text with no spaces", () => {
|
|
263
|
+
const result = nbspTransform("nospaces".repeat(1000))
|
|
264
|
+
expect(result).toBe("nospaces".repeat(1000))
|
|
265
|
+
})
|
|
266
|
+
})
|
|
255
267
|
})
|
package/src/tests/quotes.test.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { niceQuotes, classifyApostrophes } from "../quotes.js"
|
|
2
2
|
import { UNICODE_SYMBOLS, DEFAULT_SEPARATOR, TERMINAL_PUNCTUATION } from "../constants.js"
|
|
3
|
+
import { assertLinearScaling } from "./test-helpers.js"
|
|
3
4
|
|
|
4
5
|
const {
|
|
5
6
|
LEFT_DOUBLE_QUOTE,
|
|
@@ -170,13 +171,13 @@ describe("niceQuotes", () => {
|
|
|
170
171
|
expect(classifyApostrophes(result)).toBe(result)
|
|
171
172
|
})
|
|
172
173
|
|
|
173
|
-
it("stress: 200 consecutive plural possessives", () => {
|
|
174
|
+
it("stress: 200 consecutive plural possessives scales linearly", () => {
|
|
174
175
|
const words = ["dogs'", "cats'", "Bayes'", "Thomas'", "PLAYERS'"]
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
expect(performance.now() - start).toBeLessThan(1000)
|
|
176
|
+
const buildInput = (n: number) => Array.from({ length: n }, (_, i) => words[i % words.length]).join(" ")
|
|
177
|
+
|
|
178
|
+
assertLinearScaling(classifyApostrophes, buildInput)
|
|
179
179
|
// All should be MLA (no LSQ to pair with)
|
|
180
|
+
const result = classifyApostrophes(buildInput(200))
|
|
180
181
|
expect(result).not.toContain(RIGHT_SINGLE_QUOTE)
|
|
181
182
|
expect(result).not.toContain("'")
|
|
182
183
|
expect(classifyApostrophes(result)).toBe(result)
|
|
@@ -701,20 +702,16 @@ describe("niceQuotes", () => {
|
|
|
701
702
|
})
|
|
702
703
|
|
|
703
704
|
describe("pathological inputs", () => {
|
|
704
|
-
it("
|
|
705
|
+
it("scales linearly for input without closing quote", () => {
|
|
706
|
+
assertLinearScaling(classifyApostrophes, (n) => `'${"a".repeat(n)}`)
|
|
705
707
|
const input = `'${"a".repeat(1500)}`
|
|
706
|
-
|
|
707
|
-
const result = classifyApostrophes(input)
|
|
708
|
-
expect(performance.now() - start).toBeLessThan(1000)
|
|
709
|
-
expect(classifyApostrophes(result)).toBe(result)
|
|
708
|
+
expect(classifyApostrophes(classifyApostrophes(input))).toBe(classifyApostrophes(input))
|
|
710
709
|
})
|
|
711
710
|
|
|
712
711
|
it("handles 16 rapid apostrophes", () => {
|
|
713
712
|
const input = "a'b'c'd'e'f'g'h'i'j'k'l'm'n'o'p"
|
|
714
713
|
const expected = `a${MODIFIER_LETTER_APOSTROPHE}b${MODIFIER_LETTER_APOSTROPHE}c${MODIFIER_LETTER_APOSTROPHE}d${MODIFIER_LETTER_APOSTROPHE}e${MODIFIER_LETTER_APOSTROPHE}f${MODIFIER_LETTER_APOSTROPHE}g${MODIFIER_LETTER_APOSTROPHE}h${MODIFIER_LETTER_APOSTROPHE}i${MODIFIER_LETTER_APOSTROPHE}j${MODIFIER_LETTER_APOSTROPHE}k${MODIFIER_LETTER_APOSTROPHE}l${MODIFIER_LETTER_APOSTROPHE}m${MODIFIER_LETTER_APOSTROPHE}n${MODIFIER_LETTER_APOSTROPHE}o${MODIFIER_LETTER_APOSTROPHE}p`
|
|
715
|
-
const start = performance.now()
|
|
716
714
|
const result = classifyApostrophes(input)
|
|
717
|
-
expect(performance.now() - start).toBeLessThan(1000)
|
|
718
715
|
expect(result).toBe(expected)
|
|
719
716
|
expect(classifyApostrophes(result)).toBe(result)
|
|
720
717
|
})
|
|
@@ -725,4 +722,19 @@ describe("niceQuotes", () => {
|
|
|
725
722
|
})
|
|
726
723
|
})
|
|
727
724
|
|
|
725
|
+
describe("mixed-locale stress", () => {
|
|
726
|
+
it.each([
|
|
727
|
+
["german", `Er sagte, "es ist gro\u00DFartig" und sie sagte, "h\u00F6r nicht auf"`, DOUBLE_LOW_9_QUOTE],
|
|
728
|
+
["french", `"C'est magnifique," dit-elle. "N'arr\u00EAte pas."`, LEFT_GUILLEMET],
|
|
729
|
+
["american", `He said, "She said, 'They said, "No."'"`, LEFT_DOUBLE_QUOTE],
|
|
730
|
+
["british", `He said, "She said, 'They said, "No."'"`, LEFT_DOUBLE_QUOTE],
|
|
731
|
+
["german", `Er fragte, "Hat sie 'Nein' gesagt?"`, DOUBLE_LOW_9_QUOTE],
|
|
732
|
+
["french", `"Qui a dit 'bonjour'?" demanda-t-il.`, LEFT_GUILLEMET],
|
|
733
|
+
] as const)("%s style produces locale-appropriate quotes and is idempotent", (style, input, expectedChar) => {
|
|
734
|
+
const opts = { punctuationStyle: style }
|
|
735
|
+
const first = niceQuotes(input, opts)
|
|
736
|
+
expect(first).toContain(expectedChar)
|
|
737
|
+
expect(niceQuotes(first, opts)).toBe(first)
|
|
738
|
+
})
|
|
739
|
+
})
|
|
728
740
|
})
|
package/src/tests/rehype.test.ts
CHANGED
|
@@ -461,4 +461,49 @@ describe("rehypePunctilio", () => {
|
|
|
461
461
|
)
|
|
462
462
|
})
|
|
463
463
|
})
|
|
464
|
+
|
|
465
|
+
describe("stress tests", () => {
|
|
466
|
+
it("handles many sibling paragraphs", async () => {
|
|
467
|
+
// 100 siblings: enough to exercise the visitor/transformed-set logic
|
|
468
|
+
// without spending seconds on HTML parsing
|
|
469
|
+
const count = 100
|
|
470
|
+
const html = '<div>' + '<p>"Hello," she said.</p>'.repeat(count) + '</div>'
|
|
471
|
+
const result = await processHtml(html, { nbsp: false })
|
|
472
|
+
const matchCount = (result.match(new RegExp(LDQ, "g")) ?? []).length
|
|
473
|
+
expect(matchCount).toBe(count)
|
|
474
|
+
})
|
|
475
|
+
|
|
476
|
+
it("handles paragraph with many inline elements", async () => {
|
|
477
|
+
const count = 100
|
|
478
|
+
const inlineElements = Array.from({ length: count }, (_, i) =>
|
|
479
|
+
`<em>"word${i}"</em>`
|
|
480
|
+
).join(" ")
|
|
481
|
+
const html = `<p>${inlineElements}</p>`
|
|
482
|
+
const result = await processHtml(html, { nbsp: false })
|
|
483
|
+
const matchCount = (result.match(new RegExp(LDQ, "g")) ?? []).length
|
|
484
|
+
expect(matchCount).toBe(count)
|
|
485
|
+
})
|
|
486
|
+
|
|
487
|
+
it("transforms text at 100-level deep nesting", async () => {
|
|
488
|
+
let html = '"Hello"'
|
|
489
|
+
for (let i = 0; i < 100; i++) {
|
|
490
|
+
html = `<span>${html}</span>`
|
|
491
|
+
}
|
|
492
|
+
html = `<p>${html}</p>`
|
|
493
|
+
const result = await processHtml(html, { nbsp: false })
|
|
494
|
+
expect(result).toContain(LDQ)
|
|
495
|
+
expect(result).toContain(RDQ)
|
|
496
|
+
})
|
|
497
|
+
|
|
498
|
+
it("does not crash beyond MAX_RECURSION_DEPTH", async () => {
|
|
499
|
+
let html = '"Hello"'
|
|
500
|
+
for (let i = 0; i < 1050; i++) {
|
|
501
|
+
html = `<span>${html}</span>`
|
|
502
|
+
}
|
|
503
|
+
html = `<p>${html}</p>`
|
|
504
|
+
// Should not throw — deep nesting is silently skipped
|
|
505
|
+
const result = await processHtml(html, { nbsp: false })
|
|
506
|
+
expect(result).toContain("Hello")
|
|
507
|
+
})
|
|
508
|
+
})
|
|
464
509
|
})
|
package/src/tests/remark.test.ts
CHANGED
|
@@ -170,4 +170,31 @@ describe("remarkPunctilio", () => {
|
|
|
170
170
|
const first = await processMarkdown('"Hello," she said -- "it\'s pages 1-5."', { nbsp: false })
|
|
171
171
|
expect(await processMarkdown(first, { nbsp: false })).toEqual(first)
|
|
172
172
|
})
|
|
173
|
+
|
|
174
|
+
describe("stress tests", () => {
|
|
175
|
+
it("handles many paragraphs", async () => {
|
|
176
|
+
const count = 100
|
|
177
|
+
const paragraphs = Array.from({ length: count }, () => '"Hello," she said.').join("\n\n")
|
|
178
|
+
const result = await processMarkdown(paragraphs, { nbsp: false })
|
|
179
|
+
const matchCount = (result.match(new RegExp(LDQ, "g")) ?? []).length
|
|
180
|
+
expect(matchCount).toBe(count)
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
it("handles paragraph with many inline elements", async () => {
|
|
184
|
+
const count = 50
|
|
185
|
+
const inlines = Array.from({ length: count }, (_, i) => `*"word${i}"*`).join(" ")
|
|
186
|
+
const result = await processMarkdown(inlines, { nbsp: false })
|
|
187
|
+
const matchCount = (result.match(new RegExp(LDQ, "g")) ?? []).length
|
|
188
|
+
expect(matchCount).toBe(count)
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
it("handles quotes spanning nested inline elements", async () => {
|
|
192
|
+
// Exercises text node flattening across multiple nesting levels:
|
|
193
|
+
// emphasis inside strong inside link text
|
|
194
|
+
const md = `[**"Hello,** *world"*](url)`
|
|
195
|
+
const result = await processMarkdown(md, { nbsp: false })
|
|
196
|
+
expect(result).toContain(LDQ)
|
|
197
|
+
expect(result).toContain(RDQ)
|
|
198
|
+
})
|
|
199
|
+
})
|
|
173
200
|
})
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
symbolTransform,
|
|
14
14
|
} from "../symbols.js"
|
|
15
15
|
import { UNICODE_SYMBOLS, DEFAULT_SEPARATOR } from "../constants.js"
|
|
16
|
+
import { assertLinearScaling } from "./test-helpers.js"
|
|
16
17
|
|
|
17
18
|
describe("ellipsis", () => {
|
|
18
19
|
it.each([
|
|
@@ -683,11 +684,9 @@ describe("symbolTransform", () => {
|
|
|
683
684
|
})
|
|
684
685
|
|
|
685
686
|
describe("multiplication ReDoS regression", () => {
|
|
686
|
-
it("
|
|
687
|
-
|
|
688
|
-
multiplication("1".repeat(
|
|
689
|
-
// Before fix: ~4400ms (O(n²)). After fix: <50ms (O(n)).
|
|
690
|
-
expect(performance.now() - start).toBeLessThan(500)
|
|
687
|
+
it("scales linearly for long digit strings", () => {
|
|
688
|
+
// Before fix: quadratic (~100x for 10x input). After fix: linear.
|
|
689
|
+
assertLinearScaling(multiplication, (n) => "1".repeat(n), 5_000)
|
|
691
690
|
})
|
|
692
691
|
})
|
|
693
692
|
|
|
@@ -784,6 +783,8 @@ describe("fractions edge cases", () => {
|
|
|
784
783
|
["(1/2)", `(${UNICODE_SYMBOLS.FRACTION_1_2})`],
|
|
785
784
|
["5/7", "5/7"],
|
|
786
785
|
["11/12", "11/12"],
|
|
786
|
+
["2/2", "2/2"],
|
|
787
|
+
["4/3", "4/3"],
|
|
787
788
|
])('handles fraction edge: "%s"', (input, expected) => {
|
|
788
789
|
expect(fractions(input)).toBe(expected)
|
|
789
790
|
})
|
|
@@ -802,3 +803,13 @@ describe("chained multiplications", () => {
|
|
|
802
803
|
})
|
|
803
804
|
})
|
|
804
805
|
|
|
806
|
+
describe("symbol stress tests", () => {
|
|
807
|
+
it("scales linearly for ellipsis patterns", () => {
|
|
808
|
+
assertLinearScaling(ellipsis, (n) => "wait... ".repeat(n))
|
|
809
|
+
})
|
|
810
|
+
|
|
811
|
+
it("scales linearly for fraction patterns", () => {
|
|
812
|
+
assertLinearScaling(fractions, (n) => "add 1/2 cup ".repeat(n))
|
|
813
|
+
})
|
|
814
|
+
})
|
|
815
|
+
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared test utilities for punctilio test suites.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import seedrandom from "seedrandom"
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Fragments covering every transform type: quotes, dashes, apostrophes,
|
|
9
|
+
* ellipses, multiplication, math symbols, legal symbols, arrows, primes,
|
|
10
|
+
* fractions, degrees, ordinals, nbsp-triggering short words, and plain text.
|
|
11
|
+
*/
|
|
12
|
+
const FRAGMENTS = [
|
|
13
|
+
`"Hello," she said. `,
|
|
14
|
+
`It's a beautiful day -- isn't it? `,
|
|
15
|
+
`Wait... `,
|
|
16
|
+
`The temperature was 20 C. `,
|
|
17
|
+
`5x5 != 25. `,
|
|
18
|
+
`Add 1/2 cup. `,
|
|
19
|
+
`He's 5'10" tall. `,
|
|
20
|
+
`(c) 2024 Acme Corp. `,
|
|
21
|
+
`See p. 42 for details. `,
|
|
22
|
+
`Dr. Smith arrived. `,
|
|
23
|
+
`The 1st place winner. `,
|
|
24
|
+
`Go -> click -> done. `,
|
|
25
|
+
`Really?! No way!! `,
|
|
26
|
+
`A B C D E F G H. `,
|
|
27
|
+
`Pages 10-20 contain important info. `,
|
|
28
|
+
`January-March was cold. `,
|
|
29
|
+
`The value is -5. `,
|
|
30
|
+
`"Don't stop," he said, "keep going." `,
|
|
31
|
+
`J. K. Rowling wrote it. `,
|
|
32
|
+
`100 km in 2 hrs. `,
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Builds a deterministic pseudo-random string of approximately `charCount`
|
|
37
|
+
* characters by randomly sampling from FRAGMENTS using a seeded PRNG.
|
|
38
|
+
*
|
|
39
|
+
* @param charCount - Approximate desired character count
|
|
40
|
+
* @param seed - PRNG seed (default: "42")
|
|
41
|
+
*/
|
|
42
|
+
export function buildMixedContent(charCount: number, seed: string = "42"): string {
|
|
43
|
+
const random = seedrandom(seed)
|
|
44
|
+
let result = ""
|
|
45
|
+
while (result.length < charCount) {
|
|
46
|
+
const index = Math.floor(random() * FRAGMENTS.length)
|
|
47
|
+
result += FRAGMENTS[index]
|
|
48
|
+
}
|
|
49
|
+
return result
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Asserts that a function scales linearly (not quadratically) with input size.
|
|
54
|
+
*
|
|
55
|
+
* Measures ms/char at 4 input sizes (1x, 2x, 4x, 8x) after a JIT warmup pass.
|
|
56
|
+
* Compares the two largest sizes (4x vs 8x) which have the best signal-to-noise
|
|
57
|
+
* ratio. For a linear algorithm, doubling input keeps ms/char constant (ratio ~1).
|
|
58
|
+
* For a quadratic one, doubling input doubles ms/char (ratio ~2).
|
|
59
|
+
*
|
|
60
|
+
* Default startingN of 5000 produces inputs from ~5K to ~40K chars, which is
|
|
61
|
+
* past V8's string allocation overhead inflection point where ms/char stabilizes.
|
|
62
|
+
*
|
|
63
|
+
* Uses min 3 iterations and min 20ms per size to get stable averages.
|
|
64
|
+
*
|
|
65
|
+
* @param fn - The function to benchmark
|
|
66
|
+
* @param buildInput - Builds an input string of approximately `n` units
|
|
67
|
+
* @param startingN - Size parameter for the smallest input (default: 5000)
|
|
68
|
+
*/
|
|
69
|
+
export function assertLinearScaling(
|
|
70
|
+
fn: (input: string) => unknown,
|
|
71
|
+
buildInput: (n: number) => string,
|
|
72
|
+
startingN: number = 5000
|
|
73
|
+
): void {
|
|
74
|
+
const multipliers = [1, 2, 4, 8]
|
|
75
|
+
|
|
76
|
+
// Warmup with the largest input so JIT compiles all code paths before timing.
|
|
77
|
+
fn(buildInput(startingN * multipliers[multipliers.length - 1]))
|
|
78
|
+
|
|
79
|
+
function measureMsPerChar(mult: number): number {
|
|
80
|
+
const input = buildInput(startingN * mult)
|
|
81
|
+
const minIterations = 3
|
|
82
|
+
const minElapsedMs = 20
|
|
83
|
+
let totalElapsed = 0
|
|
84
|
+
let iterations = 0
|
|
85
|
+
while (iterations < minIterations || totalElapsed < minElapsedMs) {
|
|
86
|
+
const start = performance.now()
|
|
87
|
+
fn(input)
|
|
88
|
+
totalElapsed += performance.now() - start
|
|
89
|
+
iterations++
|
|
90
|
+
}
|
|
91
|
+
return totalElapsed / iterations / input.length
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Measure all sizes (exercises the function at various scales)
|
|
95
|
+
const msPerChar = multipliers.map(measureMsPerChar)
|
|
96
|
+
|
|
97
|
+
// Compare the two largest inputs (best SNR, per-call overhead is negligible).
|
|
98
|
+
// For linear: rate_8x / rate_4x ≈ 1. For quadratic: ≈ 2.
|
|
99
|
+
const rate4x = msPerChar[2]
|
|
100
|
+
const rate8x = msPerChar[3]
|
|
101
|
+
expect(rate8x / rate4x).toBeLessThan(1.5)
|
|
102
|
+
}
|