Skip to content

Commit

Permalink
Merge pull request #48 from jaredwray/making-helper-md-native-to-fuma…
Browse files Browse the repository at this point in the history
…nchu

Making helper md native to fumanchu
  • Loading branch information
jaredwray committed Jun 17, 2024
2 parents 629f8c7 + ee5d32a commit 20bb8da
Show file tree
Hide file tree
Showing 10 changed files with 291 additions and 3 deletions.
4 changes: 2 additions & 2 deletions lib/markdown.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';
const hljs = require('highlight.js');
const utils = require('handlebars-utils');
const Remarkable = require('remarkable');
const {Remarkable} = require('remarkable');

/**
* Expose markdown `helpers` (for performance we're using getters so
Expand Down Expand Up @@ -55,7 +55,7 @@ Object.defineProperty(helpers, 'markdown', {
* @api public
*/

helpers.md = require('helper-md');
helpers.md = require('./md.js');


helpers.helpersForMarkdown = function(config) {
Expand Down
119 changes: 119 additions & 0 deletions lib/md.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*!
* helper-markdown <https://github.com/jonschlinkert/helper-markdown>
*
* Copyright (c) 2014 Jon Schlinkert, contributors.
* Licensed under the MIT license.
*/

'use strict';

var fs = require('fs');
var path = require('path');
const { Remarkable } = require('remarkable');
var extend = require('extend-shallow');
var exists = require('fs-exists-sync');
var ent = require('ent');

/**
* Expose `md` helper
*/

var helper = module.exports = function(name, options, cb) {
if (typeof options === 'function') {
cb = options;
options = {};
}

if (typeof cb !== 'function') {
return helper.sync.apply(this, arguments);
}

/* c8 ignore next 3 */
if (typeof this === 'undefined' || typeof this.app === 'undefined') {
throw new Error('md async helper expects `app` to be exposed on the context');
}

var opts = extend({cwd: process.cwd()}, this.options, options);
opts = extend({}, opts, opts.hash);
var md = markdown(opts);

var filepath = path.resolve(opts.cwd, name);
var view;
var str = '';

if (exists(filepath)) {
// create a collection to ensure middleware is consistent
this.app.create('mdfiles');
str = fs.readFileSync(filepath, 'utf8');
view = this.app.mdfile(filepath, {path: filepath, content: str});
} else {
view = this.app.find(name);
}
/* c8 ignore next 4 */
if (typeof view === 'undefined') {
cb(null, '');
return;
}

view.content = ent.decode(md.render(view.content));
this.app.render(view, this.context, function(err, res) {
if (err) return cb(err);
cb(null, res.content);
});
};

helper.sync = function(name, options) {
var ctx = this || {};
var app = ctx.app || {};

var opts = extend({cwd: process.cwd()}, ctx.options, options);
opts = extend({}, opts, opts.hash);
var md = markdown(opts);

var filepath = path.resolve(opts.cwd, name);
var view;
var html = '';
var str = '';

if (exists(filepath)) {
str = fs.readFileSync(filepath, 'utf8');
html = ent.decode(md.render(str));
} else if (app.views) {
view = app.find(name);
if (view) {
html = view.content = ent.decode(md.render(view.content));
}
}

if (view && typeof view.compile === 'function') {
view.compile(opts);
var data = ctx.cache ? ctx.cache.data : {};
ctx = extend({}, data, view.data);
return view.fn(ctx);
}

if (typeof this.compile === 'function') {
var fn = this.compile(html);
return fn(this);
}
return html;
};

/**
* Shared settings for remarkable
*
* @param {Object} `options`
* @return {Object}
* @api private
*/

function markdown(options) {
let optsConfig = options || {};
optsConfig.breaks = true;
optsConfig.html = true;
optsConfig.langPrefix = 'lang-';
optsConfig.typographer = false;
optsConfig.xhtmlOut = false;
const md = new Remarkable(optsConfig);
return md;
}
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
"array-sort": "^1.0.0",
"create-frame": "^1.0.0",
"define-property": "^2.0.2",
"ent": "^2.2.0",
"falsey": "^1.0.0",
"for-in": "^1.0.2",
"for-own": "^1.0.0",
Expand All @@ -127,7 +128,6 @@
"handlebars-utils": "^1.0.6",
"has-value": "^2.0.2",
"helper-date": "^1.0.1",
"helper-md": "^0.2.2",
"highlight.js": "^11.9.0",
"html-tag": "^2.0.0",
"is-even": "^1.0.0",
Expand All @@ -138,13 +138,15 @@
"logging-helpers": "^1.0.0",
"micromatch": "^4.0.5",
"relative": "^3.0.2",
"remarkable": "^2.0.1",
"striptags": "^3.2.0",
"to-gfm-code-block": "^0.1.1",
"year": "^0.2.1"
},
"devDependencies": {
"c8": "^9.1.0",
"chai": "^4.3.10",
"lodash": "^4.17.21",
"mocha": "^10.4.0",
"rimraf": "^5.0.5",
"template-helpers": "^1.0.1",
Expand Down
3 changes: 3 additions & 0 deletions test/fixtures/a.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# AAA

> this is aaa
3 changes: 3 additions & 0 deletions test/fixtures/b.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# BBB

> this is bbb
3 changes: 3 additions & 0 deletions test/fixtures/c.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# CCC

This is {{name}}
3 changes: 3 additions & 0 deletions test/fixtures/d.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# DDD

This is <%= name %>
6 changes: 6 additions & 0 deletions test/fixtures/e.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# EEE

```
var message = 'This is an alert';
alert(message);
```
2 changes: 2 additions & 0 deletions test/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ describe('fs', function() {
path.join('lib', 'markdown.js'),
path.join('lib', 'match.js'),
path.join('lib', 'math.js'),
path.join('lib', 'md.js'),
path.join('lib', 'misc.js'),
path.join('lib', 'number.js'),
path.join('lib', 'object.js'),
Expand Down Expand Up @@ -86,6 +87,7 @@ describe('fs', function() {
path.join('lib', 'markdown.js'),
path.join('lib', 'match.js'),
path.join('lib', 'math.js'),
path.join('lib', 'md.js'),
path.join('lib', 'misc.js'),
path.join('lib', 'number.js'),
path.join('lib', 'object.js'),
Expand Down
147 changes: 147 additions & 0 deletions test/md.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*!
* helper-md <https://github.com/jonschlinkert/helper-md>
*
* Copyright (c) 2014 Jon Schlinkert, contributors.
* Licensed under the MIT License
*/

'use strict';

require('mocha');
var assert = require('assert');
var handlebars = require('handlebars');
var Templates = require('templates');
var hljs = require('highlight.js');
var md = require('../lib/md.js');
var _ = require('lodash');
var app;

describe('sync', function() {
beforeEach(function() {
app = new Templates();

app.helper('md', md.sync);
app.engine('md', require('engine-base'));
app.option('engine', 'md');

app.create('page');
app.create('partial', {viewType: ['partial']});
app.create('include', {viewType: ['partial']});

app.include('one', {content: '# heading <%= name %>', data: {name: 'one'}});
app.partial('two', {content: '# heading <%= name %>', data: {name: 'two'}});
});

it('should convert markdown on the `content` property of a template to HTML:', function(cb) {
app.page('home.md', {content: '<%= md("one") %>'});

app.render('home.md', function(err, view) {
if (err) return cb(err);
assert.equal(view.content, '<h1>heading one</h1>\n');
cb();
});
});

it('should support rendering markdown from a file:', function() {
assert.equal(md.sync('test/fixtures/a.md'), '<h1>AAA</h1>\n<blockquote>\n<p>this is aaa</p>\n</blockquote>\n');
});

describe('handlebars:', function() {
it('should support rendering markdown from a file:', function() {
handlebars.registerHelper('md', md.sync);
assert.equal(handlebars.compile('{{{md "test/fixtures/a.md"}}}')(), '<h1>AAA</h1>\n<blockquote>\n<p>this is aaa</p>\n</blockquote>\n');
});

it('should use the `render` function passed on the locals to render templates in partials :', function() {
handlebars.registerHelper('md', md.sync);
var locals = {name: 'CCC', compile: handlebars.compile};
assert.equal(handlebars.compile('{{{md "test/fixtures/c.md"}}}')(locals), '<h1>CCC</h1>\n<p>This is CCC</p>\n');
});
});
});

describe('async', function() {
beforeEach(function() {
app = new Templates();

app.asyncHelper('md', md);
app.engine('md', require('engine-base'));
app.option('engine', 'md');

app.create('page');
app.create('partial', {viewType: ['partial']});
app.create('include', {viewType: ['partial']});

app.include('one', {content: '# heading <%= name %>', data: {name: 'one'}});
app.partial('two', {content: '# heading <%= name %>', data: {name: 'two'}});
});

it('should convert markdown on the `content` property of a template to HTML:', function(cb) {
app.page('home.md', {content: '<%= md("one") %>'});

app.render('home.md', function(err, view) {
if (err) return cb(err);
assert.equal(view.content, '<h1>heading one</h1>\n');
cb();
});
});

it('should support rendering from a file', function(cb) {
app.page('home.md', {content: '<%= md("test/fixtures/d.md") %>'});

app.render('home.md', {name: 'DDD'}, function(err, view) {
if (err) return cb(err);
assert.equal(view.content, '<h1>DDD</h1>\n<p>This is DDD</p>\n');
cb();
});
});

it('should use sync helper when a callback is not passed:', function(cb) {
app.helper('md2', md);
app.page('home.md', {content: '<%= md2("one") %>'});

app.render('home.md', function(err, view) {
if (err) return cb(err);
assert.equal(view.content, '<h1>heading one</h1>\n');
cb();
});
});
});

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

it('should work when passed to lodash on the locals:', function() {
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');
});

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

describe('highlight:', function(argument) {
it('should support syntax highlighting', function() {
var actual = md.sync('test/fixtures/e.md', {
highlight: function(code, lang) {
try {
try {
return hljs.highlight(lang, code).value;
} catch (err) {
if (!/Unknown language/i.test(err.message)) {
throw err;
}
return hljs.highlightAuto(code).value;
}
} catch (err) {
return code;
}
}
});
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');
});
});

0 comments on commit 20bb8da

Please sign in to comment.