Skip to content

Commit

Permalink
Merge pull request #321 from jaredwray/adding-in-hooks-for-render,-sa…
Browse files Browse the repository at this point in the history
…ve-to-file,-and-load-from-file

Adding in hooks for render and renderSync
  • Loading branch information
jaredwray authored Dec 29, 2024
2 parents eb2a3ec + ebb2c42 commit 3f2f707
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 26 deletions.
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
- [`.loadFromFileSync(filePath: string): void`](#loadfromfilesyncfilepath-string-void)
- [`.saveToFile(filePath: string): Promise<void>`](#savetofilefilepath-string-promisevoid)
- [`.saveToFileSync(filePath: string): void`](#savetofilesyncfilepath-string-void)
- [Hooks](#hooks)
- [Code of Conduct and Contributing](#code-of-conduct-and-contributing)
- [License](#license)

Expand All @@ -47,6 +48,7 @@
* Github Flavor Markdown (remark-gfm).
* Emoji Support (remark-emoji).
* MDX Support (remark-mdx).
* Built in Hooks for adding code to render pipeline.

# ESM and Node Version Support

Expand Down Expand Up @@ -347,6 +349,38 @@ writr.cache.store.lruSize = 100;
writr.cache.store.ttl = '5m'; // setting it to 5 minutes
```

# Hooks

Hooks are a way to add additional parsing to the render pipeline. You can add hooks to the the Writr instance. Here is an example of adding a hook to the instance of Writr:

```javascript
import { Writr, WritrHooks } from 'writr';
const writr = new Writr(`# Hello World ::-):\n\n This is a test.`);
writr.onHook(WritrHooks.beforeRender, data => {
data.body = 'Hello, Universe!';
});
const result = await writr.render();
console.log(result); // Hello, Universe!
```

For `beforeRender` the data object is a `renderData` object. Here is the interface for `renderData`:

```typescript
export type renderData {
body: string;
content: string;
options: RenderOptions;
}
```

For `afterRender` the data object is a `resultData` object. Here is the interface for `resultData`:

```typescript
export type resultData {
result: string;
}
```

# Code of Conduct and Contributing
[Code of Conduct](CODE_OF_CONDUCT.md) and [Contributing](CONTRIBUTING.md) guidelines.

Expand Down
87 changes: 61 additions & 26 deletions src/writr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ export type RenderOptions = {
caching?: boolean; // Caching (default: false)
};

export enum WritrHooks {
beforeRender = 'beforeRender',
afterRender = 'afterRender',
beforeSaveToFile = 'beforeSaveToFile',
afterSaveToFile = 'afterSaveToFile',
beforeLoadFromFile = 'beforeLoadFromFile',
afterLoadFromFile = 'afterLoadFromFile',
}

export class Writr extends Hookified {
public engine = unified()
.use(remarkParse)
Expand Down Expand Up @@ -235,28 +244,40 @@ export class Writr extends Hookified {
*/
async render(options?: RenderOptions): Promise<string> {
try {
let result = '';
if (this.isCacheEnabled(options)) {
const cached = this._cache.get(this._content, options);
if (cached) {
return cached;
}
}

let {engine} = this;
if (options) {
options = {...this._options.renderOptions, ...options};
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
engine = this.createProcessor(options);
}

const file = await engine.process(this.body);
result = String(file);
if (this.isCacheEnabled(options)) {
this._cache.set(this._content, result, options);
const renderData = {
content: this._content,
body: this.body,
options,
};

await this.hook(WritrHooks.beforeRender, renderData);

const resultData = {
result: '',
};
if (this.isCacheEnabled(renderData.options)) {
const cached = this._cache.get(renderData.content, renderData.options);
if (cached) {
return cached;
}
}

const file = await engine.process(renderData.body);
resultData.result = String(file);
if (this.isCacheEnabled(renderData.options)) {
this._cache.set(renderData.content, resultData.result, renderData.options);
}

return result;
await this.hook(WritrHooks.afterRender, resultData);

return resultData.result;
} catch (error) {
throw new Error(`Failed to render markdown: ${(error as Error).message}`);
}
Expand All @@ -269,28 +290,42 @@ export class Writr extends Hookified {
*/
renderSync(options?: RenderOptions): string {
try {
let result = '';
if (this.isCacheEnabled(options)) {
const cached = this._cache.get(this._content, options);
if (cached) {
return cached;
}
}

let {engine} = this;
if (options) {
options = {...this._options.renderOptions, ...options};
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
engine = this.createProcessor(options);
}

const file = engine.processSync(this.body);
result = String(file);
if (this.isCacheEnabled(options)) {
this._cache.set(this._content, result, options);
const renderData = {
content: this._content,
body: this.body,
options,
};

// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.hook(WritrHooks.beforeRender, renderData);

const resultData = {
result: '',
};
if (this.isCacheEnabled(renderData.options)) {
const cached = this._cache.get(renderData.content, renderData.options);
if (cached) {
return cached;
}
}

const file = engine.processSync(renderData.body);
resultData.result = String(file);
if (this.isCacheEnabled(renderData.options)) {
this._cache.set(renderData.content, resultData.result, renderData.options);
}

return result;
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.hook(WritrHooks.afterRender, resultData);

return resultData.result;
} catch (error) {
throw new Error(`Failed to render markdown: ${(error as Error).message}`);
}
Expand Down
25 changes: 25 additions & 0 deletions test/writr-hooks.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

import {
test, describe, expect,
} from 'vitest';
import {Writr, WritrHooks} from '../src/writr.js';

describe('Writr Render Hooks', async () => {
test('it should change the content before rendering', async () => {
const writr = new Writr('Hello, World!');
writr.onHook(WritrHooks.beforeRender, data => {
data.body = 'Hello, Universe!';
});
const result = await writr.render();
expect(result).toBe('<p>Hello, Universe!</p>');
});

test('it should change the content before rendering sync', () => {
const writr = new Writr('Hello, World!');
writr.onHook(WritrHooks.beforeRender, data => {
data.body = 'Hello, Sync!';
});
const result = writr.renderSync();
expect(result).toBe('<p>Hello, Sync!</p>');
});
});

0 comments on commit 3f2f707

Please sign in to comment.