Skip to content

Commit

Permalink
Add support for async filters (#37)
Browse files Browse the repository at this point in the history
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
  • Loading branch information
silvenon and sindresorhus authored Sep 29, 2020
1 parent da09aed commit e145d97
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 7 deletions.
46 changes: 40 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
const through = require('through2');
const nunjucks = require('nunjucks');
const PluginError = require('plugin-error');
const is = require('@sindresorhus/is');

function compile(data, options = {}) {
return through.obj(function (file, encoding, callback) {
Expand All @@ -19,21 +20,54 @@ function compile(data, options = {}) {
const filePath = file.path;
const env = options.env || new nunjucks.Environment(new nunjucks.FileSystemLoader(file.base), options);

let isAsync = false;

if (options.filters && !options.env) {
for (const key of Object.keys(options.filters)) {
env.addFilter(key, options.filters[key]);
const filter = options.filters[key];
if (is.asyncFunction(filter)) {
isAsync = true;
env.addFilter(key, async (...args) => {
const cb = args.pop();
try {
const result = await filter(...args);
cb(null, result);
} catch (error) {
cb(error, null);
}
}, true);
} else {
env.addFilter(key, filter);
}
}
}

try {
file.contents = Buffer.from(env.renderString(file.contents.toString(), context));
file.extname = '.html';
this.push(file);
const writeResult = result => {
file.contents = Buffer.from(result);
file.extname = '.html';
this.push(file);
};

if (isAsync) {
env.renderString(file.contents.toString(), context, (error, result) => {
if (error) {
this.emit('error', new PluginError('gulp-nunjucks', error, {fileName: filePath}));
callback();
return;
}

writeResult(result);
callback();
});
} else {
writeResult(env.renderString(file.contents.toString(), context));
callback();
}
} catch (error) {
this.emit('error', new PluginError('gulp-nunjucks', error, {fileName: filePath}));
callback();
}

callback();
});
}

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"javascript"
],
"dependencies": {
"@sindresorhus/is": "^3.1.2",
"nunjucks": "^3.2.0",
"plugin-error": "^1.0.1",
"through2": "^3.0.1"
Expand Down
9 changes: 8 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,19 @@ Type: `object`

An object containing [custom filters](https://mozilla.github.io/nunjucks/api.html#custom-filters) that will be passed to Nunjucks, with the filter's name as key and the filter function as value.

Async filters should be defined as async functions. You cannot use just a promise-returning function.

Example:

```js
{
'shorten': string => string.slice(0, 5),
'round': number => Math.round(number)
'round': number => Math.round(number),
'fetch': async url => {
const response = await fetch(url);
const result = await response.text();
return result;
}
}
```

Expand Down
16 changes: 16 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,22 @@ test.cb('support custom filters', t => {
}));
});

test.cb('support async custom filters', t => {
const filters = {shorten: async x => x.slice(0, 5), shout: async x => `${x}!`};

const stream = nunjucks.compile({message: 'Lorem ipsum'}, {filters});

stream.on('data', file => {
t.is(file.contents.toString(), 'Lorem!');
t.end();
});

stream.end(new Vinyl({
path: 'foo.txt',
contents: Buffer.from('{{ message|shorten|shout }}')
}));
});

test.cb('not pass custom filters to custom environment', t => {
const nunjucksModule = require('nunjucks');

Expand Down

0 comments on commit e145d97

Please sign in to comment.