writr 4.1.3 → 4.1.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/README.md +129 -49
- package/dist/writr.d.ts +119 -17
- package/dist/writr.js +153 -49
- package/package.json +12 -13
package/README.md
CHANGED
|
@@ -1,21 +1,38 @@
|
|
|
1
1
|

|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Markdown Rendering Simplified
|
|
3
|
+
# Markdown Rendering Simplified
|
|
6
4
|
[](https://github.com/jaredwray/writr/actions/workflows/tests.yml)
|
|
7
5
|
[](https://github.com/jaredwray/writr/blob/master/LICENSE)
|
|
8
6
|
[](https://codecov.io/gh/jaredwray/writr)
|
|
9
7
|
[](https://npmjs.com/package/writr)
|
|
10
8
|
[](https://npmjs.com/package/writr)
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
## Table of Contents
|
|
10
|
+
# Table of Contents
|
|
14
11
|
- [Features](#features)
|
|
12
|
+
- [ESM and Node Version Support](#esm-and-node-version-support)
|
|
15
13
|
- [Getting Started](#getting-started)
|
|
16
|
-
- [
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
- [API](#api)
|
|
15
|
+
- [`new Writr(arg?: string | WritrOptions, options?: WritrOptions)`](#new-writrarg-string--writroptions-options-writroptions)
|
|
16
|
+
- [`.content`](#content)
|
|
17
|
+
- [`.body`](#body)
|
|
18
|
+
- [`.options`](#options)
|
|
19
|
+
- [`.frontmatter`](#frontmatter)
|
|
20
|
+
- [`.frontMatterRaw`](#frontmatterraw)
|
|
21
|
+
- [`.cache`](#cache)
|
|
22
|
+
- [`.engine`](#engine)
|
|
23
|
+
- [`.render(options?: RenderOptions): Promise<string>`](#renderoptions-renderoptions-promisestring)
|
|
24
|
+
- [`.renderSync(options?: RenderOptions): string`](#rendersyncoptions-renderoptions-string)
|
|
25
|
+
- [`.renderReact(options?: RenderOptions, reactOptions?: HTMLReactParserOptions): Promise<React.JSX.Element />`](#renderreactoptions-renderoptions-reactoptions-htmlreactparseroptions-promise-reactjsxelement-)
|
|
26
|
+
- [`.renderReactSync( options?: RenderOptions, reactOptions?: HTMLReactParserOptions): React.JSX.Element`](#renderreactsync-options-renderoptions-reactoptions-htmlreactparseroptions-reactjsxelement)
|
|
27
|
+
- [`.loadFromFile(filePath: string): Promise<void>`](#loadfromfilefilepath-string-promisevoid)
|
|
28
|
+
- [`.loadFromFileSync(filePath: string): void`](#loadfromfilesyncfilepath-string-void)
|
|
29
|
+
- [`.saveToFile(filePath: string): Promise<void>`](#savetofilefilepath-string-promisevoid)
|
|
30
|
+
- [`.saveToFileSync(filePath: string): void`](#savetofilesyncfilepath-string-void)
|
|
31
|
+
- [Code of Conduct and Contributing](#code-of-conduct-and-contributing)
|
|
32
|
+
- [License](#license)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# Features
|
|
19
36
|
* Removes the remark / unified complexity and easy to use.
|
|
20
37
|
* Built in caching 💥 making it render very fast when there isnt a change
|
|
21
38
|
* Frontmatter support built in by default. :tada:
|
|
@@ -29,11 +46,11 @@
|
|
|
29
46
|
* Emoji Support (remark-emoji).
|
|
30
47
|
* MDX Support (remark-mdx).
|
|
31
48
|
|
|
32
|
-
|
|
49
|
+
# ESM and Node Version Support
|
|
33
50
|
|
|
34
51
|
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. To learn more about using ESM please read this from `sindresorhus`: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
|
|
35
52
|
|
|
36
|
-
|
|
53
|
+
# Getting Started
|
|
37
54
|
|
|
38
55
|
```bash
|
|
39
56
|
> npm install writr
|
|
@@ -79,9 +96,9 @@ const writr = new Writr(`# Hello World ::-):\n\n This is a test.`, writrOptions)
|
|
|
79
96
|
const html = await writr.render(options); // <h1>Hello World ::-):</h1><p>This is a test.</p>
|
|
80
97
|
```
|
|
81
98
|
|
|
82
|
-
|
|
99
|
+
# API
|
|
83
100
|
|
|
84
|
-
|
|
101
|
+
## `new Writr(arg?: string | WritrOptions, options?: WritrOptions)`
|
|
85
102
|
|
|
86
103
|
By default the constructor takes in a markdown `string` or `WritrOptions` in the first parameter. You can also send in nothing and set the markdown via `.content` property. If you want to pass in your markdown and options you can easily do this with `new Writr('## Your Markdown Here', { ...options here})`. You can access the `WritrOptions` from the instance of Writr. Here is an example of WritrOptions.
|
|
87
104
|
|
|
@@ -102,7 +119,7 @@ const writrOptions = {
|
|
|
102
119
|
const writr = new Writr(writrOptions);
|
|
103
120
|
```
|
|
104
121
|
|
|
105
|
-
|
|
122
|
+
## `.content`
|
|
106
123
|
|
|
107
124
|
Setting the markdown content for the instance of Writr. This can be set via the constructor or directly on the instance and can even handle `frontmatter`.
|
|
108
125
|
|
|
@@ -116,60 +133,96 @@ title: Hello World
|
|
|
116
133
|
# Hello World ::-):\n\n This is a test.`;
|
|
117
134
|
```
|
|
118
135
|
|
|
119
|
-
|
|
136
|
+
## `.body`
|
|
137
|
+
|
|
138
|
+
gets the body of the markdown content. This is the content without the frontmatter.
|
|
139
|
+
|
|
140
|
+
```javascript
|
|
141
|
+
import { Writr } from 'writr';
|
|
142
|
+
const writr = new Writr();
|
|
143
|
+
writr.content = `---
|
|
144
|
+
title: Hello World
|
|
145
|
+
---
|
|
146
|
+
# Hello World ::-):\n\n This is a test.`;
|
|
147
|
+
console.log(writr.body); // '# Hello World ::-):\n\n This is a test.'
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## `.options`
|
|
120
151
|
|
|
121
152
|
Accessing the default options for this instance of Writr.
|
|
122
153
|
|
|
123
|
-
|
|
154
|
+
## `.frontmatter`
|
|
124
155
|
|
|
125
|
-
Accessing the
|
|
156
|
+
Accessing the frontmatter for this instance of Writr. This is a `Record<string, any>` and can be set via the `.content` property.
|
|
126
157
|
|
|
127
158
|
```javascript
|
|
128
159
|
import { Writr } from 'writr';
|
|
129
|
-
const writr = new Writr(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
160
|
+
const writr = new Writr();
|
|
161
|
+
writr.content = `---
|
|
162
|
+
title: Hello World
|
|
163
|
+
---
|
|
164
|
+
# Hello World ::-):\n\n This is a test.`;
|
|
165
|
+
console.log(writr.frontmatter); // { title: 'Hello World' }
|
|
134
166
|
```
|
|
135
167
|
|
|
136
|
-
|
|
168
|
+
you can also set the front matter directly like this:
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
import { Writr } from 'writr';
|
|
172
|
+
const writr = new Writr();
|
|
173
|
+
writr.frontmatter = { title: 'Hello World' };
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## `.frontMatterRaw`
|
|
177
|
+
|
|
178
|
+
Accessing the raw frontmatter for this instance of Writr. This is a `string` and can be set via the `.content` property.
|
|
179
|
+
|
|
180
|
+
```javascript
|
|
181
|
+
import { Writr } from 'writr';
|
|
182
|
+
const writr = new Writr();
|
|
183
|
+
writr.content = `---
|
|
184
|
+
title: Hello World
|
|
185
|
+
---
|
|
186
|
+
# Hello World ::-):\n\n This is a test.`;
|
|
187
|
+
console.log(writr.frontMatterRaw); // '---\ntitle: Hello World\n---'
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## `.cache`
|
|
191
|
+
|
|
192
|
+
Accessing the cache for this instance of Writr. By default this is an in memory cache and is disabled (set to false) by default. You can enable this by setting `caching: true` in the `RenderOptions` of the `WritrOptions` or when calling render passing the `RenderOptions` like here:
|
|
137
193
|
|
|
138
194
|
```javascript
|
|
139
195
|
import { Writr } from 'writr';
|
|
140
|
-
import Keyv from '@keyv/redis';
|
|
141
|
-
const keyvRedis = new Keyv('redis://user:pass@localhost:6379');
|
|
142
196
|
const writr = new Writr(`# Hello World ::-):\n\n This is a test.`);
|
|
143
|
-
|
|
197
|
+
const options = {
|
|
198
|
+
caching: true
|
|
199
|
+
}
|
|
200
|
+
const html = await writr.render(options); // <h1>Hello World ::-):</h1><p>This is a test.</p>
|
|
144
201
|
```
|
|
145
202
|
|
|
146
|
-
|
|
203
|
+
|
|
204
|
+
## `.engine`
|
|
147
205
|
|
|
148
206
|
Accessing the underlying engine for this instance of Writr. This is a `Processor<Root, Root, Root, undefined, undefined>` fro the unified `.use()` function. You can use this to add additional plugins to the engine.
|
|
149
207
|
|
|
150
|
-
|
|
208
|
+
## `.render(options?: RenderOptions): Promise<string>`
|
|
151
209
|
|
|
152
210
|
Rendering markdown to HTML. the options are based on RenderOptions. Which you can access from the Writr instance.
|
|
153
211
|
|
|
154
212
|
```javascript
|
|
155
|
-
import { Writr
|
|
213
|
+
import { Writr } from 'writr';
|
|
214
|
+
const writr = new Writr(`# Hello World ::-):\n\n This is a test.`);
|
|
215
|
+
const html = await writr.render(); // <h1>Hello World 🙂</h1><p>This is a test.</p>
|
|
156
216
|
|
|
157
|
-
|
|
217
|
+
//passing in with render options
|
|
218
|
+
const options = {
|
|
219
|
+
emoji: false
|
|
220
|
+
}
|
|
158
221
|
|
|
159
|
-
|
|
160
|
-
type RenderOptions = {
|
|
161
|
-
emoji?: boolean; // Emoji support (default: true)
|
|
162
|
-
toc?: boolean; // Table of contents generation (default: true)
|
|
163
|
-
slug?: boolean; // Slug generation (default: true)
|
|
164
|
-
highlight?: boolean; // Code highlighting (default: true)
|
|
165
|
-
gfm?: boolean; // Github flavor markdown (default: true)
|
|
166
|
-
math?: boolean; // Math support (default: true)
|
|
167
|
-
mdx?: boolean; // MDX support (default: true)
|
|
168
|
-
caching?: boolean; // Caching (default: true)
|
|
169
|
-
};
|
|
222
|
+
const html = await writr.render(options); // <h1>Hello World ::-):</h1><p>This is a test.</p>
|
|
170
223
|
```
|
|
171
224
|
|
|
172
|
-
|
|
225
|
+
## `.renderSync(options?: RenderOptions): string`
|
|
173
226
|
|
|
174
227
|
Rendering markdown to HTML synchronously. the options are based on RenderOptions. Which you can access from the Writr instance. The parameters are the same as the `.render()` function.
|
|
175
228
|
|
|
@@ -179,7 +232,7 @@ const writr = new Writr(`# Hello World ::-):\n\n This is a test.`);
|
|
|
179
232
|
const html = writr.renderSync(); // <h1>Hello World 🙂</h1><p>This is a test.</p>
|
|
180
233
|
```
|
|
181
234
|
|
|
182
|
-
|
|
235
|
+
## '.renderReact(options?: RenderOptions, reactOptions?: HTMLReactParserOptions): Promise<React.JSX.Element />'
|
|
183
236
|
|
|
184
237
|
Rendering markdown to React. The options are based on RenderOptions and now HTMLReactParserOptions from `html-react-parser`.
|
|
185
238
|
|
|
@@ -189,7 +242,7 @@ const writr = new Writr(`# Hello World ::-):\n\n This is a test.`);
|
|
|
189
242
|
const reactElement = await writr.renderReact(); // Will return a React.JSX.Element
|
|
190
243
|
```
|
|
191
244
|
|
|
192
|
-
|
|
245
|
+
## '.renderReactSync( options?: RenderOptions, reactOptions?: HTMLReactParserOptions): React.JSX.Element'
|
|
193
246
|
|
|
194
247
|
Rendering markdown to React. The options are based on RenderOptions and now HTMLReactParserOptions from `html-react-parser`.
|
|
195
248
|
|
|
@@ -199,7 +252,7 @@ const writr = new Writr(`# Hello World ::-):\n\n This is a test.`);
|
|
|
199
252
|
const reactElement = writr.renderReactSync(); // Will return a React.JSX.Element
|
|
200
253
|
```
|
|
201
254
|
|
|
202
|
-
|
|
255
|
+
## `.loadFromFile(filePath: string): Promise<void>`
|
|
203
256
|
|
|
204
257
|
Load your markdown content from a file path.
|
|
205
258
|
|
|
@@ -209,11 +262,11 @@ const writr = new Writr();
|
|
|
209
262
|
await writr.loadFromFile('path/to/file.md');
|
|
210
263
|
```
|
|
211
264
|
|
|
212
|
-
|
|
265
|
+
## `.loadFromFileSync(filePath: string): void`
|
|
213
266
|
|
|
214
267
|
Load your markdown content from a file path synchronously.
|
|
215
268
|
|
|
216
|
-
|
|
269
|
+
## `.saveToFile(filePath: string): Promise<void>`
|
|
217
270
|
|
|
218
271
|
Save your markdown and frontmatter (if included) content to a file path.
|
|
219
272
|
|
|
@@ -223,13 +276,40 @@ const writr = new Writr(`# Hello World ::-):\n\n This is a test.`);
|
|
|
223
276
|
await writr.saveToFile('path/to/file.md');
|
|
224
277
|
```
|
|
225
278
|
|
|
226
|
-
|
|
279
|
+
## `.saveToFileSync(filePath: string): void`
|
|
227
280
|
|
|
228
281
|
Save your markdown and frontmatter (if included) content to a file path synchronously.
|
|
229
282
|
|
|
230
|
-
|
|
283
|
+
# Caching On Render
|
|
284
|
+
|
|
285
|
+
Caching is built into Writr and is an in-memory cache using `CacheableMemory` from [Cacheable](https://cacheable.org). It is turned off by default and can be enabled by setting `caching: true` in the `RenderOptions` of the `WritrOptions` or when calling render passing the `RenderOptions` like here:
|
|
286
|
+
|
|
287
|
+
```javascript
|
|
288
|
+
import { Writr } from 'writr';
|
|
289
|
+
const writr = new Writr(`# Hello World ::-):\n\n This is a test.`, { renderOptions: { caching: true } });
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
or via `RenderOptions` such as:
|
|
293
|
+
|
|
294
|
+
```javascript
|
|
295
|
+
import { Writr } from 'writr';
|
|
296
|
+
const writr = new Writr(`# Hello World ::-):\n\n This is a test.`);
|
|
297
|
+
await writr.render({ caching: true});
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
If you want to set the caching options for the instance of Writr you can do so like this:
|
|
301
|
+
|
|
302
|
+
```javascript
|
|
303
|
+
// we will set the lruSize of the cache and the default ttl
|
|
304
|
+
import {Writr} from 'writr';
|
|
305
|
+
const writr = new Writr(`# Hello World ::-):\n\n This is a test.`, { renderOptions: { caching: true } });
|
|
306
|
+
writr.cache.store.lruSize = 100;
|
|
307
|
+
writr.cache.store.ttl = '5m'; // setting it to 5 minutes
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
# Code of Conduct and Contributing
|
|
231
311
|
[Code of Conduct](CODE_OF_CONDUCT.md) and [Contributing](CONTRIBUTING.md) guidelines.
|
|
232
312
|
|
|
233
|
-
|
|
313
|
+
# License
|
|
234
314
|
|
|
235
315
|
MIT © [Jared Wray](https://jaredwray.com)
|
package/dist/writr.d.ts
CHANGED
|
@@ -3,33 +3,42 @@ import * as hast from 'hast';
|
|
|
3
3
|
import * as mdast from 'mdast';
|
|
4
4
|
import React from 'react';
|
|
5
5
|
import { HTMLReactParserOptions } from 'html-react-parser';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { Hookified } from 'hookified';
|
|
7
|
+
import { CacheableMemory } from 'cacheable';
|
|
8
8
|
|
|
9
9
|
declare class WritrCache {
|
|
10
|
-
private
|
|
11
|
-
private readonly _markdownStoreSync;
|
|
10
|
+
private readonly _store;
|
|
12
11
|
private readonly _hashStore;
|
|
13
|
-
get
|
|
14
|
-
get markdownStoreSync(): CacheableMemory;
|
|
12
|
+
get store(): CacheableMemory;
|
|
15
13
|
get hashStore(): CacheableMemory;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
setMarkdownSync(markdown: string, value: string, options?: RenderOptions): boolean;
|
|
20
|
-
get(key: string): Promise<string | undefined>;
|
|
21
|
-
getSync(key: string): string | undefined;
|
|
22
|
-
set(key: string, value: string): Promise<boolean>;
|
|
23
|
-
setSync(key: string, value: string): boolean;
|
|
24
|
-
clear(): Promise<void>;
|
|
25
|
-
setStorageAdapter(adapter: KeyvStoreAdapter): void;
|
|
14
|
+
get(markdown: string, options?: RenderOptions): string | undefined;
|
|
15
|
+
set(markdown: string, value: string, options?: RenderOptions): void;
|
|
16
|
+
clear(): void;
|
|
26
17
|
hash(markdown: string, options?: RenderOptions): string;
|
|
27
18
|
}
|
|
28
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Writr options.
|
|
22
|
+
* @typedef {Object} WritrOptions
|
|
23
|
+
* @property {string} [openai] - Openai api key (default: undefined)
|
|
24
|
+
* @property {RenderOptions} [renderOptions] - Default render options (default: undefined)
|
|
25
|
+
*/
|
|
29
26
|
type WritrOptions = {
|
|
30
27
|
openai?: string;
|
|
31
28
|
renderOptions?: RenderOptions;
|
|
32
29
|
};
|
|
30
|
+
/**
|
|
31
|
+
* Render options.
|
|
32
|
+
* @typedef {Object} RenderOptions
|
|
33
|
+
* @property {boolean} [emoji] - Emoji support (default: true)
|
|
34
|
+
* @property {boolean} [toc] - Table of contents generation (default: true)
|
|
35
|
+
* @property {boolean} [slug] - Slug generation (default: true)
|
|
36
|
+
* @property {boolean} [highlight] - Code highlighting (default: true)
|
|
37
|
+
* @property {boolean} [gfm] - Github flavor markdown (default: true)
|
|
38
|
+
* @property {boolean} [math] - Math support (default: true)
|
|
39
|
+
* @property {boolean} [mdx] - MDX support (default: true)
|
|
40
|
+
* @property {boolean} [caching] - Caching (default: true)
|
|
41
|
+
*/
|
|
33
42
|
type RenderOptions = {
|
|
34
43
|
emoji?: boolean;
|
|
35
44
|
toc?: boolean;
|
|
@@ -40,32 +49,125 @@ type RenderOptions = {
|
|
|
40
49
|
mdx?: boolean;
|
|
41
50
|
caching?: boolean;
|
|
42
51
|
};
|
|
43
|
-
declare class Writr {
|
|
52
|
+
declare class Writr extends Hookified {
|
|
44
53
|
engine: unified.Processor<mdast.Root, mdast.Root, hast.Root, hast.Root, string>;
|
|
45
54
|
private readonly _options;
|
|
46
55
|
private _content;
|
|
47
56
|
private readonly _cache;
|
|
57
|
+
/**
|
|
58
|
+
* Initialize Writr. Accepts a string or options object.
|
|
59
|
+
* @param {string | WritrOptions} [arguments1] If you send in a string, it will be used as the markdown content. If you send in an object, it will be used as the options.
|
|
60
|
+
* @param {WritrOptions} [arguments2] This is if you send in the content in the first argument and also want to send in options.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* const writr = new Writr('Hello, world!', {caching: false});
|
|
64
|
+
*/
|
|
48
65
|
constructor(arguments1?: string | WritrOptions, arguments2?: WritrOptions);
|
|
66
|
+
/**
|
|
67
|
+
* Get the options.
|
|
68
|
+
* @type {WritrOptions}
|
|
69
|
+
*/
|
|
49
70
|
get options(): WritrOptions;
|
|
71
|
+
/**
|
|
72
|
+
* Get the Content. This is the markdown content and front matter if it exists.
|
|
73
|
+
* @type {WritrOptions}
|
|
74
|
+
*/
|
|
50
75
|
get content(): string;
|
|
76
|
+
/**
|
|
77
|
+
* Set the Content. This is the markdown content and front matter if it exists.
|
|
78
|
+
* @type {WritrOptions}
|
|
79
|
+
*/
|
|
51
80
|
set content(value: string);
|
|
81
|
+
/**
|
|
82
|
+
* Get the cache.
|
|
83
|
+
* @type {WritrCache}
|
|
84
|
+
*/
|
|
52
85
|
get cache(): WritrCache;
|
|
86
|
+
/**
|
|
87
|
+
* Get the front matter raw content.
|
|
88
|
+
* @type {string} The front matter content including the delimiters.
|
|
89
|
+
*/
|
|
53
90
|
get frontMatterRaw(): string;
|
|
91
|
+
/**
|
|
92
|
+
* Get the body content without the front matter.
|
|
93
|
+
* @type {string} The markdown content without the front matter.
|
|
94
|
+
*/
|
|
54
95
|
get body(): string;
|
|
96
|
+
/**
|
|
97
|
+
* Get the markdown content. This is an alias for the body property.
|
|
98
|
+
* @type {string} The markdown content.
|
|
99
|
+
*/
|
|
55
100
|
get markdown(): string;
|
|
101
|
+
/**
|
|
102
|
+
* Get the front matter content as an object.
|
|
103
|
+
* @type {Record<string, any>} The front matter content as an object.
|
|
104
|
+
*/
|
|
56
105
|
get frontMatter(): Record<string, any>;
|
|
106
|
+
/**
|
|
107
|
+
* Set the front matter content as an object.
|
|
108
|
+
* @type {Record<string, any>} The front matter content as an object.
|
|
109
|
+
*/
|
|
57
110
|
set frontMatter(data: Record<string, any>);
|
|
111
|
+
/**
|
|
112
|
+
* Get the front matter value for a key.
|
|
113
|
+
* @param {string} key The key to get the value for.
|
|
114
|
+
* @returns {T} The value for the key.
|
|
115
|
+
*/
|
|
58
116
|
getFrontMatterValue<T>(key: string): T;
|
|
117
|
+
/**
|
|
118
|
+
* Render the markdown content to HTML.
|
|
119
|
+
* @param {RenderOptions} [options] The render options.
|
|
120
|
+
* @returns {Promise<string>} The rendered HTML content.
|
|
121
|
+
*/
|
|
59
122
|
render(options?: RenderOptions): Promise<string>;
|
|
123
|
+
/**
|
|
124
|
+
* Render the markdown content to HTML synchronously.
|
|
125
|
+
* @param {RenderOptions} [options] The render options.
|
|
126
|
+
* @returns {string} The rendered HTML content.
|
|
127
|
+
*/
|
|
60
128
|
renderSync(options?: RenderOptions): string;
|
|
129
|
+
/**
|
|
130
|
+
* Render the markdown content to React.
|
|
131
|
+
* @param {RenderOptions} [options] The render options.
|
|
132
|
+
* @param {HTMLReactParserOptions} [reactParseOptions] The HTML React parser options.
|
|
133
|
+
* @returns {Promise<string | React.JSX.Element | React.JSX.Element[]>} The rendered React content.
|
|
134
|
+
*/
|
|
61
135
|
renderReact(options?: RenderOptions, reactParseOptions?: HTMLReactParserOptions): Promise<string | React.JSX.Element | React.JSX.Element[]>;
|
|
136
|
+
/**
|
|
137
|
+
* Render the markdown content to React synchronously.
|
|
138
|
+
* @param {RenderOptions} [options] The render options.
|
|
139
|
+
* @param {HTMLReactParserOptions} [reactParseOptions] The HTML React parser options.
|
|
140
|
+
* @returns {string | React.JSX.Element | React.JSX.Element[]} The rendered React content.
|
|
141
|
+
*/
|
|
62
142
|
renderReactSync(options?: RenderOptions, reactParseOptions?: HTMLReactParserOptions): string | React.JSX.Element | React.JSX.Element[];
|
|
143
|
+
/**
|
|
144
|
+
* Load markdown content from a file.
|
|
145
|
+
* @param {string} filePath The file path to load the markdown content from.
|
|
146
|
+
* @returns {Promise<void>}
|
|
147
|
+
*/
|
|
63
148
|
loadFromFile(filePath: string): Promise<void>;
|
|
149
|
+
/**
|
|
150
|
+
* Load markdown content from a file synchronously.
|
|
151
|
+
* @param {string} filePath The file path to load the markdown content from.
|
|
152
|
+
* @returns {void}
|
|
153
|
+
*/
|
|
64
154
|
loadFromFileSync(filePath: string): void;
|
|
155
|
+
/**
|
|
156
|
+
* Save the markdown content to a file. If the directory doesn't exist it will be created.
|
|
157
|
+
* @param {string} filePath The file path to save the markdown content to.
|
|
158
|
+
* @returns {Promise<void>}
|
|
159
|
+
*/
|
|
65
160
|
saveToFile(filePath: string): Promise<void>;
|
|
161
|
+
/**
|
|
162
|
+
* Save the markdown content to a file synchronously. If the directory doesn't exist it will be created.
|
|
163
|
+
* @param {string} filePath The file path to save the markdown content to.
|
|
164
|
+
* @returns {void}
|
|
165
|
+
*/
|
|
66
166
|
saveToFileSync(filePath: string): void;
|
|
67
167
|
private isCacheEnabled;
|
|
68
168
|
private createProcessor;
|
|
169
|
+
private mergeOptions;
|
|
170
|
+
private mergeRenderOptions;
|
|
69
171
|
}
|
|
70
172
|
|
|
71
173
|
export { type RenderOptions, Writr, type WritrOptions };
|
package/dist/writr.js
CHANGED
|
@@ -15,60 +15,31 @@ import remarkEmoji from "remark-emoji";
|
|
|
15
15
|
import remarkMDX from "remark-mdx";
|
|
16
16
|
import parse from "html-react-parser";
|
|
17
17
|
import * as yaml from "js-yaml";
|
|
18
|
+
import { Hookified } from "hookified";
|
|
18
19
|
|
|
19
20
|
// src/writr-cache.ts
|
|
20
|
-
import {
|
|
21
|
+
import { CacheableMemory } from "cacheable";
|
|
21
22
|
var WritrCache = class {
|
|
22
|
-
|
|
23
|
-
_markdownStoreSync = new CacheableMemory();
|
|
23
|
+
_store = new CacheableMemory();
|
|
24
24
|
_hashStore = new CacheableMemory();
|
|
25
|
-
get
|
|
26
|
-
return this.
|
|
27
|
-
}
|
|
28
|
-
get markdownStoreSync() {
|
|
29
|
-
return this._markdownStoreSync;
|
|
25
|
+
get store() {
|
|
26
|
+
return this._store;
|
|
30
27
|
}
|
|
31
28
|
get hashStore() {
|
|
32
29
|
return this._hashStore;
|
|
33
30
|
}
|
|
34
|
-
|
|
35
|
-
const key = this.hash(markdown, options);
|
|
36
|
-
return this.get(key);
|
|
37
|
-
}
|
|
38
|
-
getMarkdownSync(markdown, options) {
|
|
31
|
+
get(markdown, options) {
|
|
39
32
|
const key = this.hash(markdown, options);
|
|
40
|
-
return this.
|
|
33
|
+
return this._store.get(key);
|
|
41
34
|
}
|
|
42
|
-
|
|
35
|
+
set(markdown, value, options) {
|
|
43
36
|
const key = this.hash(markdown, options);
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
setMarkdownSync(markdown, value, options) {
|
|
47
|
-
const key = this.hash(markdown, options);
|
|
48
|
-
this.setSync(key, value);
|
|
49
|
-
return true;
|
|
50
|
-
}
|
|
51
|
-
async get(key) {
|
|
52
|
-
return this._markdownStore.get(key);
|
|
37
|
+
this._store.set(key, value);
|
|
53
38
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
async set(key, value) {
|
|
58
|
-
return this._markdownStore.set(key, value);
|
|
59
|
-
}
|
|
60
|
-
setSync(key, value) {
|
|
61
|
-
this._markdownStoreSync.set(key, value);
|
|
62
|
-
return true;
|
|
63
|
-
}
|
|
64
|
-
async clear() {
|
|
65
|
-
await this._markdownStore.clear();
|
|
66
|
-
this._markdownStoreSync.clear();
|
|
39
|
+
clear() {
|
|
40
|
+
this._store.clear();
|
|
67
41
|
this._hashStore.clear();
|
|
68
42
|
}
|
|
69
|
-
setStorageAdapter(adapter) {
|
|
70
|
-
this._markdownStore = new Cacheable({ primary: adapter });
|
|
71
|
-
}
|
|
72
43
|
hash(markdown, options) {
|
|
73
44
|
const content = { markdown, options };
|
|
74
45
|
const key = JSON.stringify(content);
|
|
@@ -83,7 +54,7 @@ var WritrCache = class {
|
|
|
83
54
|
};
|
|
84
55
|
|
|
85
56
|
// src/writr.ts
|
|
86
|
-
var Writr = class {
|
|
57
|
+
var Writr = class extends Hookified {
|
|
87
58
|
engine = unified().use(remarkParse).use(remarkGfm).use(remarkToc).use(remarkEmoji).use(remarkRehype).use(rehypeSlug).use(remarkMath).use(rehypeKatex).use(rehypeHighlight).use(remarkMDX).use(rehypeStringify);
|
|
88
59
|
// Stringify HTML
|
|
89
60
|
_options = {
|
|
@@ -96,39 +67,68 @@ var Writr = class {
|
|
|
96
67
|
gfm: true,
|
|
97
68
|
math: true,
|
|
98
69
|
mdx: true,
|
|
99
|
-
caching:
|
|
70
|
+
caching: false
|
|
100
71
|
}
|
|
101
72
|
};
|
|
102
73
|
_content = "";
|
|
103
74
|
_cache = new WritrCache();
|
|
75
|
+
/**
|
|
76
|
+
* Initialize Writr. Accepts a string or options object.
|
|
77
|
+
* @param {string | WritrOptions} [arguments1] If you send in a string, it will be used as the markdown content. If you send in an object, it will be used as the options.
|
|
78
|
+
* @param {WritrOptions} [arguments2] This is if you send in the content in the first argument and also want to send in options.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* const writr = new Writr('Hello, world!', {caching: false});
|
|
82
|
+
*/
|
|
104
83
|
constructor(arguments1, arguments2) {
|
|
84
|
+
super();
|
|
105
85
|
if (typeof arguments1 === "string") {
|
|
106
86
|
this._content = arguments1;
|
|
107
87
|
} else if (arguments1) {
|
|
108
|
-
this._options =
|
|
88
|
+
this._options = this.mergeOptions(this._options, arguments1);
|
|
109
89
|
if (this._options.renderOptions) {
|
|
110
90
|
this.engine = this.createProcessor(this._options.renderOptions);
|
|
111
91
|
}
|
|
112
92
|
}
|
|
113
93
|
if (arguments2) {
|
|
114
|
-
this._options =
|
|
94
|
+
this._options = this.mergeOptions(this._options, arguments2);
|
|
115
95
|
if (this._options.renderOptions) {
|
|
116
96
|
this.engine = this.createProcessor(this._options.renderOptions);
|
|
117
97
|
}
|
|
118
98
|
}
|
|
119
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Get the options.
|
|
102
|
+
* @type {WritrOptions}
|
|
103
|
+
*/
|
|
120
104
|
get options() {
|
|
121
105
|
return this._options;
|
|
122
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Get the Content. This is the markdown content and front matter if it exists.
|
|
109
|
+
* @type {WritrOptions}
|
|
110
|
+
*/
|
|
123
111
|
get content() {
|
|
124
112
|
return this._content;
|
|
125
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Set the Content. This is the markdown content and front matter if it exists.
|
|
116
|
+
* @type {WritrOptions}
|
|
117
|
+
*/
|
|
126
118
|
set content(value) {
|
|
127
119
|
this._content = value;
|
|
128
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Get the cache.
|
|
123
|
+
* @type {WritrCache}
|
|
124
|
+
*/
|
|
129
125
|
get cache() {
|
|
130
126
|
return this._cache;
|
|
131
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Get the front matter raw content.
|
|
130
|
+
* @type {string} The front matter content including the delimiters.
|
|
131
|
+
*/
|
|
132
132
|
get frontMatterRaw() {
|
|
133
133
|
if (!this._content.trimStart().startsWith("---")) {
|
|
134
134
|
return "";
|
|
@@ -140,6 +140,10 @@ var Writr = class {
|
|
|
140
140
|
}
|
|
141
141
|
return this._content.slice(start, end + 5);
|
|
142
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* Get the body content without the front matter.
|
|
145
|
+
* @type {string} The markdown content without the front matter.
|
|
146
|
+
*/
|
|
143
147
|
get body() {
|
|
144
148
|
if (this.frontMatterRaw === "") {
|
|
145
149
|
return this._content;
|
|
@@ -147,17 +151,33 @@ var Writr = class {
|
|
|
147
151
|
const end = this._content.indexOf("\n---\n");
|
|
148
152
|
return this._content.slice(Math.max(0, end + 5)).trim();
|
|
149
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* Get the markdown content. This is an alias for the body property.
|
|
156
|
+
* @type {string} The markdown content.
|
|
157
|
+
*/
|
|
150
158
|
get markdown() {
|
|
151
159
|
return this.body;
|
|
152
160
|
}
|
|
161
|
+
/**
|
|
162
|
+
* Get the front matter content as an object.
|
|
163
|
+
* @type {Record<string, any>} The front matter content as an object.
|
|
164
|
+
*/
|
|
153
165
|
get frontMatter() {
|
|
154
166
|
const frontMatter = this.frontMatterRaw;
|
|
155
167
|
const match = /^---\s*([\s\S]*?)\s*---\s*/.exec(frontMatter);
|
|
156
168
|
if (match) {
|
|
157
|
-
|
|
169
|
+
try {
|
|
170
|
+
return yaml.load(match[1].trim());
|
|
171
|
+
} catch (error) {
|
|
172
|
+
this.emit("error", error);
|
|
173
|
+
}
|
|
158
174
|
}
|
|
159
175
|
return {};
|
|
160
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* Set the front matter content as an object.
|
|
179
|
+
* @type {Record<string, any>} The front matter content as an object.
|
|
180
|
+
*/
|
|
161
181
|
set frontMatter(data) {
|
|
162
182
|
const frontMatter = this.frontMatterRaw;
|
|
163
183
|
const yamlString = yaml.dump(data);
|
|
@@ -166,14 +186,24 @@ ${yamlString}---
|
|
|
166
186
|
`;
|
|
167
187
|
this._content = this._content.replace(frontMatter, newFrontMatter);
|
|
168
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* Get the front matter value for a key.
|
|
191
|
+
* @param {string} key The key to get the value for.
|
|
192
|
+
* @returns {T} The value for the key.
|
|
193
|
+
*/
|
|
169
194
|
getFrontMatterValue(key) {
|
|
170
195
|
return this.frontMatter[key];
|
|
171
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* Render the markdown content to HTML.
|
|
199
|
+
* @param {RenderOptions} [options] The render options.
|
|
200
|
+
* @returns {Promise<string>} The rendered HTML content.
|
|
201
|
+
*/
|
|
172
202
|
async render(options) {
|
|
173
203
|
try {
|
|
174
204
|
let result = "";
|
|
175
205
|
if (this.isCacheEnabled(options)) {
|
|
176
|
-
const cached =
|
|
206
|
+
const cached = this._cache.get(this._content, options);
|
|
177
207
|
if (cached) {
|
|
178
208
|
return cached;
|
|
179
209
|
}
|
|
@@ -186,18 +216,23 @@ ${yamlString}---
|
|
|
186
216
|
const file = await engine.process(this.body);
|
|
187
217
|
result = String(file);
|
|
188
218
|
if (this.isCacheEnabled(options)) {
|
|
189
|
-
|
|
219
|
+
this._cache.set(this._content, result, options);
|
|
190
220
|
}
|
|
191
221
|
return result;
|
|
192
222
|
} catch (error) {
|
|
193
223
|
throw new Error(`Failed to render markdown: ${error.message}`);
|
|
194
224
|
}
|
|
195
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* Render the markdown content to HTML synchronously.
|
|
228
|
+
* @param {RenderOptions} [options] The render options.
|
|
229
|
+
* @returns {string} The rendered HTML content.
|
|
230
|
+
*/
|
|
196
231
|
renderSync(options) {
|
|
197
232
|
try {
|
|
198
233
|
let result = "";
|
|
199
234
|
if (this.isCacheEnabled(options)) {
|
|
200
|
-
const cached = this._cache.
|
|
235
|
+
const cached = this._cache.get(this._content, options);
|
|
201
236
|
if (cached) {
|
|
202
237
|
return cached;
|
|
203
238
|
}
|
|
@@ -210,34 +245,66 @@ ${yamlString}---
|
|
|
210
245
|
const file = engine.processSync(this.body);
|
|
211
246
|
result = String(file);
|
|
212
247
|
if (this.isCacheEnabled(options)) {
|
|
213
|
-
this._cache.
|
|
248
|
+
this._cache.set(this._content, result, options);
|
|
214
249
|
}
|
|
215
250
|
return result;
|
|
216
251
|
} catch (error) {
|
|
217
252
|
throw new Error(`Failed to render markdown: ${error.message}`);
|
|
218
253
|
}
|
|
219
254
|
}
|
|
255
|
+
/**
|
|
256
|
+
* Render the markdown content to React.
|
|
257
|
+
* @param {RenderOptions} [options] The render options.
|
|
258
|
+
* @param {HTMLReactParserOptions} [reactParseOptions] The HTML React parser options.
|
|
259
|
+
* @returns {Promise<string | React.JSX.Element | React.JSX.Element[]>} The rendered React content.
|
|
260
|
+
*/
|
|
220
261
|
async renderReact(options, reactParseOptions) {
|
|
221
262
|
const html = await this.render(options);
|
|
222
263
|
return parse(html, reactParseOptions);
|
|
223
264
|
}
|
|
265
|
+
/**
|
|
266
|
+
* Render the markdown content to React synchronously.
|
|
267
|
+
* @param {RenderOptions} [options] The render options.
|
|
268
|
+
* @param {HTMLReactParserOptions} [reactParseOptions] The HTML React parser options.
|
|
269
|
+
* @returns {string | React.JSX.Element | React.JSX.Element[]} The rendered React content.
|
|
270
|
+
*/
|
|
224
271
|
renderReactSync(options, reactParseOptions) {
|
|
225
272
|
const html = this.renderSync(options);
|
|
226
273
|
return parse(html, reactParseOptions);
|
|
227
274
|
}
|
|
275
|
+
/**
|
|
276
|
+
* Load markdown content from a file.
|
|
277
|
+
* @param {string} filePath The file path to load the markdown content from.
|
|
278
|
+
* @returns {Promise<void>}
|
|
279
|
+
*/
|
|
228
280
|
async loadFromFile(filePath) {
|
|
229
281
|
const { readFile } = fs.promises;
|
|
230
282
|
this._content = await readFile(filePath, "utf8");
|
|
231
283
|
}
|
|
284
|
+
/**
|
|
285
|
+
* Load markdown content from a file synchronously.
|
|
286
|
+
* @param {string} filePath The file path to load the markdown content from.
|
|
287
|
+
* @returns {void}
|
|
288
|
+
*/
|
|
232
289
|
loadFromFileSync(filePath) {
|
|
233
290
|
this._content = fs.readFileSync(filePath, "utf8");
|
|
234
291
|
}
|
|
292
|
+
/**
|
|
293
|
+
* Save the markdown content to a file. If the directory doesn't exist it will be created.
|
|
294
|
+
* @param {string} filePath The file path to save the markdown content to.
|
|
295
|
+
* @returns {Promise<void>}
|
|
296
|
+
*/
|
|
235
297
|
async saveToFile(filePath) {
|
|
236
298
|
const { writeFile, mkdir } = fs.promises;
|
|
237
299
|
const directoryPath = dirname(filePath);
|
|
238
300
|
await mkdir(directoryPath, { recursive: true });
|
|
239
301
|
await writeFile(filePath, this._content, "utf8");
|
|
240
302
|
}
|
|
303
|
+
/**
|
|
304
|
+
* Save the markdown content to a file synchronously. If the directory doesn't exist it will be created.
|
|
305
|
+
* @param {string} filePath The file path to save the markdown content to.
|
|
306
|
+
* @returns {void}
|
|
307
|
+
*/
|
|
241
308
|
saveToFileSync(filePath) {
|
|
242
309
|
const directoryPath = dirname(filePath);
|
|
243
310
|
fs.mkdirSync(directoryPath, { recursive: true });
|
|
@@ -276,6 +343,43 @@ ${yamlString}---
|
|
|
276
343
|
processor.use(rehypeStringify);
|
|
277
344
|
return processor;
|
|
278
345
|
}
|
|
346
|
+
mergeOptions(current, options) {
|
|
347
|
+
if (options.openai) {
|
|
348
|
+
current.openai = options.openai;
|
|
349
|
+
}
|
|
350
|
+
if (options.renderOptions) {
|
|
351
|
+
current.renderOptions ??= {};
|
|
352
|
+
this.mergeRenderOptions(current.renderOptions, options.renderOptions);
|
|
353
|
+
}
|
|
354
|
+
return current;
|
|
355
|
+
}
|
|
356
|
+
mergeRenderOptions(current, options) {
|
|
357
|
+
if (options.emoji !== void 0) {
|
|
358
|
+
current.emoji = options.emoji;
|
|
359
|
+
}
|
|
360
|
+
if (options.toc !== void 0) {
|
|
361
|
+
current.toc = options.toc;
|
|
362
|
+
}
|
|
363
|
+
if (options.slug !== void 0) {
|
|
364
|
+
current.slug = options.slug;
|
|
365
|
+
}
|
|
366
|
+
if (options.highlight !== void 0) {
|
|
367
|
+
current.highlight = options.highlight;
|
|
368
|
+
}
|
|
369
|
+
if (options.gfm !== void 0) {
|
|
370
|
+
current.gfm = options.gfm;
|
|
371
|
+
}
|
|
372
|
+
if (options.math !== void 0) {
|
|
373
|
+
current.math = options.math;
|
|
374
|
+
}
|
|
375
|
+
if (options.mdx !== void 0) {
|
|
376
|
+
current.mdx = options.mdx;
|
|
377
|
+
}
|
|
378
|
+
if (options.caching !== void 0) {
|
|
379
|
+
current.caching = options.caching;
|
|
380
|
+
}
|
|
381
|
+
return current;
|
|
382
|
+
}
|
|
279
383
|
};
|
|
280
384
|
export {
|
|
281
385
|
Writr
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "writr",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.4",
|
|
4
4
|
"description": "Markdown Rendering Simplified",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/writr.js",
|
|
@@ -53,36 +53,35 @@
|
|
|
53
53
|
"website:serve": "rimraf ./site/README.md ./site/dist && npx docula serve -s ./site -o ./site/dist"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"cacheable": "^1.8.
|
|
56
|
+
"cacheable": "^1.8.2",
|
|
57
|
+
"hookified": "^1.5.0",
|
|
57
58
|
"html-react-parser": "^5.1.18",
|
|
58
59
|
"js-yaml": "^4.1.0",
|
|
59
|
-
"keyv": "^5.1.0",
|
|
60
60
|
"react": "^18.3.1",
|
|
61
|
-
"rehype-highlight": "^7.0.
|
|
61
|
+
"rehype-highlight": "^7.0.1",
|
|
62
62
|
"rehype-katex": "^7.0.1",
|
|
63
63
|
"rehype-slug": "^6.0.0",
|
|
64
64
|
"rehype-stringify": "^10.0.1",
|
|
65
65
|
"remark-emoji": "^5.0.1",
|
|
66
66
|
"remark-gfm": "^4.0.0",
|
|
67
67
|
"remark-math": "^6.0.0",
|
|
68
|
-
"remark-mdx": "^3.0
|
|
68
|
+
"remark-mdx": "^3.1.0",
|
|
69
69
|
"remark-parse": "^11.0.0",
|
|
70
70
|
"remark-rehype": "^11.1.1",
|
|
71
71
|
"remark-toc": "^9.0.0",
|
|
72
72
|
"unified": "^11.0.5"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
|
-
"@keyv/sqlite": "^4.0.1",
|
|
76
75
|
"@types/js-yaml": "^4.0.9",
|
|
77
|
-
"@types/node": "^22.
|
|
78
|
-
"@types/react": "^18.3.
|
|
79
|
-
"@vitest/coverage-v8": "^2.1.
|
|
80
|
-
"docula": "^0.9.
|
|
76
|
+
"@types/node": "^22.8.4",
|
|
77
|
+
"@types/react": "^18.3.12",
|
|
78
|
+
"@vitest/coverage-v8": "^2.1.4",
|
|
79
|
+
"docula": "^0.9.4",
|
|
81
80
|
"rimraf": "^6.0.1",
|
|
82
81
|
"ts-node": "^10.9.2",
|
|
83
|
-
"tsup": "^8.3.
|
|
84
|
-
"typescript": "^5.6.
|
|
85
|
-
"vitest": "^2.1.
|
|
82
|
+
"tsup": "^8.3.5",
|
|
83
|
+
"typescript": "^5.6.3",
|
|
84
|
+
"vitest": "^2.1.4",
|
|
86
85
|
"webpack": "^5.95.0",
|
|
87
86
|
"xo": "^0.59.3"
|
|
88
87
|
},
|