async-helpers
Advanced tools
Comparing version 0.3.5 to 0.3.6
264
index.js
@@ -12,2 +12,3 @@ /*! | ||
var cache = {}; | ||
var stash = {}; | ||
@@ -22,5 +23,2 @@ /** | ||
* @param {Object} `options` options to pass to instance | ||
* @param {Function} `createPrefix` Create the id prefix given a prefix and current global counter. | ||
* @param {Function} `createId` Create the entire id given an already generated prefix and the current instance counter. | ||
* @param {Function} `createRegExp` Create the regex string that will be passed to `new RegExp` for testing if an async id placeholder exists. Takes the current prefix value. | ||
* @return {Object} new AsyncHelpers instance | ||
@@ -38,3 +36,2 @@ * @api public | ||
this.helpers = {}; | ||
this.stash = {}; | ||
this.counter = 0; | ||
@@ -143,3 +140,3 @@ this.globalCounter = AsyncHelpers.globalCounter++; | ||
function wrapper(name, fn, thisArg) { | ||
var prefix = createPrefix(thisArg.prefix, thisArg.globalCounter, thisArg.options); | ||
var prefix = createPrefix(thisArg.prefix, thisArg.globalCounter); | ||
@@ -152,10 +149,8 @@ return function() { | ||
for (var i = len - 1; i >= 0; i--) { | ||
var re = new RegExp(createRegExp(prefix), 'g'); | ||
var arg = args[i] = arguments[i]; | ||
// store references to other async helpers (string === '__async_0_1') | ||
if (typeof arg === 'string') { | ||
var matches = arg.match(new RegExp(createRegExp(prefix, thisArg.options), 'g')); | ||
if (matches) { | ||
argRefs.push({arg: arg, idx: i}); | ||
} | ||
if (typeof arg === 'string' && re.test(arg)) { | ||
argRefs.push({arg: arg, idx: i}); | ||
} | ||
@@ -165,3 +160,3 @@ } | ||
// generate a unique ID for the wrapped helper | ||
var id = createId(prefix, thisArg.counter++, thisArg.options); | ||
var id = createId(prefix, thisArg.counter++); | ||
var obj = { | ||
@@ -175,3 +170,3 @@ id: id, | ||
thisArg.stash[obj.id] = obj; | ||
stash[obj.id] = obj; | ||
return obj.id; | ||
@@ -216,3 +211,3 @@ }; | ||
AsyncHelpers.prototype.reset = function() { | ||
this.stash = {}; | ||
stash = {}; | ||
this.counter = 0; | ||
@@ -224,2 +219,3 @@ return this; | ||
* Resolve a stashed helper by the generated id. | ||
* This is a generator function and should be used with [co][] | ||
* | ||
@@ -229,86 +225,105 @@ * ```js | ||
* var id = upper('doowb'); | ||
* asyncHelpers.resolveId(id, function (err, result) { | ||
* console.log(result); | ||
* //=> DOOWB | ||
* }); | ||
* | ||
* co(asyncHelpers.resolveId(id)) | ||
* .then(console.log) | ||
* .catch(console.error); | ||
* | ||
* //=> DOOWB | ||
* ``` | ||
* | ||
* @param {String} `key` ID generated when from executing a wrapped helper. | ||
* @param {Function} `cb` Callback function with the results of executing the async helper. | ||
* @api public | ||
*/ | ||
AsyncHelpers.prototype.resolveId = function(key, cb) { | ||
if (typeof cb !== 'function') { | ||
throw new Error('AsyncHelpers#resolveId() expects a callback function.'); | ||
} | ||
AsyncHelpers.prototype.resolveId = function* (key) { | ||
if (typeof key !== 'string') { | ||
cb(new Error('AsyncHelpers#resolveId() expects `key` to be a string.')); | ||
throw new Error('AsyncHelpers#resolveId() expects `key` to be a string.'); | ||
} | ||
var prefix = createPrefix(this.prefix, this.globalCounter, this.options); | ||
var re = cache[prefix] || (cache[prefix] = new RegExp(createRegExp(prefix, this.options))); | ||
var stashed = this.stash[key]; | ||
if (!stashed) { | ||
return cb(new Error('Unable to resolve ' + key + '. Not Found')); | ||
var self = this; | ||
var prefix = createPrefix(this.prefix, this.globalCounter); | ||
var re = cache[prefix] || (cache[prefix] = new RegExp(createRegExp(prefix))); | ||
var helper = stash[key]; | ||
if (!helper) { | ||
throw new Error('Unable to resolve ' + key + '. Not Found'); | ||
} | ||
if (typeof stashed.fn !== 'function') { | ||
return cb(null, stashed.fn); | ||
} | ||
var res; | ||
var args = yield utils.co(this.resolveArgs(helper)); | ||
var self = this; | ||
utils.async.series([ | ||
function (next) { | ||
if (stashed.argRefs.length > 0) { | ||
utils.async.each(stashed.argRefs, function (ref, next2) { | ||
self.resolveId(ref.arg, function (err, value) { | ||
if (err) return next2(err); | ||
stashed.args[ref.idx] = value; | ||
next2(); | ||
}); | ||
}, next); | ||
return yield function(cb) { | ||
if (typeof helper.fn !== 'function') { | ||
return cb(null, helper.fn); | ||
} | ||
var done = function(err, val) { | ||
if (typeof val !== 'undefined') { | ||
helper.fn = val; | ||
return cb(err, helper.fn); | ||
} else { | ||
next(); | ||
return cb(err, ''); | ||
} | ||
}, | ||
function (next) { | ||
next = once(next); | ||
var res = null; | ||
var args = stashed.args; | ||
} | ||
if (stashed.fn.async) { | ||
args = args.concat(function (err, result) { | ||
if (err) return next(formatError(err, stashed, args)); | ||
if (re.test(result)) { | ||
return self.resolveIds(result, next); | ||
} | ||
return next(err, result); | ||
}); | ||
} | ||
try { | ||
res = stashed.fn.apply(stashed.thisArg, args); | ||
if (re.test(res)) { | ||
return self.resolveIds(res, next); | ||
if (helper.fn.async) { | ||
args = args.concat(function(err, result) { | ||
if (err) return done(formatError(err, helper, args)); | ||
if (re.test(result)) { | ||
return self.resolveIds(result, done); | ||
} | ||
} catch (err) { | ||
return next(formatError(err, stashed, args)); | ||
return done(null, result); | ||
}); | ||
} | ||
try { | ||
res = helper.fn.apply(helper.thisArg, args); | ||
if(re.test(res)) { | ||
return self.resolveIds(res, done); | ||
} | ||
if (!stashed.fn.async) { | ||
return next(null, res); | ||
} | ||
} catch (err) { | ||
return done(formatError(err, helper, args)); | ||
} | ||
], function (err, results) { | ||
if (typeof results[1] !== 'undefined') { | ||
// update the fn so if it's called again it'll just return the true results | ||
stashed.fn = results[1]; | ||
return cb(err, stashed.fn); | ||
} else { | ||
return cb(err, ''); | ||
if (!helper.fn.async) { | ||
return done(null, res); | ||
} | ||
}); | ||
} | ||
}; | ||
/** | ||
* Generator function for resolving helper arguments | ||
* that contain async ids. This function should be used | ||
* with [co][]. | ||
* | ||
* This is used inside `resolveId`: | ||
* | ||
* ```js | ||
* var args = yield co(asyncHelpers.resolveArgs(helper)); | ||
* ``` | ||
* @param {Object} `helper` helper object with an `argRefs` array. | ||
*/ | ||
AsyncHelpers.prototype.resolveArgs = function* (helper) { | ||
var args = helper.args; | ||
var len = helper.argRefs.length, i = 0; | ||
while(len--) { | ||
var ref = helper.argRefs[i++]; | ||
args[ref.idx] = yield utils.co(this.resolveId(ref.arg)); | ||
} | ||
return args; | ||
}; | ||
/** | ||
* After rendering a string using wrapped async helpers, | ||
* use `resolveIds` to invoke the original async helpers and replace | ||
* the async ids with results from the async helpers. | ||
* | ||
* ```js | ||
* asyncHelpers.resolveIds(renderedString, function(err, content) { | ||
* if (err) return console.error(err); | ||
* console.log(content); | ||
* }); | ||
* ``` | ||
* @param {String} `str` String containing async ids | ||
* @param {Function} `cb` Callback function accepting an `err` and `content` parameters. | ||
* @api public | ||
*/ | ||
AsyncHelpers.prototype.resolveIds = function(str, cb) { | ||
@@ -323,30 +338,33 @@ if (typeof cb !== 'function') { | ||
var self = this; | ||
// `stash` contains the objects created when rendering the template | ||
var stashed = this.stash; | ||
utils.async.eachSeries(Object.keys(stashed), function (key, next) { | ||
// check to see if the async ID is in the rendered string | ||
if (str.indexOf(key) === -1) { | ||
return next(null); | ||
var prefix = createPrefix(this.prefix, '(\\d)+') | ||
var re = cache[prefix] || (cache[prefix] = new RegExp('(' + createRegExp(prefix) + ')', 'g')); | ||
var keys = str.match(re); | ||
utils.co(function* () { | ||
if (!keys) return str; | ||
var len = keys.length, i = 0; | ||
while(len--) { | ||
var key = keys[i++]; | ||
var val = yield utils.co(self.resolveId(key)); | ||
str = str.split(key).join(val); | ||
} | ||
self.resolveId(key, function (err, value) { | ||
if (err) return next(err); | ||
// replace the async ID with the resolved value | ||
str = str.split(key).join(value); | ||
next(null); | ||
}); | ||
}, function (err) { | ||
if (err) return cb(err); | ||
cb(null, str); | ||
return str; | ||
}) | ||
.then(function(res) { | ||
cb(null, res); | ||
}) | ||
.catch(function(err) { | ||
cb(err); | ||
}); | ||
}; | ||
function once (fn) { | ||
return function () { | ||
if (fn.called) return fn.value; | ||
fn.called = true; | ||
fn.value = fn.apply(fn, arguments); | ||
return fn.value; | ||
}; | ||
} | ||
/** | ||
* Format an error message to provide better information about the | ||
* helper and the arguments passed to the helper when the error occurred. | ||
* | ||
* @param {Object} `err` Error object | ||
* @param {Object} `helper` helper object to provide more information | ||
* @param {Array} `args` Array of arguments passed to the helper. | ||
* @return {Object} Formatted Error object | ||
*/ | ||
@@ -371,24 +389,40 @@ function formatError(err, helper, args) { | ||
function createPrefix(prefix, counter, options) { | ||
options = options || {}; | ||
if (typeof options.createPrefix === 'function') { | ||
return option.createPrefix(prefix, counter); | ||
} | ||
/** | ||
* Create a prefix to use when generating an async id. | ||
* | ||
* @param {String} `prefix` prefix string to start with. | ||
* @param {String} `counter` string to append. | ||
* @return {String} new prefix | ||
*/ | ||
function createPrefix(prefix, counter) { | ||
return prefix + counter + '$'; | ||
} | ||
function createId(prefix, counter, options) { | ||
options = options || {}; | ||
if (typeof options.createId === 'function') { | ||
return option.createId(prefix, counter); | ||
} | ||
/** | ||
* Create an async id from the provided prefix and counter. | ||
* | ||
* @param {String} `prefix` prefix string to start with | ||
* @param {String} `counter` string to append. | ||
* @return {String} async id | ||
*/ | ||
function createId(prefix, counter) { | ||
return prefix + counter + '$}'; | ||
} | ||
function createRegExp(prefix, options) { | ||
options = options || {}; | ||
if (typeof options.createRegExp === 'function') { | ||
return option.createRegExp(prefix); | ||
/** | ||
* Create a string to pass into `RegExp` for checking for and finding async ids. | ||
* | ||
* @param {String} `prefix` prefix to use for the first part of the regex | ||
* @return {String} string to pass into `RegExp` | ||
*/ | ||
function createRegExp(prefix) { | ||
var key = 'prefix:' + prefix; | ||
if (cache[key]) { | ||
return cache[key]; | ||
} | ||
return prefix.split('$').join('\\\$') + '(\\d)+\\$}' | ||
var res = prefix.split('$').join('\\\$') + '(\\d)+\\$}'; | ||
return (cache[key] = res); | ||
} | ||
@@ -395,0 +429,0 @@ |
{ | ||
"name": "async-helpers", | ||
"description": "Use async helpers in templates with engines that typically only handle sync helpers. Handlebars and Lodash have been tested.", | ||
"version": "0.3.5", | ||
"version": "0.3.6", | ||
"homepage": "https://github.com/doowb/async-helpers", | ||
@@ -27,3 +27,3 @@ "author": { | ||
"dependencies": { | ||
"async": "^1.5.0", | ||
"co": "^4.6.0", | ||
"lazy-cache": "^1.0.3", | ||
@@ -33,4 +33,6 @@ "safe-json-stringify": "^1.0.3" | ||
"devDependencies": { | ||
"handlebars": "^3.0.3", | ||
"lodash": "^3.10.1", | ||
"async": "^1.5.2", | ||
"gulp-format-md": "^0.1.7", | ||
"handlebars": "^4.0.5", | ||
"lodash": "^4.6.1", | ||
"mocha": "*" | ||
@@ -48,3 +50,19 @@ }, | ||
"underscore" | ||
] | ||
], | ||
"verb": { | ||
"layout": "default", | ||
"plugins": [ | ||
"gulp-format-md" | ||
], | ||
"related": { | ||
"list": [ | ||
"assemble", | ||
"co", | ||
"generate", | ||
"templates", | ||
"verb" | ||
] | ||
}, | ||
"task": "readme" | ||
} | ||
} |
@@ -1,9 +0,11 @@ | ||
# async-helpers [![NPM version](https://badge.fury.io/js/async-helpers.svg)](http://badge.fury.io/js/async-helpers) [![Build Status](https://travis-ci.org/doowb/async-helpers.svg)](https://travis-ci.org/doowb/async-helpers) | ||
# async-helpers [![NPM version](https://img.shields.io/npm/v/async-helpers.svg)](https://www.npmjs.com/) [![Build Status](https://img.shields.io/travis/doowb/async-helpers.svg)](index.js#L26) | ||
> Use async helpers in templates with engines that typically only handle sync helpers. Handlebars and Lodash have been tested. | ||
Install with [npm](https://www.npmjs.com/) | ||
## Install | ||
Install with [npm](https://www.npmjs.com/): | ||
```sh | ||
$ npm i async-helpers --save | ||
$ npm install async-helpers --save | ||
``` | ||
@@ -19,6 +21,9 @@ | ||
### [AsyncHelpers](index.js#L32) | ||
### [AsyncHelpers](index.js#L26) | ||
Create a new instance of AsyncHelpers | ||
**Params** | ||
* `options` **{Object}**: options to pass to instance | ||
* `returns` **{Object}**: new AsyncHelpers instance | ||
@@ -32,3 +37,3 @@ | ||
### [.set](index.js#L68) | ||
### [.set](index.js#L62) | ||
@@ -51,3 +56,3 @@ Add a helper to the cache. | ||
### [.get](index.js#L91) | ||
### [.get](index.js#L85) | ||
@@ -69,3 +74,3 @@ Get all helpers or a helper with the given name. | ||
### [.wrap](index.js#L190) | ||
### [.wrap](index.js#L182) | ||
@@ -86,3 +91,3 @@ Wrap a helper with async handling capibilities. | ||
### [.reset](index.js#L211) | ||
### [.reset](index.js#L203) | ||
@@ -99,5 +104,5 @@ Reset all the stashed helpers. | ||
### [.resolveId](index.js#L234) | ||
### [.resolveId](index.js#L228) | ||
Resolve a stashed helper by the generated id. | ||
Resolve a stashed helper by the generated id. This is a generator function and should be used with [co](https://github.com/tj/co) | ||
@@ -107,3 +112,2 @@ **Params** | ||
* `key` **{String}**: ID generated when from executing a wrapped helper. | ||
* `cb` **{Function}**: Callback function with the results of executing the async helper. | ||
@@ -115,5 +119,25 @@ **Example** | ||
var id = upper('doowb'); | ||
asyncHelpers.resolveId(id, function (err, result) { | ||
console.log(result); | ||
//=> DOOWB | ||
co(asyncHelpers.resolveId(id)) | ||
.then(console.log) | ||
.catch(console.error); | ||
//=> DOOWB | ||
``` | ||
### [.resolveIds](index.js#L319) | ||
After rendering a string using wrapped async helpers, use `resolveIds` to invoke the original async helpers and replace the async ids with results from the async helpers. | ||
**Params** | ||
* `str` **{String}**: String containing async ids | ||
* `cb` **{Function}**: Callback function accepting an `err` and `content` parameters. | ||
**Example** | ||
```js | ||
asyncHelpers.resolveIds(renderedString, function(err, content) { | ||
if (err) return console.error(err); | ||
console.log(content); | ||
}); | ||
@@ -124,18 +148,34 @@ ``` | ||
* [engine-cache](https://www.npmjs.com/package/engine-cache): express.js inspired template-engine manager. | [homepage](https://github.com/jonschlinkert/engine-cache) | ||
* [helper-cache](https://www.npmjs.com/package/helper-cache): Easily register and get helper functions to be passed to any template engine or node.js… [more](https://www.npmjs.com/package/helper-cache) | [homepage](https://github.com/jonschlinkert/helper-cache) | ||
* [template-helpers](https://www.npmjs.com/package/template-helpers): Generic JavaScript helpers that can be used with any template engine. Handlebars, Lo-Dash, Underscore, or… [more](https://www.npmjs.com/package/template-helpers) | [homepage](https://github.com/jonschlinkert/template-helpers) | ||
* [assemble](https://www.npmjs.com/package/assemble): Assemble is a powerful, extendable and easy to use static site generator for node.js. Used… [more](https://www.npmjs.com/package/assemble) | [homepage](https://github.com/assemble/assemble) | ||
* [co](https://www.npmjs.com/package/co): generator async control flow goodness | [homepage](https://github.com/tj/co) | ||
* [generate](https://www.npmjs.com/package/generate): Fast, composable, highly extendable project generator with a user-friendly and expressive API. | [homepage](https://github.com/generate/generate) | ||
* [templates](https://www.npmjs.com/package/templates): System for creating and managing template collections, and rendering templates with any node.js template engine.… [more](https://www.npmjs.com/package/templates) | [homepage](https://github.com/jonschlinkert/templates) | ||
* [verb](https://www.npmjs.com/package/verb): Documentation generator for GitHub projects. Verb is extremely powerful, easy to use, and is used… [more](https://www.npmjs.com/package/verb) | [homepage](https://github.com/verbose/verb) | ||
## Run tests | ||
## Contributing | ||
Install dev dependencies: | ||
Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](https://github.com/doowb/async-helpers/issues/new). | ||
## Building docs | ||
Generate readme and API documentation with [verb][]: | ||
```sh | ||
$ npm i -d && npm test | ||
$ npm install verb && npm run docs | ||
``` | ||
## Contributing | ||
Or, if [verb][] is installed globally: | ||
Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](https://github.com/doowb/async-helpers/issues/new). | ||
```sh | ||
$ verb | ||
``` | ||
## Running tests | ||
Install dev dependencies: | ||
```sh | ||
$ npm install -d && npm test | ||
``` | ||
## Author | ||
@@ -145,12 +185,12 @@ | ||
+ [github/doowb](https://github.com/doowb) | ||
+ [twitter/doowb](http://twitter.com/doowb) | ||
* [github/doowb](https://github.com/doowb) | ||
* [twitter/doowb](http://twitter.com/doowb) | ||
## License | ||
Copyright © 2015 Brian Woodward | ||
Released under the MIT license. | ||
Copyright © 2016 [Brian Woodward](https://github.com/doowb) | ||
Released under the [MIT license](https://github.com/doowb/async-helpers/blob/master/LICENSE). | ||
*** | ||
_This file was generated by [verb-cli](https://github.com/assemble/verb-cli) on August 30, 2015._ | ||
_This file was generated by [verb](https://github.com/verbose/verb), v0.9.0, on March 10, 2016._ |
@@ -27,3 +27,3 @@ 'use strict'; | ||
require('async'); | ||
require('co'); | ||
require('safe-json-stringify', 'stringify'); | ||
@@ -30,0 +30,0 @@ |
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
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
18393
402
186
5
+ Addedco@^4.6.0
+ Addedco@4.6.0(transitive)
- Removedasync@^1.5.0
- Removedasync@1.5.2(transitive)