writr 5.0.0 → 5.0.2
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 +12 -0
- package/dist/writr.d.ts +8 -1
- package/dist/writr.js +56 -17
- package/package.json +36 -29
package/README.md
CHANGED
|
@@ -68,6 +68,7 @@ plugins and working with the processor directly.
|
|
|
68
68
|
- [Methods that Emit Errors](#methods-that-emit-errors)
|
|
69
69
|
- [Error Event Examples](#error-event-examples)
|
|
70
70
|
- [Event Emitter Methods](#event-emitter-methods)
|
|
71
|
+
- [Benchmarks](#benchmarks)
|
|
71
72
|
- [ESM and Node Version Support](#esm-and-node-version-support)
|
|
72
73
|
- [Code of Conduct and Contributing](#code-of-conduct-and-contributing)
|
|
73
74
|
- [License](#license)
|
|
@@ -727,6 +728,17 @@ Since Writr extends Hookified, you have access to standard event emitter methods
|
|
|
727
728
|
|
|
728
729
|
For more information about event handling capabilities, see the [Hookified documentation](https://github.com/jaredwray/hookified).
|
|
729
730
|
|
|
731
|
+
# Benchmarks
|
|
732
|
+
|
|
733
|
+
The benchmark shows rendering performance via Sync and Async methods with caching enabled and disabled.
|
|
734
|
+
|
|
735
|
+
| name | summary | ops/sec | time/op | margin | samples |
|
|
736
|
+
|---------------------------|:---------:|----------:|----------:|:--------:|----------:|
|
|
737
|
+
| render (Sync) (cached) | 🥇 | 34K | 30µs | ±0.08% | 33K |
|
|
738
|
+
| render (Async) (cached) | -1.5% | 33K | 31µs | ±0.08% | 33K |
|
|
739
|
+
| render (Sync) | -93% | 2K | 474µs | ±0.96% | 10K |
|
|
740
|
+
| render (Async) | -93% | 2K | 481µs | ±0.96% | 10K |
|
|
741
|
+
|
|
730
742
|
# ESM and Node Version Support
|
|
731
743
|
|
|
732
744
|
This package is ESM only and tested on the current lts version and its previous. Please don't open issues for questions regarding CommonJS / ESM or previous Nodejs versions.
|
package/dist/writr.d.ts
CHANGED
|
@@ -16,6 +16,13 @@ declare class WritrCache {
|
|
|
16
16
|
set(markdown: string, value: string, options?: RenderOptions): void;
|
|
17
17
|
clear(): void;
|
|
18
18
|
hash(markdown: string, options?: RenderOptions): string;
|
|
19
|
+
/**
|
|
20
|
+
* Sanitizes render options to only include serializable properties for caching.
|
|
21
|
+
* This prevents issues with structuredClone when options contain Promises, functions, or circular references.
|
|
22
|
+
* @param {RenderOptions} [options] The render options to sanitize
|
|
23
|
+
* @returns {RenderOptions | undefined} A new object with only the known RenderOptions properties
|
|
24
|
+
*/
|
|
25
|
+
private sanitizeOptions;
|
|
19
26
|
}
|
|
20
27
|
|
|
21
28
|
/**
|
|
@@ -208,9 +215,9 @@ declare class Writr extends Hookified {
|
|
|
208
215
|
* @returns {void}
|
|
209
216
|
*/
|
|
210
217
|
saveToFileSync(filePath: string): void;
|
|
218
|
+
mergeOptions(current: WritrOptions, options: WritrOptions): WritrOptions;
|
|
211
219
|
private isCacheEnabled;
|
|
212
220
|
private createProcessor;
|
|
213
|
-
private mergeOptions;
|
|
214
221
|
private mergeRenderOptions;
|
|
215
222
|
}
|
|
216
223
|
|
package/dist/writr.js
CHANGED
|
@@ -19,11 +19,12 @@ import remarkToc from "remark-toc";
|
|
|
19
19
|
import { unified } from "unified";
|
|
20
20
|
|
|
21
21
|
// src/writr-cache.ts
|
|
22
|
-
import {
|
|
22
|
+
import { CacheableMemory } from "cacheable";
|
|
23
|
+
import { Hashery } from "hashery";
|
|
23
24
|
var WritrCache = class {
|
|
24
25
|
_store = new CacheableMemory();
|
|
25
26
|
_hashStore = new CacheableMemory();
|
|
26
|
-
_hash = new
|
|
27
|
+
_hash = new Hashery();
|
|
27
28
|
get store() {
|
|
28
29
|
return this._store;
|
|
29
30
|
}
|
|
@@ -43,15 +44,53 @@ var WritrCache = class {
|
|
|
43
44
|
this._hashStore.clear();
|
|
44
45
|
}
|
|
45
46
|
hash(markdown, options) {
|
|
46
|
-
const
|
|
47
|
+
const sanitizedOptions = this.sanitizeOptions(options);
|
|
48
|
+
const content = { markdown, options: sanitizedOptions };
|
|
47
49
|
const key = JSON.stringify(content);
|
|
48
|
-
|
|
50
|
+
const result = this._hashStore.get(key);
|
|
49
51
|
if (result) {
|
|
50
52
|
return result;
|
|
51
53
|
}
|
|
52
|
-
|
|
53
|
-
this._hashStore.set(key,
|
|
54
|
-
return
|
|
54
|
+
const hash = this._hash.toHashSync(content);
|
|
55
|
+
this._hashStore.set(key, hash);
|
|
56
|
+
return hash;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Sanitizes render options to only include serializable properties for caching.
|
|
60
|
+
* This prevents issues with structuredClone when options contain Promises, functions, or circular references.
|
|
61
|
+
* @param {RenderOptions} [options] The render options to sanitize
|
|
62
|
+
* @returns {RenderOptions | undefined} A new object with only the known RenderOptions properties
|
|
63
|
+
*/
|
|
64
|
+
sanitizeOptions(options) {
|
|
65
|
+
if (!options) {
|
|
66
|
+
return void 0;
|
|
67
|
+
}
|
|
68
|
+
const sanitized = {};
|
|
69
|
+
if (options.emoji !== void 0) {
|
|
70
|
+
sanitized.emoji = options.emoji;
|
|
71
|
+
}
|
|
72
|
+
if (options.toc !== void 0) {
|
|
73
|
+
sanitized.toc = options.toc;
|
|
74
|
+
}
|
|
75
|
+
if (options.slug !== void 0) {
|
|
76
|
+
sanitized.slug = options.slug;
|
|
77
|
+
}
|
|
78
|
+
if (options.highlight !== void 0) {
|
|
79
|
+
sanitized.highlight = options.highlight;
|
|
80
|
+
}
|
|
81
|
+
if (options.gfm !== void 0) {
|
|
82
|
+
sanitized.gfm = options.gfm;
|
|
83
|
+
}
|
|
84
|
+
if (options.math !== void 0) {
|
|
85
|
+
sanitized.math = options.math;
|
|
86
|
+
}
|
|
87
|
+
if (options.mdx !== void 0) {
|
|
88
|
+
sanitized.mdx = options.mdx;
|
|
89
|
+
}
|
|
90
|
+
if (options.caching !== void 0) {
|
|
91
|
+
sanitized.caching = options.caching;
|
|
92
|
+
}
|
|
93
|
+
return sanitized;
|
|
55
94
|
}
|
|
56
95
|
};
|
|
57
96
|
|
|
@@ -528,6 +567,16 @@ ${yamlString}---
|
|
|
528
567
|
}
|
|
529
568
|
}
|
|
530
569
|
}
|
|
570
|
+
mergeOptions(current, options) {
|
|
571
|
+
if (options.throwErrors !== void 0) {
|
|
572
|
+
current.throwErrors = options.throwErrors;
|
|
573
|
+
}
|
|
574
|
+
if (options.renderOptions) {
|
|
575
|
+
current.renderOptions ??= {};
|
|
576
|
+
this.mergeRenderOptions(current.renderOptions, options.renderOptions);
|
|
577
|
+
}
|
|
578
|
+
return current;
|
|
579
|
+
}
|
|
531
580
|
isCacheEnabled(options) {
|
|
532
581
|
if (options?.caching !== void 0) {
|
|
533
582
|
return options.caching;
|
|
@@ -563,16 +612,6 @@ ${yamlString}---
|
|
|
563
612
|
processor.use(rehypeStringify);
|
|
564
613
|
return processor;
|
|
565
614
|
}
|
|
566
|
-
mergeOptions(current, options) {
|
|
567
|
-
if (options.throwErrors !== void 0) {
|
|
568
|
-
current.throwErrors = options.throwErrors;
|
|
569
|
-
}
|
|
570
|
-
if (options.renderOptions) {
|
|
571
|
-
current.renderOptions ??= {};
|
|
572
|
-
this.mergeRenderOptions(current.renderOptions, options.renderOptions);
|
|
573
|
-
}
|
|
574
|
-
return current;
|
|
575
|
-
}
|
|
576
615
|
mergeRenderOptions(current, options) {
|
|
577
616
|
if (options.emoji !== void 0) {
|
|
578
617
|
current.emoji = options.emoji;
|
package/package.json
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "writr",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.2",
|
|
4
4
|
"description": "Markdown Rendering Simplified",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/writr.js",
|
|
7
7
|
"types": "./dist/writr.d.ts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
+
"types": "./dist/writr.d.ts",
|
|
10
11
|
"import": "./dist/writr.js"
|
|
11
12
|
}
|
|
12
13
|
},
|
|
13
|
-
"repository":
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/jaredwray/writr.git"
|
|
17
|
+
},
|
|
14
18
|
"author": "Jared Wray <me@jaredwray.com>",
|
|
15
19
|
"engines": {
|
|
16
20
|
"node": ">=20"
|
|
@@ -44,29 +48,20 @@
|
|
|
44
48
|
"react-markdown",
|
|
45
49
|
"markdown-to-react"
|
|
46
50
|
],
|
|
47
|
-
"scripts": {
|
|
48
|
-
"clean": "rimraf ./dist ./coverage ./node_modules ./pnpm-lock.yaml ./site/README.md ./site/dist",
|
|
49
|
-
"build": "rimraf ./dist && tsup src/writr.ts --format esm --dts --clean",
|
|
50
|
-
"prepare": "pnpm build",
|
|
51
|
-
"lint": "biome check --write --error-on-warnings",
|
|
52
|
-
"test": "pnpm lint && vitest run --coverage",
|
|
53
|
-
"test:ci": "biome check --error-on-warnings && vitest run --coverage",
|
|
54
|
-
"website:build": "rimraf ./site/README.md ./site/dist && npx docula build -s ./site -o ./site/dist",
|
|
55
|
-
"website:serve": "rimraf ./site/README.md ./site/dist && npx docula serve -s ./site -o ./site/dist"
|
|
56
|
-
},
|
|
57
51
|
"dependencies": {
|
|
58
|
-
"cacheable": "^2.
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
52
|
+
"cacheable": "^2.3.1",
|
|
53
|
+
"hashery": "^1.3.0",
|
|
54
|
+
"hookified": "^1.14.0",
|
|
55
|
+
"html-react-parser": "^5.2.10",
|
|
56
|
+
"js-yaml": "^4.1.1",
|
|
57
|
+
"react": "^19.2.3",
|
|
63
58
|
"rehype-highlight": "^7.0.2",
|
|
64
59
|
"rehype-katex": "^7.0.1",
|
|
65
60
|
"rehype-slug": "^6.0.0",
|
|
66
61
|
"rehype-stringify": "^10.0.1",
|
|
67
62
|
"remark-emoji": "^5.0.2",
|
|
68
63
|
"remark-gfm": "^4.0.1",
|
|
69
|
-
"remark-github-blockquote-alert": "^2.0.
|
|
64
|
+
"remark-github-blockquote-alert": "^2.0.1",
|
|
70
65
|
"remark-math": "^6.0.0",
|
|
71
66
|
"remark-mdx": "^3.1.1",
|
|
72
67
|
"remark-parse": "^11.0.0",
|
|
@@ -75,21 +70,33 @@
|
|
|
75
70
|
"unified": "^11.0.5"
|
|
76
71
|
},
|
|
77
72
|
"devDependencies": {
|
|
78
|
-
"@biomejs/biome": "^2.3.
|
|
73
|
+
"@biomejs/biome": "^2.3.10",
|
|
74
|
+
"@monstermann/tinybench-pretty-printer": "^0.3.0",
|
|
79
75
|
"@types/js-yaml": "^4.0.9",
|
|
80
|
-
"@types/node": "^
|
|
81
|
-
"@types/react": "^19.2.
|
|
82
|
-
"@vitest/coverage-v8": "^4.0.
|
|
83
|
-
"docula": "^0.31.
|
|
84
|
-
"rimraf": "^6.
|
|
85
|
-
"
|
|
86
|
-
"tsup": "^8.5.
|
|
76
|
+
"@types/node": "^25.0.3",
|
|
77
|
+
"@types/react": "^19.2.7",
|
|
78
|
+
"@vitest/coverage-v8": "^4.0.16",
|
|
79
|
+
"docula": "^0.31.1",
|
|
80
|
+
"rimraf": "^6.1.2",
|
|
81
|
+
"tinybench": "^6.0.0",
|
|
82
|
+
"tsup": "^8.5.1",
|
|
83
|
+
"tsx": "^4.21.0",
|
|
87
84
|
"typescript": "^5.9.3",
|
|
88
|
-
"vitest": "^4.0.
|
|
85
|
+
"vitest": "^4.0.16"
|
|
89
86
|
},
|
|
90
87
|
"files": [
|
|
91
88
|
"dist",
|
|
92
89
|
"README.md",
|
|
93
90
|
"LICENSE"
|
|
94
|
-
]
|
|
95
|
-
|
|
91
|
+
],
|
|
92
|
+
"scripts": {
|
|
93
|
+
"clean": "rimraf ./dist ./coverage ./node_modules ./pnpm-lock.yaml ./site/README.md ./site/dist",
|
|
94
|
+
"build": "rimraf ./dist && tsup src/writr.ts --format esm --dts --clean",
|
|
95
|
+
"lint": "biome check --write --error-on-warnings",
|
|
96
|
+
"benchmark": "tsx benchmark/benchmark.ts",
|
|
97
|
+
"test": "pnpm lint && vitest run --coverage",
|
|
98
|
+
"test:ci": "biome check --error-on-warnings && vitest run --coverage",
|
|
99
|
+
"website:build": "rimraf ./site/README.md ./site/dist && npx docula build -s ./site -o ./site/dist",
|
|
100
|
+
"website:serve": "rimraf ./site/README.md ./site/dist && npx docula serve -s ./site -o ./site/dist"
|
|
101
|
+
}
|
|
102
|
+
}
|