Skip to content

Commit dde24f4

Browse files
committed
refactor
1 parent 7de8876 commit dde24f4

File tree

3 files changed

+216
-85
lines changed

3 files changed

+216
-85
lines changed

docs.md

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
## Register the helper
2+
3+
> This should work with any engine, here are a few examples
4+
5+
### [templates](https://github.com/jonschlinkert/templates)
6+
7+
Register the helper for use with any template engine
8+
9+
```js
10+
template.helper('md', require('helper-md'));
11+
```
12+
13+
### [assemble](https://github.com/assemble/assemble)
14+
15+
To register the helper for use with [assemble](https://github.com/assemble/assemble) v0.6.x:
16+
17+
```js
18+
assemble.helper('md', require('helper-md'));
19+
```
20+
21+
### [verb](https://github.com/verbose/verb)
22+
23+
Register the helper for use with [verb](https://github.com/verbose/verb):
24+
25+
```js
26+
var verb = require('verb');
27+
verb.helper('md', require('helper-md'));
28+
```
29+
30+
### [handlebars](http://www.handlebarsjs.com/)
31+
32+
```js
33+
var handlebars = require('handlebars');
34+
handlebars.registerHelper('md', require('helper-md'));
35+
```
36+
37+
### lodash
38+
39+
Should work the same with [Lo-Dash](https://lodash.com/) or [underscore](http://underscorejs.org):
40+
41+
```js
42+
var md = require('helper-md');
43+
44+
// as a mixin
45+
_.mixin({md: md});
46+
_.template('<%= _.md("posts/foo.md") %>', {});
47+
//=> '<h1>heading</h1>\n'
48+
49+
// passed on the context
50+
_.template('<%= md("posts/foo.md") %>', {md: md});
51+
//=> '<h1>heading</h1>\n'
52+
53+
// as an import
54+
var settings = {imports: {md: md}};
55+
_.template('<%= md("posts/foo.md") %>', {}, settings);
56+
//=> '<h1>heading</h1>\n'
57+
```

index.js

+72-36
Original file line numberDiff line numberDiff line change
@@ -8,58 +8,94 @@
88
'use strict';
99

1010
var fs = require('fs');
11+
var path = require('path');
1112
var Remarkable = require('remarkable');
1213
var extend = require('extend-shallow');
14+
var exists = require('fs-exists-sync');
15+
var ent = require('ent');
1316

1417
/**
1518
* Expose `md` helper
1619
*/
1720

18-
module.exports = function md(name, opts) {
19-
opts = extend({sep: '\n', cwd: process.cwd()}, opts);
20-
extend(opts, opts.hash);
21+
module.exports = function(name, options, cb) {
22+
if (typeof options === 'function') {
23+
cb = options;
24+
options = {};
25+
}
26+
27+
if (typeof cb !== 'function') {
28+
throw new Error('md async helper expects callback to be a function. Did you mean to use `md.sync`?');
29+
}
30+
if (typeof this === 'undefined' || typeof this.app === 'undefined') {
31+
throw new Error('md async helper expects `app` to be exposed on the context');
32+
}
2133

22-
// Support for Assemble, Verb and Template
23-
if (this && this.app && typeof this.app.findPartial === 'function') {
24-
extend(opts, this.options.remarkable);
34+
var opts = extend({cwd: process.cwd()}, this.options, options);
35+
opts = extend({}, opts, opts.hash);
36+
var md = markdown(opts);
2537

26-
try {
27-
var template = this.app.findPartial(name);
28-
var str = template.render(opts);
29-
return markdown(opts).render(str);
30-
} catch (err) {
31-
return err;
32-
}
38+
var filepath = path.resolve(opts.cwd, name);
39+
var view;
40+
var str = '';
3341

34-
// Support for handlebars, lo-dash, or any other engine
42+
if (exists(filepath)) {
43+
// create a collection to ensure middleware is consistent
44+
this.app.create('mdfiles');
45+
str = fs.readFileSync(filepath, 'utf8');
46+
view = this.app.mdfile(filepath, {path: filepath, content: str});
3547
} else {
36-
extend(opts, opts.data && opts.data.root);
37-
try {
38-
return read(name, opts, opts.render);
39-
} catch(err) {
40-
return err;
41-
}
48+
view = this.app.find(name);
4249
}
43-
return '';
50+
51+
if (typeof view === 'undefined') {
52+
cb(null, '');
53+
return;
54+
}
55+
56+
view.content = ent.decode(md.render(view.content));
57+
this.app.render(view, this.context, function(err, res) {
58+
if (err) return cb(err);
59+
cb(null, res.content);
60+
});
4461
};
4562

46-
/**
47-
* Utility function for reading files
48-
*
49-
* @param {String} `filepath`
50-
* @param {String} `opts`
51-
* @param {Function} `fn` Optionally pass a render / compile function on the options
52-
* @return {String}
53-
* @api private
54-
*/
63+
module.exports.sync = function(name, options) {
64+
var ctx = this || {};
65+
var app = ctx.app || {};
66+
67+
var opts = extend({cwd: process.cwd()}, ctx.options, options);
68+
opts = extend({}, opts, opts.hash);
69+
var md = markdown(opts);
5570

56-
function read(fp, opts, fn) {
57-
var str = fs.readFileSync(fp, 'utf8');
58-
if (typeof fn === 'function') {
59-
str = fn(str)(opts);
71+
var filepath = path.resolve(opts.cwd, name);
72+
var view;
73+
var html = '';
74+
var str = '';
75+
76+
if (exists(filepath)) {
77+
str = fs.readFileSync(filepath, 'utf8');
78+
html = ent.decode(md.render(str));
79+
} else if (app.views) {
80+
view = app.find(name);
81+
if (view) {
82+
html = view.content = ent.decode(md.render(view.content));
83+
}
6084
}
61-
return markdown(opts).render(str);
62-
}
85+
86+
if (view && typeof view.compile === 'function') {
87+
view.compile(opts);
88+
var data = ctx.cache ? ctx.cache.data : {};
89+
ctx = extend({}, data, view.data);
90+
return view.fn(ctx);
91+
}
92+
93+
if (typeof this.compile === 'function') {
94+
var fn = this.compile(html);
95+
return fn(this);
96+
}
97+
return html;
98+
};
6399

64100
/**
65101
* Shared settings for remarkable

test/test.js

+87-49
Original file line numberDiff line numberDiff line change
@@ -7,92 +7,130 @@
77

88
'use strict';
99

10-
var should = require('should');
10+
require('mocha');
11+
var assert = require('assert');
1112
var handlebars = require('handlebars');
12-
var _ = require('lodash');
13+
var Templates = require('templates');
14+
var hljs = require('highlight.js');
1315
var md = require('..');
16+
var _ = require('lodash');
17+
var app;
1418

15-
var Template = require('template');
16-
var template;
17-
18-
19-
describe('md helper', function() {
19+
describe('sync', function() {
2020
beforeEach(function() {
21-
template = new Template();
22-
template.helper('md', md);
21+
app = new Templates();
2322

24-
template.engine('md', require('engine-base'));
23+
app.helper('md', md.sync);
24+
app.engine('md', require('engine-base'));
25+
app.option('engine', 'md');
2526

26-
template.create('page');
27-
template.create('partial', {isPartial: true});
28-
template.create('include', {isPartial: true});
27+
app.create('page');
28+
app.create('partial', {viewType: ['partial']});
29+
app.create('include', {viewType: ['partial']});
2930

30-
template.include('one', {content: '# heading <%= name %>', name: 'one'});
31-
template.partial('two', {content: '# heading <%= name %>', name: 'two'});
32-
33-
template.page('home.md', {
34-
content: '<%= md("one") %>'
35-
});
31+
app.include('one', {content: '# heading <%= name %>', data: {name: 'one'}});
32+
app.partial('two', {content: '# heading <%= name %>', data: {name: 'two'}});
3633
});
3734

38-
it('should render markdown on the `content` property for the specified template:', function(cb) {
39-
template.render('home.md', function(err, content) {
40-
content.should.equal('<h1>heading one</h1>\n');
35+
it('should convert markdown on the `content` property of a template to HTML:', function(cb) {
36+
app.page('home.md', {content: '<%= md("one") %>'});
37+
38+
app.render('home.md', function(err, view) {
39+
if (err) return cb(err);
40+
assert.equal(view.content, '<h1>heading one</h1>\n');
4141
cb();
4242
});
4343
});
4444

4545
it('should support rendering markdown from a file:', function() {
46-
md('test/fixtures/a.md').should.equal('<h1>AAA</h1>\n<blockquote>\n<p>this is aaa</p>\n</blockquote>\n');
46+
assert.equal(md.sync('test/fixtures/a.md'), '<h1>AAA</h1>\n<blockquote>\n<p>this is aaa</p>\n</blockquote>\n');
47+
});
48+
49+
describe('handlebars:', function() {
50+
it('should support rendering markdown from a file:', function() {
51+
handlebars.registerHelper('md', md.sync);
52+
assert.equal(handlebars.compile('{{{md "test/fixtures/a.md"}}}')(), '<h1>AAA</h1>\n<blockquote>\n<p>this is aaa</p>\n</blockquote>\n');
53+
});
54+
55+
it('should use the `render` function passed on the locals to render templates in partials :', function() {
56+
handlebars.registerHelper('md', md.sync);
57+
var locals = {name: 'CCC', compile: handlebars.compile};
58+
assert.equal(handlebars.compile('{{{md "test/fixtures/c.md"}}}')(locals), '<h1>CCC</h1>\n<p>This is CCC</p>\n');
59+
});
4760
});
4861
});
4962

50-
describe('handlebars:', function() {
51-
it('should support rendering markdown from a file:', function() {
52-
handlebars.registerHelper('md', md);
53-
handlebars.compile('{{{md "test/fixtures/a.md"}}}')().should.equal('<h1>AAA</h1>\n<blockquote>\n<p>this is aaa</p>\n</blockquote>\n');
63+
describe('async', function() {
64+
beforeEach(function() {
65+
app = new Templates();
66+
67+
app.asyncHelper('md', md);
68+
app.engine('md', require('engine-base'));
69+
app.option('engine', 'md');
70+
71+
app.create('page');
72+
app.create('partial', {viewType: ['partial']});
73+
app.create('include', {viewType: ['partial']});
74+
75+
app.include('one', {content: '# heading <%= name %>', data: {name: 'one'}});
76+
app.partial('two', {content: '# heading <%= name %>', data: {name: 'two'}});
77+
});
78+
79+
it('should convert markdown on the `content` property of a template to HTML:', function(cb) {
80+
app.page('home.md', {content: '<%= md("one") %>'});
81+
82+
app.render('home.md', function(err, view) {
83+
if (err) return cb(err);
84+
assert.equal(view.content, '<h1>heading one</h1>\n');
85+
cb();
86+
});
5487
});
5588

56-
it('should use the `render` function passed on the locals to render templates in partials :', function() {
57-
handlebars.registerHelper('md', md);
58-
var locals = {name: 'CCC', render: handlebars.compile};
59-
handlebars.compile('{{{md "test/fixtures/c.md"}}}')(locals).should.equal('<h1>CCC</h1>\n<p>This is CCC</p>\n');
89+
it('should support rendering from a file', function(cb) {
90+
app.page('home.md', {content: '<%= md("test/fixtures/d.md") %>'});
91+
92+
app.render('home.md', {name: 'DDD'}, function(err, view) {
93+
if (err) return cb(err);
94+
assert.equal(view.content, '<h1>DDD</h1>\n<p>This is DDD</p>\n');
95+
cb();
96+
});
6097
});
6198
});
6299

63100
describe('lodash:', function() {
64101
it('should work as a lodash mixin:', function() {
65-
_.mixin({md: md});
66-
_.template('<%= _.md("test/fixtures/a.md") %>', {}).should.equal('<h1>AAA</h1>\n<blockquote>\n<p>this is aaa</p>\n</blockquote>\n');
102+
_.mixin({md: md.sync});
103+
assert.equal(_.template('<%= _.md("test/fixtures/a.md") %>', {})(), '<h1>AAA</h1>\n<blockquote>\n<p>this is aaa</p>\n</blockquote>\n');
67104
});
68105

69106
it('should work when passed to lodash on the locals:', function() {
70-
_.template('<%= _.md("test/fixtures/a.md") %>', {md: md}).should.equal('<h1>AAA</h1>\n<blockquote>\n<p>this is aaa</p>\n</blockquote>\n');
107+
assert.equal(_.template('<%= _.md("test/fixtures/a.md") %>')({md: md.sync}), '<h1>AAA</h1>\n<blockquote>\n<p>this is aaa</p>\n</blockquote>\n');
71108
});
72109

73110
it('should work as a lodash import:', function() {
74-
var settings = {imports: {md: md}};
75-
_.template('<%= _.md("test/fixtures/a.md") %>', {}, settings).should.equal('<h1>AAA</h1>\n<blockquote>\n<p>this is aaa</p>\n</blockquote>\n');
111+
var settings = {imports: {md: md.sync}};
112+
assert.equal(_.template('<%= _.md("test/fixtures/a.md") %>', {}, settings)(), '<h1>AAA</h1>\n<blockquote>\n<p>this is aaa</p>\n</blockquote>\n');
76113
});
77114
});
78115

79116
describe('highlight:', function(argument) {
80-
var hljs = require('highlight.js');
81-
it('should support syntax highlighting', function() {
82-
md('test/fixtures/e.md', {highlight: function highlight(code, lang) {
117+
it('should support syntax highlighting', function() {
118+
var actual = md.sync('test/fixtures/e.md', {
119+
highlight: function(code, lang) {
120+
try {
83121
try {
84-
try {
85-
return hljs.highlight(lang, code).value;
86-
} catch (err) {
87-
if (!/Unknown language/i.test(err.message)) {
88-
throw err;
89-
}
90-
return hljs.highlightAuto(code).value;
91-
}
122+
return hljs.highlight(lang, code).value;
92123
} catch (err) {
93-
return code;
124+
if (!/Unknown language/i.test(err.message)) {
125+
throw err;
126+
}
127+
return hljs.highlightAuto(code).value;
94128
}
129+
} catch (err) {
130+
return code;
95131
}
96-
}).should.equal('<h1>EEE</h1>\n<pre><code><span class="hljs-keyword">var</span> <span class="hljs-keyword">message</span> = <span class="hljs-string">\'This is an alert\'</span>;\nalert(<span class="hljs-keyword">message</span>);\n</code></pre>\n');
132+
}
97133
});
134+
assert.equal(actual, '<h1>EEE</h1>\n<pre><code><span class="hljs-keyword">var</span> <span class="hljs-keyword">message</span> = <span class="hljs-string">\'This is an alert\'</span>;\nalert(<span class="hljs-keyword">message</span>);\n</code></pre>\n');
135+
});
98136
});

0 commit comments

Comments
 (0)