punctilio 3.11.2 → 3.11.4
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/dist/cli.d.ts +1 -12
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +4 -26
- package/dist/cli.js.map +1 -1
- package/dist/constants.d.ts +13 -61
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +12 -61
- package/dist/constants.js.map +1 -1
- package/dist/dashes.d.ts +0 -9
- package/dist/dashes.d.ts.map +1 -1
- package/dist/dashes.js +5 -27
- package/dist/dashes.js.map +1 -1
- package/dist/html.d.ts +1 -32
- package/dist/html.d.ts.map +1 -1
- package/dist/html.js +1 -29
- package/dist/html.js.map +1 -1
- package/dist/index.d.ts +5 -44
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -45
- package/dist/index.js.map +1 -1
- package/dist/markdown.d.ts +1 -34
- package/dist/markdown.d.ts.map +1 -1
- package/dist/markdown.js +1 -34
- package/dist/markdown.js.map +1 -1
- package/dist/nbsp.d.ts +1 -68
- package/dist/nbsp.d.ts.map +1 -1
- package/dist/nbsp.js +7 -87
- package/dist/nbsp.js.map +1 -1
- package/dist/prettier-plugin.d.ts +0 -14
- package/dist/prettier-plugin.d.ts.map +1 -1
- package/dist/prettier-plugin.js +0 -19
- package/dist/prettier-plugin.js.map +1 -1
- package/dist/quotes.d.ts +0 -3
- package/dist/quotes.d.ts.map +1 -1
- package/dist/quotes.js +11 -58
- package/dist/quotes.js.map +1 -1
- package/dist/rehype.d.ts +5 -142
- package/dist/rehype.d.ts.map +1 -1
- package/dist/rehype.js +9 -146
- package/dist/rehype.js.map +1 -1
- package/dist/remark.d.ts +0 -30
- package/dist/remark.d.ts.map +1 -1
- package/dist/remark.js +0 -41
- package/dist/remark.js.map +1 -1
- package/dist/symbols.d.ts +1 -7
- package/dist/symbols.d.ts.map +1 -1
- package/dist/symbols.js +10 -54
- package/dist/symbols.js.map +1 -1
- package/dist/utils.d.ts +10 -58
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +10 -58
- package/dist/utils.js.map +1 -1
- package/package.json +6 -5
- package/src/cli.ts +7 -33
- package/src/constants.ts +13 -62
- package/src/dashes.ts +5 -28
- package/src/html.ts +1 -33
- package/src/index.ts +30 -70
- package/src/markdown.ts +1 -38
- package/src/nbsp.ts +7 -88
- package/src/prettier-plugin.ts +0 -20
- package/src/quotes.ts +11 -59
- package/src/rehype.ts +11 -165
- package/src/remark.ts +1 -43
- package/src/symbols.ts +10 -67
- package/src/utils.ts +10 -60
package/dist/utils.d.ts
CHANGED
|
@@ -1,76 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* @module utils
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* Formats a string for error messages. If the string exceeds the threshold,
|
|
8
|
-
* truncates it and shows the total length.
|
|
9
|
-
*
|
|
10
|
-
* In Node.js environments, also writes the full content to stderr
|
|
11
|
-
* so it's available in build logs for debugging.
|
|
2
|
+
* Formats a string for error messages, truncating above the threshold.
|
|
3
|
+
* Writes full content to stderr in Node.js so build logs capture it.
|
|
12
4
|
*/
|
|
13
5
|
export declare function formatErrorString(content: string, label: string): string;
|
|
14
|
-
/**
|
|
15
|
-
* Throws if any text node contains the separator character, which would
|
|
16
|
-
* corrupt the split/join mechanism used by the rehype and remark plugins.
|
|
17
|
-
*
|
|
18
|
-
* @throws Error if the separator is found in any text value
|
|
19
|
-
*/
|
|
6
|
+
/** Throws if any text node contains the separator (would corrupt split/join). */
|
|
20
7
|
export declare function assertSeparatorAbsent(textValues: string[], separator: string): void;
|
|
21
|
-
/**
|
|
22
|
-
* Counts non-overlapping occurrences of the separator string in the text.
|
|
23
|
-
*/
|
|
24
8
|
export declare function countSeparators(text: string, separator?: string): number;
|
|
25
|
-
/** Minimal text-node interface shared by mdast.Text and hast.Text. */
|
|
26
9
|
interface TextNode {
|
|
27
10
|
value: string;
|
|
28
11
|
}
|
|
29
12
|
/**
|
|
30
13
|
* Applies a text transformation across an array of text nodes using the
|
|
31
|
-
* separator-marking technique
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* 2. Appends the separator to each node's value, concatenates into one string.
|
|
35
|
-
* 3. Runs the transform function on the concatenated string.
|
|
36
|
-
* 4. Splits the result back on the separator and writes each fragment
|
|
37
|
-
* back into the corresponding text node.
|
|
38
|
-
*
|
|
39
|
-
* `textNodes` is mutated in place.
|
|
40
|
-
*
|
|
41
|
-
* @throws Error if the transformation alters the number of text nodes
|
|
14
|
+
* separator-marking technique: appends the separator to each node's value,
|
|
15
|
+
* concatenates, transforms, then splits back on the separator and writes
|
|
16
|
+
* each fragment into the corresponding text node. Mutates `textNodes`.
|
|
42
17
|
*/
|
|
43
18
|
export declare function transformTextNodes(textNodes: TextNode[], transformFn: (input: string) => string, separator: string): void;
|
|
44
|
-
/**
|
|
45
|
-
* Validates that a transformation preserved the separator count.
|
|
46
|
-
* Throws an error if separators were added or removed.
|
|
47
|
-
*
|
|
48
|
-
* @throws Error if separator count changed
|
|
49
|
-
*/
|
|
19
|
+
/** Throws if a transformation changed the separator count. */
|
|
50
20
|
export declare function assertSeparatorCountPreserved(original: string, transformed: string, separator?: string, transformName?: string): void;
|
|
51
|
-
/**
|
|
52
|
-
* Returns a copy of `obj` with `undefined`-valued keys removed.
|
|
53
|
-
* Used so caller-supplied `{ foo: undefined }` doesn't override a default.
|
|
54
|
-
*
|
|
55
|
-
* @internal
|
|
56
|
-
*/
|
|
21
|
+
/** Returns a copy of `obj` with `undefined`-valued keys removed. @internal */
|
|
57
22
|
export declare function filterUndefined<T extends object>(obj: T): Partial<T>;
|
|
58
|
-
/**
|
|
59
|
-
* Returns a deterministic JSON-style string for an options object: drops
|
|
60
|
-
* `undefined` values and sorts keys, so equivalent option sets always
|
|
61
|
-
* produce the same string (suitable as a cache or LRU key).
|
|
62
|
-
*
|
|
63
|
-
* @internal
|
|
64
|
-
*/
|
|
23
|
+
/** Deterministic JSON string for an options object, suitable as cache key. @internal */
|
|
65
24
|
export declare function stableStringify(obj: object): string;
|
|
66
|
-
/**
|
|
67
|
-
* Extracts the named-groups object from a `String.prototype.replace`
|
|
68
|
-
* callback's argument tuple. The last element is always the groups
|
|
69
|
-
* object when the regex has named captures. Callers supply the group
|
|
70
|
-
* shape via the type parameter to localise the unavoidable type cast.
|
|
71
|
-
*
|
|
72
|
-
* @internal
|
|
73
|
-
*/
|
|
25
|
+
/** Extracts named groups from a `.replace()` callback's arguments. @internal */
|
|
74
26
|
export declare function namedGroups<G>(args: unknown[]): G;
|
|
75
27
|
export {};
|
|
76
28
|
//# sourceMappingURL=utils.d.ts.map
|
package/dist/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAkBxE;AAED,iFAAiF;AACjF,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAanF;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE,MAA0B,GAAG,MAAM,CAS3F;AAED,UAAU,QAAQ;IAChB,KAAK,EAAE,MAAM,CAAA;CACd;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,QAAQ,EAAE,EACrB,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,EACtC,SAAS,EAAE,MAAM,GAChB,IAAI,CAmBN;AAED,8DAA8D;AAC9D,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,SAAS,GAAE,MAA0B,EACrC,aAAa,GAAE,MAAoB,GAClC,IAAI,CAUN;AAED,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAMpE;AAED,wFAAwF;AACxF,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKnD;AAED,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,CAEjD"}
|
package/dist/utils.js
CHANGED
|
@@ -1,17 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utility functions for text transformation validation.
|
|
3
|
-
*
|
|
4
|
-
* @module utils
|
|
5
|
-
*/
|
|
6
1
|
import { DEFAULT_SEPARATOR, ISSUES_URL } from "./constants.js";
|
|
7
|
-
/** Threshold above which strings are truncated in error messages. */
|
|
8
2
|
const ERROR_STRING_THRESHOLD = 2000;
|
|
9
3
|
/**
|
|
10
|
-
* Formats a string for error messages
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* In Node.js environments, also writes the full content to stderr
|
|
14
|
-
* so it's available in build logs for debugging.
|
|
4
|
+
* Formats a string for error messages, truncating above the threshold.
|
|
5
|
+
* Writes full content to stderr in Node.js so build logs capture it.
|
|
15
6
|
*/
|
|
16
7
|
export function formatErrorString(content, label) {
|
|
17
8
|
if (content.length <= ERROR_STRING_THRESHOLD) {
|
|
@@ -29,12 +20,7 @@ export function formatErrorString(content, label) {
|
|
|
29
20
|
const truncated = content.slice(0, ERROR_STRING_THRESHOLD);
|
|
30
21
|
return `[${label}: ${JSON.stringify(truncated)}... (${content.length} chars total)]`;
|
|
31
22
|
}
|
|
32
|
-
/**
|
|
33
|
-
* Throws if any text node contains the separator character, which would
|
|
34
|
-
* corrupt the split/join mechanism used by the rehype and remark plugins.
|
|
35
|
-
*
|
|
36
|
-
* @throws Error if the separator is found in any text value
|
|
37
|
-
*/
|
|
23
|
+
/** Throws if any text node contains the separator (would corrupt split/join). */
|
|
38
24
|
export function assertSeparatorAbsent(textValues, separator) {
|
|
39
25
|
for (const value of textValues) {
|
|
40
26
|
if (!value.includes(separator))
|
|
@@ -47,9 +33,6 @@ export function assertSeparatorAbsent(textValues, separator) {
|
|
|
47
33
|
`Text: ${formatErrorString(value, "input")}`);
|
|
48
34
|
}
|
|
49
35
|
}
|
|
50
|
-
/**
|
|
51
|
-
* Counts non-overlapping occurrences of the separator string in the text.
|
|
52
|
-
*/
|
|
53
36
|
export function countSeparators(text, separator = DEFAULT_SEPARATOR) {
|
|
54
37
|
if (separator.length === 0)
|
|
55
38
|
return 0;
|
|
@@ -63,17 +46,9 @@ export function countSeparators(text, separator = DEFAULT_SEPARATOR) {
|
|
|
63
46
|
}
|
|
64
47
|
/**
|
|
65
48
|
* Applies a text transformation across an array of text nodes using the
|
|
66
|
-
* separator-marking technique
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* 2. Appends the separator to each node's value, concatenates into one string.
|
|
70
|
-
* 3. Runs the transform function on the concatenated string.
|
|
71
|
-
* 4. Splits the result back on the separator and writes each fragment
|
|
72
|
-
* back into the corresponding text node.
|
|
73
|
-
*
|
|
74
|
-
* `textNodes` is mutated in place.
|
|
75
|
-
*
|
|
76
|
-
* @throws Error if the transformation alters the number of text nodes
|
|
49
|
+
* separator-marking technique: appends the separator to each node's value,
|
|
50
|
+
* concatenates, transforms, then splits back on the separator and writes
|
|
51
|
+
* each fragment into the corresponding text node. Mutates `textNodes`.
|
|
77
52
|
*/
|
|
78
53
|
export function transformTextNodes(textNodes, transformFn, separator) {
|
|
79
54
|
assertSeparatorAbsent(textNodes.map((n) => n.value), separator);
|
|
@@ -90,12 +65,7 @@ export function transformTextNodes(textNodes, transformFn, separator) {
|
|
|
90
65
|
n.value = transformedFragments[index];
|
|
91
66
|
});
|
|
92
67
|
}
|
|
93
|
-
/**
|
|
94
|
-
* Validates that a transformation preserved the separator count.
|
|
95
|
-
* Throws an error if separators were added or removed.
|
|
96
|
-
*
|
|
97
|
-
* @throws Error if separator count changed
|
|
98
|
-
*/
|
|
68
|
+
/** Throws if a transformation changed the separator count. */
|
|
99
69
|
export function assertSeparatorCountPreserved(original, transformed, separator = DEFAULT_SEPARATOR, transformName = "transform") {
|
|
100
70
|
const originalCount = countSeparators(original, separator);
|
|
101
71
|
const transformedCount = countSeparators(transformed, separator);
|
|
@@ -105,12 +75,7 @@ export function assertSeparatorCountPreserved(original, transformed, separator =
|
|
|
105
75
|
`Include the input text that caused this error.`);
|
|
106
76
|
}
|
|
107
77
|
}
|
|
108
|
-
/**
|
|
109
|
-
* Returns a copy of `obj` with `undefined`-valued keys removed.
|
|
110
|
-
* Used so caller-supplied `{ foo: undefined }` doesn't override a default.
|
|
111
|
-
*
|
|
112
|
-
* @internal
|
|
113
|
-
*/
|
|
78
|
+
/** Returns a copy of `obj` with `undefined`-valued keys removed. @internal */
|
|
114
79
|
export function filterUndefined(obj) {
|
|
115
80
|
const result = {};
|
|
116
81
|
for (const [k, v] of Object.entries(obj)) {
|
|
@@ -119,27 +84,14 @@ export function filterUndefined(obj) {
|
|
|
119
84
|
}
|
|
120
85
|
return result;
|
|
121
86
|
}
|
|
122
|
-
/**
|
|
123
|
-
* Returns a deterministic JSON-style string for an options object: drops
|
|
124
|
-
* `undefined` values and sorts keys, so equivalent option sets always
|
|
125
|
-
* produce the same string (suitable as a cache or LRU key).
|
|
126
|
-
*
|
|
127
|
-
* @internal
|
|
128
|
-
*/
|
|
87
|
+
/** Deterministic JSON string for an options object, suitable as cache key. @internal */
|
|
129
88
|
export function stableStringify(obj) {
|
|
130
89
|
const entries = Object.entries(obj)
|
|
131
90
|
.filter(([, v]) => v !== undefined)
|
|
132
91
|
.sort(([a], [b]) => a.localeCompare(b));
|
|
133
92
|
return JSON.stringify(entries);
|
|
134
93
|
}
|
|
135
|
-
/**
|
|
136
|
-
* Extracts the named-groups object from a `String.prototype.replace`
|
|
137
|
-
* callback's argument tuple. The last element is always the groups
|
|
138
|
-
* object when the regex has named captures. Callers supply the group
|
|
139
|
-
* shape via the type parameter to localise the unavoidable type cast.
|
|
140
|
-
*
|
|
141
|
-
* @internal
|
|
142
|
-
*/
|
|
94
|
+
/** Extracts named groups from a `.replace()` callback's arguments. @internal */
|
|
143
95
|
export function namedGroups(args) {
|
|
144
96
|
return args[args.length - 1];
|
|
145
97
|
}
|
package/dist/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "punctilio",
|
|
3
|
-
"version": "3.11.
|
|
3
|
+
"version": "3.11.4",
|
|
4
4
|
"description": "Smart typography transformations: curly quotes, em-dashes, en-dashes, and more",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -86,12 +86,13 @@
|
|
|
86
86
|
"@types/node": "20.19.30",
|
|
87
87
|
"@types/seedrandom": "3.0.8",
|
|
88
88
|
"eslint": "9.39.2",
|
|
89
|
+
"eslint-plugin-perfectionist": "5.9.0",
|
|
89
90
|
"eslint-plugin-redos": "4.5.0",
|
|
90
91
|
"eslint-plugin-regexp": "3.1.0",
|
|
91
92
|
"hastscript": "9.0.1",
|
|
92
93
|
"jest": "29.7.0",
|
|
93
94
|
"lint-staged": "16.4.0",
|
|
94
|
-
"prettier": "3.8.
|
|
95
|
+
"prettier": "3.8.3",
|
|
95
96
|
"recheck": "4.5.0",
|
|
96
97
|
"rehype-parse": "9.0.1",
|
|
97
98
|
"rehype-stringify": "10.0.1",
|
|
@@ -104,10 +105,10 @@
|
|
|
104
105
|
"smartquotes": "2.3.2",
|
|
105
106
|
"smartypants": "0.2.2",
|
|
106
107
|
"tipograph": "0.7.4",
|
|
107
|
-
"ts-jest": "29.4.
|
|
108
|
-
"tsx": "4.
|
|
108
|
+
"ts-jest": "29.4.11",
|
|
109
|
+
"tsx": "4.22.3",
|
|
109
110
|
"typescript": "5.9.3",
|
|
110
|
-
"typescript-eslint": "8.59.
|
|
111
|
+
"typescript-eslint": "8.59.4",
|
|
111
112
|
"typograf": "7.7.0",
|
|
112
113
|
"unified": "11.0.5"
|
|
113
114
|
},
|
package/src/cli.ts
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Command-line entry point: format Markdown and HTML files in place,
|
|
4
|
-
* or check whether they would be reformatted (for use as a pre-commit hook).
|
|
5
|
-
*
|
|
6
|
-
* @packageDocumentation
|
|
7
|
-
*/
|
|
8
2
|
|
|
9
3
|
import { createHash } from "node:crypto"
|
|
10
4
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"
|
|
@@ -17,8 +11,8 @@ import { cosmiconfig } from "cosmiconfig"
|
|
|
17
11
|
import ignore, { type Ignore } from "ignore"
|
|
18
12
|
import { glob } from "tinyglobby"
|
|
19
13
|
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
14
|
+
import { type MarkdownOptions, transformMarkdown } from "./markdown.js"
|
|
15
|
+
import { type HtmlOptions, transformHtml } from "./html.js"
|
|
22
16
|
import { PUNCTUATION_STYLES, type PunctuationStyle } from "./quotes.js"
|
|
23
17
|
import { DASH_STYLES, type DashStyle } from "./dashes.js"
|
|
24
18
|
import { stableStringify } from "./utils.js"
|
|
@@ -42,11 +36,7 @@ const RULE_MARKERS = ["-", "*", "_"] as const
|
|
|
42
36
|
const MARKDOWN_EXTENSIONS = new Set([".md", ".markdown"])
|
|
43
37
|
const HTML_EXTENSIONS = new Set([".html", ".htm"])
|
|
44
38
|
|
|
45
|
-
|
|
46
|
-
* Shape of `program.opts()` after parsing. Fields named after their CLI
|
|
47
|
-
* flags (camelCased by commander). `commander.choices()` guarantees the
|
|
48
|
-
* literal types at runtime; we assert them at the boundary.
|
|
49
|
-
*/
|
|
39
|
+
// Fields match commander's camelCased flag names; .choices() guarantees literals at runtime.
|
|
50
40
|
interface ParsedFlags {
|
|
51
41
|
check?: boolean
|
|
52
42
|
cache?: boolean
|
|
@@ -147,8 +137,7 @@ function isGlobPattern(pattern: string): boolean {
|
|
|
147
137
|
return /[*?[\]{}]/.test(pattern)
|
|
148
138
|
}
|
|
149
139
|
|
|
150
|
-
// Non-glob positionals pass through as literal paths so they error loudly
|
|
151
|
-
// if missing, matching the prior behavior of `punctilio file.md`.
|
|
140
|
+
// Non-glob positionals pass through as literal paths so they error loudly if missing.
|
|
152
141
|
async function discoverFiles(
|
|
153
142
|
patterns: string[],
|
|
154
143
|
cwd: string,
|
|
@@ -213,12 +202,7 @@ function saveCache(location: string, cache: Cache): void {
|
|
|
213
202
|
writeFileSync(location, JSON.stringify(cache))
|
|
214
203
|
}
|
|
215
204
|
|
|
216
|
-
|
|
217
|
-
* Cache key for a file. Always cwd-relative so a project that moves
|
|
218
|
-
* directories (or syncs the cache file across machines via the same
|
|
219
|
-
* repo layout) keeps hitting the cache. Files outside cwd appear as
|
|
220
|
-
* `../foo.md` and still hash consistently.
|
|
221
|
-
*/
|
|
205
|
+
// cwd-relative so the cache survives directory moves and cross-machine syncs.
|
|
222
206
|
function cacheKey(filePath: string, cwd: string): string {
|
|
223
207
|
return relative(cwd, filePath)
|
|
224
208
|
}
|
|
@@ -249,12 +233,7 @@ async function transformContent(input: string, type: FileType, opts: CliOptions)
|
|
|
249
233
|
return type === "md" ? transformMarkdown(input, opts) : transformHtml(input, opts)
|
|
250
234
|
}
|
|
251
235
|
|
|
252
|
-
|
|
253
|
-
* Preserves whether the original file ends with a trailing newline.
|
|
254
|
-
* The unified pipelines for Markdown and HTML both unconditionally append
|
|
255
|
-
* one, so without this adjustment every file lacking a trailing newline
|
|
256
|
-
* would always appear as needing a rewrite.
|
|
257
|
-
*/
|
|
236
|
+
// Unified pipelines unconditionally append a trailing newline; undo if original lacked one.
|
|
258
237
|
function matchTrailingNewline(original: string, formatted: string): string {
|
|
259
238
|
const originalHas = original.endsWith("\n")
|
|
260
239
|
const formattedHas = formatted.endsWith("\n")
|
|
@@ -282,12 +261,7 @@ async function readPackageVersion(): Promise<string> {
|
|
|
282
261
|
}
|
|
283
262
|
}
|
|
284
263
|
|
|
285
|
-
/**
|
|
286
|
-
* Runs the CLI with the given arguments and I/O streams.
|
|
287
|
-
*
|
|
288
|
-
* @returns Exit code: 0 if no changes (or all changes written),
|
|
289
|
-
* 1 if `--check` saw a file that would change, 2 for usage errors.
|
|
290
|
-
*/
|
|
264
|
+
/** Returns exit code: 0 success, 1 `--check` saw changes, 2 usage error. */
|
|
291
265
|
export async function runCli(args: string[], io: CliIO): Promise<number> {
|
|
292
266
|
const version = await readPackageVersion()
|
|
293
267
|
const program = buildProgram(version, io)
|
package/src/constants.ts
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared Unicode constants and regex utilities.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
1
|
import escapeStringRegexp from "escape-string-regexp"
|
|
6
2
|
import QuickLRU from "quick-lru"
|
|
7
3
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
*/
|
|
4
|
+
export { escapeStringRegexp }
|
|
5
|
+
|
|
11
6
|
export const UNICODE_SYMBOLS = {
|
|
12
7
|
ELLIPSIS: "\u2026",
|
|
13
8
|
MULTIPLICATION: "\u00D7",
|
|
@@ -82,13 +77,7 @@ export const UNICODE_SYMBOLS = {
|
|
|
82
77
|
GREEK_QUESTION_MARK: "\u037E", // ; (visually identical to ASCII semicolon)
|
|
83
78
|
} as const
|
|
84
79
|
|
|
85
|
-
/**
|
|
86
|
-
* All terminal punctuation characters that signal a quote is "already terminated".
|
|
87
|
-
* Covers ASCII, ellipsis, punctuation ligatures, interrobang, CJK fullwidth,
|
|
88
|
-
* CJK ideographic, Arabic, and Greek question mark.
|
|
89
|
-
*
|
|
90
|
-
* Used as a regex character class fragment in quotes.ts and as a test fixture.
|
|
91
|
-
*/
|
|
80
|
+
/** All terminal punctuation chars for regex character classes (ASCII through CJK/Arabic/Greek). */
|
|
92
81
|
export const TERMINAL_PUNCTUATION = [
|
|
93
82
|
"!", "?", ".", ",", ";", ":",
|
|
94
83
|
UNICODE_SYMBOLS.ELLIPSIS,
|
|
@@ -128,13 +117,8 @@ export const DEFAULT_SEPARATOR = "\uE000\uE001"
|
|
|
128
117
|
const ESCAPED_DEFAULT_SEPARATOR = escapeStringRegexp(DEFAULT_SEPARATOR)
|
|
129
118
|
|
|
130
119
|
/**
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
* apply to the entire separator sequence (critical for multi-character
|
|
134
|
-
* separators like the default U+E000 U+E001).
|
|
135
|
-
*
|
|
136
|
-
* @param options - Object with an optional `separator` field
|
|
137
|
-
* @returns Regex-escaped separator string wrapped in `(?:...)`
|
|
120
|
+
* Regex-escaped separator wrapped in `(?:...)` so quantifiers apply to
|
|
121
|
+
* the entire multi-character sequence.
|
|
138
122
|
*/
|
|
139
123
|
export function getEscapedSeparator(options: { separator?: string }): string {
|
|
140
124
|
const escaped = options.separator
|
|
@@ -143,10 +127,7 @@ export function getEscapedSeparator(options: { separator?: string }): string {
|
|
|
143
127
|
return `(?:${escaped})`
|
|
144
128
|
}
|
|
145
129
|
|
|
146
|
-
/**
|
|
147
|
-
* Characters that have special meaning in regular expressions.
|
|
148
|
-
* Used for testing that separator escaping works correctly.
|
|
149
|
-
*/
|
|
130
|
+
/** Regex-special characters, used for testing separator escaping. */
|
|
150
131
|
export const REGEX_SPECIAL_CHARS = [".", "*", "+", "?", "^", "$", "[", "]", "\\", "|", "(", ")"] as const
|
|
151
132
|
|
|
152
133
|
/**
|
|
@@ -179,45 +160,22 @@ export function wordBoundaryEnd(escapedSeparator: string): string {
|
|
|
179
160
|
return `\\b(?!${escapedSeparator}{0,${MAX_BOUNDARY_SEPARATORS}}\\w)`
|
|
180
161
|
}
|
|
181
162
|
|
|
182
|
-
/**
|
|
183
|
-
* Pattern string for space characters (regular space, tab, non-breaking space,
|
|
184
|
-
* and narrow no-break space). Use inside regex character classes: `[${SPACE_CHARS}]`
|
|
185
|
-
*/
|
|
163
|
+
/** Space chars for regex `[...]`: regular space, tab, NBSP, NNBSP. */
|
|
186
164
|
export const SPACE_CHARS = ` \t${UNICODE_SYMBOLS.NBSP}${UNICODE_SYMBOLS.NNBSP}`
|
|
187
165
|
|
|
188
|
-
/**
|
|
189
|
-
* Pattern string for the non-breaking space characters only (NBSP and NNBSP).
|
|
190
|
-
* Use inside regex character classes: `[${NBSP_CHARS}]`. Used by patterns
|
|
191
|
-
* that need to detect existing nbsp chains without also matching plain spaces.
|
|
192
|
-
*/
|
|
166
|
+
/** Non-breaking space chars only (NBSP, NNBSP) for regex `[...]`. */
|
|
193
167
|
export const NBSP_CHARS = `${UNICODE_SYMBOLS.NBSP}${UNICODE_SYMBOLS.NNBSP}`
|
|
194
168
|
|
|
195
|
-
/**
|
|
196
|
-
* Maximum recursion depth used by the rehype and remark tree walkers.
|
|
197
|
-
* Guards against stack overflow from maliciously or accidentally deep
|
|
198
|
-
* AST nesting. Shared so both plugins behave identically.
|
|
199
|
-
*/
|
|
169
|
+
/** Max AST recursion depth; guards against stack overflow from deep nesting. */
|
|
200
170
|
export const MAX_RECURSION_DEPTH = 1000
|
|
201
171
|
|
|
202
|
-
/**
|
|
203
|
-
* Canonical issue tracker URL, referenced in user-facing error messages
|
|
204
|
-
* so there's exactly one source of truth if the repository ever moves.
|
|
205
|
-
*/
|
|
172
|
+
/** Single source of truth for issue tracker URL in error messages. */
|
|
206
173
|
export const ISSUES_URL = "https://github.com/alexander-turner/punctilio/issues"
|
|
207
174
|
|
|
208
|
-
/**
|
|
209
|
-
* LRU cache for compiled RegExp objects keyed by `pattern + '\0' + flags`.
|
|
210
|
-
* Avoids recompiling identical regexes on every function call (common
|
|
211
|
-
* when using the default separator). Capped to prevent unbounded growth.
|
|
212
|
-
*/
|
|
213
175
|
export const MAX_REGEX_CACHE_SIZE = 1000
|
|
214
176
|
const regexCache = new QuickLRU<string, RegExp>({ maxSize: MAX_REGEX_CACHE_SIZE })
|
|
215
177
|
|
|
216
|
-
/**
|
|
217
|
-
* Returns a cached RegExp for the given pattern and flags.
|
|
218
|
-
* Resets `lastIndex` before returning to prevent stale state when
|
|
219
|
-
* callers use `.test()` or `.exec()` on global-flag regexes.
|
|
220
|
-
*/
|
|
178
|
+
/** Returns a cached RegExp, resetting `lastIndex` to prevent stale global-flag state. */
|
|
221
179
|
export function cachedRegExp(pattern: string, flags: string): RegExp {
|
|
222
180
|
const key = `${pattern}\0${flags}`
|
|
223
181
|
let re = regexCache.get(key)
|
|
@@ -229,19 +187,12 @@ export function cachedRegExp(pattern: string, flags: string): RegExp {
|
|
|
229
187
|
return re
|
|
230
188
|
}
|
|
231
189
|
|
|
232
|
-
/**
|
|
233
|
-
* Returns all currently cached RegExp objects. Exported for test
|
|
234
|
-
* introspection only (e.g. ReDoS scanning every compiled pattern).
|
|
235
|
-
* @internal
|
|
236
|
-
*/
|
|
190
|
+
/** @internal */
|
|
237
191
|
export function getCachedRegExps(): RegExp[] {
|
|
238
192
|
return Array.from(regexCache.values())
|
|
239
193
|
}
|
|
240
194
|
|
|
241
|
-
/**
|
|
242
|
-
* Clears the regex cache. Exported for test isolation only.
|
|
243
|
-
* @internal
|
|
244
|
-
*/
|
|
195
|
+
/** @internal */
|
|
245
196
|
export function clearRegexCache(): void {
|
|
246
197
|
regexCache.clear()
|
|
247
198
|
}
|
package/src/dashes.ts
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Dash transformation: hyphens → em-dashes, en-dashes, minus signs.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { UNICODE_SYMBOLS, DEFAULT_SEPARATOR, LATIN_LETTERS, wordBoundaryStart, wordBoundaryEnd, getEscapedSeparator, cachedRegExp } from "./constants.js"
|
|
1
|
+
import { cachedRegExp, DEFAULT_SEPARATOR, getEscapedSeparator, LATIN_LETTERS, UNICODE_SYMBOLS, wordBoundaryEnd, wordBoundaryStart } from "./constants.js"
|
|
6
2
|
import { namedGroups } from "./utils.js"
|
|
7
3
|
|
|
8
4
|
export const DASH_STYLES = ["american", "british", "none"] as const
|
|
@@ -17,19 +13,10 @@ export interface DashOptions {
|
|
|
17
13
|
|
|
18
14
|
const { EN_DASH, EM_DASH, MINUS, LEFT_DOUBLE_QUOTE, RIGHT_DOUBLE_QUOTE, LEFT_SINGLE_QUOTE, RIGHT_SINGLE_QUOTE } = UNICODE_SYMBOLS
|
|
19
15
|
|
|
20
|
-
|
|
21
|
-
* Characters that, when preceding a number, prevent it from being
|
|
22
|
-
* treated as the start of a number range. This prevents false positives
|
|
23
|
-
* in model names like "Llama-2-7B" where "2-7" should not become "2–7".
|
|
24
|
-
*/
|
|
16
|
+
// Prevents false-positive ranges in model names like "Llama-2-7B".
|
|
25
17
|
export const numberRangeDisallowedPrefixes = ["-", EN_DASH, EM_DASH, MINUS] as const
|
|
26
18
|
|
|
27
|
-
|
|
28
|
-
* Regex character-class fragment built from {@link numberRangeDisallowedPrefixes}.
|
|
29
|
-
* Non-ASCII dashes are escaped to `\uXXXX` form so the fragment is safe to
|
|
30
|
-
* embed inside a `[...]` class regardless of the regex source encoding.
|
|
31
|
-
* Computed once at module load — the inputs are `const`.
|
|
32
|
-
*/
|
|
19
|
+
// Non-ASCII dashes escaped to \uXXXX for safe embedding in [...] classes.
|
|
33
20
|
const DISALLOWED_PREFIX_CLASS_FRAGMENT = numberRangeDisallowedPrefixes
|
|
34
21
|
.map((c) => (c === "-" ? c : `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`))
|
|
35
22
|
.join("")
|
|
@@ -185,10 +172,6 @@ export function minusReplace(text: string, options: DashOptions = {}): string {
|
|
|
185
172
|
return text
|
|
186
173
|
}
|
|
187
174
|
|
|
188
|
-
/**
|
|
189
|
-
* Convert surrounded dashes to em/en dashes.
|
|
190
|
-
* Handles patterns like "word - word" → "word—word" (Chicago) or "word – word" (Oxford).
|
|
191
|
-
*/
|
|
192
175
|
function convertParentheticalDashes(text: string, sep: string, style: DashStyle): string {
|
|
193
176
|
const localizedDash = style === "british" ? EN_DASH : EM_DASH
|
|
194
177
|
const maybeSpace = style === "british" ? " " : ""
|
|
@@ -239,13 +222,8 @@ function convertParentheticalDashes(text: string, sep: string, style: DashStyle)
|
|
|
239
222
|
return text
|
|
240
223
|
}
|
|
241
224
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
* Removes all spaces around em-dashes per Chicago Manual of Style.
|
|
245
|
-
*
|
|
246
|
-
* TODO: Handle interrupted-then-resumed speech within quotes, where Chicago
|
|
247
|
-
* allows a space after the dash: "Don't inter— Hey! Who threw that?"
|
|
248
|
-
*/
|
|
225
|
+
// TODO: Handle interrupted-then-resumed speech within quotes, where Chicago
|
|
226
|
+
// allows a space after the dash: "Don't inter— Hey! Who threw that?"
|
|
249
227
|
function normalizeEmDashSpacing(text: string, sep: string): string {
|
|
250
228
|
const escapedSep = getEscapedSeparator({ separator: sep })
|
|
251
229
|
|
|
@@ -265,7 +243,6 @@ function normalizeEmDashSpacing(text: string, sep: string): string {
|
|
|
265
243
|
return text
|
|
266
244
|
}
|
|
267
245
|
|
|
268
|
-
/** Full dash transformation. */
|
|
269
246
|
export function hyphenReplace(text: string, options: DashOptions = {}): string {
|
|
270
247
|
const sep = options.separator ?? DEFAULT_SEPARATOR
|
|
271
248
|
const style = options.dashStyle ?? "american"
|
package/src/html.ts
CHANGED
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Convenience module for HTML-to-HTML typography transformations.
|
|
3
|
-
*
|
|
4
|
-
* Provides a single function that takes HTML input and returns
|
|
5
|
-
* typographically improved HTML output.
|
|
6
|
-
*
|
|
7
|
-
* Requires `unified`, `rehype-parse`, and `rehype-stringify` to be installed.
|
|
8
|
-
*
|
|
9
|
-
* @packageDocumentation
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
1
|
import { unified } from "unified"
|
|
13
2
|
import rehypeParse from "rehype-parse"
|
|
14
3
|
import rehypeStringify from "rehype-stringify"
|
|
@@ -17,9 +6,6 @@ import QuickLRU from "quick-lru"
|
|
|
17
6
|
import { rehypePunctilio, type RehypePunctilioOptions } from "./rehype.js"
|
|
18
7
|
import { stableStringify } from "./utils.js"
|
|
19
8
|
|
|
20
|
-
/**
|
|
21
|
-
* Options for the HTML transform pipeline.
|
|
22
|
-
*/
|
|
23
9
|
export interface HtmlOptions extends RehypePunctilioOptions {
|
|
24
10
|
/**
|
|
25
11
|
* Whether to parse the input as an HTML fragment (no implicit `<html>`,
|
|
@@ -43,29 +29,11 @@ const processorCache = new QuickLRU<string, ReturnType<typeof createProcessor>>(
|
|
|
43
29
|
maxSize: MAX_PROCESSOR_CACHE_SIZE,
|
|
44
30
|
})
|
|
45
31
|
|
|
46
|
-
/**
|
|
47
|
-
* Clears the processor cache. Exported for test isolation only.
|
|
48
|
-
* @internal
|
|
49
|
-
*/
|
|
32
|
+
/** @internal */
|
|
50
33
|
export function clearProcessorCache(): void {
|
|
51
34
|
processorCache.clear()
|
|
52
35
|
}
|
|
53
36
|
|
|
54
|
-
/**
|
|
55
|
-
* Transforms HTML text with typographic improvements.
|
|
56
|
-
*
|
|
57
|
-
* Parses the input as HTML, applies punctilio typography transformations,
|
|
58
|
-
* and serializes back to HTML. The unified processor pipeline is cached
|
|
59
|
-
* and reused across calls with identical options.
|
|
60
|
-
*
|
|
61
|
-
* @example
|
|
62
|
-
* ```ts
|
|
63
|
-
* import { transformHtml } from 'punctilio/html'
|
|
64
|
-
*
|
|
65
|
-
* await transformHtml('<p>"Hello" -- world</p>')
|
|
66
|
-
* // → '<p>“Hello”—world</p>'
|
|
67
|
-
* ```
|
|
68
|
-
*/
|
|
69
37
|
export async function transformHtml(
|
|
70
38
|
input: string,
|
|
71
39
|
options: HtmlOptions = {}
|