UNPKG

en-route

Version:

Routing for static site generators, build systems and task runners, heavily based on express.js routes but works with file objects. Used by Assemble, Verb, and Template.

124 lines (107 loc) 2.71 kB
'use strict'; const assert = require('assert'); const toRegex = require('./to-regex'); /** * Create a new `Layer` with the given `pattern`, handler function and options. * * ```js * const layer = new Layer('/', file => { * // do stuff to file * file.extname = '.html'; * }); * ``` * @name Layer * @param {string} `pattern` * @param {function} `handler` * @param {object} `options` * @api public */ class Layer { constructor(pattern, fn, options) { assert.equal(typeof fn, 'function', 'expected handler to be a function'); this.options = { strict: false, end: false, ...options }; this.pattern = pattern; this.handler = file => { let params = this.match(file.path); if (params) { return fn(file, params); } }; } /** * Calls the layer handler on the given file if the `file.path` matches * the layer pattern. * * ```js * layer.handle(file) * .then(() => console.log('Done:', file)) * .then(console.error) * ``` * @name .handle * @param {object} `file` File object * @return {Promise} * @api public */ handle(file) { let params = this.handler(file); if (params instanceof Promise) { return params.then(res => { file.params = res; return file; }); } file.params = params; return file; } /** * Attempts to match a file path with the layer pattern. If the path matches, * an object of params is returned (see [path-to-regexp][] for details), otherwise * `null` is returned. * * ```js * const layer = new Layer('/:name'); * console.log(layer.match('/foo')) //=> { name: 'foo' } * ``` * @name .match * @param {string} `filepath` * @return {object|null} * @api public */ match(filepath) { if (!filepath) return null; let match = this.regex.exec(filepath); if (!match) return null; let captures = match.slice(1); let params = {}; let n = 0; for (let i = 0; i < captures.length; i++) { let val = captures[i]; let key = this._regex.keys[i]; let prop = key && key.name ? key.name : n++; params[prop] = val; } return params; } /** * Lazily create the regex to use for matching */ get regex() { if (this._regex instanceof RegExp) { this._regex.lastIndex = 0; return this._regex; } if (this.pattern && !this._regex) { let pattern = this.pattern; let keys = []; let regex = this._regex = toRegex(pattern, keys, this.options); regex.lastIndex = 0; regex.keys = keys; this._regex = regex; return regex; } } } /** * Expose `Layer` */ module.exports = Layer;