Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ If you are familiar with Blade, React, Vue or similar, you will find the syntax
| **propsSlot** | `String` | `'props'` | Used to retrieve props passed to slot via `$slots.slotName.props`. |
| **parserOptions** | `Object` | `{recognizeSelfClosing: true}` | Pass options to `posthtml-parser`. |
| **expressions** | `Object` | `{}` | Pass options to `posthtml-expressions`. |
| **plugins** | `Array` | `[]` | PostHTML plugins to apply to every parsed component. |
| **plugins** | `Array\|Object` | `[]` | PostHTML plugins to [apply](#plugins) to every parsed component. |
| **matcher** | `Object` | `[{tag: options.tagPrefix}]` | Array of objects used to match tags. |
| **attrsParserRules** | `Object` | `{}` | Additional rules for attributes parser plugin. |
| **strict** | `Boolean` | `true` | Toggle exception throwing. |
Expand Down Expand Up @@ -842,6 +842,35 @@ Result:

You can add custom rules to define how attributes are parsed - we use [posthtml-attrs-parser](https://github.com/posthtml/posthtml-attrs-parser) to handle them.


### Plugins

You can specify whether plugins are applied before or after the `posthtml-expressions` plugin:

```js
const options = {
plugins: {
before: [/* ... */],
after: [/* ... */],
}
};
```

For backwards compatibility, passing an array will default to applying plugins after the `posthtml-expressions` plugin. The following options are equivalent:

```js
const options = {
plugins: [/* ... */]
};

const options = {
plugins: {
before: [/* ... */],
after: [],
}
};
```

### Advanced attributes configurations

If default configurations for valid attributes are not right for you, you may configure them as explained below.
Expand Down
2 changes: 1 addition & 1 deletion src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ export type PostHTMLComponents = {
*
* @default []
*/
plugins?: Array<() => void>;
plugins?: Array<() => void>|Record<'before','after', Array<() => void>>;

/**
* Array of objects used to match tags.
Expand Down
24 changes: 20 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,21 @@ module.exports = (options = {}) => tree => {
options.props = {...options.expressions.locals};
options.aware = {};

if (Array.isArray(options.plugins)) {
options.plugins = {
before: [],
after: options.plugins
};
}

const pushedContent = {};

log('Start of processing..', 'init', 'success');

if (options.plugins.before.length > 0) {
tree = applyPluginsToTree(tree, options.plugins.before);
}

return processStacks(
processPushes(
processTree(options)(
Expand All @@ -169,8 +180,8 @@ function processTree(options) {
return (tree, messages) => {
log(`Processing tree number ${processCounter}..`, 'processTree');

if (options.plugins.length > 0) {
tree = applyPluginsToTree(tree, options.plugins);
if (options.plugins.after.length > 0) {
tree = applyPluginsToTree(tree, options.plugins.after);
}

match.call(tree, options.matcher, currentNode => {
Expand Down Expand Up @@ -217,10 +228,15 @@ function processTree(options) {
options.expressions.locals = attributes;
options.expressions.locals.$slots = filledSlots;
// const plugins = [...options.plugins, expressions(options.expressions)];

if (options.plugins.before.length > 0) {
nextNode = applyPluginsToTree(nextNode, options.plugins.before);
}

nextNode = expressions(options.expressions)(nextNode);

if (options.plugins.length > 0) {
nextNode = applyPluginsToTree(nextNode, options.plugins);
if (options.plugins.after.length > 0) {
nextNode = applyPluginsToTree(nextNode, options.plugins.after);
}

// Process <yield> tag
Expand Down
37 changes: 37 additions & 0 deletions test/test-plugins.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { test, expect } from 'vitest';
import { process } from './process.js';
import { walk } from 'posthtml/lib/api';

const plugin = tree => walk.call(tree, node => typeof node === 'string' && node === "{{title}}"? "{{replaced}}": node);

test('posthtml-include', async () => {
process(
Expand All @@ -22,6 +25,40 @@ test('posthtml-include', async () => {
});
});

test('Run plugin before expressions', async () => {
process(
`<component src="components/component-locals.html"></component>`,
{
root: './test/templates',
tag: 'component',
attribute: 'src',
plugins: { before: [plugin], after: []},
expressions: {
strict: false,
missingLocal: '{local}',
}
}
)
.then(html => {
expect(html).toBe(`<div><h1>{{replaced}}</h1></div><div>Default body</div>`);
});
});

test('Run plugin after expressions', async () => {
process(
`<component src="components/component-locals.html"></component>`,
{
root: './test/templates',
tag: 'component',
attribute: 'src',
plugins: { before: [], after: [plugin]},
}
)
.then(html => {
expect(html).toBe(`<div><h1>Default title</h1></div><div>Default body</div>`);
});
});

// test.skip('Must work with posthtml-extend syntax', async () => {
// const actual = `<extends src="layouts/extend.html"><block name="content">My Content</block></extends>`;
// const expected = `<html><head><title>Extend Layout</title></head><body><main>My Content</main><footer>footer content</footer></body></html>`;
Expand Down