Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for source-locators #4

Merged
merged 4 commits into from
Mar 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 28 additions & 7 deletions .thought/partials/usage.md.hbs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## Usage

The following example demonstrates how to use this module:
The following examples demonstrate how to use this module. The following files are involved:

{{{dirTree 'examples/' }}}

Expand All @@ -11,11 +11,11 @@ of the Handlebars-engine:

{{{example 'examples/example.js'}}}

This example loads its configuration from the module `config-module.js`
This example loads its configuration from the module `config-module.js`:

{{{include 'examples/config-module.js'}}}

*A quick note: If your are really creating a configuration-module, you should always
*A quick note: If your are creating a real configuration-module, you should always
use `require.resolve` or `__dirname` to determine the correct path to referenced files.*

All the templates in the `templates` directory are called with the provided `data` (name and city).
Expand All @@ -39,7 +39,7 @@ the `footer.hbs` partial.

The output of this example is:

{{{exec 'node example.js' cwd='examples/'}}}
{{{exec 'node -r "../.thought/stable-console" example.js' cwd='examples/'}}}


### Customizing configurations
Expand All @@ -57,13 +57,13 @@ The new `footer.hbs` writes only the current temperature, instead of the weather

The output of this example is

{{{exec 'node example-merge.js' cwd='examples/'}}}
{{{exec 'node -r "../.thought/stable-console" example-merge.js' cwd='examples/'}}}

In a similar fashion, we could replace other parts of the configuration, like templates, helpers
and the pre-processor. If we would provide a new preprocessor, it could call the old one,
by calling `this.parent(args)`

### Which partial generates what?
### Which partial generates what? (Method 1)

When we want to overriding parts of the output, we are looking for the correct partial to do so.
For this purpose, the engine allows to specify a "wrapper function" for partials. This function
Expand All @@ -74,7 +74,28 @@ to override in order to modify a given part of the output.

{{{example 'examples/example-partial-names.js'}}}

{{{exec 'node example-partial-names.js' cwd='examples/'}}}
{{{exec 'node -r "../.thought/stable-console" example-partial-names.js' cwd='examples/'}}}

### Which partial generates what? (Method 2)

Another method for gathering information about the source of parts of the output are source-locators.
The engine incoorporates the library {{npm 'handlebars-source-locators'}} to integrate a kind of
"source-map for the poor" into the output. Source-locators are activated by setting the option
`addSourceLocators` to `true`:

{{{example 'examples/example-source-locators.js'}}}

The output contain tags that contain location-information of the succeeding text:

* `<sl line="1" col="12" file="templates/text1.txt.hbs"></sl>text...` for text the originate from a template file
* `<sl line="1" col="0" partial="footer" file="partials2/footer.hbs"></sl>text...` for text the originate from a partial

Example output:

{{{exec 'node -r "../.thought/stable-console" example-source-locators.js' cwd='examples/'}}}




### Accessing engine and configuration helpers

Expand Down
11 changes: 11 additions & 0 deletions .thought/stable-console.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// For the examples, make sure that the output is stable
var consoleLog = console.log
var stringify = require('json-stable-stringify')

console.log = function () {
consoleLog.apply(this, Array.prototype.map.call(
arguments, (arg) => JSON.parse(stringify(arg, { space: 2 }))
))
}


22 changes: 15 additions & 7 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
sudo: false
cache:
directories:
- node_modules
language: "node_js"
node_js:
- "0.10"
- "0.12"
- "iojs"
- "4"
- "6"
- "7"
before_script:
- npm install standard
- standard
matrix:
include:
- node_js: "6"
env: STATIC_CHECKS=true
script:
- |
if [ "${STATIC_CHECKS}" = "true" ]; then
# Just perform static checks and exit
standard || exit 1
# npm install thought
# thought -d up-to-date || exit 1
exit 0
fi
- npm install istanbul
- istanbul cover ./node_modules/.bin/_mocha --report lcovonly
after_script:
Expand Down
63 changes: 51 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# customize-engine-handlebars

