Socket
Socket
Sign inDemoInstall

ablock

Package Overview
Dependencies
1
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.0.1 to 0.0.2

test.js

188

index.js

@@ -1,1 +0,187 @@

module.exports = require('./lib')
var Stream = require('stream')
var cat = require('cat-stream')
var fs = require('fs')
var PassThrough = Stream.PassThrough
var splitBlock = /(\{\{\s*\w+\s*\}\})/
var matchBlock = /\{\{\s*(\w+)\s*\}\}/
module.exports = Block
Block.read = function (filename, minify) {
var string = fs.readFileSync(filename, 'utf8')
return new Block(minify ? string.replace(/\n\s*/g, '') : string)
}
/*
blocks = string[]
names = {
key: index[]
}
*/
function Block(string) {
if (!(this instanceof Block))
return new Block(string)
var blocks = this.blocks = string.split(splitBlock)
var names = this.names = Object.create(null)
this._locals = Object.create(null)
for (var i = 0, l = blocks.length; i < l; i++) {
var block = blocks[i]
var match = block.match(matchBlock)
var name = match && match[1]
if (name)
(names[name] = names[name] || []).push(i)
}
}
// Permanently writes a local to the block.
// Useful for building blocks.
Block.prototype.local =
Block.prototype.locals = function (name, value) {
// locals({}) support
if (typeof name === 'object') {
Object.keys(name).forEach(function (key) {
this.local(key, name[key])
}, this)
return this
} else if (typeof name !== 'string') {
throw new Error('Local key must be a string.')
}
var indices = this.names[name]
if (!indices || !indices.length)
throw new Error('The block name "' + name + '" is not defined.')
value = value || ''
if (typeof value === 'function' || typeof value === 'string' || Buffer.isBuffer(value))
this._locals[name] = value
else if (value instanceof Stream)
throw new TypeError('Streams are not allowed as permanent locals as they can only be consumed once.')
else
throw new TypeError('Value must either be falsey, a string, a buffer, or a function.')
return this
}
Block.prototype.render = function (locals, callback) {
if (typeof locals === 'function') {
callback = locals
locals = {}
} else if (!locals) {
locals = {}
}
extend(locals, this._locals)
var names = this.names
var blocks = this.blocks.slice(0)
// Execute the functions and streams in parallel.
Object.keys(locals).forEach(function (key) {
var indices = names[key]
var value = locals[key] || ''
// In this case, we convert the stream into a function
// so we can replace all the blocks
if (value instanceof Stream && indices.length > 1) {
var stream = value
value = function (done) {
stream.pipe(cat(done))
}
}
// When its done, we replace all the blocks.
// Otherwise, we replace the blocks with a function
// that callbacks when the function is done.
if (typeof value === 'function') {
var fn = value
value = function (done) {
fn(function (err, string) {
if (err)
return done(err)
string = string || ''
indices.forEach(function (i) {
blocks[i] = string
})
done(null, string)
})
}
}
// Replace all the blocks with the local value
indices.forEach(function (i) {
blocks[i] = value
})
})
// Now we iterate through the blocks.
var stream = new PassThrough()
var i = 0
var l = blocks.length
;(function next(err) {
if (err)
return stream.emit('error', err)
if (i >= l)
return stream.end()
var block = blocks[i++]
if (!block) {
next()
} else if (typeof block === 'string') {
stream.write(block)
next()
} else if (Buffer.isBuffer(block) && block.length) {
stream.write(block)
next()
} else if (typeof block === 'function') {
block(function (err, buf) {
if (buf && buf.length)
stream.write(buf)
next(err)
})
} else if (block instanceof Stream) {
var cleanup = function cleanup() {
block.removeListener('error', next)
block.removeListener('error', cleanup)
block.removeListener('end', next)
block.removeListener('end', cleanup)
block.removeListener('close', next)
block.removeListener('close', cleanup)
}
block
.once('error', next)
.once('error', cleanup)
.once('end', next)
.once('end', cleanup)
.once('close', next)
.once('close', cleanup)
.pipe(stream, {
end: false
})
}
})()
if (callback)
stream.pipe(cat(callback))
return stream
}
function extend(dest, src) {
Object.keys(src).forEach(function (key) {
if (!(key in dest))
dest[key] = src[key]
})
}

11

package.json
{
"name": "ablock",
"description": "Asynchronous block-based templating",
"version": "0.0.1",
"version": "0.0.2",
"dependencies": {
"cat-stream": "~0.0.1"
},
"devDependencies": {
"should": "*",
"mocha": "*",
"concat-stream": "*",
"express": "*",
"supertest": "*",
"jade": "*"
"mocha": "*"
},

@@ -13,0 +12,0 @@ "scripts": {

# ABlock - Asynchronous Block Templating [![Build Status](https://travis-ci.org/funraiseme/ablock.png)](https://travis-ci.org/funraiseme/ablock)
Split your templates into asynchronous blocks,
then asynchronously render the template,
with a streaming option.
then asynchronously render the template.
This is a asynchronous, server-side extension of [block](https://github.com/funraiseme/block).
This is similar to [hyperstream](https://github.com/substack/hyperstream) except:
- More than just streams are allowed
- No CSS selector support - `ablock` is template type agnostic. You can stream JSON if you really want.
## API
### new Block(string)
Creates a block instance from an input string.
Each block can only be a word and must be surrounded by `{{}}`.
Example, `{{header}}` is okay, but not `{{body.header}}`.
### block.local({} || [key'', value]), block.locals()
Permanently replaces a block with a string or an asynchronous function.
`block.local()` and `block.locals()` are aliases of each other.
For example:
```js
var template = new Block('<html>{{head}}{{body}}</html>')
// This would permanently replace {{head}} with the following string
template.local('head', '<title>My Site</title>')
// This would permanently replace {{body}} with an asynchronous template
template.local('body', function (done) {
res.render('homepage', done)
})
// This would set both locals at the same time:
template.local({
head: '<title>My Site</title>',
body: function (done) {
res.render('homepage', done)
}
})
```
This is useful when building templates from pieces.
### block.render([locals], [callback])
This returns a readable stream.
`locals` are optional, temporary locals for the template.
Unlike `block.local()`, these locals are not permanent.
`locals` must be an object.
`callback` is an optional callback that returns the resulting template as a `Buffer` instance. For example:
```js
function (req, res, next) {
block.render(res.locals, function (err, buf) {
if (err)
return next(err)
if (!buf)
// One of the underlying streams was destroyed.
return next(new Error('Something wrong happened.'))
res.setHeader('Content-Type', 'text/html; charset=utf-8')
res.send(buf)
})
}
```
If you want the result in a single string, just call `buf.toString('utf8')`.
However, this is pretty much unnecessary.
If no `callback` is set, you are expected to `block.render().pipe()` into a writable stream. For example:
```js
function (req, res) {
res.setHeader('Content-Type', 'text/html; charset=utf-8')
block.render(res.locals).pipe(res)
}
```
If you want to use conditional GETs (ie send 304 status codes when possible),
you should use a callback.
Otherwise, you should stream it.
### Valid block types
Each block can be:
- A string
- A buffer (ASCII or UTF-8)
- A readable stream
- A thunk (function that only takes a callback)
## License

@@ -9,0 +99,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc