This commit is contained in:
Mikito Takada 2015-01-23 22:22:03 -08:00
parent 073932e84f
commit 5fb468fd0a
10 changed files with 355 additions and 73 deletions

View File

@ -1,8 +1,9 @@
#!/usr/bin/env node
var fs = require('fs'),
path = require('path'),
List = require('minitask').list,
opts = require('yargs');
opts = require('yargs'),
resolveArgs = require('../lib/resolve-args'),
render = require('../lib/render');
opts.options({
'layouts': { },
@ -20,43 +21,17 @@ opts.options({
var argv = opts.parse(process.argv);
// defaults
argv.input = path.resolve(process.cwd(), argv.input || './input/');
argv.output = path.resolve(process.cwd(), argv.output || './output/');
if(!argv.layout) {
argv.layout = 'jasonm23-markdown';
}
argv.defaultMeta = { title: 'example' };
argv = resolveArgs(argv);
// default runner
if(argv.runner) {
argv.runner = path.resolve(process.cwd(), argv.runner);
runner = require(argv.runner);
}
// Load the layout
var layoutDir = __dirname + '/../layouts/';
// template is one of:
if(fs.existsSync(process.cwd() + '/' + argv.layout)) {
// 1) the supplied argument (normalized)
argv.template = path.normalize(process.cwd() + '/' + argv.layout);
} else if(fs.existsSync(layoutDir+argv.layout+'/page.html')) {
// 2) a preset layout from the layout dir
argv.template = path.normalize(layoutDir+argv.layout+'/page.html');
} else {
// 3) the default layout
argv.template = path.normalize(layoutDir+'plain/page.html');
}
if(argv.layouts || !fs.existsSync(argv.input)) {
if(!fs.existsSync(argv.input)) {
console.log(argv.input+' does not exist');
}
// show layouts
console.log('Available layouts:\n'+
fs.readdirSync(__dirname+'/../layouts/')
fs.readdirSync(layoutDir)
.sort(function(a, b) { return a.localeCompare(b); })
.map(function(name) { return '\t' + name})
.join('\n')
@ -64,43 +39,18 @@ if(argv.layouts || !fs.existsSync(argv.input)) {
process.exit();
}
if(argv['command']) {
argv['command'] = argv['command'].split(' ');
}
if(argv['asset-dir']) {
argv.assetDir = path.resolve(process.cwd() + '/' + argv['asset-dir']);
}
// parse --highlight-<extension>
var hl = {};
Object.keys(argv).forEach(function(name) {
var matched = (typeof name === 'string' ? name.match(/highlight\-(.*)/) : false);
if(name == 'highlight') {
argv[name] = findModule(argv[name], [ process.cwd, __dirname ]);
hl['default'] = require(argv[name]);
} else if(matched) {
var ext = matched[1];
argv[name] = findModule(argv[name], [ process.cwd, __dirname ]);
hl[ext] = require(argv[name]);
}
});
console.log('Layout: ' + argv.layout);
console.log('Template file: ' + argv.template);
console.log('Input: ' + argv.input);
console.log('Output: ' + path.relative(process.cwd(), argv.output));
console.log('Output: ' + argv.output);
/*
if(Object.keys(hl).length > 0) {
console.log('Highlighters:');
Object.keys(hl).forEach(function(ext) {
console.log('\t' + ext, (ext === 'default' ? argv['highlight'] : argv['highlight-' + ext]));
});
}
*/
argv['highlight'] = hl;
var runner = require('../lib2/runner.js');
runner(argv);
render(argv);

View File

@ -88,8 +88,9 @@ I am a robot
Maybe you want to print `robot` to the console 1000 times. Why not?
```ruby
def robot_invasion
puts("robot " * 1000)
class Car < ActiveRecord::Base
has_many :wheels, class_name: 'Wheel', foreign_key: 'car_id'
scope :available, -> { where(available: true) }
end
```
You see, that was formatted as code because it's been indented by four spaces.

View File

@ -8,7 +8,7 @@ module.exports = function(argv) {
argv.input = path.resolve(process.cwd(), argv.input || './input/');
argv.output = path.resolve(process.cwd(), argv.output || './output/');
if(!argv.layout) {
argv.layout = 'jasonm23-markdown';
argv.layout = 'github';
}
// template is one of:
@ -70,9 +70,5 @@ module.exports = function(argv) {
argv.assetDir = path.normalize(__dirname + '/../layouts/' + argv.layout + '/assets/');
}
console.log(argv);
return argv;
};

View File

@ -24,17 +24,20 @@
"highlight"
],
"main": "lib/index.js",
"scripts": {
"test": "mocha -R spec ./test/*.test.js"
},
"dependencies": {
"async": "~0.2.10",
"filewalker": "~0.1.2",
"handlebars": "~2.0.0",
"marked": "0.2.9",
"minitask": "0.0.0",
"markdown-stream-utils": "~1.0.0",
"mkdirp": "0.3.5",
"pipe-iterators": "~1.1.0",
"readable-stream": "1.0.2",
"resolve": "~0.6.1",
"wildglob": "0.0.1",
"xtend": "~4.0.0",
"yargs": "~1.1.3"
},
"devDependencies": {
"file-fixture": "0.0.2"
}
}

78
test/api.test.js Normal file
View File

@ -0,0 +1,78 @@
var fs = require('fs'),
path = require('path'),
fixture = require('file-fixture'),
mds = require('../');
var layouts = fs.readdirSync(__dirname + '/../layouts');
/*
it('has a render(opts, onDone) function that works like bin/generate-md', function(done) {
// params:
// input
// output
// template
// partials
// helpers
// layout
// assetDir
});
it('has a pipeline(opts) function that returns a pipeline that accepts items', function(done) {
// params:
// input
// output
// template
// partials
// helpers
});
*/
describe('can render every sample layout', function() {
var dir;
before(function() {
dir = fixture.dir({
'index.md': [
'title: Hello world',
'author: Anonymous',
'----',
'# Test',
'```js',
'var foo = "bar";',
'```'
].join('\n')
});
});
function render(layout, done) {
var out = fixture.dirname();
mds.render(mds.resolveArgs({
input: dir,
output: out,
layout: layout
}), function() {
// console.log(layout, out);
/*
assert.equal(fs.readFileSync(out + '/index.html', 'utf8'), [
'"Hello world" by Anonymous',
'<h1 id="test">Test</h1>',
'<p>abcdef</p>\n'
].join('\n'));
*/
done();
});
}
layouts.forEach(function(layout) {
it('can render layout ' + layout, function(done) { render(layout, done); });
});
});

View File

@ -0,0 +1,5 @@
var handlebars = require('handlebars');
module.exports = function(context, options) {
return 'Hello ' + context + '!';
};

View File

@ -0,0 +1 @@
Sample partial

4
test/fixtures/partials/toc.hbs vendored Normal file
View File

@ -0,0 +1,4 @@
TOC:
{{#each headings}}
- Hello {{text}}!
{{/each}}

View File

@ -1 +1,245 @@
integration.test.js
var assert = require('assert'),
fs = require('fs'),
pi = require('pipe-iterators'),
xtend = require('xtend'),
applyTemplate = require('../lib/apply-template'),
setOutputPath = require('../lib/set-output-path'),
md = require('markdown-stream-utils'),
fixture = require('file-fixture'),
mds = require('../');
describe('integration tests', function() {
describe('metadata tests', function() {
var templateDir = fixture.dir({
'page.html': '"{{title}}" by {{author}}\n{{> content}}'
});
it('reads and renders metadata stored in a file', function(done) {
var dir = fixture.dir({
'foo.md': [
'title: Hello world',
'author: Anonymous',
'----',
'# Test',
'abcdef'
].join('\n')
});
var out = fixture.dirname();
mds.render({
input: dir,
output: out,
template: templateDir + '/page.html'
}, function() {
assert.equal(fs.readFileSync(out + '/foo.html', 'utf8'), [
'"Hello world" by Anonymous',
'<h1 id="test">Test</h1>',
'<p>abcdef</p>\n'
].join('\n'));
done();
});
});
it('will implicitly pick up the first heading as the title if no meta title is set', function(done) {
var dir = fixture.dir({
'foo.md': [
'# Some title',
'abcdef'
].join('\n')
});
var out = fixture.dirname();
mds.render({
input: dir,
output: out,
template: templateDir + '/page.html'
}, function() {
assert.equal(fs.readFileSync(out + '/foo.html', 'utf8'), [
'"Some title" by ',
'<h1 id="some-title">Some title</h1>',
'<p>abcdef</p>\n'
].join('\n'));
done();
});
});
it('reads and scopes the meta.json based on the path relative to target directory', function(done) {
var dir = fixture.dir({
'meta.json': JSON.stringify({
foo: { pn: 'foo' },
'abc/bar': { pn: 'abc/bar' }
}),
'foo.md': 'foo', // projectName foo
'foo/bar.md': 'bar', // projectName foo
'abc/bar/baz.md': 'baz', // projectName abc/bar
});
var templateDir = fixture.dir({
'page.html': '"{{pn}}"\n{{> content}}'
});
var out = fixture.dirname();
mds.render({
input: dir,
output: out,
template: templateDir + '/page.html'
}, function() {
assert.equal(fs.readFileSync(out + '/foo.html', 'utf8'), [
'"foo"',
'<p>foo</p>\n'
].join('\n'));
assert.equal(fs.readFileSync(out + '/foo/bar.html', 'utf8'), [
'"foo"',
'<p>bar</p>\n'
].join('\n'));
assert.equal(fs.readFileSync(out + '/abc/bar/baz.html', 'utf8'), [
'"abc/bar"',
'<p>baz</p>\n'
].join('\n'));
done();
});
});
});
describe('theme tests', function() {
function render(item, opts, onDone) {
pi.fromArray([
xtend({ path: '/fake/input/index.md' }, item)
])
.pipe(pi.head([
md.parseHeader(),
md.parseMd(),
md.annotateMdHeadings(),
md.highlight(),
md.convertMd(),
setOutputPath({
input: '/fake/input',
output: '/fake/output',
assetDir: '/fake/output/assets/'
}),
applyTemplate(opts),
pi.toArray(function(results) {
onDone(results[0].contents);
})
]));
}
it('renders {{> content}}', function(done) {
render({ contents: 'Hello world' }, { template: 'a{{> content}}b' }, function(html) {
assert.equal(html, 'a<p>Hello world</p>\nb');
done();
});
});
it('renders {{title}}', function(done) {
render({ title: 'foo', contents: 'a' }, { template: 'a{{title}}b' }, function(html) {
assert.equal(html, 'afoob');
done();
});
});
it('renders {{> toc}}', function(done) {
render({ contents: [
'a',
'# foo',
'b',
'## bar',
'c'
].join('\n')
}, { template: 'a{{> toc}}b' }, function(html) {
assert.equal(html, [
'a<ul class="nav nav-list">',
' <li><a href="#foo">foo</a></li>',
' <li><a href="#bar">bar</a></li>',
'</ul>',
'b'
].join('\n'));
done();
});
});
it('renders {{asset "css/style.css"}}', function(done) {
render({ contents: 'a' }, { template: 'src="{{asset "css/style.css"}}"' }, function(html) {
assert.equal(html, 'src="assets/css/style.css"');
done();
});
});
it('renders partials via {{> partialName}}', function(done) {
render({ contents: 'a' }, {
template: 'a{{> sample-partial}}b',
partials: __dirname + '/fixtures/partials'
}, function(html) {
assert.equal(html, 'aSample partial\nb');
done();
});
});
it('can override base partial such as {{> toc}}', function(done) {
render({ contents: [
'a',
'# foo',
'b',
'## bar',
'c'
].join('\n') }, {
template: 'a{{> toc}}b',
partials: __dirname + '/fixtures/partials'
}, function(html) {
assert.equal(html, [
'aTOC:',
' - Hello foo!',
' - Hello bar!',
'b'
].join('\n'));
done();
});
});
it('loads helpers from the helpers directory', function(done) {
render({ contents: 'a' }, {
template: 'a{{sample-helper "world"}}b',
helpers: __dirname + '/fixtures/helpers'
}, function(html) {
assert.equal(html, 'aHello world!b');
done();
});
});
it('renders code with syntax highlighting', function(done) {
render({ contents: [
'a',
'# foo',
'',
'```js',
'var foo = bar;',
'```'
].join('\n') }, {
template: 'a{{> content}}b'
}, function(html) {
assert.equal(html, [
'a<p>a</p>',
'<h1 id="foo">foo</h1>',
'<pre class="hljs"><code>' +
'<span class="hljs-keyword">var</span> foo = bar;</code></pre>b',
].join('\n'));
done();
});
});
it('supports custom syntax highlighters for specific languages', function(done) {
done();
});
});
});

View File

@ -1,6 +1,6 @@
var assert = require('assert'),
pi = require('pipe-iterators'),
setOutputPath = require('../lib2/set-output-path');
setOutputPath = require('../lib/set-output-path');
describe('set output path', function() {