From 712d3941a781f61ce26eecd9f2c369b8d6abe0a6 Mon Sep 17 00:00:00 2001 From: Cosmin Popovici Date: Thu, 21 Mar 2024 17:48:44 +0200 Subject: [PATCH] chore: add async plugin example --- README.md | 50 +++++++++++++++++++++++++++++++++++++++++++++- lib/asyncPlugin.js | 11 ++++++++++ lib/index.js | 5 ++--- test/test.js | 7 +++++++ 4 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 lib/asyncPlugin.js diff --git a/README.md b/README.md index 2cdec95..e458455 100644 --- a/README.md +++ b/README.md @@ -19,12 +19,60 @@ git clone https://github.com/posthtml/posthtml-plugin-starter.git ### Features +- [Async](#async-plugins) and [sync](#sync-plugins) examples +- ESM, Node.js 18+ - Tests with [`vitest`](https://vitest.dev) - Linting with [`eslint`](https://eslint.org) - Releases with [`np`](https://github.com/sindresorhus/np) -- ESM, Node.js 18+ - CI with GitHub Actions +#### Async plugins + +When writing an async PostHTML plugin, you must return a `Promise` that resolves the current `tree`: + +```js +export default (options = {}) => tree => { + // Accept options and set defaults + options.foo = options.foo || {} + + return new Promise((resolve, reject) => { + try { + // do something async + + // finally, resolve the promise by returning the tree + resolve(tree) + } catch (error) { + reject(error) + } + }) +} +``` + +Note: async plugins can't be used in PostHTML's [`sync` mode](https://posthtml.org/#/core?id=posthtml-options). + +#### Sync plugins + +Synchronous plugins just need to return the `tree`. + +You may use the `tree.walk` method to traverse the `tree` and handle nodes. + +The handling of nodes can be a function that is passed to `tree.walk`, and which must return the node: + +```js +export default (options = {}) => tree => { + options.foo = options.foo || {} + + const handleNodes = node => { + // Write your code... + + // Return the node + return node + } + + return tree.walk(handleNodes) +} +``` + #### Tests The testing boilerplate includes a `process()` method which accepts 4 parameters: diff --git a/lib/asyncPlugin.js b/lib/asyncPlugin.js new file mode 100644 index 0000000..72c3eb6 --- /dev/null +++ b/lib/asyncPlugin.js @@ -0,0 +1,11 @@ +export default (options = {}) => tree => { + // Accept options and set defaults + options.foo = options.foo || {} + + return new Promise((resolve) => { + // do something async + + // finally, resolve the promise by returning the tree + resolve(tree) + }) +} diff --git a/lib/index.js b/lib/index.js index 9c7c5fe..c10b97a 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,4 +1,5 @@ -const plugin = (options = {}) => tree => { +export default (options = {}) => tree => { + // Accept options and set defaults options.foo = options.foo || {} const process = node => { @@ -10,5 +11,3 @@ const plugin = (options = {}) => tree => { return tree.walk(process) } - -export default plugin diff --git a/test/test.js b/test/test.js index 557a24b..e245d69 100644 --- a/test/test.js +++ b/test/test.js @@ -4,6 +4,7 @@ import {fileURLToPath} from 'node:url' import {test, expect} from 'vitest' import posthtml from 'posthtml' import plugin from '../lib/index.js' +import asyncPlugin from '../lib/asyncPlugin.js' const __dirname = path.dirname(fileURLToPath(import.meta.url)) @@ -24,3 +25,9 @@ const process = (name, options, log = false) => { test('Basic', () => { return process('basic') }) + +test('Async plugin', () => { + return posthtml([asyncPlugin()]) + .process(fixture('basic')) + .then(result => expect(clean(result.html)).toEqual(expected('basic'))) +})