[![Greenkeeper badge](https://badges.greenkeeper.io/bootprint/customize-engine-handlebars.svg)](https://greenkeeper.io/)

[![NPM version](https://badge.fury.io/js/customize-engine-handlebars.svg)](http://badge.fury.io/js/customize-engine-handlebars)
[![Travis Build Status](https://travis-ci.org/bootprint/customize-engine-handlebars.svg?branch=master)](https://travis-ci.org/bootprint/customize-engine-handlebars)
[![Coverage Status](https://img.shields.io/coveralls/bootprint/customize-engine-handlebars.svg)](https://coveralls.io/r/bootprint/customize-engine-handlebars)
Expand All @@ -18,13 +16,14 @@ npm install customize-engine-handlebars

## Usage

The following example demonstrates how to use this module:
The following examples demonstrate how to use this module. The following files are involved:

<pre><code>

├── config-module.js
├── example-merge.js
├── example-partial-names.js
├── example-source-locators.js
├── example.js
├── hb-helpers.js
├── hb-preprocessor.js
Expand All @@ -51,7 +50,7 @@ customize()
.done(console.log)
```

This example loads its configuration from the module `config-module.js`
This example loads its configuration from the module `config-module.js`:

```js
module.exports = function (customize) {
Expand All @@ -77,7 +76,7 @@ module.exports = function (customize) {
```


*A quick note: If your are really creating a configuration-module, you should always
*A quick note: If your are creating a real configuration-module, you should always
use `require.resolve` or `__dirname` to determine the correct path to referenced files.*

All the templates in the `templates` directory are called with the provided `data` (name and city).
Expand Down Expand Up @@ -131,8 +130,8 @@ The output of this example is:
```
https://api.github.com/users/nknapp
{ handlebars:
{ 'text2.txt': 'I\'m nknapp\n\nI\'m living in DARMSTADT.\n\n------\nGithub-Name: Nils Knappmeier',
'text1.txt': 'I\'m nknapp\n\nI\'m living in Darmstadt.\n\n------\nGithub-Name: Nils Knappmeier' } }
{ 'text1.txt': 'I\'m nknapp\n\nI\'m living in Darmstadt.\n\n------\nGithub-Name: Nils Knappmeier',
'text2.txt': 'I\'m nknapp\n\nI\'m living in DARMSTADT.\n\n------\nGithub-Name: Nils Knappmeier' } }
```


Expand Down Expand Up @@ -170,15 +169,15 @@ The output of this example is
```
https://api.github.com/users/nknapp
{ handlebars:
{ 'text2.txt': 'I\'m nknapp\n\nI\'m living in DARMSTADT.\n\n------\nBlog: http://www.knappmeier.de',
'text1.txt': 'I\'m nknapp\n\nI\'m living in Darmstadt.\n\n------\nBlog: http://www.knappmeier.de' } }
{ 'text1.txt': 'I\'m nknapp\n\nI\'m living in Darmstadt.\n\n------\nBlog: https://blog.knappi.org',
'text2.txt': 'I\'m nknapp\n\nI\'m living in DARMSTADT.\n\n------\nBlog: https://blog.knappi.org' } }
```

In a similar fashion, we could replace other parts of the configuration, like templates, helpers
and the pre-processor. If we would provide a new preprocessor, it could call the old one,
by calling `this.parent(args)`

### Which partial generates what?
### Which partial generates what? (Method 1)

When we want to overriding parts of the output, we are looking for the correct partial to do so.
For this purpose, the engine allows to specify a "wrapper function" for partials. This function
Expand Down Expand Up @@ -207,10 +206,49 @@ customize()
```
https://api.github.com/users/nknapp
{ handlebars:
{ 'text1.txt': 'I\'m nknapp\n\nI\'m living in Darmstadt.\n\n[BEGIN footer]\n------\nBlog: http://www.knappmeier.de[END footer]',
'text2.txt': 'I\'m nknapp\n\nI\'m living in DARMSTADT.\n\n[BEGIN footer]\n------\nBlog: http://www.knappmeier.de[END footer]' } }
{ 'text1.txt': 'I\'m nknapp\n\nI\'m living in Darmstadt.\n\n[BEGIN footer]\n------\nBlog: https://blog.knappi.org[END footer]',
'text2.txt': 'I\'m nknapp\n\nI\'m living in DARMSTADT.\n\n[BEGIN footer]\n------\nBlog: https://blog.knappi.org[END footer]' } }
```

### Which partial generates what? (Method 2)

Another method for gathering information about the source of parts of the output are source-locators.
The engine incoorporates the library [handlebars-source-locators](https://npmjs.com/package/handlebars-source-locators) to integrate a kind of
"source-map for the poor" into the output. Source-locators are activated by setting the option
`addSourceLocators` to `true`:

```js
var customize = require('customize')
customize()
.registerEngine('handlebars', require('customize-engine-handlebars'))
.load(require('./config-module.js'))
.merge({
handlebars: {
partials: 'partials2',
addSourceLocators: true
}
})
.run()
.done(console.log)
```

The output contain tags that contain location-information of the succeeding text:

* `<sl line="1" col="12" file="templates/text1.txt.hbs"></sl>text...` for text the originate from a template file
* `<sl line="1" col="0" partial="footer" file="partials2/footer.hbs"></sl>text...` for text the originate from a partial

Example output:

```
https://api.github.com/users/nknapp
{ handlebars:
{ 'text1.txt': '<sl line="1" col="0" file="templates/text1.txt.hbs"></sl>I\'m <sl line="1" col="4" file="templates/text1.txt.hbs"></sl>nknapp<sl line="1" col="12" file="templates/text1.txt.hbs"></sl>\n\nI\'m living in <sl line="3" col="14" file="templates/text1.txt.hbs"></sl>Darmstadt<sl line="3" col="22" file="templates/text1.txt.hbs"></sl>.\n\n<sl line="5" col="0" file="templates/text1.txt.hbs"></sl><sl line="1" col="0" partial="footer" file="partials2/footer.hbs"></sl>------\nBlog: <sl line="2" col="6" partial="footer" file="partials2/footer.hbs"></sl>https://blog.knappi.org',
'text2.txt': '<sl line="1" col="0" file="templates/text2.txt.hbs"></sl>I\'m <sl line="1" col="4" file="templates/text2.txt.hbs"></sl>nknapp<sl line="1" col="12" file="templates/text2.txt.hbs"></sl>\n\nI\'m living in <sl line="3" col="14" file="templates/text2.txt.hbs"></sl>DARMSTADT<sl line="3" col="28" file="templates/text2.txt.hbs"></sl>.\n\n<sl line="5" col="0" file="templates/text2.txt.hbs"></sl><sl line="1" col="0" partial="footer" file="partials2/footer.hbs"></sl>------\nBlog: <sl line="2" col="6" partial="footer" file="partials2/footer.hbs"></sl>https://blog.knappi.org' } }
```




### Accessing engine and configuration helpers

The configuration and the engine itself is passed as additional parameter into each helper call:
Expand Down Expand Up @@ -283,6 +321,7 @@ The default configuration for the handlebars engine
| data | <code>string</code> &#124; <code>object</code> &#124; <code>function</code> | a javascript-object to use as input for handlebars. Same as with the `helpers`, it is also acceptable to specify the path to a module exporting the data and a function computing the data. |
| preprocessor | <code>function</code> &#124; <code>string</code> | a function that takes the input data as first parameter and transforms it into another object or the promise for an object. It the input data is a promise itself, is resolved before calling this function. If the preprocessor is overridden, the parent preprocessor is available with `this.parent(data)` |
| hbsOptions | <code>object</code> | options to pass to `Handlebars.compile`. |
| addSourceLocators | <code>boolean</code> | add [handlebars-source-locators](https://github.com/nknapp/handlebars-source-locators) to the output of each template |



Expand Down
12 changes: 12 additions & 0 deletions examples/example-source-locators.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
var customize = require('customize')
customize()
.registerEngine('handlebars', require('../'))
.load(require('./config-module.js'))
.merge({
handlebars: {
partials: 'partials2',
addSourceLocators: true
}
})
.run()
.done(console.log)
42 changes: 37 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ var contents = function (partials) {
* is resolved before calling this function. If the preprocessor is overridden, the parent
* preprocessor is available with `this.parent(data)`
* @property {object} hbsOptions options to pass to `Handlebars.compile`.
* @property {boolean} addSourceLocators add [handlebars-source-locators](https://github.com/nknapp/handlebars-source-locators)
* to the output of each template
* @api public
*/

Expand All @@ -60,6 +62,8 @@ var contents = function (partials) {
* @property {function(object): (object|Promise<object>)} preprocessor
* preprocessor for the handlebars data
* @property {object} hbsOptions options to pass to `Handlebars.compile`.
* @property {boolean} addSourceLocators add [handlebars-source-locators](https://github.com/nknapp/handlebars-source-locators)
* to the output of each template
* @private
*/

Expand All @@ -71,7 +75,9 @@ module.exports = {

defaultConfig: {
partials: {},
partialWrapper: function (contents, name) { return contents },
partialWrapper: function (contents, name) {
return contents
},
helpers: {},
templates: {},
data: {},
Expand Down Expand Up @@ -105,7 +111,8 @@ module.exports = {
templates: files(config.templates),
data: data,
preprocessor: preprocessor && customize.withParent(preprocessor),
hbsOptions: config.hbsOptions
hbsOptions: config.hbsOptions,
addSourceLocators: config.addSourceLocators
}
},

Expand Down Expand Up @@ -139,7 +146,7 @@ module.exports = {
run: function run (config) {
// Run the preprocessor
return Q(config.preprocessor(config.data))
// Resolve any new promises
// Resolve any new promises
.then(deep)
// Process the result with Handlebars
.then(function (data) {
Expand All @@ -149,19 +156,44 @@ module.exports = {
var hbs = promisedHandlebars(Handlebars, {
Promise: Q.Promise
})
if (config.addSourceLocators) {
require('handlebars-source-locators')(hbs)
}

var partials = _.mapValues(contents(config.partials), config.partialWrapper)
hbs.registerPartial(partials)
hbs.registerHelper(addEngine(config.helpers, hbs, config))
var templates = contents(config.templates)

return _.mapValues(templates, function (template) {
var result = _.mapValues(templates, function (template) {
var fn = hbs.compile(template, config.hbsOptions)
debug('hbs-data', data)
var result = fn(data)
debug('fn(data) =' + data)
debug('fn(data) =' + result)
return result
})

if (config.addSourceLocators) {
// Lookup-tables for partial-/template-name to the source-file
// (which contains the original path to the actual file)
var partialToSourceFile = _.mapKeys(config.partials, stripHandlebarsExt)
var templateToSourceFile = _.mapKeys(config.templates, stripHandlebarsExt)
result = _.mapValues(result, function (contents, filename) {
// Post-process locator-tags to include file-paths
return contents.then((resolvedContents) => resolvedContents.replace(
/(<sl line="\d+" col="\d+")( partial="(.+?)")?(><\/sl>)/g,
function (match, head, partialPart, partialName, tail) {
if (partialName) {
return head + partialPart + ' file="' + partialToSourceFile[partialName].path + '"' + tail
} else {
return head + ' file="' + templateToSourceFile[filename].path + '"' + tail
}
}
))
})
}

return result
})
}
}
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"dependencies": {
"debug": "^2.2.0",
"handlebars": "^4.0.6",
"handlebars-source-locators": "^1.0.0",
"lodash": "^4.17.4",
"m-io": "^0.5.0",
"promised-handlebars": "^2.0.1",
Expand All @@ -42,7 +43,9 @@
"customize": "^1.0.0",
"get-promise": "^1.4.0",
"ghooks": "^2.0.0",
"json-stable-stringify": "^1.0.1",
"mocha": "^3.2.0",
"standard": "^9.0.1",
"thoughtful-release": "^0.3.0",
"trace-and-clarify-if-possible": "^1.0.0"
},
Expand All @@ -60,7 +63,7 @@
],
"config": {
"ghooks": {
"pre-push": "thoughtful precommit && standard"
"pre-commit": "thoughtful precommit && standard --fix"
}
},
"keywords": []
Expand Down
4 changes: 4 additions & 0 deletions schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ module.exports = {
},
'hbsOptions': {
description: 'Options passed to Handlebars#compile()'
},
'addSourceLocator': {
type: 'boolean',
description: 'If set to true, tags of the form `<sl line="1" col="0" file="test/fixtures/templates/a.md.hbs"></sl>` and `<sl line="1" col="0" partial="eins" file="test/fixtures/testPartials1/eins.hbs">` will be inserted into the output to provide source-coordinates.'
}
}
}
Loading