Comparing version 0.9.0 to 0.10.0
130
index.js
'use strict'; | ||
var isFalsey = require('falsey'); | ||
var Buffer = require('buffer').Buffer; | ||
var delims = require('delimiter-regex'); | ||
@@ -11,61 +12,90 @@ var get = require('get-value'); | ||
module.exports = layouts; | ||
module.exports = renderLayouts; | ||
/** | ||
* Wrap a string one or more layouts. | ||
* Cache compiled delimiter regex. | ||
* | ||
* @param {String} `str` The content string to be wrapped with a layout. | ||
* @param {String} `key` The object key of the starting layout. | ||
* @param {Object} `templates` Object of layouts. | ||
* @param {Object} `options` | ||
* @option {Object} [options] `layoutDelims` Custom delimiters to use. | ||
* @option {Object} [options] `defaultLayout` The name (key) of the default layout to use. | ||
* @return {String} String wrapped with a layout or layouts. | ||
* If delimiters need to be generated, this ensures that | ||
* runtime compilation only happens once. | ||
*/ | ||
var cache = {}; | ||
/** | ||
* Wrap one or more layouts around `string`. | ||
* | ||
* ```js | ||
* renderLayouts(string, layoutName, layoutStack, options, fn); | ||
* ``` | ||
* | ||
* @param {String} `string` The string to wrap with a layout. | ||
* @param {String} `layoutName` The name (key) of the layout object to use. | ||
* @param {Object} `layoutStack` Object of layout objects. | ||
* @param {Object} `options` Optionally define a `defaultLayout` (string), pass custom delimiters (`layoutDelims`) to use as the placeholder for the content insertion point, or change the name of the placeholder tag with the `tag` option. | ||
* @param {Function} `fn` Optionally pass a function to modify the context as each layout is applied. | ||
* @return {String} Returns the original string wrapped with one or more layouts. | ||
* @api public | ||
*/ | ||
function layouts(str, key, templates, opts, fn) { | ||
function renderLayouts(str, name, layoutStack, opts, fn) { | ||
if (isBuffer(str)) { | ||
str = str.toString(); | ||
} | ||
if (typeof str !== 'string') { | ||
throw new TypeError('layouts expects a string'); | ||
throw new TypeError('layouts expects a string.'); | ||
} | ||
if (typeof opts === 'function') { | ||
fn = opts; opts = {}; | ||
fn = opts; | ||
opts = {}; | ||
} | ||
opts = opts || {}; | ||
var template = {}, prev, i = 0; | ||
var res = {options: {}, stack: []}; | ||
var layout = {}; | ||
var depth = 0; | ||
var prev; | ||
while (key && (prev !== key) && (template = templates[key])) { | ||
// `view` is the object we'll use to store the result | ||
var view = {options: {}, history: []}; | ||
// recursively resolve layouts | ||
while (name && (prev !== name) && (layout = layoutStack[name])) { | ||
var delims = opts.layoutDelims; | ||
// `context` is passed to `interpolate` to resolve templates | ||
// to the values on the context object. | ||
var context = {}; | ||
context[opts.tag || 'body'] = str; | ||
// `data` is passed to `wrapLayout` to resolve layouts | ||
// to the values on the data object. | ||
var data = {}; | ||
data[opts.tag || 'body'] = str; | ||
// get the context for the layout and push it onto `stack` | ||
// get info about the current layout | ||
var obj = {}; | ||
obj.layout = template; | ||
obj.layout.key = key; | ||
obj.layout = layout; | ||
obj.layout.name = name; | ||
obj.before = str; | ||
obj.depth = i++; | ||
obj.depth = depth++; | ||
str = interpolate(template.content, context, delims); | ||
// inject the string into the layout | ||
str = wrapLayout(layout.content, data, delims); | ||
obj.after = str; | ||
// if a (sync) callback is passed, allow it modify | ||
// the result in place | ||
if (typeof fn === 'function') { | ||
fn(obj, res, i); | ||
fn(obj, view, depth); | ||
} | ||
res.stack.push(obj); | ||
prev = key; | ||
key = assertLayout(template.layout, opts.defaultLayout); | ||
// push info about the layout onto `history` | ||
view.history.push(obj); | ||
prev = name; | ||
// should we recurse again? | ||
// (does the `layout` itself specify another layout?) | ||
name = assertLayout(layout.layout, opts.defaultLayout); | ||
} | ||
res.options = opts; | ||
res.result = str; | ||
return res; | ||
}; | ||
view.options = opts; | ||
view.result = str; | ||
return view; | ||
} | ||
@@ -95,22 +125,13 @@ /** | ||
/** | ||
* Cache compiled regexps to prevent runtime | ||
* compilation for the same delimiter strings | ||
* multiple times (this trick can be used for | ||
* any compiled regex) | ||
*/ | ||
var cache = {}; | ||
/** | ||
* Resolve template strings to the values on the given | ||
* `context` object. | ||
* `data` object. | ||
*/ | ||
function interpolate(content, context, syntax) { | ||
function wrapLayout(content, data, syntax) { | ||
var re = makeDelimiterRegex(syntax); | ||
return toString(content).replace(re, function(_, $1) { | ||
if ($1.indexOf('.') !== -1) { | ||
return toString(get(context, $1.trim())); | ||
return toString(content).replace(re, function(_, tagName) { | ||
if (tagName.indexOf('.') !== -1) { | ||
return toString(get(data, tagName.trim())); | ||
} | ||
return context[$1.trim()]; | ||
return data[tagName.trim()]; | ||
}); | ||
@@ -131,9 +152,9 @@ } | ||
} | ||
var name = syntax + ''; | ||
if (cache.hasOwnProperty(name)) { | ||
return cache[name]; | ||
} | ||
if (typeof syntax === 'string') { | ||
return new RegExp(syntax, 'g'); | ||
} | ||
var key = syntax.toString(); | ||
if (cache.hasOwnProperty(key)) { | ||
return cache[key]; | ||
} | ||
if (Array.isArray(syntax)) { | ||
@@ -148,4 +169,9 @@ return (cache[syntax] = delims(syntax)); | ||
function toString(val){ | ||
function toString(val) { | ||
return val == null ? '' : val.toString(); | ||
} | ||
function isBuffer(val) { | ||
return typeof val === 'object' | ||
&& val instanceof Buffer; | ||
} |
{ | ||
"name": "layouts", | ||
"description": "Wrap templates with layouts. Layouts can be nested and optionally use other layouts.", | ||
"version": "0.9.0", | ||
"description": "Wraps templates with layouts. Layouts can use other layouts and be nested to any depth. This can be used 100% standalone to wrap any kind of file with banners, headers or footer content. Use for markdown, HTML, handlebars views, lo-dash templates, etc.", | ||
"version": "0.10.0", | ||
"homepage": "https://github.com/doowb/layouts", | ||
"author": { | ||
"name": "Brian Woodward", | ||
"url": "https://github.com/doowb" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/doowb/layouts.git" | ||
}, | ||
"author": "Brian Woodward (https://github.com/doowb)", | ||
"repository": "doowb/layouts", | ||
"bugs": { | ||
"url": "https://github.com/doowb/layouts/issues" | ||
}, | ||
"license": { | ||
"type": "MIT", | ||
"url": "https://github.com/doowb/layouts/blob/master/LICENSE" | ||
}, | ||
"contributors": [ | ||
"Jon Schlinkert, (https://github.com/jonschlinkert)" | ||
], | ||
"license": "MIT", | ||
"files": [ | ||
@@ -32,13 +26,14 @@ "index.js" | ||
"dependencies": { | ||
"delimiter-regex": "^1.3.0", | ||
"delimiter-regex": "^1.3.1", | ||
"falsey": "^0.2.1", | ||
"get-value": "^1.0.4" | ||
"get-value": "^1.1.5" | ||
}, | ||
"devDependencies": { | ||
"lodash": "^3.5.0", | ||
"mocha": "^2.2.0", | ||
"should": "^5.1.0" | ||
"lodash": "^3.10.0", | ||
"mocha": "^2.2.5", | ||
"should": "^7.0.2" | ||
}, | ||
"keywords": [ | ||
"atpl", | ||
"coffee", | ||
"consolidate", | ||
@@ -53,6 +48,8 @@ "dot", | ||
"express", | ||
"haml", | ||
"haml-coffee", | ||
"hamljs", | ||
"handlebars", | ||
"hogan.js", | ||
"hogan", | ||
"hogan-js", | ||
"jade", | ||
@@ -86,3 +83,14 @@ "jazz", | ||
"wrap" | ||
] | ||
], | ||
"verb": { | ||
"related": { | ||
"list": [ | ||
"template", | ||
"assemble", | ||
"verb", | ||
"handlebars-helpers", | ||
"template-helpers" | ||
] | ||
} | ||
} | ||
} |
173
README.md
@@ -1,9 +0,11 @@ | ||
# layouts [![NPM version](https://badge.fury.io/js/layouts.svg)](http://badge.fury.io/js/layouts) [![Build Status](https://travis-ci.org/doowb/layouts.svg)](https://travis-ci.org/doowb/layouts) | ||
# layouts [![NPM version](https://badge.fury.io/js/layouts.svg)](http://badge.fury.io/js/layouts) [![Build Status](https://travis-ci.org/doowb/layouts.svg)](https://travis-ci.org/doowb/layouts) | ||
> Wrap templates with layouts. Layouts can be nested and optionally use other layouts. | ||
> Wraps templates with layouts. Layouts can use other layouts and be nested to any depth. This can be used 100% standalone to wrap any kind of file with banners, headers or footer content. Use for markdown, HTML, handlebars views, lo-dash templates, etc. | ||
## Install with [npm](npmjs.org) | ||
## Install | ||
```bash | ||
npm i layouts --save | ||
Install with [npm](https://www.npmjs.com/) | ||
```sh | ||
$ npm i layouts --save | ||
``` | ||
@@ -14,15 +16,22 @@ | ||
```js | ||
var layouts = require('layouts'); | ||
var renderLayouts = require('layouts'); | ||
``` | ||
## Usage | ||
## Examples | ||
**Basic example** | ||
In this example, two layouts are used: | ||
* the first layout, `one`, will wrap the string | ||
* the second layout, `two`, will wrap the first layout | ||
```js | ||
var stack = { | ||
foo: {content: 'foo above\n{% body %}\nfoo below', layout: 'bar'}, | ||
bar: {content: 'bar above\n{% body %}\nbar below', layout: 'baz'}, | ||
baz: {content: 'baz above\n{% body %}\nbaz below'}, | ||
var layouts = { | ||
one: {content: 'one before\n{% body %}\none after', layout: 'two'}, | ||
two: {content: 'two before\n{% body %}\ntwo after'}, | ||
}; | ||
layouts('<div>This is content</div>', 'foo', stack); | ||
// `one` is the name of the first layout to use on the provided string | ||
renderLayouts('<div>Wrap me with a layout!!!</div>', 'one', layouts); | ||
``` | ||
@@ -33,43 +42,118 @@ | ||
```html | ||
baz above | ||
bar above | ||
foo above | ||
<div>This is content</div> | ||
foo below | ||
bar below | ||
baz below | ||
two before | ||
one before | ||
<div>Wrap me with a layout!!!</div> | ||
one after | ||
two after | ||
``` | ||
**HTML** | ||
This example shows how to use nested HTML layouts to wrap content: | ||
```js | ||
var layouts = {}; | ||
layouts.base = { | ||
content: [ | ||
'<!DOCTYPE html>', | ||
'<html lang="en">', | ||
' <head>', | ||
' <meta charset="UTF-8">', | ||
' <title>Home</title>', | ||
' </head>', | ||
' <body>', | ||
' {% body %}', | ||
' </body>', | ||
'</html>', | ||
].join('\n') | ||
}; | ||
// this `nav` layout will be wrapped with the `base` layout | ||
layouts.nav = { | ||
layout: 'base', | ||
content: '<nav>\n{% body %}\n</nav>' | ||
}; | ||
// this string will be wrapped with the `nav` layout | ||
var str = [ | ||
'<ul class="categories">', | ||
' <li class="active"> <a href="#"> Development </a> </li>', | ||
' <li> <a href="#"> Design </a> </li>', | ||
' <li> <a href="#"> Node.js </a> </li>', | ||
'</ul>' | ||
].join('\n') | ||
// `nav` is the name of the layout to use | ||
renderLayouts(str, nav, layouts); | ||
``` | ||
Results in something like: | ||
```html | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<title>Home</title> | ||
</head> | ||
<body> | ||
<nav> | ||
<ul class="categories"> | ||
<li class="active"> <a href="#"> Development </a> </li> | ||
<li> <a href="#"> Design </a> </li> | ||
<li> <a href="#"> Node.js </a> </li> | ||
</ul> | ||
</nav> | ||
</body> | ||
</html> | ||
``` | ||
## Customization | ||
By default, `{% body %}` is used as the placeholder (insertion point) for content, but this can easily be customized with the following options: | ||
* `layoutDelims`: the delimiters to use. This can be a regex, like `/\{{([^}]+)\}}/`, or an array of delimiter strings, like `['{{', '}}']` | ||
* `tag`: the name of the placeholder tag. | ||
## API | ||
### [layouts](./index.js#L26) | ||
* `str` **{String}**: The content string to be wrapped with a layout. | ||
* `key` **{String}**: The object key of the starting layout. | ||
* `templates` **{Object}**: Object of layouts. | ||
* `options` **{Object}** | ||
- `layoutDelims` **{Object}**: Custom delimiters to use. | ||
- `defaultLayout` **{Object}**: The name (key) of the default layout to use. | ||
* `returns` **{String}**: String wrapped with a layout or layouts. | ||
### [renderLayouts](index.js#L39) | ||
Wrap a string one or more layouts. | ||
Wrap one or more layouts around `string`. | ||
**Params** | ||
* `string` **{String}**: The string to wrap with a layout. | ||
* `layoutName` **{String}**: The name (key) of the layout object to use. | ||
* `layoutStack` **{Object}**: Object of layout objects. | ||
* `options` **{Object}**: Optionally define a `defaultLayout` (string), pass custom delimiters (`layoutDelims`) to use as the placeholder for the content insertion point, or change the name of the placeholder tag with the `tag` option. | ||
* `fn` **{Function}**: Optionally pass a function to modify the context as each layout is applied. | ||
* `returns` **{String}**: Returns the original string wrapped with one or more layouts. | ||
**Example** | ||
```js | ||
renderLayouts(string, layoutName, layoutStack, options, fn); | ||
``` | ||
## Related | ||
* [template](https://github.com/jonschlinkert/template): Render templates from any engine. Make custom template types, use layouts on pages, partials or any custom template type, custom delimiters, helpers, middleware, routes, loaders, and lots more. Powers Assemble v0.6.0, Verb v0.3.0 and your application. | ||
* [assemble](http://assemble.io): Static site generator for Grunt.js, Yeoman and Node.js. Used by Zurb Foundation, Zurb Ink, H5BP/Effeckt, Less.js / lesscss.org, Topcoat, Web Experience Toolkit, and hundreds of other projects to build sites, themes, components, documentation, blogs and gh | ||
* [verb](https://github.com/assemble/verb): Verb makes it dead simple to generate markdown documentation, using simple templates, with zero configuration required. A project without documentation is like a project that doesn't exist. | ||
* [handlebars-helpers](https://github.com/assemble/handlebars-helpers): 120+ Handlebars helpers in ~20 categories, for Assemble, YUI, Ghost or any Handlebars project. Includes helpers like {{i18}}, {{markdown}}, {{relative}}, {{extend}}, {{moment}}, and so on. | ||
* [template-helpers](https://github.com/jonschlinkert/template-helpers): Generic JavaScript helpers that can be used with any template engine. Handlebars, Lo-Dash, Underscore, or any engine that supports helper functions. | ||
* [assemble](http://assemble.io): Static site generator for Grunt.js, Yeoman and Node.js. Used by Zurb Foundation, Zurb Ink, H5BP/Effeckt,… [more](http://assemble.io) | ||
* [handlebars-helpers](https://github.com/assemble/handlebars-helpers): 120+ Handlebars helpers in ~20 categories, for Assemble, YUI, Ghost or any Handlebars project. Includes… [more](https://github.com/assemble/handlebars-helpers) | ||
* [template](https://github.com/jonschlinkert/template): Render templates using any engine. Supports, layouts, pages, partials and custom template types. Use template… [more](https://github.com/jonschlinkert/template) | ||
* [template-helpers](https://github.com/jonschlinkert/template-helpers): Generic JavaScript helpers that can be used with any template engine. Handlebars, Lo-Dash, Underscore, or… [more](https://github.com/jonschlinkert/template-helpers) | ||
* [verb](https://github.com/assemble/verb): Documentation generator for GitHub projects. Extremely powerful, easy to use, can generate anything from API… [more](https://github.com/assemble/verb) | ||
## Running tests | ||
Install dev dependencies. | ||
```bash | ||
npm i -d && npm test | ||
Install dev dependencies: | ||
```sh | ||
$ npm i -d && npm test | ||
``` | ||
## Contributing | ||
Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](https://github.com/doowb/layouts/issues) | ||
Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](https://github.com/doowb/layouts/issues/new) | ||
@@ -79,12 +163,13 @@ ## Author | ||
**Brian Woodward** | ||
+ [github/doowb](https://github.com/doowb) | ||
+ [twitter/doowb](http://twitter.com/doowb) | ||
+ [twitter/doowb](http://twitter.com/doowb) | ||
## License | ||
Copyright (c) 2014-2015 Brian Woodward | ||
Released under the MIT license | ||
Copyright © 2014-2015 [Brian Woodward](https://github.com/doowb) | ||
Released under the MIT license. | ||
*** | ||
_This file was generated by [verb-cli](https://github.com/assemble/verb-cli) on March 09, 2015._ | ||
_This file was generated by [verb-cli](https://github.com/assemble/verb-cli) on July 17, 2015._ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
12334
145
172
1
Updateddelimiter-regex@^1.3.1
Updatedget-value@^1.1.5