Skip to content
Permalink
Browse files

feat: add custom filters

  • Loading branch information...
dmelikhov
dmelikhov committed Mar 1, 2019
1 parent 37e0549 commit 35642611f8c6388d342648cfabb74f434c428f78
@@ -0,0 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`filter should generate correct code 1`] = `"module.exports = \\"<!DOCTYPE html>\\\\r\\\\n<html lang=\\\\\\"ru\\\\\\">\\\\r\\\\n<head>\\\\r\\\\n <meta charset=\\\\\\"utf-8\\\\\\">\\\\r\\\\n <meta name=\\\\\\"viewport\\\\\\" content=\\\\\\"width=device-width, initial-scale=1, maximum-scale=1\\\\\\">\\\\r\\\\n <meta http-equiv=\\\\\\"X-UA-Compatible\\\\\\" content=\\\\\\"IE=edge\\\\\\">\\\\r\\\\n <meta name=\\\\\\"format-detection\\\\\\" content=\\\\\\"telephone=no\\\\\\">\\\\r\\\\n <meta name=\\\\\\"format-detection\\\\\\" content=\\\\\\"address=no\\\\\\">\\\\r\\\\n <title>Filter</title>\\\\r\\\\n</head>\\\\r\\\\n<body>\\\\r\\\\n \\\\r\\\\n\\\\r\\\\n \\\\r\\\\n A message for you: ipsum dolor sit amet, consectetur adipisicing elit.\\\\r\\\\n\\\\r\\\\n \\\\r\\\\n A message for you: t amet, consectetur adipisicing elit.\\\\r\\\\n</body>\\\\r\\\\n</html>\\\\r\\\\n\\";"`;
@@ -30,10 +30,7 @@ module.exports = (fixture, options = {}) => {
},
{
loader: path.resolve(process.cwd(), 'index.js'),
options: {
root: options.root,
data: options.data,
},
options,
},
],
}],
@@ -0,0 +1,18 @@
const compiler = require('./compiler');

describe('filter', () => {
test('should generate correct code', async () => {
const stats = await compiler('fixtures/filter.njk', {
env: {
filters: {
shorten(value, count) {
return value.slice(count || 5);
},
},
},
});
const output = stats.toJson().modules[0].source;

expect(output).toMatchSnapshot();
});
});
@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="format-detection" content="telephone=no">
<meta name="format-detection" content="address=no">
<title>Filter</title>
</head>
<body>
{% set message = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' %}

{# Show the first 5 characters #}
A message for you: {{ message|shorten }}

{# Show the first 20 characters #}
A message for you: {{ message|shorten(20) }}
</body>
</html>

Some generated files are not rendered by default. Learn more.

@@ -13,5 +13,13 @@
{% include "b.njk" %}
{% include "a.njk" %}
{% include "b.njk" %}

{% set message = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' %}

{# Show the first 20 characters #}
A message for you: {{ message|shorten(20) }}

{# Converts a string to uppercase letters #}
A message for you: {{ message|upper }}
</body>
</html>
@@ -23,6 +23,16 @@ module.exports = {
a: 'a',
b: 'b',
},
env: {
filters: {
shorten(value, count) {
return value.slice(count || 5);
},
upper(value) {
return value.toUpperCase();
},
},
},
},
},
],
@@ -12,7 +12,7 @@ module.exports = async function (source) {
const callback = this.async();

try {
const loader = new Loader(source, this, options.root);
const loader = new Loader(source, this, options);

callback(null, await loader.render(options.data));
} catch (exc) {
@@ -0,0 +1,43 @@
const Entity = require('./');

/**
* Filters Entity
* @type {module.Filters}
*/
module.exports = class Filters extends Entity {
/**
* Represents filters
* @param {Njk} env
* @param {Object} fns
*/
constructor(env, fns) {
super(env);

this.init(fns);
}

/**
* Initializes custom filters
* @param {Object} fns
*/
init(fns) {
if (typeof fns === 'object' && fns !== null) {
const filtersKeys = Object.keys(fns);

if (filtersKeys.length) {
filtersKeys.forEach(item => this.addFilter(item, fns[item]));
}
}
}

/**
* Add custom filter to environment
* @param {string} name
* @param {Function} fn
*/
addFilter(name, fn) {
this.env.addFilter(name, fn);

return this;
}
};
@@ -0,0 +1,18 @@
/**
* Class Entity
* @type {module.Index}
*/
module.exports = class Entity {
/**
* Represents entity
* @param {Njk} env
*/
constructor(env) {
this.env = env;
}

/**
* Initializes base entity
*/
init() {}
};
@@ -1,4 +1,6 @@
const nunjucks = require('nunjucks');
const path = require('path');
const { readdirSync } = require('fs');

const Njk = require('./njk');

@@ -11,33 +13,83 @@ module.exports = class Loader {
* Represents loader
* @param {string} source
* @param {string|Array} contextLoader
* @param {string} root
* @param {Object} options
*/
constructor(source, contextLoader, root = '.') {
constructor(source, contextLoader, options) {
const defaultOptions = {
data: null,
root: '.',
env: {},
};

this.options = { ...defaultOptions, ...options };
this.options.root = this.initRoot();

this.source = source;
this.contextLoader = contextLoader;

if (root) {
this.root = Array.isArray(root) ? root : [root];
} else {
this.root = '.';
}
this.entities = [];

this.env = new nunjucks.Environment(
new Njk(
this.root,
this.options.root,
path => this.contextLoader.addDependency(path),
),
);

this.loadEntities();

this.compile();
}

/**
* Initializes root
* @returns {String.root}
*/
initRoot() {
const { root } = this.options;
let result = root;

if (root) {
if (typeof root === 'string') {
result = [root];
} else if (Array.isArray(root)) {
result = root;
}
} else {
result = '.';
}

return result;
}

/**
* Load entities from entity dir
* @returns {module.Loader}
*/
loadEntities() {
const { env } = this.options;
const pathname = path.resolve(__dirname, 'entity');

readdirSync(pathname).forEach((item) => {
const name = item.split('.')[0];
/* eslint import/no-dynamic-require: off */
if (name !== 'index' && Object.prototype.hasOwnProperty.call(env, name)) {
const Entity = require(path.resolve(pathname, item));
this.entities.push(new Entity(this.env, env[name]));
}
});

return this;
}

/**
* Compiles njk-file
* @returns {module.Loader}
*/
compile() {
this.compiled = nunjucks.compile(this.source, this.env);

return this;
}

/**
@@ -47,7 +99,7 @@ module.exports = class Loader {
*/
render(data) {
return new Promise((resolve, reject) => {
this.compiled.render(typeof data === 'object' ? data : {}, (err, res) => {
this.compiled.render(typeof data === 'object' && data !== null ? data : {}, (err, res) => {
if (err) {
return reject(err);
}

Some generated files are not rendered by default. Learn more.

@@ -1,6 +1,6 @@
{
"name": "njk-html-loader",
"version": "1.0.0",
"version": "1.1.0",
"description": "Nunjucks HTML loader for webpack",
"main": "index.js",
"keywords": [

0 comments on commit 3564261

Please sign in to comment.
You can’t perform that action at this time.