mirror of https://github.com/lukechilds/node.git
Jérémy Lal
15 years ago
committed by
Ryan Dahl
11 changed files with 2259 additions and 5 deletions
@ -0,0 +1,12 @@ |
|||||
|
Ronnjs Changes and Release Notes |
||||
|
============================== |
||||
|
|
||||
|
Version 0.2 |
||||
|
------------------------------ |
||||
|
|
||||
|
Supports output to html fragment. |
||||
|
|
||||
|
Version 0.1 |
||||
|
------------------------------ |
||||
|
|
||||
|
Initial release. |
@ -0,0 +1,62 @@ |
|||||
|
Ronnjs is a javascript port of Ronn, which is an original |
||||
|
work of Ryan Tomayko. |
||||
|
|
||||
|
Copyright: 2009 Ryan Tomayko <tomayko.com/about> |
||||
|
License: MIT |
||||
|
|
||||
|
Files: bin/ronn.js, lib/ronn.js |
||||
|
Copyright: 2010 Jérémy Lal <kapouer@melix.org> |
||||
|
License : MIT |
||||
|
|
||||
|
Files: lib/ext/markdown.js |
||||
|
Copyright: 2009-2010 Dominic Baggott, 2009-2010 Ash Berlin |
||||
|
License: MIT |
||||
|
|
||||
|
Files: lib/ext/opts.js |
||||
|
Copyright: 2010 Joey Mazzarelli <mazzarelli@gmail.com>. All rights reserved. |
||||
|
License: Simplified BSD License |
||||
|
Redistribution and use in source and binary forms, with or without |
||||
|
modification, are permitted provided that the following conditions are met: |
||||
|
|
||||
|
1. Redistributions of source code must retain the above copyright notice, |
||||
|
this list of conditions and the following disclaimer. |
||||
|
|
||||
|
2. Redistributions in binary form must reproduce the above copyright notice, |
||||
|
this list of conditions and the following disclaimer in the documentation |
||||
|
and/or other materials provided with the distribution. |
||||
|
|
||||
|
THIS SOFTWARE IS PROVIDED BY JOEY MAZZARELLI 'AS IS' AND ANY EXPRESS OR IMPLIED |
||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
||||
|
EVENT SHALL JOEY MAZZARELLI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
||||
|
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||
|
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
|
||||
|
The views and conclusions contained in the software and documentation are those |
||||
|
of the authors and should not be interpreted as representing official policies, |
||||
|
either expressed or implied, of Joey Mazzarelli. |
||||
|
|
||||
|
License: MIT |
||||
|
Permission is hereby granted, free of charge, to any person |
||||
|
obtaining a copy of this software and associated documentation |
||||
|
files (the "Software"), to deal in the Software without restriction, |
||||
|
including without limitation the rights to use, copy, modify, |
||||
|
merge, publish, distribute, sublicense, and/or sell copies of |
||||
|
the Software, and to permit persons to whom the Software is furnished |
||||
|
to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be |
||||
|
included in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
||||
|
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
||||
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
|
SOFTWARE. |
@ -0,0 +1,25 @@ |
|||||
|
ronnjs(1) -- markdown to roff converter |
||||
|
======================================= |
||||
|
|
||||
|
## Synopsis |
||||
|
|
||||
|
Javascript port of [ronn], using [markdown-js] to produce roff man pages. |
||||
|
Not fully compatible with [ronn], although it aims to be, wherever possible. |
||||
|
|
||||
|
## Usage |
||||
|
|
||||
|
This outputs doc.roff from a markdown file : |
||||
|
|
||||
|
ronn.js --build --roff doc.md |
||||
|
|
||||
|
Command-line options are listed with -h |
||||
|
|
||||
|
|
||||
|
## How it works ? |
||||
|
|
||||
|
[markdown-js] parses markdown text to a document model, which in turn is |
||||
|
used to ouput a man page. |
||||
|
|
||||
|
|
||||
|
[ronn]: http://github.com/rtomayko/ronn |
||||
|
[markdown-js]: http://github.com/evilstreak/markdown-js |
@ -0,0 +1,7 @@ |
|||||
|
# TODO |
||||
|
|
||||
|
* show <hr> tags using something like |
||||
|
\l'\n(.lu*8u/10u' |
||||
|
and take care of the current indentation. |
||||
|
|
||||
|
* tests ! |
@ -0,0 +1,102 @@ |
|||||
|
#!/usr/bin/nodejs
|
||||
|
|
||||
|
var opts = require(__dirname + '/../lib/ext/opts'); |
||||
|
var ronn = require(__dirname + '/../lib/ronn'); |
||||
|
|
||||
|
var options = [ |
||||
|
{ short : 'V' |
||||
|
, description : 'Show version and exit' |
||||
|
, callback : function () { sys.puts('0.1'); process.exit(1); } |
||||
|
}, |
||||
|
{ short : 'b' |
||||
|
, long : 'build' |
||||
|
, description : 'Output to files with appropriate extension' |
||||
|
}, |
||||
|
{ short : 'm' |
||||
|
, long : 'man' |
||||
|
, description : 'Convert to roff and open with man' |
||||
|
}, |
||||
|
{ short : 'r' |
||||
|
, long : 'roff' |
||||
|
, description : 'Convert to roff format' |
||||
|
}, |
||||
|
{ short : '5' |
||||
|
, long : 'html' |
||||
|
, description : 'Convert to html format' |
||||
|
}, |
||||
|
{ short : 'f' |
||||
|
, long : 'fragment' |
||||
|
, description : 'Convert to html fragment format' |
||||
|
}, |
||||
|
{ long : 'manual' |
||||
|
, description : 'Set "manual" attribute' |
||||
|
, value : true |
||||
|
}, |
||||
|
{ long : 'version' |
||||
|
, description : 'Set "version" attribute' |
||||
|
, value : true |
||||
|
}, |
||||
|
{ long : 'date' |
||||
|
, description : 'Set "date" attribute' |
||||
|
, value : true |
||||
|
} |
||||
|
]; |
||||
|
var arguments = [ |
||||
|
{ name : 'file' |
||||
|
, required : true |
||||
|
, description: 'A ronn file' |
||||
|
} |
||||
|
]; |
||||
|
opts.parse(options, arguments, true); |
||||
|
|
||||
|
|
||||
|
var sys = require('sys'); |
||||
|
var fs = require('fs'); |
||||
|
var path = require('path'); |
||||
|
|
||||
|
var fPath = opts.arg('file'); |
||||
|
var fBase = path.join(path.dirname(fPath), path.basename(fPath, path.extname(fPath))); |
||||
|
|
||||
|
var fTxt = fs.readFileSync(fPath, 'utf8'); |
||||
|
var ronn = new ronn.Ronn(fTxt, opts.get("version"), opts.get("manual"), opts.get("date")); |
||||
|
|
||||
|
if (opts.get("man") && !opts.get("build")) { |
||||
|
var spawn = require('child_process').spawn; |
||||
|
var man = spawn('man', ['--warnings', '-E UTF-8', '-l', '-'], {"LANG":"C"}); |
||||
|
man.stdout.addListener('data', function (data) { |
||||
|
sys.puts(data); |
||||
|
}); |
||||
|
man.stderr.addListener('data', function (data) { |
||||
|
sys.puts(data); |
||||
|
}); |
||||
|
man.addListener('exit', function() { |
||||
|
process.exit(0); |
||||
|
}); |
||||
|
man.stdin.write(ronn.roff(), 'utf8'); |
||||
|
man.stdin.end(); |
||||
|
} else { |
||||
|
var fRoff = null; |
||||
|
var fHtml = null; |
||||
|
var fFrag = null; |
||||
|
if (!opts.get("html") && !opts.get("fragment")) fRoff = ronn.roff(); |
||||
|
else { |
||||
|
if (opts.get("roff")) fRoff = ronn.roff(); |
||||
|
if (opts.get("html")) fHtml = ronn.html(); |
||||
|
if (opts.get("fragment")) { |
||||
|
if (opts.get("html")) { |
||||
|
sys.debug("Can't use both --fragment and --html"); |
||||
|
process.exit(-1); |
||||
|
} |
||||
|
fFrag = ronn.fragment(); |
||||
|
} |
||||
|
} |
||||
|
if (opts.get("build")) { |
||||
|
if (fRoff) fs.writeFileSync(fBase + ".roff", fRoff, 'utf8'); |
||||
|
if (fHtml) fs.writeFileSync(fBase + ".html", fHtml, 'utf8'); |
||||
|
if (fFrag) fs.writeFileSync(fBase + ".fragment", fFrag, 'utf8'); |
||||
|
} else { |
||||
|
if (fRoff) sys.puts(fRoff); |
||||
|
if (fHtml) sys.puts(fHtml); |
||||
|
if (fFrag) sys.puts(fFrag); |
||||
|
} |
||||
|
} |
File diff suppressed because it is too large
@ -0,0 +1,268 @@ |
|||||
|
/*************************************************************************** |
||||
|
Author : Joey Mazzarelli |
||||
|
Email : mazzarelli@gmail.com |
||||
|
Homepage : http://joey.mazzarelli.com/js-opts
|
||||
|
Source : http://bitbucket.org/mazzarell/js-opts/
|
||||
|
License : Simplified BSD License |
||||
|
Version : 1.0 |
||||
|
|
||||
|
Copyright 2010 Joey Mazzarelli. All rights reserved. |
||||
|
|
||||
|
Redistribution and use in source and binary forms, with or without |
||||
|
modification, are permitted provided that the following conditions are met: |
||||
|
|
||||
|
1. Redistributions of source code must retain the above copyright notice, |
||||
|
this list of conditions and the following disclaimer. |
||||
|
|
||||
|
2. Redistributions in binary form must reproduce the above copyright notice, |
||||
|
this list of conditions and the following disclaimer in the documentation |
||||
|
and/or other materials provided with the distribution. |
||||
|
|
||||
|
THIS SOFTWARE IS PROVIDED BY JOEY MAZZARELLI 'AS IS' AND ANY EXPRESS OR IMPLIED |
||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
||||
|
EVENT SHALL JOEY MAZZARELLI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
||||
|
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||
|
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
|
||||
|
The views and conclusions contained in the software and documentation are those |
||||
|
of the authors and should not be interpreted as representing official policies, |
||||
|
either expressed or implied, of Joey Mazzarelli. |
||||
|
***************************************************************************/ |
||||
|
|
||||
|
var puts = require('sys').puts |
||||
|
, values = {} |
||||
|
, args = {} |
||||
|
, argv = [] |
||||
|
, errors = [] |
||||
|
, descriptors = {opts:[], args:[]}; |
||||
|
|
||||
|
/** |
||||
|
* Add a set of option descriptors, not yet ready to be parsed. |
||||
|
* See exports.parse for description of options object |
||||
|
* |
||||
|
* Additionally, it takes a namespace as an argument, useful for |
||||
|
* building options for a library in addition to the main app. |
||||
|
*/ |
||||
|
exports.add = function (options, namespace) { |
||||
|
for (var i=0; i<options.length; i++) { |
||||
|
options[i].namespace = namespace; |
||||
|
descriptors.opts.push(options[i]); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Parse the command line options |
||||
|
* @param array options Options to parse |
||||
|
* @param array args Arguments to parse |
||||
|
* @param bool help Automatically generate help message, default false |
||||
|
* |
||||
|
* ===== Options Docs ===== |
||||
|
* Each option in the array can have the following fields. None are required, |
||||
|
* but you should at least provide a short or long name. |
||||
|
* { |
||||
|
* short : 'l', |
||||
|
* long : 'list', |
||||
|
* description : 'Show a list', |
||||
|
* value : false, // default false
|
||||
|
* required : true, // default false
|
||||
|
* callback : function (value) { ... }, |
||||
|
* } |
||||
|
* |
||||
|
* You can add an automatically generated help message by passing |
||||
|
* a second parameter of <true> or by including the option; |
||||
|
* { |
||||
|
* long : 'help', |
||||
|
* description : 'Show this help message', |
||||
|
* callback : require('./opts').help, |
||||
|
* } |
||||
|
* |
||||
|
* ===== Arguments Docs ===== |
||||
|
* Arguments are different than options, and simpler. They typically come |
||||
|
* after the options, but the library really doesn't care. Each argument |
||||
|
* can have the form of: |
||||
|
* { |
||||
|
* name : 'script', |
||||
|
* required : true, // default false
|
||||
|
* callback : function (value) { ... }, |
||||
|
* } |
||||
|
*/ |
||||
|
exports.parse = function (options, params, help) { |
||||
|
|
||||
|
if (params === true) { |
||||
|
help = true; |
||||
|
} else if (!params) { |
||||
|
params = []; |
||||
|
} else { |
||||
|
for (var i=0; i<params.length; i++) { |
||||
|
descriptors.args.push(params[i]); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (help) { |
||||
|
options.push({ long : 'help' |
||||
|
, description : 'Show this help message' |
||||
|
, callback : exports.help |
||||
|
}); |
||||
|
} |
||||
|
for (var i=0; i<options.length; i++) { |
||||
|
descriptors.opts.unshift(options[i]); |
||||
|
} |
||||
|
options = descriptors.opts; |
||||
|
|
||||
|
var checkDup = function (opt, type) { |
||||
|
var prefix = (type == 'short')? '-': '--'; |
||||
|
var name = opt[type]; |
||||
|
if (!opts[prefix + name]) { |
||||
|
opts[prefix + name] = opt; |
||||
|
} else { |
||||
|
if (opt.namespace && !opts[prefix + opt.namespace + '.' + name]) { |
||||
|
opts[prefix + opt.namespace + '.' + name] = opt; |
||||
|
for (var i=0; i<descriptors.opts.length; i++) { |
||||
|
var desc = descriptors.opts[i]; |
||||
|
if (desc.namespace == opt.namespace) { |
||||
|
if (type == 'long' && desc.long == opt.long) { |
||||
|
descriptors.opts[i].long = opt.namespace + '.' + opt.long; |
||||
|
} else if (type == 'short') { |
||||
|
delete descriptors.opts[i].short; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} else { |
||||
|
puts('Conflicting flags: ' + prefix + name + '\n'); |
||||
|
puts(helpString()); |
||||
|
process.exit(1); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
var opts = {}; |
||||
|
for (var i=0; i<options.length; i++) { |
||||
|
if (options[i].short) checkDup(options[i], 'short'); |
||||
|
if (options[i].long) checkDup(options[i], 'long'); |
||||
|
} |
||||
|
|
||||
|
for (var i=2; i<process.argv.length; i++) { |
||||
|
var inp = process.argv[i]; |
||||
|
if (opts[inp]) { |
||||
|
// found a match, process it.
|
||||
|
var opt = opts[inp]; |
||||
|
if (!opt.value) { |
||||
|
if (opt.callback) opt.callback(true); |
||||
|
if (opt.short) values[opt.short] = true; |
||||
|
if (opt.long) values[opt.long] = true; |
||||
|
} else { |
||||
|
var next = process.argv[i+1]; |
||||
|
if (!next || opts[next]) { |
||||
|
var flag = opt.short || opt.long; |
||||
|
errors.push('Missing value for option: ' + flag); |
||||
|
if (opt.short) values[opt.short] = true; |
||||
|
if (opt.long) values[opt.long] = true; |
||||
|
} else { |
||||
|
if (opt.callback) opt.callback(next); |
||||
|
if (opt.short) values[opt.short] = next; |
||||
|
if (opt.long) values[opt.long] = next; |
||||
|
i++; |
||||
|
} |
||||
|
} |
||||
|
} else { |
||||
|
// No match. If it starts with a dash, show an error. Otherwise
|
||||
|
// add it to the extra params.
|
||||
|
if (inp[0] == '-') { |
||||
|
puts('Unknown option: ' + inp); |
||||
|
if (opts['--help']) puts('Try --help'); |
||||
|
process.exit(1); |
||||
|
} else { |
||||
|
argv.push(inp); |
||||
|
var arg = params.shift(); |
||||
|
if (arg) { |
||||
|
args[arg.name] = inp; |
||||
|
if (arg.callback) arg.callback(inp); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
for (var i=0; i<options.length; i++) { |
||||
|
var flag = options[i].short || options[i].long; |
||||
|
if (options[i].required && !exports.get(flag)) { |
||||
|
errors.push('Missing required option: ' + flag); |
||||
|
} |
||||
|
} |
||||
|
for (var i=0; i<params.length; i++) { |
||||
|
if (params[i].required && !args[params[i].name]) { |
||||
|
errors.push('Missing required argument: ' + params[i].name); |
||||
|
} |
||||
|
} |
||||
|
if (errors.length) { |
||||
|
for (var i=0; i<errors.length; i++) puts(errors[i]); |
||||
|
puts('\n' + helpString()); |
||||
|
process.exit(1); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Get the value of an option. Can be the short or long option |
||||
|
* @return string |
||||
|
*/ |
||||
|
exports.get = function (opt) { |
||||
|
return values[opt] || values['-' + opt] || values['--' + opt]; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Get unknown args. Could have special meaning to client |
||||
|
*/ |
||||
|
exports.args = function () { |
||||
|
return argv; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Get an arg by name. |
||||
|
* This only works if arg names were passed into the parse function. |
||||
|
* @param string name Name of arg |
||||
|
* @return string Value of arg |
||||
|
*/ |
||||
|
exports.arg = function (name) { |
||||
|
//puts(require('sys').inspect(arguments));
|
||||
|
return args[name]; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Print the help message and exit |
||||
|
*/ |
||||
|
exports.help = function () { |
||||
|
puts(helpString()); |
||||
|
process.exit(0); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// Create the help string
|
||||
|
var helpString = function () { |
||||
|
var str = 'Usage: ' + process.argv[0] + ' ' + process.argv[1]; |
||||
|
if (descriptors.opts.length) str += ' [options]'; |
||||
|
if (descriptors.args.length) { |
||||
|
for (var i=0; i<descriptors.args.length; i++) { |
||||
|
if (descriptors.args[i].required) { |
||||
|
str += ' ' + descriptors.args[i].name; |
||||
|
} else { |
||||
|
str += ' [' + descriptors.args[i].name + ']'; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
str += '\n'; |
||||
|
for (var i=0; i<descriptors.opts.length; i++) { |
||||
|
var opt = descriptors.opts[i]; |
||||
|
if (opt.description) str += (opt.description) + '\n'; |
||||
|
var line = ''; |
||||
|
if (opt.short && !opt.long) line += '-' + opt.short; |
||||
|
else if (opt.long && !opt.short) line += '--' + opt.long; |
||||
|
else line += '-' + opt.short + ', --' + opt.long; |
||||
|
if (opt.value) line += ' <value>'; |
||||
|
if (opt.required) line += ' (required)'; |
||||
|
str += ' ' + line + '\n'; |
||||
|
} |
||||
|
return str; |
||||
|
}; |
@ -0,0 +1,321 @@ |
|||||
|
/* ronn.js version 0.1 |
||||
|
* Copyright : 2010 Jérémy Lal <kapouer@melix.org> |
||||
|
* License : MIT |
||||
|
*/ |
||||
|
|
||||
|
var md = require(__dirname + '/ext/markdown'); |
||||
|
var sys = require('sys'); |
||||
|
|
||||
|
/* exports Ronn class |
||||
|
* usage : |
||||
|
* var ronn = new Ronn(rofftext, "1.0", "my manual name", "2010-12-25"); |
||||
|
* ronn.roff(); |
||||
|
* ronn.html(); |
||||
|
* ronn.fragment(); |
||||
|
*/ |
||||
|
|
||||
|
exports.Ronn = function(text, version, manual, date) { |
||||
|
if (!manual) manual = ""; |
||||
|
if (!version) version = ""; |
||||
|
if (!date) date = new Date(); |
||||
|
else date = new Date(date + " GMT"); |
||||
|
|
||||
|
var gHtml = md.toHTMLTree(text); |
||||
|
|
||||
|
this.roff = function() { |
||||
|
return blockFilter("", gHtml, {parent:null, previous:null, position:null}); |
||||
|
}; |
||||
|
|
||||
|
this.html = function() { |
||||
|
return toHTML(gHtml); |
||||
|
}; |
||||
|
|
||||
|
this.fragment = function() { |
||||
|
return toHTMLfragment(gHtml); |
||||
|
}; |
||||
|
|
||||
|
function blockFilter(out, node, context) { |
||||
|
if (typeof node == "string") { |
||||
|
if (!node.match(/^\s*$/m)) sys.debug("unexpected text: " + node); |
||||
|
return out; |
||||
|
} |
||||
|
var tag = node.shift(); |
||||
|
var attributes = null; |
||||
|
if (node.length && typeof node[0] === "object" && !(node[0] instanceof Array)) { |
||||
|
attributes = node.shift(); |
||||
|
} |
||||
|
var fParent = context.parent; |
||||
|
var fPrevious = context.previous; |
||||
|
context.previous = null; |
||||
|
context.parent = tag; |
||||
|
switch (tag) { |
||||
|
case "html": |
||||
|
out = comment(out, "Generated with Ronnjs/v0.1"); |
||||
|
out = comment(out, "http://github.com/kapouer/ronnjs/"); |
||||
|
while (node.length) out = blockFilter(out, node.shift(), context); |
||||
|
break; |
||||
|
case "h1": |
||||
|
var fTagline = node.shift(); |
||||
|
var fMatch = /([\w_.\[\]~+=@:-]+)\s*\((\d\w*)\)\s*-+\s*(.*)/.exec(fTagline); |
||||
|
var fName, fSection; |
||||
|
if (fMatch != null) { |
||||
|
fName = fMatch[1]; |
||||
|
fSection = fMatch[2]; |
||||
|
fTagline = fMatch[3]; |
||||
|
} else { |
||||
|
fMatch = /([\w_.\[\]~+=@:-]+)\s+-+\s+(.*)/.exec(fTagline); |
||||
|
if (fMatch != null) { |
||||
|
fName = fMatch[1]; |
||||
|
fTagline = fMatch[2]; |
||||
|
} |
||||
|
} |
||||
|
if (fMatch == null) { |
||||
|
fName = ""; |
||||
|
fSection = ""; |
||||
|
fName = ""; |
||||
|
} |
||||
|
out = macro(out, "TH", [ |
||||
|
quote(esc(fName.toUpperCase())) |
||||
|
, quote(fSection) |
||||
|
, quote(manDate(date)) |
||||
|
, quote(version) |
||||
|
, quote(manual) |
||||
|
]); |
||||
|
out = macro(out, "SH", quote("NAME")); |
||||
|
out += "\\fB" + fName + "\\fR"; |
||||
|
if (fTagline.length > 0) out += " \\-\\- " + esc(fTagline); |
||||
|
break; |
||||
|
case "h2": |
||||
|
out = macro(out, "SH", quote(esc(toHTML(node.shift())))); |
||||
|
break; |
||||
|
case "h3": |
||||
|
out = macro(out, "SS", quote(esc(toHTML(node.shift())))); |
||||
|
break; |
||||
|
case "hr": |
||||
|
out = macro(out, "HR"); |
||||
|
break; |
||||
|
case "p": |
||||
|
if (fPrevious && fParent && (fParent == "dd" || fParent == "li")) |
||||
|
out = macro(out, "IP"); |
||||
|
else if (fPrevious && !(fPrevious == "h1" || fPrevious == "h2" || fPrevious == "h3")) |
||||
|
out = macro(out, "P"); |
||||
|
out = callInlineChildren(out, node, context); |
||||
|
break; |
||||
|
case "pre": |
||||
|
var indent = (fPrevious == null || !(fPrevious == "h1" || fPrevious == "h2" || fPrevious == "h3")); |
||||
|
if (indent) out = macro(out, "IP", [quote(""), 4]); |
||||
|
out = macro(out, "nf"); |
||||
|
out = callInlineChildren(out, node, context); |
||||
|
out = macro(out, "fi"); |
||||
|
if (indent) out = macro(out, "IP", [quote(""), 0]); |
||||
|
break; |
||||
|
case "dl": |
||||
|
out = macro(out, "TP"); |
||||
|
while (node.length) out = blockFilter(out, node.shift(), context); |
||||
|
break; |
||||
|
case "dt": |
||||
|
if (fPrevious != null) out = macro(out, "TP"); |
||||
|
out = callInlineChildren(out, node, context); |
||||
|
out += "\n"; |
||||
|
break; |
||||
|
case "dd": |
||||
|
if (containsTag(node, {'p':true})) { |
||||
|
while (node.length) out = blockFilter(out, node.shift(), context); |
||||
|
} else { |
||||
|
out = callInlineChildren(out, node, context); |
||||
|
} |
||||
|
out += "\n"; |
||||
|
break; |
||||
|
case "ol": |
||||
|
case "ul": |
||||
|
context.position = 0; |
||||
|
while (node.length) { |
||||
|
out = blockFilter(out, node.shift(), context); |
||||
|
} |
||||
|
context.position = null; |
||||
|
out = macro(out, "IP", [quote(""), 0]); |
||||
|
break; |
||||
|
case "li": |
||||
|
if (fParent == "ol") { |
||||
|
context.position += 1; |
||||
|
out = macro(out, "IP", [quote(context.position), 4]); |
||||
|
} else if (fParent == "ul") { |
||||
|
out = macro(out, "IP", [quote("\\(bu"), 4]); |
||||
|
} |
||||
|
if (containsTag(node, {"p":true, "ol":true, "ul":true, "dl":true, "div":true})) { |
||||
|
while (node.length) out = blockFilter(out, node.shift(), context); |
||||
|
} else { |
||||
|
out = callInlineChildren(out, node, context); |
||||
|
} |
||||
|
out += "\n"; |
||||
|
break; |
||||
|
default: |
||||
|
sys.debug("unrecognized block tag: " + tag); |
||||
|
break; |
||||
|
} |
||||
|
context.parent = fParent; |
||||
|
context.previous = tag; |
||||
|
return out; |
||||
|
} |
||||
|
|
||||
|
function callInlineChildren(out, node, context) { |
||||
|
while (node.length) { |
||||
|
var lChild = node.shift(); |
||||
|
if (node.length > 0) context.hasNext = true; |
||||
|
else context.hasNext = false; |
||||
|
out = inlineFilter(out, lChild, context); |
||||
|
} |
||||
|
return out; |
||||
|
} |
||||
|
|
||||
|
function inlineFilter(out, node, context) { |
||||
|
if (typeof node == "string") { |
||||
|
if (context.previous && context.previous == "br") node = node.replace(/^\n+/gm, ''); |
||||
|
if (context.parent == "pre") { |
||||
|
// do nothing
|
||||
|
} else if (context.previous == null && !context.hasNext) { |
||||
|
node = node.replace(/\n+$/gm, ''); |
||||
|
} else { |
||||
|
node = node.replace(/\n+$/gm, ' '); |
||||
|
} |
||||
|
out += esc(node); |
||||
|
return out; |
||||
|
} |
||||
|
var tag = node.shift(); |
||||
|
var attributes = null; |
||||
|
if (node.length && typeof node[0] === "object" && !(node[0] instanceof Array)) { |
||||
|
attributes = node.shift(); |
||||
|
} |
||||
|
var fParent = context.parent; |
||||
|
var fPrevious = context.previous; |
||||
|
context.parent = tag; |
||||
|
context.previous = null; |
||||
|
switch(tag) { |
||||
|
case "code": |
||||
|
if (fParent == "pre") { |
||||
|
out = callInlineChildren(out, node, context); |
||||
|
} else { |
||||
|
out += '\\fB'; |
||||
|
out = callInlineChildren(out, node, context); |
||||
|
out += '\\fR'; |
||||
|
} |
||||
|
break; |
||||
|
case "b": |
||||
|
case "strong": |
||||
|
case "kbd": |
||||
|
case "samp": |
||||
|
out += '\\fB'; |
||||
|
out = callInlineChildren(out, node, context); |
||||
|
out += '\\fR'; |
||||
|
break; |
||||
|
case "var": |
||||
|
case "em": |
||||
|
case "i": |
||||
|
case "u": |
||||
|
out += '\\fI'; |
||||
|
out = callInlineChildren(out, node, context); |
||||
|
out += '\\fR'; |
||||
|
break; |
||||
|
case "br": |
||||
|
out = macro(out, "br"); |
||||
|
break; |
||||
|
case "a": |
||||
|
var fStr = node[0]; |
||||
|
var fHref = attributes['href']; |
||||
|
if (fHref == fStr || decodeURI(fHref) == "mailto:" + decodeURI(fStr)) { |
||||
|
out += '\\fI'; |
||||
|
out = callInlineChildren(out, node, context); |
||||
|
out += '\\fR'; |
||||
|
} else { |
||||
|
out = callInlineChildren(out, node, context); |
||||
|
out += " "; |
||||
|
out += '\\fI'; |
||||
|
out += esc(fHref); |
||||
|
out += '\\fR'; |
||||
|
} |
||||
|
break; |
||||
|
default: |
||||
|
sys.debug("unrecognized inline tag: " + tag); |
||||
|
break; |
||||
|
} |
||||
|
context.parent = fParent; |
||||
|
context.previous = tag; |
||||
|
return out; |
||||
|
} |
||||
|
|
||||
|
function containsTag(node, tags) { |
||||
|
// browse ml tree searching for tags (hash {tag : true, ...})
|
||||
|
if (typeof node == "string") return false; |
||||
|
var jml = node.slice(0); |
||||
|
if (jml.length == 0) return false; |
||||
|
else while (jml.length && jml[0] instanceof Array) { |
||||
|
if (containsTag(jml.shift(), tags)) return true; |
||||
|
} |
||||
|
var tag = jml.shift(); |
||||
|
if (tags[tag] === true) return true; |
||||
|
if (jml.length && typeof jml[0] === "object" && !(jml[0] instanceof Array)) { |
||||
|
// skip attributes
|
||||
|
jml.shift(); |
||||
|
} |
||||
|
// children
|
||||
|
if (jml.length) { |
||||
|
if (containsTag(jml.shift(), tags)) return true; |
||||
|
} |
||||
|
// siblings
|
||||
|
if (jml.length) return containsTag(jml, tags); |
||||
|
} |
||||
|
|
||||
|
function toHTML(node) { |
||||
|
// problème ici : les & sont remplacés par des &
|
||||
|
return md.renderJsonML(node, {root:true}); |
||||
|
} |
||||
|
|
||||
|
function toHTMLfragment(node) { |
||||
|
return md.renderJsonML(node); |
||||
|
} |
||||
|
|
||||
|
function comment(out, str) { |
||||
|
return writeln(out, '.\\" ' + str); |
||||
|
} |
||||
|
|
||||
|
function quote(str) { |
||||
|
return '"' + str + '"'; |
||||
|
} |
||||
|
|
||||
|
function esc(str) { |
||||
|
return str |
||||
|
.replace(/\\/gm, "\\\\") |
||||
|
.replace(/-/gm, "\\-") |
||||
|
.replace(/^\./gm, "\\|.") |
||||
|
.replace(/\./gm, "\\.") |
||||
|
.replace(/'/gm, "\\'") |
||||
|
; |
||||
|
} |
||||
|
|
||||
|
function writeln(out, str) { |
||||
|
if (out.length && out[out.length - 1] != "\n") out += "\n"; |
||||
|
out += str + "\n"; |
||||
|
return out; |
||||
|
} |
||||
|
|
||||
|
function macro(out, name, list) { |
||||
|
var fText = ".\n." + name; |
||||
|
if (list != null) { |
||||
|
if (typeof list == "string") { |
||||
|
fText += ' ' + list; |
||||
|
} else { |
||||
|
for (var i=0, len=list.length; i < len; i++) { |
||||
|
var item = list[i]; |
||||
|
if (item == null) continue; |
||||
|
fText += ' ' + item; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return writeln(out, fText); |
||||
|
} |
||||
|
|
||||
|
function manDate(pDate) { |
||||
|
var fMonth = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"][pDate.getMonth()]; |
||||
|
return fMonth + " " + pDate.getFullYear(); |
||||
|
} |
||||
|
}; |
Loading…
Reference in new issue