Skip to content

Commit

Permalink
Add support for source-locators
Browse files Browse the repository at this point in the history
- Add an options for activating source-locators

If activated, the following is done:

- Use "handlebars-source-locators" to add source-locator tags
  to the output
- Post-process the output to insert actual filenames into the tags
  • Loading branch information
nknapp committed Mar 14, 2017
1 parent 463251d commit ff8b107
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 13 deletions.
23 changes: 22 additions & 1 deletion .thought/partials/usage.md.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ In a similar fashion, we could replace other parts of the configuration, like te
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 @@ -76,6 +76,27 @@ to override in order to modify a given part of the output.

{{{exec 'node 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 example-source-locators.js' cwd='examples/'}}}




### Accessing engine and configuration helpers

The configuration and the engine itself is passed as additional parameter into each helper call:
Expand Down
55 changes: 48 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ The following example demonstrates how to use this module:
├── config-module.js
├── example-merge.js
├── example-partial-names.js
├── example-source-locators.js
├── example.js
├── hb-helpers.js
├── hb-preprocessor.js
Expand Down Expand Up @@ -131,8 +132,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 +171,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 +208,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 +323,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
1 change: 1 addition & 0 deletions 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 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.'
}
}
}
14 changes: 14 additions & 0 deletions test/main-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,18 @@ describe('customize-engine-handlebars', function () {
}
})
})

it('should add source-locators if the "addSourceLocator"-option is enabled"', function () {
var hb2 = hb.merge({
handlebars: {
addSourceLocators: true
}
})
return expect(hb2.run()).to.eventually.deep.equal({
handlebars: {
'a.md': '<sl line="1" col="0" file="test/fixtures/templates/a.md.hbs"></sl>a.md <sl line="1" col="5" file="test/fixtures/templates/a.md.hbs"></sl><sl line="1" col="0" partial="eins" file="test/fixtures/testPartials1/eins.hbs"></sl>testPartials1/eins <sl line="1" col="19" partial="eins" file="test/fixtures/testPartials1/eins.hbs"></sl>->one<-',
'b.md': '<sl line="1" col="0" file="test/fixtures/templates/b.md.hbs"></sl>b.md <sl line="1" col="5" file="test/fixtures/templates/b.md.hbs"></sl><sl line="1" col="0" partial="zwei" file="test/fixtures/testPartials1/zwei.hbs"></sl>testPartials1/zwei <sl line="1" col="19" partial="zwei" file="test/fixtures/testPartials1/zwei.hbs"></sl>->two<-<sl line="1" col="14" file="test/fixtures/templates/b.md.hbs"></sl> <sl line="1" col="15" file="test/fixtures/templates/b.md.hbs"></sl>helper1(->two<-)'
}
})
})
})

0 comments on commit ff8b107

Please sign in to comment.