punctilio 3.3.7 → 3.3.8
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/markdown.d.ts +8 -0
- package/dist/markdown.d.ts.map +1 -1
- package/dist/markdown.js +43 -19
- package/dist/markdown.js.map +1 -1
- package/dist/rehype.d.ts.map +1 -1
- package/dist/rehype.js +5 -10
- package/dist/rehype.js.map +1 -1
- package/package.json +2 -1
- package/src/markdown.ts +52 -22
- package/src/rehype.ts +5 -12
- package/src/tests/markdown.test.ts +29 -1
package/dist/markdown.d.ts
CHANGED
|
@@ -28,12 +28,20 @@ export interface MarkdownOptions extends RemarkPunctilioOptions {
|
|
|
28
28
|
/** Thematic break marker. Default: "-" */
|
|
29
29
|
ruleMarker?: "-" | "*" | "_";
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Clears the processor cache. Exported for test isolation only.
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
35
|
+
export declare function clearProcessorCache(): void;
|
|
31
36
|
/**
|
|
32
37
|
* Transforms Markdown text with typographic improvements.
|
|
33
38
|
*
|
|
34
39
|
* Parses the input as Markdown, applies punctilio typography transformations
|
|
35
40
|
* (smart quotes, em-dashes, ellipses, etc.), and serializes back to Markdown.
|
|
36
41
|
*
|
|
42
|
+
* The unified processor pipeline is cached and reused across calls with
|
|
43
|
+
* identical options, avoiding redundant pipeline construction.
|
|
44
|
+
*
|
|
37
45
|
* @param input - The Markdown text to transform
|
|
38
46
|
* @param options - Configuration options for both the transform and serializer
|
|
39
47
|
* @returns The typographically improved Markdown text
|
package/dist/markdown.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,OAAO,EAAmB,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAE1E;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,sBAAsB;IAC7D;;;OAGG;IACH,cAAc,CAAC,EAAE,GAAG,GAAG,GAAG,CAAA;IAE1B;;;OAGG;IACH,YAAY,CAAC,EAAE,GAAG,GAAG,GAAG,CAAA;IAExB,yDAAyD;IACzD,YAAY,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;IAE9B,0CAA0C;IAC1C,UAAU,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;CAC7B;AAED
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,OAAO,EAAmB,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAE1E;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,sBAAsB;IAC7D;;;OAGG;IACH,cAAc,CAAC,EAAE,GAAG,GAAG,GAAG,CAAA;IAE1B;;;OAGG;IACH,YAAY,CAAC,EAAE,GAAG,GAAG,GAAG,CAAA;IAExB,yDAAyD;IACzD,YAAY,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;IAE9B,0CAA0C;IAC1C,UAAU,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;CAC7B;AAqCD;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAYjB"}
|
package/dist/markdown.js
CHANGED
|
@@ -14,26 +14,11 @@ import remarkGfm from "remark-gfm";
|
|
|
14
14
|
import remarkStringify from "remark-stringify";
|
|
15
15
|
import { remarkPunctilio } from "./remark.js";
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* Parses the input as Markdown, applies punctilio typography transformations
|
|
20
|
-
* (smart quotes, em-dashes, ellipses, etc.), and serializes back to Markdown.
|
|
21
|
-
*
|
|
22
|
-
* @param input - The Markdown text to transform
|
|
23
|
-
* @param options - Configuration options for both the transform and serializer
|
|
24
|
-
* @returns The typographically improved Markdown text
|
|
25
|
-
*
|
|
26
|
-
* @example
|
|
27
|
-
* ```ts
|
|
28
|
-
* import { transformMarkdown } from 'punctilio/markdown'
|
|
29
|
-
*
|
|
30
|
-
* await transformMarkdown('"Hello" -- world')
|
|
31
|
-
* // → '\u201CHello\u201D\u2014world'
|
|
32
|
-
* ```
|
|
17
|
+
* Creates a unified processor pipeline for Markdown typography transformations.
|
|
33
18
|
*/
|
|
34
|
-
|
|
19
|
+
function createProcessor(options) {
|
|
35
20
|
const { emphasisMarker, strongMarker, bulletMarker, ruleMarker, ...punctilioOptions } = options;
|
|
36
|
-
|
|
21
|
+
return unified()
|
|
37
22
|
.use(remarkParse)
|
|
38
23
|
.use(remarkGfm)
|
|
39
24
|
.use(remarkPunctilio, punctilioOptions)
|
|
@@ -50,7 +35,46 @@ export async function transformMarkdown(input, options = {}) {
|
|
|
50
35
|
// output is re-parsed by markdown renderers.
|
|
51
36
|
unsafe: [{ character: "]", inConstruct: "phrasing" }],
|
|
52
37
|
});
|
|
53
|
-
|
|
38
|
+
}
|
|
39
|
+
/** Cached processor and the options key it was built with. */
|
|
40
|
+
let cachedProcessor = null;
|
|
41
|
+
let cachedOptionsKey = "";
|
|
42
|
+
/**
|
|
43
|
+
* Clears the processor cache. Exported for test isolation only.
|
|
44
|
+
* @internal
|
|
45
|
+
*/
|
|
46
|
+
export function clearProcessorCache() {
|
|
47
|
+
cachedProcessor = null;
|
|
48
|
+
cachedOptionsKey = "";
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Transforms Markdown text with typographic improvements.
|
|
52
|
+
*
|
|
53
|
+
* Parses the input as Markdown, applies punctilio typography transformations
|
|
54
|
+
* (smart quotes, em-dashes, ellipses, etc.), and serializes back to Markdown.
|
|
55
|
+
*
|
|
56
|
+
* The unified processor pipeline is cached and reused across calls with
|
|
57
|
+
* identical options, avoiding redundant pipeline construction.
|
|
58
|
+
*
|
|
59
|
+
* @param input - The Markdown text to transform
|
|
60
|
+
* @param options - Configuration options for both the transform and serializer
|
|
61
|
+
* @returns The typographically improved Markdown text
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* import { transformMarkdown } from 'punctilio/markdown'
|
|
66
|
+
*
|
|
67
|
+
* await transformMarkdown('"Hello" -- world')
|
|
68
|
+
* // → '\u201CHello\u201D\u2014world'
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export async function transformMarkdown(input, options = {}) {
|
|
72
|
+
const optionsKey = JSON.stringify(Object.entries(options).sort(([a], [b]) => a.localeCompare(b)));
|
|
73
|
+
if (!cachedProcessor || cachedOptionsKey !== optionsKey) {
|
|
74
|
+
cachedProcessor = createProcessor(options);
|
|
75
|
+
cachedOptionsKey = optionsKey;
|
|
76
|
+
}
|
|
77
|
+
const result = await cachedProcessor.process(input);
|
|
54
78
|
return String(result);
|
|
55
79
|
}
|
|
56
80
|
//# sourceMappingURL=markdown.js.map
|
package/dist/markdown.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,WAAW,MAAM,cAAc,CAAA;AACtC,OAAO,SAAS,MAAM,YAAY,CAAA;AAClC,OAAO,eAAe,MAAM,kBAAkB,CAAA;AAE9C,OAAO,EAAE,eAAe,EAA+B,MAAM,aAAa,CAAA;AAyB1E
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,WAAW,MAAM,cAAc,CAAA;AACtC,OAAO,SAAS,MAAM,YAAY,CAAA;AAClC,OAAO,eAAe,MAAM,kBAAkB,CAAA;AAE9C,OAAO,EAAE,eAAe,EAA+B,MAAM,aAAa,CAAA;AAyB1E;;GAEG;AACH,SAAS,eAAe,CAAC,OAAwB;IAC/C,MAAM,EACJ,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,GAAG,gBAAgB,EACpB,GAAG,OAAO,CAAA;IAEX,OAAO,OAAO,EAAE;SACb,GAAG,CAAC,WAAW,CAAC;SAChB,GAAG,CAAC,SAAS,CAAC;SACd,GAAG,CAAC,eAAe,EAAE,gBAAgB,CAAC;SACtC,GAAG,CAAC,eAAe,EAAE;QACpB,QAAQ,EAAE,cAAc,IAAI,GAAG;QAC/B,MAAM,EAAE,YAAY,IAAI,GAAG;QAC3B,MAAM,EAAE,YAAY,IAAI,GAAG;QAC3B,IAAI,EAAE,UAAU,IAAI,GAAG;QACvB,kEAAkE;QAClE,uDAAuD;QACvD,GAAG,CAAC,UAAU,KAAK,GAAG,IAAI,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChF,sEAAsE;QACtE,sEAAsE;QACtE,6CAA6C;QAC7C,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC;KACtD,CAAC,CAAA;AACN,CAAC;AAED,8DAA8D;AAC9D,IAAI,eAAe,GAA8C,IAAI,CAAA;AACrE,IAAI,gBAAgB,GAAG,EAAE,CAAA;AAEzB;;;GAGG;AACH,MAAM,UAAU,mBAAmB;IACjC,eAAe,GAAG,IAAI,CAAA;IACtB,gBAAgB,GAAG,EAAE,CAAA;AACvB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAAa,EACb,UAA2B,EAAE;IAE7B,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAC/B,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAC/D,CAAA;IAED,IAAI,CAAC,eAAe,IAAI,gBAAgB,KAAK,UAAU,EAAE,CAAC;QACxD,eAAe,GAAG,eAAe,CAAC,OAAO,CAAC,CAAA;QAC1C,gBAAgB,GAAG,UAAU,CAAA;IAC/B,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IACnD,OAAO,MAAM,CAAC,MAAM,CAAC,CAAA;AACvB,CAAC"}
|
package/dist/rehype.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rehype.d.ts","sourceRoot":"","sources":["../src/rehype.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,MAAM,CAAA;AACpF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAI1C,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAI7D,8FAA8F;AAC9F,KAAK,gBAAgB,GAAG,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAA;AAElD,gFAAgF;AAChF,KAAK,eAAe,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;AAEhD;;GAEG;AACH,MAAM,WAAW,sBAAuB,SAAQ,gBAAgB;IAC9D;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IAEnB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CACvB;AAwCD;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,OAAO,GAAG,cAAc,EAC9B,UAAU,EAAE,gBAAgB,EAC5B,KAAK,GAAE,MAAU,GAChB,IAAI,EAAE,CAkBR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,OAAO,EACb,UAAU,GAAE,gBAA8B,GACzC,MAAM,CAIR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,GAAG,WAAW,EAC1B,KAAK,GAAE,MAAU,GAChB,IAAI,GAAG,IAAI,CAeb;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAuB1D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,OAAO,EACb,WAAW,EAAE,eAAe,EAC5B,UAAU,EAAE,gBAAgB,EAC5B,SAAS,EAAE,MAAM,EACjB,eAAe,GAAE,OAAe,GAC/B,IAAI,CAiCN;AA2ED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,OAAO,EACb,UAAU,EAAE,gBAAgB,EAC5B,KAAK,GAAE,MAAU,GAChB,OAAO,EAAE,CAsCX;AAqBD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,eAAe,CAC7B,OAAO,GAAE,sBAA2B,GACnC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"rehype.d.ts","sourceRoot":"","sources":["../src/rehype.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,MAAM,CAAA;AACpF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAI1C,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAI7D,8FAA8F;AAC9F,KAAK,gBAAgB,GAAG,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAA;AAElD,gFAAgF;AAChF,KAAK,eAAe,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;AAEhD;;GAEG;AACH,MAAM,WAAW,sBAAuB,SAAQ,gBAAgB;IAC9D;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IAEnB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CACvB;AAwCD;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,OAAO,GAAG,cAAc,EAC9B,UAAU,EAAE,gBAAgB,EAC5B,KAAK,GAAE,MAAU,GAChB,IAAI,EAAE,CAkBR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,OAAO,EACb,UAAU,GAAE,gBAA8B,GACzC,MAAM,CAIR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,GAAG,WAAW,EAC1B,KAAK,GAAE,MAAU,GAChB,IAAI,GAAG,IAAI,CAeb;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAuB1D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,OAAO,EACb,WAAW,EAAE,eAAe,EAC5B,UAAU,EAAE,gBAAgB,EAC5B,SAAS,EAAE,MAAM,EACjB,eAAe,GAAE,OAAe,GAC/B,IAAI,CAiCN;AA2ED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,OAAO,EACb,UAAU,EAAE,gBAAgB,EAC5B,KAAK,GAAE,MAAU,GAChB,OAAO,EAAE,CAsCX;AAqBD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,eAAe,CAC7B,OAAO,GAAE,sBAA2B,GACnC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CA+DzB;AAED,eAAe,eAAe,CAAA"}
|
package/dist/rehype.js
CHANGED
|
@@ -64,7 +64,7 @@ export function flattenTextNodes(node, shouldSkip, depth = 0) {
|
|
|
64
64
|
if (node.type === "text") {
|
|
65
65
|
return [node];
|
|
66
66
|
}
|
|
67
|
-
if (node.type === "element"
|
|
67
|
+
if (node.type === "element") {
|
|
68
68
|
return node.children.flatMap((child) => flattenTextNodes(child, shouldSkip, depth + 1));
|
|
69
69
|
}
|
|
70
70
|
return [];
|
|
@@ -406,25 +406,20 @@ export function rehypePunctilio(options = {}) {
|
|
|
406
406
|
return (tree) => {
|
|
407
407
|
// Track transformed elements to avoid double-processing
|
|
408
408
|
const transformed = new Set();
|
|
409
|
-
visitParents(tree, (node, ancestors) => {
|
|
410
|
-
// Only process element nodes
|
|
411
|
-
if (node.type !== "element") {
|
|
412
|
-
return;
|
|
413
|
-
}
|
|
414
|
-
const element = node;
|
|
409
|
+
visitParents(tree, "element", (node, ancestors) => {
|
|
415
410
|
// Skip if already transformed
|
|
416
|
-
if (transformed.has(
|
|
411
|
+
if (transformed.has(node)) {
|
|
417
412
|
return;
|
|
418
413
|
}
|
|
419
414
|
// Check if this node or any ancestor should be skipped
|
|
420
|
-
if (shouldSkip(
|
|
415
|
+
if (shouldSkip(node)) {
|
|
421
416
|
return;
|
|
422
417
|
}
|
|
423
418
|
if (hasAncestor(ancestors, shouldSkip)) {
|
|
424
419
|
return;
|
|
425
420
|
}
|
|
426
421
|
// Collect and transform elements with text content
|
|
427
|
-
const elementsToTransform = collectTransformableElements(
|
|
422
|
+
const elementsToTransform = collectTransformableElements(node, shouldSkip);
|
|
428
423
|
for (const elt of elementsToTransform) {
|
|
429
424
|
if (!transformed.has(elt)) {
|
|
430
425
|
transformElement(elt, transformFn, shouldSkip, separator);
|
package/dist/rehype.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rehype.js","sourceRoot":"","sources":["../src/rehype.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAEvD,OAAO,EAAE,SAAS,EAAyB,MAAM,YAAY,CAAA;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAClD,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AA8BlE,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAA;AAElF;;;GAGG;AACH,MAAM,mBAAmB,GAAG,IAAI,CAAA;AAEhC;;GAEG;AACH,SAAS,QAAQ,CAAC,IAAa,EAAE,SAAiB;IAChD,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,SAAS,CAAA;IAC7C,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9B,OAAO,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;IACvC,CAAC;IACD,iGAAiG;IACjG,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE,CAAC;QACnC,OAAO,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;IACpD,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAClB,SAAmB,EACnB,SAA2B;IAE3B,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;QACjC,IAAI,QAAQ,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAChC,OAAO,SAAS,CAAC,QAAmB,CAAC,CAAA;QACvC,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,gBAAgB,CAC9B,IAA8B,EAC9B,UAA4B,EAC5B,QAAgB,CAAC;IAEjB,IAAI,KAAK,GAAG,mBAAmB,EAAE,CAAC;QAChC,OAAO,EAAE,CAAA;IACX,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,OAAO,EAAE,CAAA;IACX,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC,CAAA;IACf,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,
|
|
1
|
+
{"version":3,"file":"rehype.js","sourceRoot":"","sources":["../src/rehype.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "punctilio",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.8",
|
|
4
4
|
"description": "Smart typography transformations: curly quotes, em-dashes, en-dashes, and more",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
6
7
|
"main": "./dist/index.js",
|
|
7
8
|
"types": "./dist/index.d.ts",
|
|
8
9
|
"exports": {
|
package/src/markdown.ts
CHANGED
|
@@ -40,27 +40,9 @@ export interface MarkdownOptions extends RemarkPunctilioOptions {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* Parses the input as Markdown, applies punctilio typography transformations
|
|
46
|
-
* (smart quotes, em-dashes, ellipses, etc.), and serializes back to Markdown.
|
|
47
|
-
*
|
|
48
|
-
* @param input - The Markdown text to transform
|
|
49
|
-
* @param options - Configuration options for both the transform and serializer
|
|
50
|
-
* @returns The typographically improved Markdown text
|
|
51
|
-
*
|
|
52
|
-
* @example
|
|
53
|
-
* ```ts
|
|
54
|
-
* import { transformMarkdown } from 'punctilio/markdown'
|
|
55
|
-
*
|
|
56
|
-
* await transformMarkdown('"Hello" -- world')
|
|
57
|
-
* // → '\u201CHello\u201D\u2014world'
|
|
58
|
-
* ```
|
|
43
|
+
* Creates a unified processor pipeline for Markdown typography transformations.
|
|
59
44
|
*/
|
|
60
|
-
|
|
61
|
-
input: string,
|
|
62
|
-
options: MarkdownOptions = {}
|
|
63
|
-
): Promise<string> {
|
|
45
|
+
function createProcessor(options: MarkdownOptions) {
|
|
64
46
|
const {
|
|
65
47
|
emphasisMarker,
|
|
66
48
|
strongMarker,
|
|
@@ -69,7 +51,7 @@ export async function transformMarkdown(
|
|
|
69
51
|
...punctilioOptions
|
|
70
52
|
} = options
|
|
71
53
|
|
|
72
|
-
|
|
54
|
+
return unified()
|
|
73
55
|
.use(remarkParse)
|
|
74
56
|
.use(remarkGfm)
|
|
75
57
|
.use(remarkPunctilio, punctilioOptions)
|
|
@@ -86,7 +68,55 @@ export async function transformMarkdown(
|
|
|
86
68
|
// output is re-parsed by markdown renderers.
|
|
87
69
|
unsafe: [{ character: "]", inConstruct: "phrasing" }],
|
|
88
70
|
})
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Cached processor and the options key it was built with. */
|
|
74
|
+
let cachedProcessor: ReturnType<typeof createProcessor> | null = null
|
|
75
|
+
let cachedOptionsKey = ""
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Clears the processor cache. Exported for test isolation only.
|
|
79
|
+
* @internal
|
|
80
|
+
*/
|
|
81
|
+
export function clearProcessorCache(): void {
|
|
82
|
+
cachedProcessor = null
|
|
83
|
+
cachedOptionsKey = ""
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Transforms Markdown text with typographic improvements.
|
|
88
|
+
*
|
|
89
|
+
* Parses the input as Markdown, applies punctilio typography transformations
|
|
90
|
+
* (smart quotes, em-dashes, ellipses, etc.), and serializes back to Markdown.
|
|
91
|
+
*
|
|
92
|
+
* The unified processor pipeline is cached and reused across calls with
|
|
93
|
+
* identical options, avoiding redundant pipeline construction.
|
|
94
|
+
*
|
|
95
|
+
* @param input - The Markdown text to transform
|
|
96
|
+
* @param options - Configuration options for both the transform and serializer
|
|
97
|
+
* @returns The typographically improved Markdown text
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts
|
|
101
|
+
* import { transformMarkdown } from 'punctilio/markdown'
|
|
102
|
+
*
|
|
103
|
+
* await transformMarkdown('"Hello" -- world')
|
|
104
|
+
* // → '\u201CHello\u201D\u2014world'
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
export async function transformMarkdown(
|
|
108
|
+
input: string,
|
|
109
|
+
options: MarkdownOptions = {}
|
|
110
|
+
): Promise<string> {
|
|
111
|
+
const optionsKey = JSON.stringify(
|
|
112
|
+
Object.entries(options).sort(([a], [b]) => a.localeCompare(b))
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
if (!cachedProcessor || cachedOptionsKey !== optionsKey) {
|
|
116
|
+
cachedProcessor = createProcessor(options)
|
|
117
|
+
cachedOptionsKey = optionsKey
|
|
118
|
+
}
|
|
89
119
|
|
|
90
|
-
const result = await
|
|
120
|
+
const result = await cachedProcessor.process(input)
|
|
91
121
|
return String(result)
|
|
92
122
|
}
|
package/src/rehype.ts
CHANGED
|
@@ -112,7 +112,7 @@ export function flattenTextNodes(
|
|
|
112
112
|
return [node]
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
if (node.type === "element"
|
|
115
|
+
if (node.type === "element") {
|
|
116
116
|
return node.children.flatMap((child) => flattenTextNodes(child, shouldSkip, depth + 1))
|
|
117
117
|
}
|
|
118
118
|
|
|
@@ -509,21 +509,14 @@ export function rehypePunctilio(
|
|
|
509
509
|
// Track transformed elements to avoid double-processing
|
|
510
510
|
const transformed = new Set<Element>()
|
|
511
511
|
|
|
512
|
-
visitParents(tree, (node, ancestors) => {
|
|
513
|
-
// Only process element nodes
|
|
514
|
-
if (node.type !== "element") {
|
|
515
|
-
return
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
const element = node as Element
|
|
519
|
-
|
|
512
|
+
visitParents(tree, "element", (node, ancestors) => {
|
|
520
513
|
// Skip if already transformed
|
|
521
|
-
if (transformed.has(
|
|
514
|
+
if (transformed.has(node)) {
|
|
522
515
|
return
|
|
523
516
|
}
|
|
524
517
|
|
|
525
518
|
// Check if this node or any ancestor should be skipped
|
|
526
|
-
if (shouldSkip(
|
|
519
|
+
if (shouldSkip(node)) {
|
|
527
520
|
return
|
|
528
521
|
}
|
|
529
522
|
if (hasAncestor(ancestors as Parent[], shouldSkip)) {
|
|
@@ -531,7 +524,7 @@ export function rehypePunctilio(
|
|
|
531
524
|
}
|
|
532
525
|
|
|
533
526
|
// Collect and transform elements with text content
|
|
534
|
-
const elementsToTransform = collectTransformableElements(
|
|
527
|
+
const elementsToTransform = collectTransformableElements(node, shouldSkip)
|
|
535
528
|
for (const elt of elementsToTransform) {
|
|
536
529
|
if (!transformed.has(elt)) {
|
|
537
530
|
transformElement(elt, transformFn, shouldSkip, separator)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from "fs"
|
|
2
2
|
import { resolve } from "path"
|
|
3
3
|
import { fileURLToPath } from "url"
|
|
4
|
-
import { transformMarkdown } from "../markdown.js"
|
|
4
|
+
import { transformMarkdown, clearProcessorCache } from "../markdown.js"
|
|
5
5
|
import { transform } from "../index.js"
|
|
6
6
|
import { UNICODE_SYMBOLS } from "../constants.js"
|
|
7
7
|
|
|
@@ -16,6 +16,10 @@ const {
|
|
|
16
16
|
} = UNICODE_SYMBOLS
|
|
17
17
|
|
|
18
18
|
describe("transformMarkdown", () => {
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
clearProcessorCache()
|
|
21
|
+
})
|
|
22
|
+
|
|
19
23
|
it("transforms basic typography", async () => {
|
|
20
24
|
const result = await transformMarkdown('"Hello," she said.', { nbsp: false })
|
|
21
25
|
expect(result.trimEnd()).toEqual(`${LDQ}Hello,${RDQ} she said.`)
|
|
@@ -92,6 +96,30 @@ describe("transformMarkdown", () => {
|
|
|
92
96
|
expect(result).toContain(LDQ)
|
|
93
97
|
})
|
|
94
98
|
|
|
99
|
+
it("reuses cached processor for identical options", async () => {
|
|
100
|
+
const opts = { punctuationStyle: "british" as const, nbsp: false }
|
|
101
|
+
const first = await transformMarkdown('"Hello."', opts)
|
|
102
|
+
const second = await transformMarkdown('"World."', opts)
|
|
103
|
+
expect(first.trimEnd()).toEqual(`${LDQ}Hello${RDQ}.`)
|
|
104
|
+
expect(second.trimEnd()).toEqual(`${LDQ}World${RDQ}.`)
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it("invalidates cache when options change", async () => {
|
|
108
|
+
const american = await transformMarkdown('"Hello."', { punctuationStyle: "american", nbsp: false })
|
|
109
|
+
const british = await transformMarkdown('"Hello."', { punctuationStyle: "british", nbsp: false })
|
|
110
|
+
expect(american.trimEnd()).toEqual(`${LDQ}Hello.${RDQ}`)
|
|
111
|
+
expect(british.trimEnd()).toEqual(`${LDQ}Hello${RDQ}.`)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it("distinguishes explicit undefined from absent options in cache key", async () => {
|
|
115
|
+
// { nbsp: undefined } overrides the default (true), disabling nbsp.
|
|
116
|
+
// The cache must not conflate this with {} which uses the default.
|
|
117
|
+
const withDefault = await transformMarkdown("Dr. Smith")
|
|
118
|
+
const withUndefined = await transformMarkdown("Dr. Smith", { nbsp: undefined })
|
|
119
|
+
expect(withDefault).toContain("\u00A0")
|
|
120
|
+
expect(withUndefined).not.toContain("\u00A0")
|
|
121
|
+
})
|
|
122
|
+
|
|
95
123
|
it("README.md prose is already typographically correct", () => {
|
|
96
124
|
const readme = readFileSync(resolve(__dirname, "../../README.md"), "utf-8")
|
|
97
125
|
const lines = readme.split("\n")
|