-
-
Save mklabs/1332036 to your computer and use it in GitHub Desktop.
docs simple as cake
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# this script install itself (npm package), create a tasks/docs.js, install the docs' task dependencies, | |
# and run the gh-pages task. | |
# | |
# Install: | |
# | |
# curl https://raw.github.com/gist/1332036/70f8f3f9b85082569aff7f10773fc40e2fd7388d/bash | sh | |
# | |
# It'll generate documentation based on the likely location of | |
# directories in your package.json (lib/doc), create a gh-pages (empty branch), | |
# add the docs/ folder generated and perform a new commit. | |
# | |
# Directories - http://npmjs.org/doc/json.html#directories | |
# | |
# * directories.lib: Walk the dir for any .js/.coffee file and execute docco to generate docs page. | |
# * directories.doc: Walk the dir for any markdown file, parse them and generate documentation pages using the index.html mustache template. | |
# | |
# | |
# The push is left to you. | |
npm install https://gist.github.com/gists/1332036/download --loglevel info | |
echo Ok.. Now install tasks/docs.js deps | |
npm install mkdirp markdown findit mustache | |
echo Install Done, Use it: | |
./node_modules/cakes-docs/node_modules/.bin/cheesecake | |
./node_modules/cakes-docs/node_modules/.bin/cheesecake init | |
./node_modules/cakes-docs/node_modules/.bin/cheesecake gh-pages |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var path = require('path'), | |
fs = require('fs'), | |
exec = require('child_process').exec, | |
mkdirp = require('mkdirp'), | |
markdown = require('markdown'), | |
findit = require('findit'), | |
mustache = require('mustache'), | |
template = fs.readFileSync(path.join(__dirname, 'support', 'index.html'), 'utf8'); | |
task('docs', 'Generates documention, based on the likely location of directories in your package.json', function(options, em) { | |
em.emit('log', 'Doc start'); | |
var package = JSON.parse(fs.readFileSync(gimme(module, 'package.json', em), 'utf8')); | |
var dirs = package.directories = package.directories || {}; | |
// http://npmjs.org/doc/json.html#directories | |
dirs.lib = dirs.lib || './lib'; | |
dirs.bin = dirs.bin || './bin'; | |
dirs.man = dirs.man || './man'; | |
dirs.doc = dirs.doc || './'; | |
dirs.example = dirs.example || './examples'; | |
// default repository, fail safe fallback | |
package.repository = package.repository || {}; | |
package.repository.url = package.repository.url || ''; | |
// default config.doc location, the link to docco entry point | |
package.config = package.config || {}; | |
package.config.doc = package.config.doc || ''; | |
em | |
.on('doc:lib', next.bind(em, 'lib')) | |
.on('doc:doc', next.bind(em, 'doc')) | |
mkdirp(path.resolve('docs/docco'), 0755, function(err) { | |
if(err) return em.emit('error', err); | |
docco(dirs, em); | |
}); | |
em.on('doc:lib', function(files) { | |
markdowns(dirs, package, files, em); | |
}); | |
var remaining = 2; | |
function next() { | |
if(--remaining) return; | |
em.emit('end'); | |
} | |
}); | |
task('gh-pages', 'Set up a gh-pages branch.', function(options, em) { | |
em.emit('log', 'Setting up a gh-pages branch'); | |
gem.on('end:docs', function() { | |
var commands = [ | |
'git symbolic-ref HEAD refs/heads/gh-pages', | |
'rm .git/index', | |
'git add docs/', | |
'git clean -fdx', | |
'git mv docs/index.html index.html', | |
'git commit -m "Docs commit"' | |
].join('&&'); | |
exec(commands, function(err, stdout) { | |
if(err) return em.emit('error', err); | |
em.emit('silly', stdout); | |
em.emit('end'); | |
}); | |
}); | |
invoke('docs'); | |
}); | |
// ### Helpers | |
function gimme(pmodule, name, em, dir) { | |
var dir = path.dirname(dir || pmodule.filename); | |
var files = fs.readdirSync(dir); | |
if (~files.indexOf(name)) { | |
return path.join(dir, name); | |
} | |
if (dir === '/') { | |
return em.emit('error', new Error('Could not find ' + name + ' up from: ' + dir)); | |
} | |
return gimme(pmodule, name, em, dir); | |
} | |
function docco(dirs, em) { | |
em.emit('log', 'Trying to generate documentation at the likely location of lib folder: ' + path.resolve(dirs.lib)); | |
if(!dirs.lib) { | |
em.emit('warn', 'no dirs lib'); | |
return em.emit('doc:lib'); | |
} | |
var files = findit.findSync(dirs.lib).filter(function(it) { | |
var ext = path.extname(it); | |
return !!~['.js', '.coffee'].indexOf(ext); | |
}); | |
exec('./node_modules/cakes-docs/node_modules/.bin/docco ' + files.join(' '), function(err, stdout) { | |
if(err) return em.emit('error', err); | |
em.emit('log', stdout); | |
em.emit('doc:lib', files); | |
}); | |
} | |
function markdowns(dirs, pkg, doccos, em) { | |
em.emit('log', 'Trying to generate documentation at the likely location of doc folder: ' + path.resolve(dirs.doc)); | |
em.emit('data', doccos); | |
if(!dirs.doc) { | |
em.emit('doc', 'no dirs doc'); | |
return em.emit('doc:doc'); | |
} | |
var parts = pkg.repository.url.match(/git:\/\/github.com\/([a-z0-9_\-+=.]+)\/([a-z0-9_\-+=.]+).git/), | |
username = parts && parts[1], | |
repo = parts && parts[2]; | |
var source = path.resolve(dirs.doc), | |
files = findit.findSync(source) | |
.filter(function(it) { | |
// you must be a file | |
if(!fs.statSync(it).isFile()) return false; | |
// you must be a markdown one | |
if(!~['.mkd', '.md', '.markdown'].indexOf(path.extname(it))) return false; | |
// also, are you in node_modules folder? | |
if(/node_modules/.test(it)) return false; | |
return true; | |
}) | |
.map(function(it) { | |
return { | |
file: path.basename(it), | |
path: it, | |
content: fs.readFileSync(it, 'utf8') | |
} | |
}); | |
var remaining = files.length; | |
files.forEach(function(mds) { | |
em.emit('log', 'Generating from ' + mds.file); | |
var html = markdown.parse(postparse(preparse(mds.content), username, repo, [username, repo].join('/'))); | |
pkg.content = html; | |
pkg.docpath = pkg.config.doc || 'docs/' + path.basename(doccos.slice(-1)[0]).replace(/\..+$/, '') + '.html'; | |
html = mustache.to_html(template, pkg, {}); | |
em.emit('log', 'Writing html page for ' + mds.path); | |
em.emit('log', 'Creating folder structure for ' + path.dirname(output)); | |
// If that's a readme, and is at the root of the repo, write as index.html | |
var output = new RegExp('readme', 'i').test(mds.file) && path.dirname(mds.path) === path.resolve() ? 'index.html' : mds.file, | |
output = path.join(__dirname, '..', 'docs', path.dirname(mds.path.replace(source, '')), output); | |
mkdirp(path.dirname(output), 0755, function(err) { | |
if(err) return em.emit('error', err); | |
em.emit('log', path.dirname(output) + ' created. Writing ' + mds.file); | |
fs.writeFile(output.replace(/\..+/, '.html'), html, function(err) { | |
if(err) return em.emit('errpr', err); | |
em.emit('log', 'Ok for ' + mds.path); | |
if(--remaining) return; | |
em.emit('doc:doc'); | |
}); | |
}); | |
}); | |
} | |
// handle ```js kind of marker, remove them and indent code block with 4 spaces. | |
function preparse(file) { | |
var lines = file.split('\n'), | |
code = false, | |
sections = []; | |
lines = lines.map(function(line) { | |
if(/^```\w+$/.test(line)) { | |
code = true; | |
return ''; | |
} | |
if(/^```$/.test(line)) { | |
code = false; | |
return ''; | |
} | |
var prefix = code ? new Array(8).join(' ') : ''; | |
return prefix + line; | |
}); | |
return lines.join('\n'); | |
} | |
// ok.. lame function name | |
function postparse(text, username, repoName, nameWithOwner) { | |
// ** GFM ** Auto-link URLs | |
text = text.replace(/https?\:\/\/[^"\s\<\>]*[^.,;'">\:\s\<\>\)\]\!]/g, function(wholeMatch,matchIndex){ | |
var left = text.slice(0, matchIndex), right = text.slice(matchIndex) | |
if (left.match(/<[^>]+$/) && right.match(/^[^>]*>/)) {return wholeMatch} | |
href = wholeMatch.replace(/^http:\/\/github.com\//, "https://github.com/") | |
return "[" + wholeMatch + "](" + wholeMatch + ")"; | |
}); | |
// ** GFM ** Auto-link sha1 if both name and repo are defined | |
text = text.replace(/[a-f0-9]{40}/ig, function(wholeMatch,matchIndex) { | |
if(!nameWithOwner) return wholeMatch; | |
var left = text.slice(0, matchIndex), right = text.slice(matchIndex); | |
if (left.match(/@$/) || (left.match(/<[^>]+$/) && right.match(/^[^>]*>/))) {return wholeMatch;} | |
return "[" + wholeMatch.substring(0, 7) + "](http://github.com/" + nameWithOwner + "/commit/" + wholeMatch + ")"; | |
}); | |
// ** GFM ** Auto-link user/repo@sha1 | |
text = text.replace(/([a-z0-9_\-+=.]+\/[a-z0-9_\-+=.]+)@([a-f0-9]{40})/ig, function(wholeMatch,repo,sha) { | |
return "["+ repo + "@" + sha.substring(0,7) + "](http://github.com/" + repo + "/commit/" + sha + ")"; | |
}); | |
// ** GFM ** Auto-link #issue if nameWithOwner is defined | |
text = text.replace(/#([0-9]+)/ig, function(wholeMatch,issue,matchIndex){ | |
if (!nameWithOwner) {return wholeMatch;} | |
var left = text.slice(0, matchIndex), right = text.slice(matchIndex) | |
if (left == "" || left.match(/[a-z0-9_\-+=.]$/) || (left.match(/<[^>]+$/) && right.match(/^[^>]*>/))) {return wholeMatch;} | |
return "[" + wholeMatch + "](http://github.com/" + nameWithOwner + "/issues/#issue/" + issue + ")"; | |
}); | |
// ** GFM ** Auto-link user/repo#issue | |
text = text.replace(/([a-z0-9_\-+=.]+\/[a-z0-9_\-+=.]+)#([0-9]+)/ig, function(wholeMatch,repo,issue){ | |
return "[" + wholeMatch + "](http://github.com/" + repo + "/issues/#issue/" + issue + ")"; | |
}); | |
return text; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<!-- paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/ --> | |
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]--> | |
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8" lang="en"> <![endif]--> | |
<!--[if IE 8]> <html class="no-js lt-ie9" lang="en"> <![endif]--> | |
<!-- Consider adding a manifest.appcache: h5bp.com/d/Offline --> | |
<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]--> | |
<head> | |
<meta charset="utf-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> | |
<title>{{ name }} :: {{ description }}</title> | |
<meta name="description" content="{{ description }} "> | |
<meta name="author" content="{{ author }}"> | |
<!-- Mobile viewport optimized: j.mp/bplateviewport --> | |
<meta name="viewport" content="width=device-width,initial-scale=1"> | |
<style> | |
/* HTML5 ✰ Boilerplate | |
* ==|== normalize ========================================================== | |
*/ | |
article, aside, details, figcaption, figure, footer, header, hgroup, nav, section { display: block; } | |
audio, canvas, video { display: inline-block; *display: inline; *zoom: 1; } | |
audio:not([controls]) { display: none; } | |
[hidden] { display: none; } | |
html { font-size: 100%; overflow-y: scroll; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; } | |
body { margin: 0; font-size: 13px; line-height: 1.231; } | |
body, button, input, select, textarea { font-family: sans-serif; color: #222; } | |
::-moz-selection { background: #fe57a1; color: #fff; text-shadow: none; } | |
::selection { background: #fe57a1; color: #fff; text-shadow: none; } | |
a { color: #00e; } | |
a:visited { color: #551a8b; } | |
a:hover { color: #06e; } | |
a:focus { outline: thin dotted; } | |
a:hover, a:active { outline: 0; } | |
abbr[title] { border-bottom: 1px dotted; } | |
b, strong { font-weight: bold; } | |
blockquote { margin: 1em 40px; } | |
dfn { font-style: italic; } | |
hr { display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; } | |
ins { background: #ff9; color: #000; text-decoration: none; } | |
mark { background: #ff0; color: #000; font-style: italic; font-weight: bold; } | |
pre, code, kbd, samp { font-family: monospace, monospace; _font-family: 'courier new', monospace; font-size: 1em; } | |
pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; } | |
q { quotes: none; } | |
q:before, q:after { content: ""; content: none; } | |
small { font-size: 85%; } | |
sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } | |
sup { top: -0.5em; } | |
sub { bottom: -0.25em; } | |
ul, ol { margin: 1em 0; padding: 0 0 0 40px; } | |
dd { margin: 0 0 0 40px; } | |
nav ul, nav ol { list-style: none; list-style-image: none; margin: 0; padding: 0; } | |
img { border: 0; -ms-interpolation-mode: bicubic; vertical-align: middle; } | |
svg:not(:root) { overflow: hidden; } | |
figure { margin: 0; } | |
form { margin: 0; } | |
fieldset { border: 0; margin: 0; padding: 0; } | |
label { cursor: pointer; } | |
legend { border: 0; *margin-left: -7px; padding: 0; } | |
button, input, select, textarea { font-size: 100%; margin: 0; vertical-align: baseline; *vertical-align: middle; } | |
button, input { line-height: normal; *overflow: visible; } | |
table button, table input { *overflow: auto; } | |
button, input[type="button"], input[type="reset"], input[type="submit"] { cursor: pointer; -webkit-appearance: button; } | |
input[type="checkbox"], input[type="radio"] { box-sizing: border-box; } | |
input[type="search"] { -webkit-appearance: textfield; -moz-box-sizing: content-box; -webkit-box-sizing: content-box; box-sizing: content-box; } | |
input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; } | |
button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; } | |
textarea { overflow: auto; vertical-align: top; resize: vertical; } | |
input:valid, textarea:valid { } | |
input:invalid, textarea:invalid { background-color: #f0dddd; } | |
table { border-collapse: collapse; border-spacing: 0; } | |
td { vertical-align: top; } | |
/* ==|== primary styles ===================================================== | |
Author: | |
========================================================================== */ | |
body { | |
padding: 50px; | |
color: #8b8b8b; | |
} | |
h1, h2, h3 { | |
font-size: 33px; | |
font-weight: normal; | |
color: #333; | |
-webkit-font-smoothing: antialiased; | |
} | |
h2 { | |
padding: 5px 0; | |
font-size: 24px; | |
border-bottom: 3px solid #eee; | |
} | |
h3 { | |
padding: 5px 0; | |
font-size: 18px; | |
border-bottom: 3px solid #eee; | |
} | |
h4 { font-size: 16px; } | |
h5 { font-size: 14px; } | |
a { color: #33f; text-decoration: none; } | |
a:visited { color: #06e; } | |
a:hover { color: #06e; text-decoration: underline; } | |
a:focus { outline: thin dotted; } | |
a:hover, a:active { outline: 0; } | |
.docs { text-align: right } | |
/** wikistyle,credits to github guys. **/ | |
p{margin:1em 0 !important;line-height:1.5em !important;} | |
a.absent{color:#a00;} | |
ul {margin:1em 0 1em 0.5em !important;} | |
ol {margin:1em 0 1em 0.5em !important;} | |
ul li{margin-top:.5em;margin-bottom:.5em;} | |
ul ul, ul ol, ol ol, ol ul{ margin: 0 !important;} | |
blockquote{margin:1em 0 !important;border-left:5px solid #ddd !important;padding-left:.6em !important;color:#555 !important;} | |
dt{font-weight:bold !important;margin-left:1em !important;} | |
dd{margin-left:2em !important;margin-bottom:1em !important;} | |
table{margin:1em 0 !important;} | |
table{margin:1em 0 !important;} | |
table th{border-bottom:1px solid #bbb !important;padding:.2em 1em !important;} | |
table td{border-bottom:1px solid #ddd !important;padding:.2em 1em !important;} | |
pre{margin:1em 0;font-size:12px;background-color:#eee;border:1px solid #ddd;padding:5px;line-height:1.5em;color:#444;overflow:auto;-webkit-box-shadow:rgba(0,0,0,0.07) 0 1px 2px inset;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} | |
pre::-webkit-scrollbar{height:8px;width:8px;} | |
pre::-webkit-scrollbar-track-piece{margin-bottom:10px;background-color:#eee;border-bottom-left-radius:4px 4px;border-bottom-right-radius:4px 4px;border-top-left-radius:4px 4px;border-top-right-radius:4px 4px;} | |
pre::-webkit-scrollbar-thumb:vertical{height:25px;background-color:#ccc;-webkit-border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(255,255,255,1);} | |
pre::-webkit-scrollbar-thumb:horizontal{width:25px;background-color:#ccc;-webkit-border-radius:4px;} | |
a code, a:link code, a:visited code{color:#4183c4 !important;} | |
img{max-width:100%;} | |
pre.console{margin:1em 0 !important;font-size:12px !important;background-color:black !important;padding:.5em !important;line-height:1.5em !important;color:white !important;} | |
pre.console code{padding:0 !important;font-size:12px !important;background-color:black !important;border:none !important;color:white !important;} | |
pre.console span{color:#888 !important;} | |
pre.console span.command{color:yellow !important;} | |
.frame{margin:0;display:inline-block;} | |
.frame img{display:block;} | |
.frame>span{display:block;border:1px solid #aaa;padding:4px;} | |
.frame span span{display:block;font-size:10pt;margin:0;padding:4px 0 2px 0;text-align:center;line-height:10pt;font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;} | |
.float-left{float:left;padding:.5em 1em .25em 0;} | |
.float-right{float:right;padding:.5em 0 .25em 1em;} | |
.align-left{display:block;text-align:left;} | |
.align-center{display:block;text-align:center;} | |
.align-right{display:block;text-align:right;} | |
/* ==|== non-semantic helper classes ======================================== */ | |
.ir { display: block; border: 0; text-indent: -999em; overflow: hidden; background-color: transparent; background-repeat: no-repeat; text-align: left; direction: ltr; } | |
.ir br { display: none; } | |
.hidden { display: none !important; visibility: hidden; } | |
.visuallyhidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; } | |
.visuallyhidden.focusable:active, .visuallyhidden.focusable:focus { clip: auto; height: auto; margin: 0; overflow: visible; position: static; width: auto; } | |
.invisible { visibility: hidden; } | |
.clearfix:before, .clearfix:after { content: ""; display: table; } | |
.clearfix:after { clear: both; } | |
.clearfix { zoom: 1; } | |
/* ==|== media queries ====================================================== */ | |
@media only screen and (min-width: 480px) { | |
} | |
@media only screen and (min-width: 768px) { | |
} | |
/* ==|== print styles ======================================================= */ | |
@media print { | |
* { background: transparent !important; color: black !important; text-shadow: none !important; filter:none !important; -ms-filter: none !important; } | |
a, a:visited { text-decoration: underline; } | |
a[href]:after { content: " (" attr(href) ")"; } | |
abbr[title]:after { content: " (" attr(title) ")"; } | |
.ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; } | |
pre, blockquote { border: 1px solid #999; page-break-inside: avoid; } | |
thead { display: table-header-group; } | |
tr, img { page-break-inside: avoid; } | |
img { max-width: 100% !important; } | |
@page { margin: 0.5cm; } | |
p, h2, h3 { orphans: 3; widows: 3; } | |
h2, h3 { page-break-after: avoid; } | |
} | |
</style> | |
</head> | |
<body> | |
<header> | |
<h1>{{ name }}<h1> | |
<h2>{{ description }}</h2> | |
</header> | |
<div role="main"> | |
{{#docpath}} | |
<p class="docs"><a href="{{docpath}}">Moar docs</a></p> | |
{{/docpath}} | |
{{{ content }}} | |
</div> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "cakes-docs", | |
"version": "0.0.1", | |
"dependencies": { | |
"mustache": "0.3.1-dev", | |
"mkdirp": "0.0.7", | |
"markdown": "~0.3.1", | |
"findit": "~0.1.1", | |
"docco": "~0.3.0", | |
"cheesecake": "https://gist.github.com/gists/1332010/download" | |
}, | |
"scripts": { "postinstall": "sh postinstall.sh" } | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
echo Copying tasks/docs.js and tasks/support/index.html | |
base=../.. | |
mkdir -p $base/tasks/support | |
cp docs.js $base/tasks/ && cp index.html $base/tasks/support | |
echo Install done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment