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