punctilio 1.3.1 → 1.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 +32 -25
- package/dist/constants.d.ts +5 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +5 -0
- package/dist/constants.js.map +1 -1
- package/dist/dashes.d.ts.map +1 -1
- package/dist/dashes.js +26 -8
- package/dist/dashes.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -3
- package/dist/index.js.map +1 -1
- package/dist/quotes.d.ts.map +1 -1
- package/dist/quotes.js +17 -12
- package/dist/quotes.js.map +1 -1
- package/dist/rehype.d.ts +161 -0
- package/dist/rehype.d.ts.map +1 -0
- package/dist/rehype.js +401 -0
- package/dist/rehype.js.map +1 -0
- package/dist/symbols.d.ts.map +1 -1
- package/dist/symbols.js +2 -1
- package/dist/symbols.js.map +1 -1
- package/dist/utils.d.ts +5 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +19 -0
- package/dist/utils.js.map +1 -1
- package/package.json +28 -4
- package/src/constants.ts +161 -0
- package/src/dashes.ts +211 -0
- package/src/index.ts +243 -0
- package/src/quotes.ts +132 -0
- package/src/rehype.ts +503 -0
- package/src/symbols.ts +324 -0
- package/src/tests/dashes.test.ts +649 -0
- package/src/tests/index.test.ts +528 -0
- package/src/tests/quotes.test.ts +344 -0
- package/src/tests/rehype.test.ts +418 -0
- package/src/tests/symbols.test.ts +708 -0
- package/src/tests/utils.test.ts +98 -0
- package/src/utils.ts +65 -0
- package/tsconfig.json +20 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
> *punctilio* (n.): precise observance of formalities.
|
|
2
2
|
|
|
3
|
-
The
|
|
3
|
+
Pretty good at making your text pretty. The most feature-complete and reliable English typography package.
|
|
4
4
|
|
|
5
5
|
```typescript
|
|
6
6
|
import { transform } from 'punctilio'
|
|
@@ -32,7 +32,7 @@ I tested `punctilio` 1.2.9 against [`smartypants`](https://www.npmjs.com/package
|
|
|
32
32
|
| She said—"Hi!" | She said—”Hi!” (✗) | She said—“Hi!” (✓) |
|
|
33
33
|
| 5x5 | 5x5 (✗) | 5×5 (✓) |
|
|
34
34
|
|
|
35
|
-
My [`benchmark.mjs`](
|
|
35
|
+
My [`benchmark.mjs`](https://github.com/alexander-turner/punctilio/blob/main/benchmark.mjs) measures how well libraries handle a [wide range of scenarios](https://github.com/alexander-turner/punctilio/blob/main/benchmark_cases.json). The benchmark normalizes stylistic differences (e.g. non-breaking vs regular space, British vs American dash spacing) for fair comparison.
|
|
36
36
|
|
|
37
37
|
| Package | Passed (of 154) |
|
|
38
38
|
|--------:|:----------------|
|
|
@@ -45,26 +45,24 @@ My [`benchmark.mjs`](./benchmark.mjs) measures how well libraries handle a [wide
|
|
|
45
45
|
|
|
46
46
|
| Feature | Example | `punctilio` | `smartypants` | `tipograph` | `smartquotes` | `typograf` |
|
|
47
47
|
|--------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|
|
|
48
|
-
| Smart quotes | "hello" → “hello
|
|
49
|
-
| Leading apostrophe | 'Twas → ’Twas | ✓ | ✗ | ✗ | ~ | ✗ |
|
|
50
|
-
| Em dash |
|
|
51
|
-
| En dash (ranges) | 1-5 → 1–5 | ✓ | ✗ | ✓ | ✗ | ✗ |
|
|
52
|
-
| Minus sign | -5 → −5 | ✓ | ✗ | ✓ | ✗ | ✗ |
|
|
53
|
-
| Ellipsis |
|
|
54
|
-
| Multiplication | 5x5 → 5×5 | ✓ | ✗ | ✗ | ✗ | ~ |
|
|
55
|
-
| Math symbols |
|
|
56
|
-
| Legal symbols | (c) →
|
|
57
|
-
| Arrows |
|
|
58
|
-
| Prime marks | 5'10" → 5′10
|
|
59
|
-
| Degrees | 20 C → 20 °C | ✓ | ✗ | ✗ | ✗ | ✓ |
|
|
60
|
-
| Fractions | 1/2 →
|
|
61
|
-
| Superscripts | 2nd → 2
|
|
62
|
-
|
|
|
63
|
-
| Ligatures |
|
|
64
|
-
| Non-English quotes |
|
|
65
|
-
| Non-breaking spaces | Chapter 1 | ✗ | ✗ | ✗ | ✗ | ✓ |
|
|
66
|
-
|
|
67
|
-
_~ = partial success (handles main example but misses edge cases)_
|
|
48
|
+
| Smart quotes | <span class="no-formatting">"hello" → “hello”</span> | ✓ | ✓ | ✓ | ✓ | ✓ |
|
|
49
|
+
| Leading apostrophe | <span class="no-formatting">'Twas → ’Twas</span> | ✓ | ✗ | ✗ | ~ | ✗ |
|
|
50
|
+
| Em dash | <span class="no-formatting">-- → —</span> | ✓ | ✓ | ✗ | ✗ | ✓ |
|
|
51
|
+
| En dash (ranges) | <span class="no-formatting">1-5 → 1–5</span> | ✓ | ✗ | ✓ | ✗ | ✗ |
|
|
52
|
+
| Minus sign | <span class="no-formatting">-5 → −5</span> | ✓ | ✗ | ✓ | ✗ | ✗ |
|
|
53
|
+
| Ellipsis | <span class="no-formatting">... → …</span> | ✓ | ✓ | ✓ | ✗ | ✓ |
|
|
54
|
+
| Multiplication | <span class="no-formatting">5x5 → 5×5</span> | ✓ | ✗ | ✗ | ✗ | ~ |
|
|
55
|
+
| Math symbols | <span class="no-formatting">!= → ≠</span> | ✓ | ✗ | ~ | ✗ | ~ |
|
|
56
|
+
| Legal symbols | <span class="no-formatting">(c) → ©</span> | ✓ | ✗ | ~ | ✗ | ✓ |
|
|
57
|
+
| Arrows | <span class="no-formatting">-> → →</span> | ✓ | ✗ | ~ | ✗ | ~ |
|
|
58
|
+
| Prime marks | <span class="no-formatting">5'10" → 5′10″</span> | ✓ | ✗ | ✓ | ✓ | ✗ |
|
|
59
|
+
| Degrees | <span class="no-formatting">20 C → 20 °C</span> | ✓ | ✗ | ✗ | ✗ | ✓ |
|
|
60
|
+
| Fractions | <span class="no-formatting">1/2 → ½</span> | ✓ | ✗ | ✗ | ✗ | ✓ |
|
|
61
|
+
| Superscripts | <span class="no-formatting">2nd → 2ⁿᵈ</span> | ✓ | ✗ | ✗ | ✗ | ✗ |
|
|
62
|
+
| English localization | <span class="no-formatting">American / British</span> | ✓ | ✗ | ✗ | ✗ | ✗ |
|
|
63
|
+
| Ligatures | <span class="no-formatting">?? → ⁇</span> | ✓ | ✗ | ✓ | ✗ | ✗ |
|
|
64
|
+
| Non-English quotes | <span class="no-formatting">„Hallo”</span> | ✗ | ✗ | ✓ | ✗ | ~ |
|
|
65
|
+
| Non-breaking spaces | <span class="no-formatting">Chapter 1</span> | ✗ | ✗ | ✗ | ✗ | ✓ |
|
|
68
66
|
|
|
69
67
|
`typograf` uniquely inserts non-breaking spaces to prevent bad line breaks (e.g. before numbers, after colons). I might add this to `punctilio` in the future. `punctilio`’s other missing feature is non-English quote support—feel free to make a pull request!
|
|
70
68
|
|
|
@@ -100,11 +98,20 @@ transform(`"Wait${DEFAULT_SEPARATOR}"`)
|
|
|
100
98
|
// The separator doesn’t block the information that this should be an end-quote!
|
|
101
99
|
```
|
|
102
100
|
|
|
103
|
-
|
|
101
|
+
For `rehype` / `unified` pipelines, use the built-in plugin which handles the separator logic automatically:
|
|
104
102
|
|
|
105
|
-
|
|
103
|
+
```typescript
|
|
104
|
+
import rehypePunctilio from 'punctilio/rehype'
|
|
105
|
+
|
|
106
|
+
unified()
|
|
107
|
+
.use(rehypeParse)
|
|
108
|
+
.use(rehypePunctilio, { dashStyle: 'american' })
|
|
109
|
+
.use(rehypeStringify)
|
|
110
|
+
.process('<p>"Hello..." -- world</p>')
|
|
111
|
+
// → <p>"Hello…"—world</p>
|
|
112
|
+
```
|
|
106
113
|
|
|
107
|
-
`punctilio` transforms plain text or
|
|
114
|
+
For manual DOM walking or custom transforms, use `transformElement` from `punctilio/rehype`. Note: `punctilio` transforms plain text or HTML—not raw Markdown.
|
|
108
115
|
|
|
109
116
|
## Options
|
|
110
117
|
|
package/dist/constants.d.ts
CHANGED
|
@@ -78,6 +78,11 @@ export declare const LATIN_LETTERS = "A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F
|
|
|
78
78
|
*/
|
|
79
79
|
export declare const DEFAULT_SEPARATOR = "\uE000";
|
|
80
80
|
export declare const ESCAPED_DEFAULT_SEPARATOR: string;
|
|
81
|
+
/**
|
|
82
|
+
* Characters that have special meaning in regular expressions.
|
|
83
|
+
* Used for testing that separator escaping works correctly.
|
|
84
|
+
*/
|
|
85
|
+
export declare const REGEX_SPECIAL_CHARS: readonly [".", "*", "+", "?", "^", "$", "[", "]", "\\", "|", "(", ")"];
|
|
81
86
|
/**
|
|
82
87
|
* Creates a marker-aware word boundary pattern for the START of a match.
|
|
83
88
|
*
|
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkDlB,CAAA;AAEV;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,sFAAsF,CAAA;AAEhH;;;GAGG;AACH,eAAO,MAAM,iBAAiB,WAAW,CAAA;AACzC,eAAO,MAAM,yBAAyB,QAAwC,CAAA;AAE9E;;;;;;;;;;;;;;;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;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED;;;;;;GAMG;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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkDlB,CAAA;AAEV;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,sFAAsF,CAAA;AAEhH;;;GAGG;AACH,eAAO,MAAM,iBAAiB,WAAW,CAAA;AACzC,eAAO,MAAM,yBAAyB,QAAwC,CAAA;AAE9E;;;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;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAEjE"}
|
package/dist/constants.js
CHANGED
|
@@ -81,6 +81,11 @@ export const LATIN_LETTERS = "A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u00F
|
|
|
81
81
|
*/
|
|
82
82
|
export const DEFAULT_SEPARATOR = "\uE000";
|
|
83
83
|
export const ESCAPED_DEFAULT_SEPARATOR = escapeStringRegexp(DEFAULT_SEPARATOR);
|
|
84
|
+
/**
|
|
85
|
+
* Characters that have special meaning in regular expressions.
|
|
86
|
+
* Used for testing that separator escaping works correctly.
|
|
87
|
+
*/
|
|
88
|
+
export const REGEX_SPECIAL_CHARS = [".", "*", "+", "?", "^", "$", "[", "]", "\\", "|", "(", ")"];
|
|
84
89
|
/**
|
|
85
90
|
* Creates a marker-aware word boundary pattern for the START of a match.
|
|
86
91
|
*
|
package/dist/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,kBAAkB,MAAM,sBAAsB,CAAA;AAErD;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,QAAQ,EAAE,QAAQ;IAClB,cAAc,EAAE,QAAQ;IACxB,SAAS,EAAE,QAAQ;IACnB,UAAU,EAAE,QAAQ;IACpB,SAAS,EAAE,QAAQ;IACnB,UAAU,EAAE,QAAQ;IACpB,SAAS,EAAE,QAAQ;IACnB,MAAM,EAAE,QAAQ;IAChB,WAAW,EAAE,QAAQ;IACrB,UAAU,EAAE,QAAQ;IACpB,gBAAgB,EAAE,QAAQ;IAC1B,WAAW,EAAE,QAAQ;IACrB,UAAU,EAAE,QAAQ;IACpB,aAAa,EAAE,QAAQ;IACvB,KAAK,EAAE,QAAQ;IACf,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,OAAO,EAAE,QAAQ;IACjB,OAAO,EAAE,QAAQ;IACjB,KAAK,EAAE,QAAQ;IACf,iBAAiB,EAAE,QAAQ;IAC3B,kBAAkB,EAAE,QAAQ;IAC5B,iBAAiB,EAAE,QAAQ;IAC3B,kBAAkB,EAAE,QAAQ;IAC5B,IAAI,EAAE,QAAQ;IACd,+BAA+B;IAC/B,cAAc,EAAE,cAAc,EAAE,KAAK;IACrC,cAAc,EAAE,cAAc,EAAE,KAAK;IACrC,cAAc,EAAE,cAAc,EAAE,KAAK;IACrC,cAAc,EAAE,cAAc,EAAE,KAAK;IACrC,wBAAwB;IACxB,eAAe,EAAE,QAAQ,EAAE,IAAI;IAC/B,oBAAoB,EAAE,QAAQ,EAAE,IAAI;IACpC,oBAAoB,EAAE,QAAQ,EAAE,IAAI;IACpC,kBAAkB,EAAE,QAAQ,EAAE,IAAI;CAC1B,CAAA;AAEV;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,mFAAmF,CAAA;AAEhH;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAA;AACzC,MAAM,CAAC,MAAM,yBAAyB,GAAG,kBAAkB,CAAC,iBAAiB,CAAC,CAAA;AAE9E;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,iBAAiB,CAAC,gBAAwB;IACxD,OAAO,UAAU,gBAAgB,OAAO,CAAA;AAC1C,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe,CAAC,gBAAwB;IACtD,OAAO,SAAS,gBAAgB,OAAO,CAAA;AACzC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,eAAe,CAAC,IAAI,EAAE,CAAA;AAErD;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,gBAAwB;IACzD,OAAO,WAAW,gBAAgB,MAAM,CAAA;AAC1C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,gBAAwB;IACvD,OAAO,UAAU,gBAAgB,MAAM,CAAA;AACzC,CAAC"}
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
|
package/dist/dashes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashes.d.ts","sourceRoot":"","sources":["../src/dashes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,CAAA;AAEvD,MAAM,WAAW,WAAW;IAC1B,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mFAAmF;IACnF,SAAS,CAAC,EAAE,SAAS,CAAA;CACtB;AAID;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,+BAA0C,CAAA;AAEpF,eAAO,MAAM,MAAM,QAKR,CAAA;AAEX,8DAA8D;AAC9D,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAuDjF;AAED,iFAAiF;AACjF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAc/E;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"dashes.d.ts","sourceRoot":"","sources":["../src/dashes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,CAAA;AAEvD,MAAM,WAAW,WAAW;IAC1B,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mFAAmF;IACnF,SAAS,CAAC,EAAE,SAAS,CAAA;CACtB;AAID;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,+BAA0C,CAAA;AAEpF,eAAO,MAAM,MAAM,QAKR,CAAA;AAEX,8DAA8D;AAC9D,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAuDjF;AAED,iFAAiF;AACjF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAc/E;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CA0B5E;AAkED,gCAAgC;AAChC,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAS7E"}
|
package/dist/dashes.js
CHANGED
|
@@ -76,9 +76,18 @@ export function enDashDateRange(text, options = {}) {
|
|
|
76
76
|
}
|
|
77
77
|
/** Convert hyphens to minus signs in numeric contexts (e.g., "-5" → "−5"). */
|
|
78
78
|
export function minusReplace(text, options = {}) {
|
|
79
|
-
const chr = options.separator ?? DEFAULT_SEPARATOR;
|
|
79
|
+
const chr = escapeStringRegexp(options.separator ?? DEFAULT_SEPARATOR);
|
|
80
|
+
// Pattern 1a: Subtraction of negative number (e.g., "5 - -3" → "5 − −3")
|
|
81
|
+
// Must come before Pattern 1b so the negative hyphen is consumed first
|
|
82
|
+
text = text.replaceAll(new RegExp(`(?<=\\d${chr}?) - -(?<num>${chr}?\\d*\\.?\\d+)`, "g"), ` ${MINUS} ${MINUS}$<num>`);
|
|
83
|
+
// Pattern 1b: Spaced math subtraction (e.g., "5 - 3" → "5 − 3")
|
|
84
|
+
// Only when preceded by a digit - this distinguishes "5 - 3" from "Safari) - 9"
|
|
85
|
+
text = text.replaceAll(new RegExp(`(?<=\\d${chr}?) - (?<num>${chr}?\\d*\\.?\\d+)`, "g"), ` ${MINUS} $<num>`);
|
|
86
|
+
// Pattern 2: Direct negative numbers (e.g., "-5" → "−5", "(-3)" → "(−3)")
|
|
80
87
|
// Match after: start of line, whitespace, (, separator, or quotes (straight or curly)
|
|
81
|
-
|
|
88
|
+
// No space allowed between hyphen and digit
|
|
89
|
+
text = text.replaceAll(new RegExp(`(?<before>^|[\\s\\("${chr}${LEFT_DOUBLE_QUOTE}${RIGHT_DOUBLE_QUOTE}])-(?<num>\\d*\\.?\\d+)`, "gm"), `$<before>${MINUS}$<num>`);
|
|
90
|
+
return text;
|
|
82
91
|
}
|
|
83
92
|
/**
|
|
84
93
|
* Convert surrounded dashes to em/en dashes.
|
|
@@ -89,16 +98,24 @@ function convertParentheticalDashes(text, sep, style) {
|
|
|
89
98
|
return text;
|
|
90
99
|
const localizedDash = style === "british" ? EN_DASH : EM_DASH;
|
|
91
100
|
const maybeSpace = style === "british" ? " " : "";
|
|
101
|
+
const escapedSep = escapeStringRegexp(sep);
|
|
92
102
|
// Convert spaced dashes: "word - word" or "word — word"
|
|
93
|
-
|
|
103
|
+
// When a separator follows the dash, preserve trailing spaces (they belong to the next text segment).
|
|
104
|
+
const spacedDashPattern = new RegExp(`(?<=[^\\s]|^)(?<sepBefore>${escapedSep}?)[ ]+[~${EN_DASH}${EM_DASH}-]+(?!-*>)[ ]*(?<sepAfter>${escapedSep}?)(?<trailing>[ ]*)(?=\\S|$)`, "g");
|
|
105
|
+
text = text.replace(spacedDashPattern, (_match, sepBefore, sepAfter, trailing) => {
|
|
106
|
+
// For British style (spaced en-dash), preserve trailing spaces after separator
|
|
107
|
+
// For American style (unspaced em-dash), consume trailing spaces (em-dash replaces surrounding space)
|
|
108
|
+
const keepTrailing = maybeSpace && sepAfter ? trailing : "";
|
|
109
|
+
return `${sepBefore}${maybeSpace}${localizedDash}${maybeSpace}${sepAfter}${keepTrailing}`;
|
|
110
|
+
});
|
|
94
111
|
// Convert multiple dashes: "word--word" or "word---word" or "quote"--"quote"
|
|
95
112
|
const quoteChars = `"'${LEFT_DOUBLE_QUOTE}${RIGHT_DOUBLE_QUOTE}${LEFT_SINGLE_QUOTE}${RIGHT_SINGLE_QUOTE}`;
|
|
96
|
-
text = text.replace(new RegExp(`(?<=[${LATIN_LETTERS}\\d${quoteChars}])(?<sepBefore>${
|
|
113
|
+
text = text.replace(new RegExp(`(?<=[${LATIN_LETTERS}\\d${quoteChars}])(?<sepBefore>${escapedSep}?)[~${EN_DASH}${EM_DASH}-]{2,}(?<sepAfter>${escapedSep}?)(?=[${LATIN_LETTERS}${quoteChars} ])`, "g"), `$<sepBefore>${maybeSpace}${localizedDash}${maybeSpace}$<sepAfter>`);
|
|
97
114
|
// Convert dashes at start of line
|
|
98
|
-
text = text.replace(new RegExp(`^(?<leadingSep>${
|
|
115
|
+
text = text.replace(new RegExp(`^(?<leadingSep>${escapedSep})?[-]+ `, "gm"), `$<leadingSep>${localizedDash} `);
|
|
99
116
|
// British: convert unspaced em-dashes to spaced en-dashes (word—word → word – word)
|
|
100
117
|
if (style === "british") {
|
|
101
|
-
text = text.replace(new RegExp(`(?<=[${LATIN_LETTERS}.!?'"])(?<sepBefore>${
|
|
118
|
+
text = text.replace(new RegExp(`(?<=[${LATIN_LETTERS}.!?'"])(?<sepBefore>${escapedSep}?)${EM_DASH}(?<sepAfter>${escapedSep}?)(?=[${LATIN_LETTERS}])`, "g"), `$<sepBefore>${maybeSpace}${localizedDash}${maybeSpace}$<sepAfter>`);
|
|
102
119
|
}
|
|
103
120
|
return text;
|
|
104
121
|
}
|
|
@@ -110,10 +127,11 @@ function convertParentheticalDashes(text, sep, style) {
|
|
|
110
127
|
* allows a space after the dash: "Don't inter— Hey! Who threw that?"
|
|
111
128
|
*/
|
|
112
129
|
function normalizeEmDashSpacing(text, sep) {
|
|
130
|
+
const escapedSep = escapeStringRegexp(sep);
|
|
113
131
|
// Remove all spaces around em-dashes
|
|
114
|
-
text = text.replace(new RegExp(`(?<before>${
|
|
132
|
+
text = text.replace(new RegExp(`(?<before>${escapedSep}?)[ ]*${EM_DASH}[ ]*(?<after>${escapedSep}?)`, "g"), `$<before>${EM_DASH}$<after>`);
|
|
115
133
|
// Preserve space after em-dash at start of line (e.g., attribution)
|
|
116
|
-
text = text.replace(new RegExp(`^(?<sep>${
|
|
134
|
+
text = text.replace(new RegExp(`^(?<sep>${escapedSep}?)${EM_DASH}(?<after>[A-Z0-9])`, "gm"), `$<sep>${EM_DASH} $<after>`);
|
|
117
135
|
return text;
|
|
118
136
|
}
|
|
119
137
|
/** Full dash transformation. */
|
package/dist/dashes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashes.js","sourceRoot":"","sources":["../src/dashes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,kBAAkB,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,aAAa,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAWjJ,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,GAAG,eAAe,CAAA;AAEjI;;;;GAIG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,CAAU,CAAA;AAEpF,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM;IACtD,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU;IAChE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK;IACxC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK;CACzC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAEX,8DAA8D;AAC9D,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,UAAuB,EAAE;IACvE,MAAM,GAAG,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,yBAAyB,CAAA;IACjG,MAAM,EAAE,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAA;IACjC,MAAM,GAAG,GAAG,eAAe,CAAC,GAAG,CAAC,CAAA;IAEhC,2FAA2F;IAC3F,MAAM,UAAU,GAAG,6BAA6B,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAEzI,2CAA2C;IAC3C,MAAM,UAAU,GAAG,OAAO,CAAA;IAE1B,wDAAwD;IACxD,MAAM,aAAa,GAAG,+CAA+C,CAAA,CAAE,gBAAgB;IACvF,MAAM,YAAY,GAAG,QAAQ,UAAU,GAAG,aAAa,KAAK,CAAA,CAAW,qBAAqB;IAC5F,MAAM,UAAU,GAAG,sBAAsB,UAAU,iBAAiB,GAAG,IAAI,CAAA,CAAE,oBAAoB;IACjG,MAAM,QAAQ,GAAG,UAAU,GAAG,KAAK,UAAU,gBAAgB,CAAA,CAAU,kBAAkB;IACzF,MAAM,YAAY,GAAG,mBAAmB,GAAG,KAAK,GAAG,UAAU,CAAA,CAAU,yBAAyB;IAChG,MAAM,UAAU,GAAG,aAAa,GAAG,2BAA2B,CAAA,CAAS,eAAe;IAEtF,mDAAmD;IACnD,MAAM,oBAAoB,GAAG;QAC3B,aAAa,EAAE,EAAE,EAAE,YAAY,EAAE,UAAU,EAAE,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,GAAG;KAC1F,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAEV,IAAI,GAAG,IAAI,CAAC,OAAO,CACjB,IAAI,MAAM,CAAC,oBAAoB,EAAE,GAAG,CAAC,EACrC,CAAC,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,GAAG,EAAE,EAAE,EAAE;QAC/D,IAAI,SAAS;YAAE,OAAO,KAAK,CAAA;QAC3B,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAA;QACxD,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAA;QACpD,IAAI,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,qBAAqB,CAAC,IAAI,CAAC,MAAM,CAAC;YAAE,OAAO,KAAK,CAAA;QACzF,qFAAqF;QACrF,gFAAgF;QAChF,IAAI,iBAAiB,IAAI,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;YAAE,OAAO,KAAK,CAAA;QACzF,+DAA+D;QAC/D,sDAAsD;QACtD,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;YAAE,OAAO,KAAK,CAAA;QAChE,OAAO,GAAG,iBAAiB,IAAI,EAAE,GAAG,KAAK,GAAG,OAAO,GAAG,GAAG,GAAG,MAAM,IAAI,EAAE,EAAE,CAAA;IAC5E,CAAC,CACF,CAAA;IAED,8CAA8C;IAC9C,sFAAsF;IACtF,IAAI,GAAG,IAAI,CAAC,OAAO,CACjB,IAAI,MAAM,CACR,QAAQ,aAAa,cAAc,KAAK,cAAc,GAAG,uBAAuB,GAAG,gCAAgC,GAAG,KAAK,GAAG,qBAAqB,GAAG,aAAa,GAAG,EAAE,EACxK,GAAG,CACJ,EACD,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,GAAG,EAAE,EAAE,EAAE;QACjD,IAAI,SAAS;YAAE,OAAO,KAAK,CAAA;QAC3B,OAAO,GAAG,KAAK,GAAG,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,GAAG,MAAM,IAAI,EAAE,EAAE,CAAA;IACrE,CAAC,CACF,CAAA;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,UAAuB,EAAE;IACrE,MAAM,GAAG,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,yBAAyB,CAAA;IACjG,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,UAAU,CAAA;IACjD,MAAM,EAAE,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAA;IACjC,MAAM,GAAG,GAAG,eAAe,CAAC,GAAG,CAAC,CAAA;IAEhC,OAAO,IAAI,CAAC,OAAO,CACjB,IAAI,MAAM,CAAC,GAAG,EAAE,iBAAiB,MAAM,iBAAiB,GAAG,uBAAuB,GAAG,gDAAgD,GAAG,iBAAiB,MAAM,wBAAwB,GAAG,EAAE,EAAE,GAAG,CAAC,EAClM,CAAC,GAAG,IAAI,EAAE,EAAE;QACV,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAA2B,CAAA;QAC/C,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;QACtH,OAAO,GAAG,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,SAAS,IAAI,EAAE,GAAG,CAAC,CAAC,MAAM,GAAG,GAAG,GAAG,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,OAAO,IAAI,EAAE,EAAE,CAAA;IAC3H,CAAC,CACF,CAAA;AACH,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,UAAuB,EAAE;IAClE,MAAM,GAAG,GAAG,OAAO,CAAC,SAAS,IAAI,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"dashes.js","sourceRoot":"","sources":["../src/dashes.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,KAAK,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAClF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,MAAM,EACN,6BAA6B,EAC7B,KAAK,WAAW,EAChB,KAAK,SAAS,GACf,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EACL,QAAQ,EACR,cAAc,EACd,WAAW,EACX,YAAY,EACZ,MAAM,EACN,OAAO,EACP,SAAS,EACT,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,KAAK,aAAa,GACnB,MAAM,cAAc,CAAA;AAErB,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IAExB;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IAEnC;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,SAAS,CAAA;IAErB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IAErB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B;AAQD,OAAO,EAAE,6BAA6B,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAC3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AA+ClD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,KAAK,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAClF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,MAAM,EACN,6BAA6B,EAC7B,KAAK,WAAW,EAChB,KAAK,SAAS,GACf,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EACL,QAAQ,EACR,cAAc,EACd,WAAW,EACX,YAAY,EACZ,MAAM,EACN,OAAO,EACP,SAAS,EACT,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,KAAK,aAAa,GACnB,MAAM,cAAc,CAAA;AAErB,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IAExB;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IAEnC;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,SAAS,CAAA;IAErB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IAErB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B;AAQD,OAAO,EAAE,6BAA6B,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAC3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AA+ClD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,CA6D9E"}
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ export { ellipsis, multiplication, mathSymbols, legalSymbols, arrows, degrees, f
|
|
|
13
13
|
import { niceQuotes } from "./quotes.js";
|
|
14
14
|
import { hyphenReplace } from "./dashes.js";
|
|
15
15
|
import { symbolTransform, fractions as fractionsTransform, degrees as degreesTransform, superscriptOrdinal as superscriptTransform, primeMarks, collapseSpaces as collapseSpacesTransform, punctuationLigatures as ligaturesTransform } from "./symbols.js";
|
|
16
|
-
import { assertSeparatorCountPreserved } from "./utils.js";
|
|
16
|
+
import { assertSeparatorCountPreserved, formatErrorString } from "./utils.js";
|
|
17
17
|
import { DEFAULT_SEPARATOR } from "./constants.js";
|
|
18
18
|
export { assertSeparatorCountPreserved, countSeparators } from "./utils.js";
|
|
19
19
|
export { DEFAULT_SEPARATOR } from "./constants.js";
|
|
@@ -63,6 +63,13 @@ const defaultOpts = {
|
|
|
63
63
|
};
|
|
64
64
|
export function transform(text, options = {}) {
|
|
65
65
|
const separator = options.separator ?? DEFAULT_SEPARATOR;
|
|
66
|
+
// Validate separator: must be a single UTF-16 code unit (BMP character)
|
|
67
|
+
// Multi-codepoint characters (surrogate pairs like emoji) cause issues with regex patterns
|
|
68
|
+
if (separator.length !== 1) {
|
|
69
|
+
throw new Error(`Invalid separator: must be a single character. ` +
|
|
70
|
+
`Received "${separator}" (length: ${separator.length}). ` +
|
|
71
|
+
`Use a single-codepoint character like the default "\\uE000".`);
|
|
72
|
+
}
|
|
66
73
|
const original = text;
|
|
67
74
|
const { symbols, fractions, degrees, superscript, ligatures, collapseSpaces, checkIdempotency, ...separatorOpts } = { ...defaultOpts, ...options };
|
|
68
75
|
text = hyphenReplace(text, separatorOpts);
|
|
@@ -92,8 +99,8 @@ export function transform(text, options = {}) {
|
|
|
92
99
|
/* istanbul ignore if -- defensive check that should never trigger */
|
|
93
100
|
if (text !== secondPass) {
|
|
94
101
|
throw new Error(`Transform is not idempotent.\n` +
|
|
95
|
-
`First pass: ${
|
|
96
|
-
`Second pass: ${
|
|
102
|
+
`First pass: ${formatErrorString(text, "first-pass")}\n` +
|
|
103
|
+
`Second pass: ${formatErrorString(secondPass, "second-pass")}\n` +
|
|
97
104
|
`This is a bug in punctilio. Please file an issue at https://github.com/alexander-turner/punctilio/issues\n` +
|
|
98
105
|
`Include the input text that caused this error.`);
|
|
99
106
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAA4C,MAAM,aAAa,CAAA;AAElF,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,MAAM,EACN,6BAA6B,GAG9B,MAAM,aAAa,CAAA;AAEpB,OAAO,EACL,QAAQ,EACR,cAAc,EACd,WAAW,EACX,YAAY,EACZ,MAAM,EACN,OAAO,EACP,SAAS,EACT,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,GAEhB,MAAM,cAAc,CAAA;AA0FrB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,eAAe,EAAE,SAAS,IAAI,kBAAkB,EAAE,OAAO,IAAI,gBAAgB,EAAE,kBAAkB,IAAI,oBAAoB,EAAE,UAAU,EAAE,cAAc,IAAI,uBAAuB,EAAE,oBAAoB,IAAI,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAC3P,OAAO,EAAE,6BAA6B,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/quotes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quotes.d.ts","sourceRoot":"","sources":["../src/quotes.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"quotes.d.ts","sourceRoot":"","sources":["../src/quotes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAcH,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,CAAA;AAE9D,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;CACpC;AAkGD,+CAA+C;AAC/C,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,MAAM,CAS3E"}
|
package/dist/quotes.js
CHANGED
|
@@ -1,61 +1,66 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Smart quote transformation: straight quotes → curly quotes.
|
|
3
3
|
*/
|
|
4
|
+
import escapeStringRegexp from "escape-string-regexp";
|
|
4
5
|
import { UNICODE_SYMBOLS, DEFAULT_SEPARATOR, LATIN_LETTERS } from "./constants.js";
|
|
5
6
|
const { EM_DASH, LEFT_DOUBLE_QUOTE, RIGHT_DOUBLE_QUOTE, LEFT_SINGLE_QUOTE, RIGHT_SINGLE_QUOTE, ELLIPSIS, } = UNICODE_SYMBOLS;
|
|
6
7
|
/** Convert straight single quotes to curly quotes and apostrophes */
|
|
7
8
|
function convertSingleQuotes(text, sep) {
|
|
9
|
+
const escapedSep = escapeStringRegexp(sep);
|
|
8
10
|
// Handle empty single quotes '' and whitespace-only quotes ' ' first
|
|
9
11
|
// Only match straight quotes, not already-converted curly quotes
|
|
10
12
|
const singleQuoteChars = `'${LEFT_SINGLE_QUOTE}${RIGHT_SINGLE_QUOTE}`;
|
|
11
13
|
text = text.replace(new RegExp(`(?<![${singleQuoteChars}])''(?![${singleQuoteChars}])`, "g"), `${LEFT_SINGLE_QUOTE}${RIGHT_SINGLE_QUOTE}`);
|
|
12
14
|
text = text.replace(new RegExp(`(?<![${singleQuoteChars}])'(\\s+)'(?![${singleQuoteChars}])`, "g"), `${LEFT_SINGLE_QUOTE}$1${RIGHT_SINGLE_QUOTE}`);
|
|
13
15
|
const afterEndingSinglePatterns = `\\s\\.!?;,\\)${EM_DASH}\\-\\]"`;
|
|
14
|
-
const afterEndingSingle = `(?=${
|
|
16
|
+
const afterEndingSingle = `(?=${escapedSep}?(?:s${escapedSep}?)?(?:[${afterEndingSinglePatterns}]|$))`;
|
|
15
17
|
const endingSingle = `(?<=[^\\s${LEFT_DOUBLE_QUOTE}'])[']${afterEndingSingle}`;
|
|
16
18
|
text = text.replace(new RegExp(endingSingle, "gm"), RIGHT_SINGLE_QUOTE);
|
|
17
|
-
const contraction = `(?<=[${LATIN_LETTERS}])['${RIGHT_SINGLE_QUOTE}](?=${
|
|
19
|
+
const contraction = `(?<=[${LATIN_LETTERS}])['${RIGHT_SINGLE_QUOTE}](?=${escapedSep}?[${LATIN_LETTERS}])`;
|
|
18
20
|
text = text.replace(new RegExp(contraction, "gm"), RIGHT_SINGLE_QUOTE);
|
|
19
21
|
const apostropheWhitelist = `(?=n${RIGHT_SINGLE_QUOTE} )`;
|
|
20
22
|
const endQuoteNotContraction = `(?!${contraction})${RIGHT_SINGLE_QUOTE}${afterEndingSingle}`;
|
|
21
|
-
|
|
23
|
+
// Limit lookahead scan to 1000 chars to prevent catastrophic backtracking on pathological inputs
|
|
24
|
+
const apostropheRegex = new RegExp(`(?<=^|[^\\w])'(${apostropheWhitelist}|(?![^${LEFT_SINGLE_QUOTE}'\\n]{0,1000}${endQuoteNotContraction}))`, "gm");
|
|
22
25
|
text = text.replace(apostropheRegex, RIGHT_SINGLE_QUOTE);
|
|
23
|
-
const beginningSingle = `(?<beforeContext>(?:^|[\\s${LEFT_DOUBLE_QUOTE}${RIGHT_DOUBLE_QUOTE}${EM_DASH}\\-\\(])${
|
|
26
|
+
const beginningSingle = `(?<beforeContext>(?:^|[\\s${LEFT_DOUBLE_QUOTE}${RIGHT_DOUBLE_QUOTE}${EM_DASH}\\-\\(])${escapedSep}?)['](?=${escapedSep}?\\S)`;
|
|
24
27
|
text = text.replace(new RegExp(beginningSingle, "gm"), `$<beforeContext>${LEFT_SINGLE_QUOTE}`);
|
|
25
28
|
return text;
|
|
26
29
|
}
|
|
27
30
|
/** Convert straight double quotes to curly quotes */
|
|
28
31
|
function convertDoubleQuotes(text, sep) {
|
|
32
|
+
const escapedSep = escapeStringRegexp(sep);
|
|
29
33
|
// Handle empty quotes "" first - match only when not part of adjacent quotes
|
|
30
34
|
// Require word boundary or start/end of string on at least one side
|
|
31
35
|
text = text.replace(/(?<=^|[\s([{])""(?=$|[\s)\]}.!?,;:])/g, `${LEFT_DOUBLE_QUOTE}${RIGHT_DOUBLE_QUOTE}`);
|
|
32
36
|
// Handle whitespace-only quotes " " - require non-quote chars on both sides
|
|
33
37
|
text = text.replace(/(?<=^|[\s([{])"(?<whitespace>\s+)"(?=$|[\s)\]}.!?,;:])/g, `${LEFT_DOUBLE_QUOTE}$<whitespace>${RIGHT_DOUBLE_QUOTE}`);
|
|
34
|
-
const beginningDouble = new RegExp(`(?<=^|[\\s\\(\\/\\[\\{\\-${EM_DASH}${
|
|
38
|
+
const beginningDouble = new RegExp(`(?<=^|[\\s\\(\\/\\[\\{\\-${EM_DASH}${escapedSep}])(?<beforeChr>${escapedSep}?)["](?<afterChr>(?<sepWithPunct>${escapedSep}[ .,])|(?=${escapedSep}?\\.{3}|${escapedSep}?[^\\s\\)\\${EM_DASH},!?${escapedSep};:.\\}]))`, "gm");
|
|
35
39
|
text = text.replace(beginningDouble, `$<beforeChr>${LEFT_DOUBLE_QUOTE}$<afterChr>`);
|
|
36
|
-
text = text.replace(new RegExp(`(?<=\\{)(?<sepSpace>${
|
|
37
|
-
const endingDouble = `(?<beforeQuote>[^\\s\\(])["]((?<sepAfter>${
|
|
40
|
+
text = text.replace(new RegExp(`(?<=\\{)(?<sepSpace>${escapedSep}? )?["]`, "g"), `$<sepSpace>${LEFT_DOUBLE_QUOTE}`);
|
|
41
|
+
const endingDouble = `(?<beforeQuote>[^\\s\\(])["]((?<sepAfter>${escapedSep})?)(?=${escapedSep}|[\\s/\\).,;${EM_DASH}:\\-\\}!?s]|$)`;
|
|
38
42
|
text = text.replace(new RegExp(endingDouble, "g"), `$<beforeQuote>${RIGHT_DOUBLE_QUOTE}$<sepAfter>`);
|
|
39
|
-
text = text.replace(new RegExp(`["](?<sepEnd>${
|
|
43
|
+
text = text.replace(new RegExp(`["](?<sepEnd>${escapedSep}?)$`, "g"), `${RIGHT_DOUBLE_QUOTE}$<sepEnd>`);
|
|
40
44
|
text = text.replace(new RegExp(`'(?=${RIGHT_DOUBLE_QUOTE})`, "gu"), RIGHT_SINGLE_QUOTE);
|
|
41
45
|
return text;
|
|
42
46
|
}
|
|
43
47
|
/** Apply American or British punctuation style */
|
|
44
48
|
function applyPunctuationStyle(text, sep, style) {
|
|
49
|
+
const escapedSep = escapeStringRegexp(sep);
|
|
45
50
|
if (style === "american") {
|
|
46
51
|
// Period outside → inside: "Hello". → "Hello."
|
|
47
|
-
const periodOutsideRegex = new RegExp(`(?<![!?:\\.${ELLIPSIS}])(?<sepBefore>${
|
|
52
|
+
const periodOutsideRegex = new RegExp(`(?<![!?:\\.${ELLIPSIS}])(?<sepBefore>${escapedSep}?)(?<quote>[${RIGHT_SINGLE_QUOTE}${RIGHT_DOUBLE_QUOTE}])(?<sepAfter>${escapedSep}?)(?!\\.\\.\\.)\\.`, "g");
|
|
48
53
|
text = text.replace(periodOutsideRegex, "$<sepBefore>.$<quote>$<sepAfter>");
|
|
49
54
|
// Comma outside → inside: "Hello", → "Hello,"
|
|
50
|
-
const commaOutsideRegex = new RegExp(`(?<sepBefore>${
|
|
55
|
+
const commaOutsideRegex = new RegExp(`(?<sepBefore>${escapedSep}?)(?<quote>[${RIGHT_SINGLE_QUOTE}${RIGHT_DOUBLE_QUOTE}])(?<sepAfter>${escapedSep}?),`, "g");
|
|
51
56
|
text = text.replace(commaOutsideRegex, "$<sepBefore>,$<quote>$<sepAfter>");
|
|
52
57
|
}
|
|
53
58
|
else if (style === "british") {
|
|
54
59
|
// Period inside → outside: "Hello." → "Hello".
|
|
55
|
-
const periodInsideRegex = new RegExp(`(?<![!?:\\.${ELLIPSIS}])(?<sepBefore>${
|
|
60
|
+
const periodInsideRegex = new RegExp(`(?<![!?:\\.${ELLIPSIS}])(?<sepBefore>${escapedSep}?)\\.(?<sepMiddle>${escapedSep}?)(?<quote>[${RIGHT_SINGLE_QUOTE}${RIGHT_DOUBLE_QUOTE}])`, "g");
|
|
56
61
|
text = text.replace(periodInsideRegex, "$<sepBefore>$<sepMiddle>$<quote>.");
|
|
57
62
|
// Comma inside → outside: "Hello," → "Hello",
|
|
58
|
-
const commaInsideRegex = new RegExp(`(?<![!?]),(?<sepAndQuote>${
|
|
63
|
+
const commaInsideRegex = new RegExp(`(?<![!?]),(?<sepAndQuote>${escapedSep}?[${RIGHT_DOUBLE_QUOTE}${RIGHT_SINGLE_QUOTE}])`, "g");
|
|
59
64
|
text = text.replace(commaInsideRegex, "$<sepAndQuote>,");
|
|
60
65
|
}
|
|
61
66
|
return text;
|
package/dist/quotes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quotes.js","sourceRoot":"","sources":["../src/quotes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAElF,MAAM,EACJ,OAAO,EACP,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,QAAQ,GACT,GAAG,eAAe,CAAA;AAWnB,qEAAqE;AACrE,SAAS,mBAAmB,CAAC,IAAY,EAAE,GAAW;IACpD,qEAAqE;IACrE,iEAAiE;IACjE,MAAM,gBAAgB,GAAG,IAAI,iBAAiB,GAAG,kBAAkB,EAAE,CAAA;IACrE,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,QAAQ,gBAAgB,WAAW,gBAAgB,IAAI,EAAE,GAAG,CAAC,EAAE,GAAG,iBAAiB,GAAG,kBAAkB,EAAE,CAAC,CAAA;IAC1I,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,QAAQ,gBAAgB,iBAAiB,gBAAgB,IAAI,EAAE,GAAG,CAAC,EAAE,GAAG,iBAAiB,KAAK,kBAAkB,EAAE,CAAC,CAAA;IAElJ,MAAM,yBAAyB,GAAG,gBAAgB,OAAO,SAAS,CAAA;IAClE,MAAM,iBAAiB,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"quotes.js","sourceRoot":"","sources":["../src/quotes.ts"],"names":[],"mappings":"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"}
|
package/dist/rehype.d.ts
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rehype plugin for applying punctilio typography transformations to HTML.
|
|
3
|
+
*
|
|
4
|
+
* This plugin integrates punctilio with the unified/rehype ecosystem,
|
|
5
|
+
* allowing you to apply smart typography transformations to HTML ASTs.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
import type { Root, Element, Text, ElementContent, Parent, RootContent } from "hast";
|
|
10
|
+
import type { Transformer } from "unified";
|
|
11
|
+
import { type TransformOptions } from "./index.js";
|
|
12
|
+
/**
|
|
13
|
+
* Options for the rehype-punctilio plugin.
|
|
14
|
+
*/
|
|
15
|
+
export interface RehypePunctilioOptions extends TransformOptions {
|
|
16
|
+
/**
|
|
17
|
+
* HTML tag names to skip when applying transformations.
|
|
18
|
+
* Content inside these elements won't have formatting improvements applied.
|
|
19
|
+
*
|
|
20
|
+
* Default: ["code", "pre", "script", "style", "kbd", "var", "samp"]
|
|
21
|
+
*/
|
|
22
|
+
skipTags?: string[];
|
|
23
|
+
/**
|
|
24
|
+
* CSS class names that indicate content should skip formatting.
|
|
25
|
+
* Elements with any of these classes (or descendants of such elements)
|
|
26
|
+
* will be skipped.
|
|
27
|
+
*
|
|
28
|
+
* Default: []
|
|
29
|
+
*/
|
|
30
|
+
skipClasses?: string[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Flattens text nodes from an element tree into a single array.
|
|
34
|
+
*
|
|
35
|
+
* @param node - The element or element content to process
|
|
36
|
+
* @param shouldSkip - Function to determine which elements to skip
|
|
37
|
+
* @param depth - Current recursion depth (internal use)
|
|
38
|
+
* @returns Array of Text nodes
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* const textNodes = flattenTextNodes(paragraphElement, (el) => el.tagName === 'code')
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare function flattenTextNodes(node: Element | ElementContent, shouldSkip: (n: Element) => boolean, depth?: number): Text[];
|
|
46
|
+
/**
|
|
47
|
+
* Extracts concatenated text content from an element.
|
|
48
|
+
*
|
|
49
|
+
* @param node - The element to extract text from
|
|
50
|
+
* @param shouldSkip - Optional function to determine which elements to skip
|
|
51
|
+
* @returns The combined text content
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* const text = getTextContent(paragraphElement)
|
|
56
|
+
* // Returns "Hello, world!" for <p>Hello, <em>world!</em></p>
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare function getTextContent(node: Element, shouldSkip?: (n: Element) => boolean): string;
|
|
60
|
+
/**
|
|
61
|
+
* Recursively finds the first text node in a tree of HTML elements.
|
|
62
|
+
*
|
|
63
|
+
* @param node - The root node to search from
|
|
64
|
+
* @param depth - Current recursion depth (internal use)
|
|
65
|
+
* @returns The first text node found, or null if no text nodes exist
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* const textNode = getFirstTextNode(divElement)
|
|
70
|
+
* if (textNode) console.log(textNode.value)
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export declare function getFirstTextNode(node: Parent | RootContent, depth?: number): Text | null;
|
|
74
|
+
/**
|
|
75
|
+
* Validates that smart quotes in a text string are properly matched.
|
|
76
|
+
*
|
|
77
|
+
* @param input - The text to validate
|
|
78
|
+
* @throws Error if quotes are mismatched
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* assertSmartQuotesMatch('\u201CHello\u201D') // OK
|
|
83
|
+
* assertSmartQuotesMatch('\u201CHello') // throws Error
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
export declare function assertSmartQuotesMatch(input: string): void;
|
|
87
|
+
/**
|
|
88
|
+
* Applies a transformation to element text content while preserving HTML structure.
|
|
89
|
+
*
|
|
90
|
+
* This function uses a marker technique to handle text that spans multiple
|
|
91
|
+
* HTML elements. It:
|
|
92
|
+
* 1. Appends a private-use Unicode character to each child's text content
|
|
93
|
+
* 2. Concatenates and transforms the whole paragraph
|
|
94
|
+
* 3. Splits the result back into the original text nodes
|
|
95
|
+
*
|
|
96
|
+
* @param node - The element to transform
|
|
97
|
+
* @param transformFn - The transformation function to apply
|
|
98
|
+
* @param shouldSkip - Function to determine which elements to skip
|
|
99
|
+
* @param separator - The marker character to use (default: DEFAULT_SEPARATOR)
|
|
100
|
+
* @param checkInvariance - Whether to verify that the transform produces the same
|
|
101
|
+
* result with and without markers. When true, checks that
|
|
102
|
+
* `stripMarkers(transform(textWithMarkers)) === transform(stripMarkers(text))`.
|
|
103
|
+
* Useful for debugging transforms that accidentally interact with markers.
|
|
104
|
+
* Default: false
|
|
105
|
+
* @throws Error if transformation alters the number of text nodes
|
|
106
|
+
* @throws Error if checkInvariance is true and the invariance check fails
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```ts
|
|
110
|
+
* import { transformElement, DEFAULT_SEPARATOR } from 'punctilio/rehype'
|
|
111
|
+
*
|
|
112
|
+
* // Apply a custom transform to an element
|
|
113
|
+
* transformElement(
|
|
114
|
+
* paragraphElement,
|
|
115
|
+
* (text) => text.replace(/eg\b/g, 'e.g.'),
|
|
116
|
+
* (el) => el.tagName === 'code',
|
|
117
|
+
* DEFAULT_SEPARATOR
|
|
118
|
+
* )
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
export declare function transformElement(node: Element, transformFn: (input: string) => string, shouldSkip: (input: Element) => boolean, separator: string, checkInvariance?: boolean): void;
|
|
122
|
+
/**
|
|
123
|
+
* Collects elements that should have text transformations applied.
|
|
124
|
+
* Only collects elements that directly contain text nodes.
|
|
125
|
+
*
|
|
126
|
+
* @param node - The root element to search from
|
|
127
|
+
* @param shouldSkip - Function to determine which elements to skip
|
|
128
|
+
* @param depth - Current recursion depth (internal use)
|
|
129
|
+
* @returns Array of elements that contain transformable text
|
|
130
|
+
*/
|
|
131
|
+
export declare function collectTransformableElements(node: Element, shouldSkip: (n: Element) => boolean, depth?: number): Element[];
|
|
132
|
+
/**
|
|
133
|
+
* Rehype plugin that applies punctilio typography transformations to HTML.
|
|
134
|
+
*
|
|
135
|
+
* @param options - Plugin configuration options
|
|
136
|
+
* @returns Unified transformer function
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```ts
|
|
140
|
+
* import { unified } from 'unified'
|
|
141
|
+
* import remarkParse from 'remark-parse'
|
|
142
|
+
* import remarkRehype from 'remark-rehype'
|
|
143
|
+
* import rehypeStringify from 'rehype-stringify'
|
|
144
|
+
* import { rehypePunctilio } from 'punctilio/rehype'
|
|
145
|
+
*
|
|
146
|
+
* const result = await unified()
|
|
147
|
+
* .use(remarkParse)
|
|
148
|
+
* .use(remarkRehype)
|
|
149
|
+
* .use(rehypePunctilio, {
|
|
150
|
+
* punctuationStyle: 'american',
|
|
151
|
+
* dashStyle: 'american',
|
|
152
|
+
* })
|
|
153
|
+
* .use(rehypeStringify)
|
|
154
|
+
* .process('"Hello," she said -- "it\'s nice."')
|
|
155
|
+
*
|
|
156
|
+
* // Output HTML will have smart quotes and em-dashes
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
export declare function rehypePunctilio(options?: RehypePunctilioOptions): Transformer<Root, Root>;
|
|
160
|
+
export default rehypePunctilio;
|
|
161
|
+
//# sourceMappingURL=rehype.d.ts.map
|
|
@@ -0,0 +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;;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,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,EACnC,KAAK,GAAE,MAAU,GAChB,IAAI,EAAE,CAkBR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,OAAO,EACb,UAAU,GAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAqB,GAChD,MAAM,CAIR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,GAAG,WAAW,EAC1B,KAAK,GAAE,MAAU,GAChB,IAAI,GAAG,IAAI,CAeb;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAmB1D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,OAAO,EACb,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,EACtC,UAAU,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,EACvC,SAAS,EAAE,MAAM,EACjB,eAAe,GAAE,OAAe,GAC/B,IAAI,CA8CN;AA6DD;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,OAAO,EACb,UAAU,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,EACnC,KAAK,GAAE,MAAU,GAChB,OAAO,EAAE,CA4BX;AAqBD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,eAAe,CAC7B,OAAO,GAAE,sBAA2B,GACnC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CA2DzB;AAED,eAAe,eAAe,CAAA"}
|