diff --git a/.gitignore b/.gitignore index a20b24d..c20a2cb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ coverage node_modules/ -scripts/*.svg \ No newline at end of file +scripts/*.svg +.DS_Store \ No newline at end of file diff --git a/README.md b/README.md index ed224bb..cf3d59f 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ## Pug.js engine interface [![npm (scoped)](https://img.shields.io/npm/v/@dadi/web-pugjs.svg?maxAge=10800&style=flat-square)](https://www.npmjs.com/package/@dadi/web-pugjs) -[![coverage](https://img.shields.io/badge/coverage-85%25-yellow.svg?style=flat?style=flat-square)](https://github.com/dadi/web-pugjs) +[![coverage](https://img.shields.io/badge/coverage-78%25-yellow.svg?style=flat?style=flat-square)](https://github.com/dadi/web-pugjs) [![Build Status](https://travis-ci.org/dadi/web-pugjs.svg?branch=master)](https://travis-ci.org/dadi/web-pugjs) [![JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](http://standardjs.com/) [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=flat-square)](https://github.com/semantic-release/semantic-release) @@ -54,3 +54,54 @@ include /partials/common/header.pug //- Relative path include common/header.pug ``` + +### Helper functions + +Add a DADI Web configuration setting for `helpers`, pointing to a directory containing helper files. Each `.js` helper file will be added as a property to template locals for use within templates. + +#### Configuration + +``` + engines: { + pug: { + paths: { + helpers: 'test/workspace/helpers' + } + } + } +``` + +#### Directory structure + +``` +helpers/ +|_ trim.js +pages/ +|_ partials/ +|_ |_ common/ +|_ |_ |_ header.pug +|_ |_ contact-info.pug +|_ home.pug +``` + +#### Locals + +The function is added to the template locals, along with data objects: + +``` +{ + products: [ + { name: 'The Old Man and the Sea' } + ], + trim: [Function] +} +``` + +#### Usage + +Use the function in templates like so: + +``` +h1= trim(product.name) +``` + diff --git a/index.js b/index.js index 9a0ed33..42856dc 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,11 @@ const ENGINE = { + config: { + paths: { + doc: 'Paths required by Pug.js', + format: Object, + default: {} + } + }, extensions: ['.pug'], handle: 'pug' } @@ -6,6 +13,7 @@ const ENGINE = { module.exports = () => { const debug = require('debug')('web:templates:pug') const pug = require('pug') + const requireDir = require('require-dir') const EnginePug = function (options) { debug('Starting Pug.js engine...') @@ -44,6 +52,13 @@ module.exports = () => { */ EnginePug.prototype.initialise = function () { debug('Pug initialised') + + if (this.config.engines && + this.config.engines.pug && + this.config.engines.pug.paths && this.config.engines.pug.paths.helpers + ) { + this.helperFunctions = requireDir(this.config.engines.pug.paths.helpers, { recurse: true, camelcase: true }) + } } /** @@ -69,6 +84,10 @@ module.exports = () => { * @return {Promise} A Promise that resolves with the render result. */ EnginePug.prototype.render = function (name, data, locals, options) { + if (this.helperFunctions) { + Object.assign(locals, this.helperFunctions) + } + return Promise.resolve(this.templates[name](locals)) } diff --git a/package.json b/package.json index 649ef92..c3fe7c4 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "web", "pug", "pug.js", - "jade" + "jade", + "dadi-web-engine" ], "author": "Eduardo Boucas ", "bugs": { @@ -26,7 +27,8 @@ "homepage": "https://github.com/dadi/web-pugjs#readme", "dependencies": { "debug": "^2.6.6", - "pug": "^2.0.0-rc.1" + "pug": "^2.0.0-rc.1", + "require-dir": "^0.3.2" }, "devDependencies": { "colors": "^1.1.2", diff --git a/test/helpers/config.js b/test/helpers/config.js index 13b782b..70c4a82 100644 --- a/test/helpers/config.js +++ b/test/helpers/config.js @@ -4,7 +4,7 @@ const objectPath = require('object-path') const CONFIG_PROPERTIES = { engines: { - dust: { + pug: { paths: { filters: 'test/workspace/filters', helpers: 'test/workspace/helpers' diff --git a/test/helpers/index.js b/test/helpers/index.js index 3f9d5ce..3453f96 100644 --- a/test/helpers/index.js +++ b/test/helpers/index.js @@ -14,7 +14,8 @@ const ADDITIONAL_TEMPLATES = { } const PAGES = { - products: fs.readFileSync(path.join(PATHS.workspace, 'pages/products.pug'), 'utf8') + products: fs.readFileSync(path.join(PATHS.workspace, 'pages/products.pug'), 'utf8'), + 'products-with-helpers': fs.readFileSync(path.join(PATHS.workspace, 'pages/products-with-helpers.pug'), 'utf8') } module.exports.additionalTemplates = ADDITIONAL_TEMPLATES diff --git a/test/pug.js b/test/pug.js index 38c28b7..eef1887 100644 --- a/test/pug.js +++ b/test/pug.js @@ -52,7 +52,7 @@ describe('Pug.js interface', function () { const Engine = factory() const instance = new Engine({ additionalTemplates: Object.keys(helpers.additionalTemplates).map(name => helpers.additionalTemplates[name]), - config: config, + config: config.config, pagesPath: path.join(helpers.paths.workspace, 'pages') }) @@ -65,11 +65,25 @@ describe('Pug.js interface', function () { }) }) + it('should load helpers', done => { + const Engine = factory() + const instance = new Engine({ + additionalTemplates: Object.keys(helpers.additionalTemplates).map(name => helpers.additionalTemplates[name]), + config: config.config, + pagesPath: path.join(helpers.paths.workspace, 'pages') + }) + + Promise.resolve(instance.initialise()).then(() => { + (typeof instance.helperFunctions.trim).should.eql('function') + done() + }) + }) + it('should render pages with locals', done => { const Engine = factory() const instance = new Engine({ additionalTemplates: Object.keys(helpers.additionalTemplates).map(name => helpers.additionalTemplates[name]), - config: config, + config: config.config, pagesPath: path.join(helpers.paths.workspace, 'pages') }) @@ -110,4 +124,49 @@ describe('Pug.js interface', function () { done() }) }) + + it('should render pages with helpers', done => { + const Engine = factory() + const instance = new Engine({ + additionalTemplates: Object.keys(helpers.additionalTemplates).map(name => helpers.additionalTemplates[name]), + config: config.config, + pagesPath: path.join(helpers.paths.workspace, 'pages') + }) + + const locals = { + products: [ + { + name: ' Super Thing 3000 ', + price: 5000 + }, + { + name: ' Mega Thang XL', + price: 8000 + } + ] + } + + const expected = ` +
My online store
+ +

Products:

+ + + + + ` + + Promise.resolve(instance.initialise()).then(() => { + return instance.register('products-with-helpers', helpers.pages['products-with-helpers']) + }).then(() => { + return instance.render('products-with-helpers', helpers.pages['products-with-helpers'], locals) + }).then(output => { + htmlLooksLike(output, expected) + + done() + }) + }) }) diff --git a/test/workspace/helpers/trim.js b/test/workspace/helpers/trim.js index e1140a8..dec048a 100644 --- a/test/workspace/helpers/trim.js +++ b/test/workspace/helpers/trim.js @@ -1,10 +1,6 @@ -const dust = require('dustjs-linkedin') - /* - * Returns the supplied 'data' parameter trimmed of whitespace on both left and right sides - * Usage: {@Trim data="{body}"/} + * Returns the supplied 'input' parameter trimmed of whitespace on both left and right sides */ -dust.helpers.Trim = function (chunk, context, bodies, params) { - var data = context.resolve(params.data) - return chunk.write(data.trim()) +module.exports = input => { + return input.trim() } diff --git a/test/workspace/pages/products-with-helpers.json b/test/workspace/pages/products-with-helpers.json new file mode 100644 index 0000000..cad0d6e --- /dev/null +++ b/test/workspace/pages/products-with-helpers.json @@ -0,0 +1,7 @@ +{ + "page": { + "name": "products", + "description": "The products page", + "language": "en" + } +} \ No newline at end of file diff --git a/test/workspace/pages/products-with-helpers.pug b/test/workspace/pages/products-with-helpers.pug new file mode 100644 index 0000000..532fa44 --- /dev/null +++ b/test/workspace/pages/products-with-helpers.pug @@ -0,0 +1,9 @@ +include /partials/header.pug + +h1 Products: + +ul + each val, index in products + li= trim(val.name) + ' - £' + val.price + +include /partials/footer.pug \ No newline at end of file