├── LICENSE ├── README.md ├── addon-verify.js ├── generate.js ├── html.js ├── json.js ├── node_modules ├── .bin │ └── marked └── marked │ ├── .npmignore │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── bin │ └── marked │ ├── index.js │ ├── lib │ └── marked.js │ ├── man │ └── marked.1 │ └── package.json ├── package.json └── preprocess.js /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Joyent, Inc. and other Node contributors. All rights reserved. 2 | Permission is hereby granted, free of charge, to any person obtaining a copy 3 | of this software and associated documentation files (the "Software"), to 4 | deal in the Software without restriction, including without limitation the 5 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 6 | sell copies of the Software, and to permit persons to whom the Software is 7 | furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 17 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 18 | IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Here's how the node docs work. 2 | 3 | 1:1 relationship from `lib/.js` to `doc/api/.markdown` 4 | 5 | Each type of heading has a description block. 6 | 7 | 8 | ## module 9 | 10 | Stability: 3 - Stable 11 | 12 | description and examples. 13 | 14 | ### module.property 15 | 16 | * Type 17 | 18 | description of the property. 19 | 20 | ### module.someFunction(x, y, [z=100]) 21 | 22 | * `x` {String} the description of the string 23 | * `y` {Boolean} Should I stay or should I go? 24 | * `z` {Number} How many zebras to bring. 25 | 26 | A description of the function. 27 | 28 | ### Event: 'blerg' 29 | 30 | * Argument: SomeClass object. 31 | 32 | Modules don't usually raise events on themselves. `cluster` is the 33 | only exception. 34 | 35 | ## Class: SomeClass 36 | 37 | description of the class. 38 | 39 | ### Class Method: SomeClass.classMethod(anArg) 40 | 41 | * `anArg` {Object} Just an argument 42 | * `field` {String} anArg can have this field. 43 | * `field2` {Boolean} Another field. Default: `false`. 44 | * Return: {Boolean} `true` if it worked. 45 | 46 | Description of the method for humans. 47 | 48 | ### someClass.nextSibling() 49 | 50 | * Return: {SomeClass object | null} The next someClass in line. 51 | 52 | ### someClass.someProperty 53 | 54 | * String 55 | 56 | The indication of what someProperty is. 57 | 58 | ### Event: 'grelb' 59 | 60 | * `isBlerg` {Boolean} 61 | 62 | This event is emitted on instances of SomeClass, not on the module itself. 63 | 64 | 65 | * Modules have (description, Properties, Functions, Classes, Examples) 66 | * Properties have (type, description) 67 | * Functions have (list of arguments, description) 68 | * Classes have (description, Properties, Methods, Events) 69 | * Events have (list of arguments, description) 70 | * Methods have (list of arguments, description) 71 | * Properties have (type, description) 72 | 73 | ## Stability ratings: 0-5 74 | 75 | These can show up below any section heading, and apply to that section. 76 | 77 | 0 - Deprecated. This feature is known to be problematic, and changes are 78 | planned. Do not rely on it. Use of the feature may cause warnings. Backwards 79 | compatibility should not be expected. 80 | 81 | 1 - Experimental. This feature was introduced recently, and may change 82 | or be removed in future versions. Please try it out and provide feedback. 83 | If it addresses a use-case that is important to you, tell the node core team. 84 | 85 | 2 - Unstable. The API is in the process of settling, but has not yet had 86 | sufficient real-world testing to be considered stable. Backwards-compatibility 87 | will be maintained if reasonable. 88 | 89 | 3 - Stable. The API has proven satisfactory, but cleanup in the underlying 90 | code may cause minor changes. Backwards-compatibility is guaranteed. 91 | 92 | 4 - API Frozen. This API has been tested extensively in production and is 93 | unlikely to ever have to change. 94 | 95 | 5 - Locked. Unless serious bugs are found, this code will not ever 96 | change. Please do not suggest changes in this area, they will be refused. 97 | -------------------------------------------------------------------------------- /addon-verify.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var path = require('path'); 3 | var marked = require('marked'); 4 | 5 | var doc = path.resolve(__dirname, '..', '..', 'doc', 'api', 'addons.markdown'); 6 | var verifyDir = path.resolve(__dirname, '..', '..', 'test', 'addons'); 7 | 8 | var contents = fs.readFileSync(doc).toString(); 9 | 10 | var tokens = marked.lexer(contents, {}); 11 | var files = null; 12 | var id = 0; 13 | 14 | // Just to make sure that all examples will be processed 15 | tokens.push({ type: 'heading' }); 16 | 17 | var oldDirs = fs.readdirSync(verifyDir); 18 | oldDirs = oldDirs.filter(function(dir) { 19 | return /^doc-/.test(dir); 20 | }).map(function(dir) { 21 | return path.resolve(verifyDir, dir); 22 | }); 23 | 24 | for (var i = 0; i < tokens.length; i++) { 25 | var token = tokens[i]; 26 | if (token.type === 'heading') { 27 | if (files && Object.keys(files).length !== 0) { 28 | verifyFiles(files, function(err) { 29 | if (err) 30 | console.log(err); 31 | else 32 | console.log('done'); 33 | }); 34 | } 35 | files = {}; 36 | } else if (token.type === 'code') { 37 | var match = token.text.match(/^\/\/\s+(.*\.(?:cc|h|js))[\r\n]/); 38 | if (match === null) 39 | continue; 40 | files[match[1]] = token.text; 41 | } 42 | } 43 | 44 | function once(fn) { 45 | var once = false; 46 | return function() { 47 | if (once) 48 | return; 49 | once = true; 50 | fn.apply(this, arguments); 51 | }; 52 | } 53 | 54 | function verifyFiles(files, callback) { 55 | var dir = path.resolve(verifyDir, 'doc-' + id++); 56 | 57 | files = Object.keys(files).map(function(name) { 58 | return { 59 | path: path.resolve(dir, name), 60 | name: name, 61 | content: files[name] 62 | }; 63 | }); 64 | files.push({ 65 | path: path.resolve(dir, 'binding.gyp'), 66 | content: JSON.stringify({ 67 | targets: [ 68 | { 69 | target_name: 'addon', 70 | sources: files.map(function(file) { 71 | return file.name; 72 | }) 73 | } 74 | ] 75 | }) 76 | }); 77 | 78 | fs.mkdir(dir, function() { 79 | // Ignore errors 80 | 81 | var waiting = files.length; 82 | for (var i = 0; i < files.length; i++) 83 | fs.writeFile(files[i].path, files[i].content, next); 84 | 85 | var done = once(callback); 86 | function next(err) { 87 | if (err) 88 | return done(err); 89 | 90 | if (--waiting === 0) 91 | done(); 92 | } 93 | }); 94 | } 95 | -------------------------------------------------------------------------------- /generate.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | // Copyright Joyent, Inc. and other Node contributors. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a 5 | // copy of this software and associated documentation files (the 6 | // "Software"), to deal in the Software without restriction, including 7 | // without limitation the rights to use, copy, modify, merge, publish, 8 | // distribute, sublicense, and/or sell copies of the Software, and to permit 9 | // persons to whom the Software is furnished to do so, subject to the 10 | // following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 18 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | var processIncludes = require('./preprocess.js'); 24 | var marked = require('marked'); 25 | var fs = require('fs'); 26 | var path = require('path'); 27 | 28 | // parse the args. 29 | // Don't use nopt or whatever for this. It's simple enough. 30 | 31 | var args = process.argv.slice(2); 32 | var format = 'json'; 33 | var template = null; 34 | var inputFile = null; 35 | 36 | args.forEach(function (arg) { 37 | if (!arg.match(/^\-\-/)) { 38 | inputFile = arg; 39 | } else if (arg.match(/^\-\-format=/)) { 40 | format = arg.replace(/^\-\-format=/, ''); 41 | } else if (arg.match(/^\-\-template=/)) { 42 | template = arg.replace(/^\-\-template=/, ''); 43 | } 44 | }) 45 | 46 | 47 | if (!inputFile) { 48 | throw new Error('No input file specified'); 49 | } 50 | 51 | 52 | console.error('Input file = %s', inputFile); 53 | fs.readFile(inputFile, 'utf8', function(er, input) { 54 | if (er) throw er; 55 | // process the input for @include lines 56 | processIncludes(inputFile, input, next); 57 | }); 58 | 59 | 60 | 61 | 62 | function next(er, input) { 63 | if (er) throw er; 64 | switch (format) { 65 | case 'json': 66 | require('./json.js')(input, inputFile, function(er, obj) { 67 | console.log(JSON.stringify(obj, null, 2)); 68 | if (er) throw er; 69 | }); 70 | break; 71 | 72 | case 'html': 73 | require('./html.js')(input, inputFile, template, function(er, html) { 74 | if (er) throw er; 75 | console.log(html); 76 | }); 77 | break; 78 | 79 | default: 80 | throw new Error('Invalid format: ' + format); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /html.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var fs = require('fs'); 23 | var marked = require('marked'); 24 | var path = require('path'); 25 | var preprocess = require('./preprocess.js'); 26 | 27 | module.exports = toHTML; 28 | 29 | // TODO(chrisdickinson): never stop vomitting / fix this. 30 | var gtocPath = path.resolve(path.join(__dirname, '..', '..', 'doc', 'api', '_toc.markdown')); 31 | var gtocLoading = null; 32 | var gtocData = null; 33 | 34 | function toHTML(input, filename, template, cb) { 35 | if (gtocData) { 36 | return onGtocLoaded(); 37 | } 38 | 39 | if (gtocLoading === null) { 40 | gtocLoading = [onGtocLoaded]; 41 | return loadGtoc(function(err, data) { 42 | if (err) throw err; 43 | gtocData = data; 44 | gtocLoading.forEach(function(xs) { 45 | xs(); 46 | }); 47 | }); 48 | } 49 | 50 | if (gtocLoading) { 51 | return gtocLoading.push(onGtocLoaded); 52 | } 53 | 54 | function onGtocLoaded() { 55 | var lexed = marked.lexer(input); 56 | fs.readFile(template, 'utf8', function(er, template) { 57 | if (er) return cb(er); 58 | render(lexed, filename, template, cb); 59 | }); 60 | } 61 | } 62 | 63 | function loadGtoc(cb) { 64 | fs.readFile(gtocPath, 'utf8', function(err, data) { 65 | if (err) return cb(err); 66 | 67 | preprocess(gtocPath, data, function(err, data) { 68 | if (err) return cb(err); 69 | 70 | data = marked(data).replace(/' }); 142 | } 143 | depth++; 144 | output.push(tok); 145 | return; 146 | } 147 | state = null; 148 | output.push(tok); 149 | return; 150 | } 151 | if (state === 'LIST') { 152 | if (tok.type === 'list_start') { 153 | depth++; 154 | output.push(tok); 155 | return; 156 | } 157 | if (tok.type === 'list_end') { 158 | depth--; 159 | if (depth === 0) { 160 | state = null; 161 | output.push({ type:'html', text: '' }); 162 | } 163 | output.push(tok); 164 | return; 165 | } 166 | if (tok.text) { 167 | tok.text = parseListItem(tok.text); 168 | } 169 | } 170 | output.push(tok); 171 | }); 172 | 173 | return output; 174 | } 175 | 176 | 177 | function parseListItem(text) { 178 | var parts = text.split('`'); 179 | var i; 180 | 181 | for (i = 0; i < parts.length; i += 2) { 182 | parts[i] = parts[i].replace(/\{([^\}]+)\}/, '$1'); 183 | } 184 | 185 | //XXX maybe put more stuff here? 186 | return parts.join('`'); 187 | } 188 | 189 | function parseAPIHeader(text) { 190 | text = text.replace(/(.*:)\s(\d)([\s\S]*)/, 191 | '
$1 $2$3
'); 192 | return text; 193 | } 194 | 195 | // section is just the first heading 196 | function getSection(lexed) { 197 | var section = ''; 198 | for (var i = 0, l = lexed.length; i < l; i++) { 199 | var tok = lexed[i]; 200 | if (tok.type === 'heading') return tok.text; 201 | } 202 | return ''; 203 | } 204 | 205 | 206 | function buildToc(lexed, filename, cb) { 207 | var indent = 0; 208 | var toc = []; 209 | var depth = 0; 210 | lexed.forEach(function(tok) { 211 | if (tok.type !== 'heading') return; 212 | if (tok.depth - depth > 1) { 213 | return cb(new Error('Inappropriate heading level\n' + 214 | JSON.stringify(tok))); 215 | } 216 | 217 | depth = tok.depth; 218 | var id = getId(filename + '_' + tok.text.trim()); 219 | toc.push(new Array((depth - 1) * 2 + 1).join(' ') + 220 | '*
' + 221 | tok.text + ''); 222 | tok.text += '#'; 224 | }); 225 | 226 | toc = marked.parse(toc.join('\n')); 227 | cb(null, toc); 228 | } 229 | 230 | var idCounters = {}; 231 | function getId(text) { 232 | text = text.toLowerCase(); 233 | text = text.replace(/[^a-z0-9]+/g, '_'); 234 | text = text.replace(/^_+|_+$/, ''); 235 | text = text.replace(/^([^a-z])/, '_$1'); 236 | if (idCounters.hasOwnProperty(text)) { 237 | text += '_' + (++idCounters[text]); 238 | } else { 239 | idCounters[text] = 0; 240 | } 241 | return text; 242 | } 243 | 244 | -------------------------------------------------------------------------------- /json.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | module.exports = doJSON; 23 | 24 | // Take the lexed input, and return a JSON-encoded object 25 | // A module looks like this: https://gist.github.com/1777387 26 | 27 | var marked = require('marked'); 28 | 29 | function doJSON(input, filename, cb) { 30 | var root = {source: filename}; 31 | var stack = [root]; 32 | var depth = 0; 33 | var current = root; 34 | var state = null; 35 | var lexed = marked.lexer(input); 36 | lexed.forEach(function (tok) { 37 | var type = tok.type; 38 | var text = tok.text; 39 | 40 | // 41 | // This is for cases where the markdown semantic structure is lacking. 42 | if (type === 'paragraph' || type === 'html') { 43 | var metaExpr = /\n*/g; 44 | text = text.replace(metaExpr, function(_0, k, v) { 45 | current[k.trim()] = v.trim(); 46 | return ''; 47 | }); 48 | text = text.trim(); 49 | if (!text) return; 50 | } 51 | 52 | if (type === 'heading' && 53 | !text.trim().match(/^example/i)) { 54 | if (tok.depth - depth > 1) { 55 | return cb(new Error('Inappropriate heading level\n'+ 56 | JSON.stringify(tok))); 57 | } 58 | 59 | // Sometimes we have two headings with a single 60 | // blob of description. Treat as a clone. 61 | if (current && 62 | state === 'AFTERHEADING' && 63 | depth === tok.depth) { 64 | var clone = current; 65 | current = newSection(tok); 66 | current.clone = clone; 67 | // don't keep it around on the stack. 68 | stack.pop(); 69 | } else { 70 | // if the level is greater than the current depth, 71 | // then it's a child, so we should just leave the stack 72 | // as it is. 73 | // However, if it's a sibling or higher, then it implies 74 | // the closure of the other sections that came before. 75 | // root is always considered the level=0 section, 76 | // and the lowest heading is 1, so this should always 77 | // result in having a valid parent node. 78 | var d = tok.depth; 79 | while (d <= depth) { 80 | finishSection(stack.pop(), stack[stack.length - 1]); 81 | d++; 82 | } 83 | current = newSection(tok); 84 | } 85 | 86 | depth = tok.depth; 87 | stack.push(current); 88 | state = 'AFTERHEADING'; 89 | return; 90 | } // heading 91 | 92 | // Immediately after a heading, we can expect the following 93 | // 94 | // { type: 'code', text: 'Stability: ...' }, 95 | // 96 | // a list: starting with list_start, ending with list_end, 97 | // maybe containing other nested lists in each item. 98 | // 99 | // If one of these isnt' found, then anything that comes between 100 | // here and the next heading should be parsed as the desc. 101 | var stability 102 | if (state === 'AFTERHEADING') { 103 | if (type === 'code' && 104 | (stability = text.match(/^Stability: ([0-5])(?:\s*-\s*)?(.*)$/))) { 105 | current.stability = parseInt(stability[1], 10); 106 | current.stabilityText = stability[2].trim(); 107 | return; 108 | } else if (type === 'list_start' && !tok.ordered) { 109 | state = 'AFTERHEADING_LIST'; 110 | current.list = current.list || []; 111 | current.list.push(tok); 112 | current.list.level = 1; 113 | } else { 114 | current.desc = current.desc || []; 115 | if (!Array.isArray(current.desc)) { 116 | current.shortDesc = current.desc; 117 | current.desc = []; 118 | } 119 | current.desc.push(tok); 120 | state = 'DESC'; 121 | } 122 | return; 123 | } 124 | 125 | if (state === 'AFTERHEADING_LIST') { 126 | current.list.push(tok); 127 | if (type === 'list_start') { 128 | current.list.level++; 129 | } else if (type === 'list_end') { 130 | current.list.level--; 131 | } 132 | if (current.list.level === 0) { 133 | state = 'AFTERHEADING'; 134 | processList(current); 135 | } 136 | return; 137 | } 138 | 139 | current.desc = current.desc || []; 140 | current.desc.push(tok); 141 | 142 | }); 143 | 144 | // finish any sections left open 145 | while (root !== (current = stack.pop())) { 146 | finishSection(current, stack[stack.length - 1]); 147 | } 148 | 149 | return cb(null, root) 150 | } 151 | 152 | 153 | // go from something like this: 154 | // [ { type: 'list_item_start' }, 155 | // { type: 'text', 156 | // text: '`settings` Object, Optional' }, 157 | // { type: 'list_start', ordered: false }, 158 | // { type: 'list_item_start' }, 159 | // { type: 'text', 160 | // text: 'exec: String, file path to worker file. Default: `__filename`' }, 161 | // { type: 'list_item_end' }, 162 | // { type: 'list_item_start' }, 163 | // { type: 'text', 164 | // text: 'args: Array, string arguments passed to worker.' }, 165 | // { type: 'text', 166 | // text: 'Default: `process.argv.slice(2)`' }, 167 | // { type: 'list_item_end' }, 168 | // { type: 'list_item_start' }, 169 | // { type: 'text', 170 | // text: 'silent: Boolean, whether or not to send output to parent\'s stdio.' }, 171 | // { type: 'text', text: 'Default: `false`' }, 172 | // { type: 'space' }, 173 | // { type: 'list_item_end' }, 174 | // { type: 'list_end' }, 175 | // { type: 'list_item_end' }, 176 | // { type: 'list_end' } ] 177 | // to something like: 178 | // [ { name: 'settings', 179 | // type: 'object', 180 | // optional: true, 181 | // settings: 182 | // [ { name: 'exec', 183 | // type: 'string', 184 | // desc: 'file path to worker file', 185 | // default: '__filename' }, 186 | // { name: 'args', 187 | // type: 'array', 188 | // default: 'process.argv.slice(2)', 189 | // desc: 'string arguments passed to worker.' }, 190 | // { name: 'silent', 191 | // type: 'boolean', 192 | // desc: 'whether or not to send output to parent\'s stdio.', 193 | // default: 'false' } ] } ] 194 | 195 | function processList(section) { 196 | var list = section.list; 197 | var values = []; 198 | var current; 199 | var stack = []; 200 | 201 | // for now, *just* build the heirarchical list 202 | list.forEach(function(tok) { 203 | var type = tok.type; 204 | if (type === 'space') return; 205 | if (type === 'list_item_start') { 206 | if (!current) { 207 | var n = {}; 208 | values.push(n); 209 | current = n; 210 | } else { 211 | current.options = current.options || []; 212 | stack.push(current); 213 | var n = {}; 214 | current.options.push(n); 215 | current = n; 216 | } 217 | return; 218 | } else if (type === 'list_item_end') { 219 | if (!current) { 220 | throw new Error('invalid list - end without current item\n' + 221 | JSON.stringify(tok) + '\n' + 222 | JSON.stringify(list)); 223 | } 224 | current = stack.pop(); 225 | } else if (type === 'text') { 226 | if (!current) { 227 | throw new Error('invalid list - text without current item\n' + 228 | JSON.stringify(tok) + '\n' + 229 | JSON.stringify(list)); 230 | } 231 | current.textRaw = current.textRaw || ''; 232 | current.textRaw += tok.text + ' '; 233 | } 234 | }); 235 | 236 | // shove the name in there for properties, since they are always 237 | // just going to be the value etc. 238 | if (section.type === 'property' && values[0]) { 239 | values[0].textRaw = '`' + section.name + '` ' + values[0].textRaw; 240 | } 241 | 242 | // now pull the actual values out of the text bits. 243 | values.forEach(parseListItem); 244 | 245 | // Now figure out what this list actually means. 246 | // depending on the section type, the list could be different things. 247 | 248 | switch (section.type) { 249 | case 'ctor': 250 | case 'classMethod': 251 | case 'method': 252 | // each item is an argument, unless the name is 'return', 253 | // in which case it's the return value. 254 | section.signatures = section.signatures || []; 255 | var sig = {} 256 | section.signatures.push(sig); 257 | sig.params = values.filter(function(v) { 258 | if (v.name === 'return') { 259 | sig.return = v; 260 | return false; 261 | } 262 | return true; 263 | }); 264 | parseSignature(section.textRaw, sig); 265 | break; 266 | 267 | case 'property': 268 | // there should be only one item, which is the value. 269 | // copy the data up to the section. 270 | var value = values[0] || {}; 271 | delete value.name; 272 | section.typeof = value.type; 273 | delete value.type; 274 | Object.keys(value).forEach(function(k) { 275 | section[k] = value[k]; 276 | }); 277 | break; 278 | 279 | case 'event': 280 | // event: each item is an argument. 281 | section.params = values; 282 | break; 283 | } 284 | 285 | // section.listParsed = values; 286 | delete section.list; 287 | } 288 | 289 | 290 | // textRaw = "someobject.someMethod(a[, b=100][, c])" 291 | function parseSignature(text, sig) { 292 | var params = text.match(paramExpr); 293 | if (!params) return; 294 | params = params[1]; 295 | // the [ is irrelevant. ] indicates optionalness. 296 | params = params.replace(/\[/g, ''); 297 | params = params.split(/,/) 298 | params.forEach(function(p, i, _) { 299 | p = p.trim(); 300 | if (!p) return; 301 | var param = sig.params[i]; 302 | var optional = false; 303 | var def; 304 | // [foo] -> optional 305 | if (p.charAt(p.length - 1) === ']') { 306 | optional = true; 307 | p = p.substr(0, p.length - 1); 308 | p = p.trim(); 309 | } 310 | var eq = p.indexOf('='); 311 | if (eq !== -1) { 312 | def = p.substr(eq + 1); 313 | p = p.substr(0, eq); 314 | } 315 | if (!param) { 316 | param = sig.params[i] = { name: p }; 317 | } 318 | // at this point, the name should match. 319 | if (p !== param.name) { 320 | console.error('Warning: invalid param "%s"', p); 321 | console.error(' > ' + JSON.stringify(param)); 322 | console.error(' > ' + text); 323 | } 324 | if (optional) param.optional = true; 325 | if (def !== undefined) param.default = def; 326 | }); 327 | } 328 | 329 | 330 | function parseListItem(item) { 331 | if (item.options) item.options.forEach(parseListItem); 332 | if (!item.textRaw) return; 333 | 334 | // the goal here is to find the name, type, default, and optional. 335 | // anything left over is 'desc' 336 | var text = item.textRaw.trim(); 337 | // text = text.replace(/^(Argument|Param)s?\s*:?\s*/i, ''); 338 | 339 | text = text.replace(/^, /, '').trim(); 340 | var retExpr = /^returns?\s*:?\s*/i; 341 | var ret = text.match(retExpr); 342 | if (ret) { 343 | item.name = 'return'; 344 | text = text.replace(retExpr, ''); 345 | } else { 346 | var nameExpr = /^['`"]?([^'`": \{]+)['`"]?\s*:?\s*/; 347 | var name = text.match(nameExpr); 348 | if (name) { 349 | item.name = name[1]; 350 | text = text.replace(nameExpr, ''); 351 | } 352 | } 353 | 354 | text = text.trim(); 355 | var defaultExpr = /\(default\s*[:=]?\s*['"`]?([^, '"`]*)['"`]?\)/i; 356 | var def = text.match(defaultExpr); 357 | if (def) { 358 | item.default = def[1]; 359 | text = text.replace(defaultExpr, ''); 360 | } 361 | 362 | text = text.trim(); 363 | var typeExpr = /^\{([^\}]+)\}/; 364 | var type = text.match(typeExpr); 365 | if (type) { 366 | item.type = type[1]; 367 | text = text.replace(typeExpr, ''); 368 | } 369 | 370 | text = text.trim(); 371 | var optExpr = /^Optional\.|(?:, )?Optional$/; 372 | var optional = text.match(optExpr); 373 | if (optional) { 374 | item.optional = true; 375 | text = text.replace(optExpr, ''); 376 | } 377 | 378 | text = text.replace(/^\s*-\s*/, ''); 379 | text = text.trim(); 380 | if (text) item.desc = text; 381 | } 382 | 383 | 384 | function finishSection(section, parent) { 385 | if (!section || !parent) { 386 | throw new Error('Invalid finishSection call\n'+ 387 | JSON.stringify(section) + '\n' + 388 | JSON.stringify(parent)); 389 | } 390 | 391 | if (!section.type) { 392 | section.type = 'module'; 393 | if (parent && (parent.type === 'misc')) { 394 | section.type = 'misc'; 395 | } 396 | section.displayName = section.name; 397 | section.name = section.name.toLowerCase() 398 | .trim().replace(/\s+/g, '_'); 399 | } 400 | 401 | if (section.desc && Array.isArray(section.desc)) { 402 | section.desc.links = section.desc.links || []; 403 | section.desc = marked.parser(section.desc); 404 | } 405 | 406 | if (!section.list) section.list = []; 407 | processList(section); 408 | 409 | // classes sometimes have various 'ctor' children 410 | // which are actually just descriptions of a constructor 411 | // class signature. 412 | // Merge them into the parent. 413 | if (section.type === 'class' && section.ctors) { 414 | section.signatures = section.signatures || []; 415 | var sigs = section.signatures; 416 | section.ctors.forEach(function(ctor) { 417 | ctor.signatures = ctor.signatures || [{}]; 418 | ctor.signatures.forEach(function(sig) { 419 | sig.desc = ctor.desc; 420 | }); 421 | sigs.push.apply(sigs, ctor.signatures); 422 | }); 423 | delete section.ctors; 424 | } 425 | 426 | // properties are a bit special. 427 | // their "type" is the type of object, not "property" 428 | if (section.properties) { 429 | section.properties.forEach(function (p) { 430 | if (p.typeof) p.type = p.typeof; 431 | else delete p.type; 432 | delete p.typeof; 433 | }); 434 | } 435 | 436 | // handle clones 437 | if (section.clone) { 438 | var clone = section.clone; 439 | delete section.clone; 440 | delete clone.clone; 441 | deepCopy(section, clone); 442 | finishSection(clone, parent); 443 | } 444 | 445 | var plur; 446 | if (section.type.slice(-1) === 's') { 447 | plur = section.type + 'es'; 448 | } else if (section.type.slice(-1) === 'y') { 449 | plur = section.type.replace(/y$/, 'ies'); 450 | } else { 451 | plur = section.type + 's'; 452 | } 453 | 454 | // if the parent's type is 'misc', then it's just a random 455 | // collection of stuff, like the "globals" section. 456 | // Make the children top-level items. 457 | if (section.type === 'misc') { 458 | Object.keys(section).forEach(function(k) { 459 | switch (k) { 460 | case 'textRaw': 461 | case 'name': 462 | case 'type': 463 | case 'desc': 464 | case 'miscs': 465 | return; 466 | default: 467 | if (parent.type === 'misc') { 468 | return; 469 | } 470 | if (Array.isArray(k) && parent[k]) { 471 | parent[k] = parent[k].concat(section[k]); 472 | } else if (!parent[k]) { 473 | parent[k] = section[k]; 474 | } else { 475 | // parent already has, and it's not an array. 476 | return; 477 | } 478 | } 479 | }); 480 | } 481 | 482 | parent[plur] = parent[plur] || []; 483 | parent[plur].push(section); 484 | } 485 | 486 | 487 | // Not a general purpose deep copy. 488 | // But sufficient for these basic things. 489 | function deepCopy(src, dest) { 490 | Object.keys(src).filter(function(k) { 491 | return !dest.hasOwnProperty(k); 492 | }).forEach(function(k) { 493 | dest[k] = deepCopy_(src[k]); 494 | }); 495 | } 496 | 497 | function deepCopy_(src) { 498 | if (!src) return src; 499 | if (Array.isArray(src)) { 500 | var c = new Array(src.length); 501 | src.forEach(function(v, i) { 502 | c[i] = deepCopy_(v); 503 | }); 504 | return c; 505 | } 506 | if (typeof src === 'object') { 507 | var c = {}; 508 | Object.keys(src).forEach(function(k) { 509 | c[k] = deepCopy_(src[k]); 510 | }); 511 | return c; 512 | } 513 | return src; 514 | } 515 | 516 | 517 | // these parse out the contents of an H# tag 518 | var eventExpr = /^Event(?::|\s)+['"]?([^"']+).*$/i; 519 | var classExpr = /^Class:\s*([^ ]+).*?$/i; 520 | var propExpr = /^(?:property:?\s*)?[^\.]+\.([^ \.\(\)]+)\s*?$/i; 521 | var braceExpr = /^(?:property:?\s*)?[^\.\[]+(\[[^\]]+\])\s*?$/i; 522 | var classMethExpr = 523 | /^class\s*method\s*:?[^\.]+\.([^ \.\(\)]+)\([^\)]*\)\s*?$/i; 524 | var methExpr = 525 | /^(?:method:?\s*)?(?:[^\.]+\.)?([^ \.\(\)]+)\([^\)]*\)\s*?$/i; 526 | var newExpr = /^new ([A-Z][a-z]+)\([^\)]*\)\s*?$/; 527 | var paramExpr = /\((.*)\);?$/; 528 | 529 | function newSection(tok) { 530 | var section = {}; 531 | // infer the type from the text. 532 | var text = section.textRaw = tok.text; 533 | if (text.match(eventExpr)) { 534 | section.type = 'event'; 535 | section.name = text.replace(eventExpr, '$1'); 536 | } else if (text.match(classExpr)) { 537 | section.type = 'class'; 538 | section.name = text.replace(classExpr, '$1'); 539 | } else if (text.match(braceExpr)) { 540 | section.type = 'property'; 541 | section.name = text.replace(braceExpr, '$1'); 542 | } else if (text.match(propExpr)) { 543 | section.type = 'property'; 544 | section.name = text.replace(propExpr, '$1'); 545 | } else if (text.match(classMethExpr)) { 546 | section.type = 'classMethod'; 547 | section.name = text.replace(classMethExpr, '$1'); 548 | } else if (text.match(methExpr)) { 549 | section.type = 'method'; 550 | section.name = text.replace(methExpr, '$1'); 551 | } else if (text.match(newExpr)) { 552 | section.type = 'ctor'; 553 | section.name = text.replace(newExpr, '$1'); 554 | } else { 555 | section.name = text; 556 | } 557 | return section; 558 | } 559 | -------------------------------------------------------------------------------- /node_modules/.bin/marked: -------------------------------------------------------------------------------- 1 | ../marked/bin/marked -------------------------------------------------------------------------------- /node_modules/marked/.npmignore: -------------------------------------------------------------------------------- 1 | .git* 2 | test/ 3 | -------------------------------------------------------------------------------- /node_modules/marked/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2012, Christopher Jeffrey (https://github.com/chjj/) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /node_modules/marked/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | @cp lib/marked.js marked.js 3 | @uglifyjs -o marked.min.js marked.js 4 | 5 | clean: 6 | @rm marked.js 7 | @rm marked.min.js 8 | 9 | .PHONY: clean all 10 | -------------------------------------------------------------------------------- /node_modules/marked/README.md: -------------------------------------------------------------------------------- 1 | # marked 2 | 3 | A full-featured markdown parser and compiler. 4 | Built for speed. 5 | 6 | ## Benchmarks 7 | 8 | node v0.4.x 9 | 10 | ``` bash 11 | $ node test --bench 12 | marked completed in 12071ms. 13 | showdown (reuse converter) completed in 27387ms. 14 | showdown (new converter) completed in 75617ms. 15 | markdown-js completed in 70069ms. 16 | ``` 17 | 18 | node v0.6.x 19 | 20 | ``` bash 21 | $ node test --bench 22 | marked completed in 6485ms. 23 | marked (with gfm) completed in 7466ms. 24 | discount completed in 7169ms. 25 | showdown (reuse converter) completed in 15937ms. 26 | showdown (new converter) completed in 18279ms. 27 | markdown-js completed in 23572ms. 28 | ``` 29 | 30 | __Marked is now faster than Discount, which is written in C.__ 31 | 32 | For those feeling skeptical: These benchmarks run the entire markdown test suite 33 | 1000 times. The test suite tests every feature. It doesn't cater to specific 34 | aspects. 35 | 36 | Benchmarks for other engines to come (?). 37 | 38 | ## Install 39 | 40 | ``` bash 41 | $ npm install marked 42 | ``` 43 | 44 | ## Another javascript markdown parser 45 | 46 | The point of marked was to create a markdown compiler where it was possible to 47 | frequently parse huge chunks of markdown without having to worry about 48 | caching the compiled output somehow...or blocking for an unnecesarily long time. 49 | 50 | marked is very concise and still implements all markdown features. It is also 51 | now fully compatible with the client-side. 52 | 53 | marked more or less passes the official markdown test suite in its 54 | entirety. This is important because a surprising number of markdown compilers 55 | cannot pass more than a few tests. It was very difficult to get marked as 56 | compliant as it is. It could have cut corners in several areas for the sake 57 | of performance, but did not in order to be exactly what you expect in terms 58 | of a markdown rendering. In fact, this is why marked could be considered at a 59 | disadvantage in the benchmarks above. 60 | 61 | Along with implementing every markdown feature, marked also implements 62 | [GFM features](http://github.github.com/github-flavored-markdown/). 63 | 64 | ## Usage 65 | 66 | ``` js 67 | var marked = require('marked'); 68 | console.log(marked('i am using __markdown__.')); 69 | ``` 70 | 71 | You also have direct access to the lexer and parser if you so desire. 72 | 73 | ``` js 74 | var tokens = marked.lexer(str); 75 | console.log(marked.parser(tokens)); 76 | ``` 77 | 78 | ``` bash 79 | $ node 80 | > require('marked').lexer('> i am using marked.') 81 | [ { type: 'blockquote_start' }, 82 | { type: 'text', text: ' i am using marked.' }, 83 | { type: 'blockquote_end' }, 84 | links: {} ] 85 | ``` 86 | 87 | ## CLI 88 | 89 | ``` bash 90 | $ marked -o hello.html 91 | hello world 92 | ^D 93 | $ cat hello.html 94 |

hello world

95 | ``` 96 | 97 | ## Syntax Highlighting 98 | 99 | Marked has an interface that allows for a syntax highlighter to highlight code 100 | blocks before they're output. 101 | 102 | Example implementation: 103 | 104 | ``` js 105 | var highlight = require('my-syntax-highlighter') 106 | , marked_ = require('marked'); 107 | 108 | var marked = function(text) { 109 | var tokens = marked_.lexer(text) 110 | , l = tokens.length 111 | , i = 0 112 | , token; 113 | 114 | for (; i < l; i++) { 115 | token = tokens[i]; 116 | if (token.type === 'code') { 117 | token.text = highlight(token.text, token.lang); 118 | // marked should not escape this 119 | token.escaped = true; 120 | } 121 | } 122 | 123 | text = marked_.parser(tokens); 124 | 125 | return text; 126 | }; 127 | 128 | module.exports = marked; 129 | ``` 130 | 131 | ## License 132 | 133 | Copyright (c) 2011-2012, Christopher Jeffrey. (MIT License) 134 | 135 | See LICENSE for more info. 136 | -------------------------------------------------------------------------------- /node_modules/marked/bin/marked: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Marked CLI 5 | * Copyright (c) 2011-2012, Christopher Jeffrey (MIT License) 6 | */ 7 | 8 | var fs = require('fs') 9 | , util = require('util') 10 | , marked = require('../'); 11 | 12 | /** 13 | * Man Page 14 | */ 15 | 16 | var help = function() { 17 | var spawn = require('child_process').spawn; 18 | 19 | var options = { 20 | cwd: process.cwd(), 21 | env: process.env, 22 | setsid: false, 23 | customFds: [0, 1, 2] 24 | }; 25 | 26 | spawn('man', 27 | [__dirname + '/../man/marked.1'], 28 | options); 29 | }; 30 | 31 | /** 32 | * Main 33 | */ 34 | 35 | var main = function(argv) { 36 | var files = [] 37 | , data = '' 38 | , input 39 | , output 40 | , arg 41 | , tokens; 42 | 43 | var getarg = function() { 44 | var arg = argv.shift(); 45 | arg = arg.split('='); 46 | if (arg.length > 1) { 47 | argv.unshift(arg.slice(1).join('=')); 48 | } 49 | return arg[0]; 50 | }; 51 | 52 | while (argv.length) { 53 | arg = getarg(); 54 | switch (arg) { 55 | case '-o': 56 | case '--output': 57 | output = argv.shift(); 58 | break; 59 | case '-i': 60 | case '--input': 61 | input = argv.shift(); 62 | break; 63 | case '-t': 64 | case '--tokens': 65 | tokens = true; 66 | break; 67 | case '-h': 68 | case '--help': 69 | return help(); 70 | default: 71 | files.push(arg); 72 | break; 73 | } 74 | } 75 | 76 | if (!input) { 77 | if (files.length <= 2) { 78 | var stdin = process.stdin; 79 | 80 | stdin.setEncoding('utf8'); 81 | stdin.resume(); 82 | 83 | stdin.on('data', function(text) { 84 | data += text; 85 | }); 86 | 87 | stdin.on('end', write); 88 | 89 | return; 90 | } 91 | input = files.pop(); 92 | } 93 | 94 | data = fs.readFileSync(input, 'utf8'); 95 | write(); 96 | 97 | function write() { 98 | data = tokens 99 | ? JSON.stringify(marked.lexer(data), null, 2) 100 | : marked(data); 101 | 102 | if (!output) { 103 | process.stdout.write(data + '\n'); 104 | } else { 105 | fs.writeFileSync(output, data); 106 | } 107 | } 108 | }; 109 | 110 | if (!module.parent) { 111 | process.title = 'marked'; 112 | main(process.argv.slice()); 113 | } else { 114 | module.exports = main; 115 | } 116 | -------------------------------------------------------------------------------- /node_modules/marked/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/marked'); 2 | -------------------------------------------------------------------------------- /node_modules/marked/lib/marked.js: -------------------------------------------------------------------------------- 1 | /** 2 | * marked - A markdown parser (https://github.com/chjj/marked) 3 | * Copyright (c) 2011-2012, Christopher Jeffrey. (MIT Licensed) 4 | */ 5 | 6 | ;(function() { 7 | 8 | /** 9 | * Block-Level Grammar 10 | */ 11 | 12 | var block = { 13 | newline: /^\n+/, 14 | code: /^ {4,}[^\n]*(?:\n {4,}[^\n]*|\n)*(?:\n+|$)/, 15 | gfm_code: /^ *``` *(\w+)? *\n([^\0]+?)\s*``` *(?:\n+|$)/, 16 | hr: /^( *[\-*_]){3,} *(?:\n+|$)/, 17 | heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/, 18 | lheading: /^([^\n]+)\n *(=|-){3,} *\n*/, 19 | blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/, 20 | list: /^( *)([*+-]|\d+\.) [^\0]+?(?:\n{2,}(?! )|\s*$)(?!\1bullet)\n*/, 21 | html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/, 22 | def: /^ *\[([^\]]+)\]: *([^\s]+)(?: +["(]([^\n]+)[")])? *(?:\n+|$)/, 23 | paragraph: /^([^\n]+\n?(?!body))+\n*/, 24 | text: /^[^\n]+/ 25 | }; 26 | 27 | block.list = (function() { 28 | var list = block.list.source; 29 | 30 | list = list 31 | .replace('bullet', /(?:[*+-](?!(?: *[-*]){2,})|\d+\.)/.source); 32 | 33 | return new RegExp(list); 34 | })(); 35 | 36 | block.html = (function() { 37 | var html = block.html.source; 38 | 39 | html = html 40 | .replace('comment', //.source) 41 | .replace('closed', /<(tag)[^\0]+?<\/\1>/.source) 42 | .replace('closing', /])*?>/.source) 43 | .replace(/tag/g, tag()); 44 | 45 | return new RegExp(html); 46 | })(); 47 | 48 | block.paragraph = (function() { 49 | var paragraph = block.paragraph.source 50 | , body = []; 51 | 52 | (function push(rule) { 53 | rule = block[rule] ? block[rule].source : rule; 54 | body.push(rule.replace(/(^|[^\[])\^/g, '$1')); 55 | return push; 56 | }) 57 | ('gfm_code') 58 | ('hr') 59 | ('heading') 60 | ('lheading') 61 | ('blockquote') 62 | ('<' + tag()) 63 | ('def'); 64 | 65 | return new 66 | RegExp(paragraph.replace('body', body.join('|'))); 67 | })(); 68 | 69 | /** 70 | * Block Lexer 71 | */ 72 | 73 | block.lexer = function(src) { 74 | var tokens = []; 75 | 76 | tokens.links = {}; 77 | 78 | src = src 79 | .replace(/\r\n|\r/g, '\n') 80 | .replace(/\t/g, ' '); 81 | 82 | return block.token(src, tokens, true); 83 | }; 84 | 85 | block.token = function(src, tokens, top) { 86 | var src = src.replace(/^ +$/gm, '') 87 | , next 88 | , loose 89 | , cap 90 | , item 91 | , space 92 | , i 93 | , l; 94 | 95 | while (src) { 96 | // newline 97 | if (cap = block.newline.exec(src)) { 98 | src = src.substring(cap[0].length); 99 | if (cap[0].length > 1) { 100 | tokens.push({ 101 | type: 'space' 102 | }); 103 | } 104 | } 105 | 106 | // code 107 | if (cap = block.code.exec(src)) { 108 | src = src.substring(cap[0].length); 109 | cap = cap[0].replace(/^ {4}/gm, ''); 110 | tokens.push({ 111 | type: 'code', 112 | text: cap.replace(/\n+$/, '') 113 | }); 114 | continue; 115 | } 116 | 117 | // gfm_code 118 | if (cap = block.gfm_code.exec(src)) { 119 | src = src.substring(cap[0].length); 120 | tokens.push({ 121 | type: 'code', 122 | lang: cap[1], 123 | text: cap[2] 124 | }); 125 | continue; 126 | } 127 | 128 | // heading 129 | if (cap = block.heading.exec(src)) { 130 | src = src.substring(cap[0].length); 131 | tokens.push({ 132 | type: 'heading', 133 | depth: cap[1].length, 134 | text: cap[2] 135 | }); 136 | continue; 137 | } 138 | 139 | // lheading 140 | if (cap = block.lheading.exec(src)) { 141 | src = src.substring(cap[0].length); 142 | tokens.push({ 143 | type: 'heading', 144 | depth: cap[2] === '=' ? 1 : 2, 145 | text: cap[1] 146 | }); 147 | continue; 148 | } 149 | 150 | // hr 151 | if (cap = block.hr.exec(src)) { 152 | src = src.substring(cap[0].length); 153 | tokens.push({ 154 | type: 'hr' 155 | }); 156 | continue; 157 | } 158 | 159 | // blockquote 160 | if (cap = block.blockquote.exec(src)) { 161 | src = src.substring(cap[0].length); 162 | tokens.push({ 163 | type: 'blockquote_start' 164 | }); 165 | 166 | cap = cap[0].replace(/^ *> ?/gm, ''); 167 | 168 | // Pass `top` to keep the current 169 | // "toplevel" state. This is exactly 170 | // how markdown.pl works. 171 | block.token(cap, tokens, top); 172 | 173 | tokens.push({ 174 | type: 'blockquote_end' 175 | }); 176 | continue; 177 | } 178 | 179 | // list 180 | if (cap = block.list.exec(src)) { 181 | src = src.substring(cap[0].length); 182 | 183 | tokens.push({ 184 | type: 'list_start', 185 | ordered: isFinite(cap[2]) 186 | }); 187 | 188 | // Get each top-level item. 189 | cap = cap[0].match( 190 | /^( *)([*+-]|\d+\.)[^\n]*(?:\n(?!\1(?:[*+-]|\d+\.))[^\n]*)*/gm 191 | ); 192 | 193 | next = false; 194 | l = cap.length; 195 | i = 0; 196 | 197 | for (; i < l; i++) { 198 | item = cap[i]; 199 | 200 | // Remove the list item's bullet 201 | // so it is seen as the next token. 202 | space = item.length; 203 | item = item.replace(/^ *([*+-]|\d+\.) */, ''); 204 | 205 | // Outdent whatever the 206 | // list item contains. Hacky. 207 | if (~item.indexOf('\n ')) { 208 | space -= item.length; 209 | item = item.replace(new RegExp('^ {1,' + space + '}', 'gm'), ''); 210 | } 211 | 212 | // Determine whether item is loose or not. 213 | // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/ 214 | // for discount behavior. 215 | loose = next || /\n\n(?!\s*$)/.test(item); 216 | if (i !== l - 1) { 217 | next = item[item.length-1] === '\n'; 218 | if (!loose) loose = next; 219 | } 220 | 221 | tokens.push({ 222 | type: loose 223 | ? 'loose_item_start' 224 | : 'list_item_start' 225 | }); 226 | 227 | // Recurse. 228 | block.token(item, tokens); 229 | 230 | tokens.push({ 231 | type: 'list_item_end' 232 | }); 233 | } 234 | 235 | tokens.push({ 236 | type: 'list_end' 237 | }); 238 | 239 | continue; 240 | } 241 | 242 | // html 243 | if (cap = block.html.exec(src)) { 244 | src = src.substring(cap[0].length); 245 | tokens.push({ 246 | type: 'html', 247 | text: cap[0] 248 | }); 249 | continue; 250 | } 251 | 252 | // def 253 | if (top && (cap = block.def.exec(src))) { 254 | src = src.substring(cap[0].length); 255 | tokens.links[cap[1].toLowerCase()] = { 256 | href: cap[2], 257 | title: cap[3] 258 | }; 259 | continue; 260 | } 261 | 262 | // top-level paragraph 263 | if (top && (cap = block.paragraph.exec(src))) { 264 | src = src.substring(cap[0].length); 265 | tokens.push({ 266 | type: 'paragraph', 267 | text: cap[0] 268 | }); 269 | continue; 270 | } 271 | 272 | // text 273 | if (cap = block.text.exec(src)) { 274 | // Top-level should never reach here. 275 | src = src.substring(cap[0].length); 276 | tokens.push({ 277 | type: 'text', 278 | text: cap[0] 279 | }); 280 | continue; 281 | } 282 | } 283 | 284 | return tokens; 285 | }; 286 | 287 | /** 288 | * Inline Processing 289 | */ 290 | 291 | var inline = { 292 | escape: /^\\([\\`*{}\[\]()#+\-.!_>])/, 293 | autolink: /^<([^ >]+(@|:\/)[^ >]+)>/, 294 | gfm_autolink: /^(\w+:\/\/[^\s]+[^.,:;"')\]\s])/, 295 | tag: /^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/, 296 | link: /^!?\[((?:\[[^\]]*\]|[^\[\]]|\[|\](?=[^[\]]*\]))*)\]\(([^\)]*)\)/, 297 | reflink: /^!?\[((?:\[[^\]]*\]|[^\[\]]|\[|\](?=[^[\]]*\]))*)\]\s*\[([^\]]*)\]/, 298 | nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/, 299 | strong: /^__([^\0]+?)__(?!_)|^\*\*([^\0]+?)\*\*(?!\*)/, 300 | em: /^\b_([^\0]+?)_\b|^\*((?:\*\*|[^\0])+?)\*(?!\*)/, 301 | code: /^(`+)([^\0]*?[^`])\1(?!`)/, 302 | br: /^ {2,}\n(?!\s*$)/, 303 | text: /^[^\0]+?(?=[\\' 341 | + text 342 | + ''; 343 | continue; 344 | } 345 | 346 | // gfm_autolink 347 | if (cap = inline.gfm_autolink.exec(src)) { 348 | src = src.substring(cap[0].length); 349 | text = escape(cap[1]); 350 | href = text; 351 | out += '' 354 | + text 355 | + ''; 356 | continue; 357 | } 358 | 359 | // tag 360 | if (cap = inline.tag.exec(src)) { 361 | src = src.substring(cap[0].length); 362 | out += cap[0]; 363 | continue; 364 | } 365 | 366 | // link 367 | if (cap = inline.link.exec(src)) { 368 | src = src.substring(cap[0].length); 369 | text = /^\s*?(?:\s+"([^\n]+)")?\s*$/.exec(cap[2]); 370 | if (!text) { 371 | out += cap[0][0]; 372 | src = cap[0].substring(1) + src; 373 | continue; 374 | } 375 | out += outputLink(cap, { 376 | href: text[1], 377 | title: text[2] 378 | }); 379 | continue; 380 | } 381 | 382 | // reflink, nolink 383 | if ((cap = inline.reflink.exec(src)) 384 | || (cap = inline.nolink.exec(src))) { 385 | src = src.substring(cap[0].length); 386 | link = (cap[2] || cap[1]).replace(/\s+/g, ' '); 387 | link = links[link.toLowerCase()]; 388 | if (!link || !link.href) { 389 | out += cap[0][0]; 390 | src = cap[0].substring(1) + src; 391 | continue; 392 | } 393 | out += outputLink(cap, link); 394 | continue; 395 | } 396 | 397 | // strong 398 | if (cap = inline.strong.exec(src)) { 399 | src = src.substring(cap[0].length); 400 | out += '' 401 | + inline.lexer(cap[2] || cap[1]) 402 | + ''; 403 | continue; 404 | } 405 | 406 | // em 407 | if (cap = inline.em.exec(src)) { 408 | src = src.substring(cap[0].length); 409 | out += '' 410 | + inline.lexer(cap[2] || cap[1]) 411 | + ''; 412 | continue; 413 | } 414 | 415 | // code 416 | if (cap = inline.code.exec(src)) { 417 | src = src.substring(cap[0].length); 418 | out += '' 419 | + escape(cap[2], true) 420 | + ''; 421 | continue; 422 | } 423 | 424 | // br 425 | if (cap = inline.br.exec(src)) { 426 | src = src.substring(cap[0].length); 427 | out += '
'; 428 | continue; 429 | } 430 | 431 | // text 432 | if (cap = inline.text.exec(src)) { 433 | src = src.substring(cap[0].length); 434 | out += escape(cap[0]); 435 | continue; 436 | } 437 | } 438 | 439 | return out; 440 | }; 441 | 442 | var outputLink = function(cap, link) { 443 | if (cap[0][0] !== '!') { 444 | return '' 453 | + inline.lexer(cap[1]) 454 | + ''; 455 | } else { 456 | return ''
459 |       + escape(cap[1])
460 |       + ''; 467 | } 468 | }; 469 | 470 | /** 471 | * Parsing 472 | */ 473 | 474 | var tokens 475 | , token; 476 | 477 | var next = function() { 478 | return token = tokens.pop(); 479 | }; 480 | 481 | var tok = function() { 482 | switch (token.type) { 483 | case 'space': { 484 | return ''; 485 | } 486 | case 'hr': { 487 | return '
\n'; 488 | } 489 | case 'heading': { 490 | return '' 493 | + inline.lexer(token.text) 494 | + '\n'; 497 | } 498 | case 'code': { 499 | return '
'
506 |         + (token.escaped
507 |         ? token.text
508 |         : escape(token.text, true))
509 |         + '
\n'; 510 | } 511 | case 'blockquote_start': { 512 | var body = ''; 513 | 514 | while (next().type !== 'blockquote_end') { 515 | body += tok(); 516 | } 517 | 518 | return '
\n' 519 | + body 520 | + '
\n'; 521 | } 522 | case 'list_start': { 523 | var type = token.ordered ? 'ol' : 'ul' 524 | , body = ''; 525 | 526 | while (next().type !== 'list_end') { 527 | body += tok(); 528 | } 529 | 530 | return '<' 531 | + type 532 | + '>\n' 533 | + body 534 | + '\n'; 537 | } 538 | case 'list_item_start': { 539 | var body = ''; 540 | 541 | while (next().type !== 'list_item_end') { 542 | body += token.type === 'text' 543 | ? parseText() 544 | : tok(); 545 | } 546 | 547 | return '
  • ' 548 | + body 549 | + '
  • \n'; 550 | } 551 | case 'loose_item_start': { 552 | var body = ''; 553 | 554 | while (next().type !== 'list_item_end') { 555 | body += tok(); 556 | } 557 | 558 | return '
  • ' 559 | + body 560 | + '
  • \n'; 561 | } 562 | case 'html': { 563 | return inline.lexer(token.text); 564 | } 565 | case 'paragraph': { 566 | return '

    ' 567 | + inline.lexer(token.text) 568 | + '

    \n'; 569 | } 570 | case 'text': { 571 | return '

    ' 572 | + parseText() 573 | + '

    \n'; 574 | } 575 | } 576 | }; 577 | 578 | var parseText = function() { 579 | var body = token.text 580 | , top; 581 | 582 | while ((top = tokens[tokens.length-1]) 583 | && top.type === 'text') { 584 | body += '\n' + next().text; 585 | } 586 | 587 | return inline.lexer(body); 588 | }; 589 | 590 | var parse = function(src) { 591 | tokens = src.reverse(); 592 | 593 | var out = ''; 594 | while (next()) { 595 | out += tok(); 596 | } 597 | 598 | tokens = null; 599 | token = null; 600 | 601 | return out; 602 | }; 603 | 604 | /** 605 | * Helpers 606 | */ 607 | 608 | var escape = function(html, encode) { 609 | return html 610 | .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&') 611 | .replace(//g, '>') 613 | .replace(/"/g, '"') 614 | .replace(/'/g, '''); 615 | }; 616 | 617 | var mangle = function(text) { 618 | var out = '' 619 | , l = text.length 620 | , i = 0 621 | , ch; 622 | 623 | for (; i < l; i++) { 624 | ch = text.charCodeAt(i); 625 | if (Math.random() > 0.5) { 626 | ch = 'x' + ch.toString(16); 627 | } 628 | out += '&#' + ch + ';'; 629 | } 630 | 631 | return out; 632 | }; 633 | 634 | function tag() { 635 | var tag = '(?!(?:' 636 | + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code' 637 | + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo' 638 | + '|span|br|wbr|ins|del|img)\\b)\\w+'; 639 | 640 | return tag; 641 | } 642 | 643 | /** 644 | * Expose 645 | */ 646 | 647 | var marked = function(src) { 648 | return parse(block.lexer(src)); 649 | }; 650 | 651 | marked.parser = parse; 652 | marked.lexer = block.lexer; 653 | 654 | marked.parse = marked; 655 | 656 | if (typeof module !== 'undefined') { 657 | module.exports = marked; 658 | } else { 659 | this.marked = marked; 660 | } 661 | 662 | }).call(this); 663 | -------------------------------------------------------------------------------- /node_modules/marked/man/marked.1: -------------------------------------------------------------------------------- 1 | .ds q \N'34' 2 | .TH marked 1 3 | .SH NAME 4 | marked \- a javascript markdown parser 5 | .SH SYNOPSIS 6 | .nf 7 | .B marked [\-o output] [\-i input] [\-th] 8 | .fi 9 | .SH DESCRIPTION 10 | .B marked 11 | is a full-featured javascript markdown parser, built for speed. It also includes 12 | multiple GFM features. 13 | .SH OPTIONS 14 | .TP 15 | .BI \-o,\ \-\-output\ [output] 16 | Specify file output. If none is specified, write to stdout. 17 | .TP 18 | .BI \-i,\ \-\-input\ [input] 19 | Specify file input, otherwise use last argument as input file. If no input file 20 | is specified, read from stdin. 21 | .TP 22 | .BI \-t,\ \-\-tokens 23 | Output a token stream instead of html. 24 | .TP 25 | .BI \-h,\ \-\-help 26 | Display help information. 27 | .SH EXAMPLES 28 | .TP 29 | cat in.md | marked > out.html 30 | .TP 31 | echo "hello *world*" | marked 32 | .TP 33 | marked -o out.html in.md 34 | .TP 35 | marked --output="hello world.html" -i in.md 36 | .SH BUGS 37 | Please report any bugs to https://github.com/chjj/marked. 38 | .SH LICENSE 39 | Copyright (c) 2011-2012, Christopher Jeffrey (MIT License) 40 | -------------------------------------------------------------------------------- /node_modules/marked/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "marked", 3 | "description": "A markdown parser built for speed", 4 | "author": "Christopher Jeffrey", 5 | "version": "0.1.9", 6 | "main": "./lib/marked.js", 7 | "bin": "./bin/marked", 8 | "man": "./man/marked.1", 9 | "preferGlobal": false, 10 | "repository": "git://github.com/chjj/marked.git", 11 | "homepage": "https://github.com/chjj/marked", 12 | "bugs": "http://github.com/chjj/marked/issues", 13 | "keywords": [ "markdown", "markup", "html" ], 14 | "tags": [ "markdown", "markup", "html" ] 15 | } 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Isaac Z. Schlueter (http://blog.izs.me/)", 3 | "name": "iojs-doctool", 4 | "description": "Internal tool for generating io.js API docs", 5 | "version": "1.0.0", 6 | "engines": { 7 | "node": ">=0.6.10" 8 | }, 9 | "dependencies": { 10 | "marked": "^0.3.5" 11 | }, 12 | "devDependencies": {}, 13 | "optionalDependencies": {}, 14 | "bin": "./generate.js" 15 | } 16 | -------------------------------------------------------------------------------- /preprocess.js: -------------------------------------------------------------------------------- 1 | module.exports = preprocess; 2 | 3 | var path = require('path'); 4 | var fs = require('fs'); 5 | 6 | var includeExpr = /^@include\s+([A-Za-z0-9-_]+)(?:\.)?([a-zA-Z]*)$/gmi; 7 | var includeData = {}; 8 | 9 | function preprocess(inputFile, input, cb) { 10 | input = stripComments(input); 11 | processIncludes(inputFile, input, function (err, data) { 12 | if (err) return cb(err); 13 | 14 | cb(null, data); 15 | }); 16 | } 17 | 18 | function stripComments(input) { 19 | return input.replace(/^@\/\/.*$/gmi, ''); 20 | } 21 | 22 | function processIncludes(inputFile, input, cb) { 23 | var includes = input.match(includeExpr); 24 | if (includes === null) return cb(null, input); 25 | var errState = null; 26 | console.error(includes); 27 | var incCount = includes.length; 28 | if (incCount === 0) cb(null, input); 29 | includes.forEach(function(include) { 30 | var fname = include.replace(/^@include\s+/, ''); 31 | if (!fname.match(/\.markdown$/)) fname += '.markdown'; 32 | 33 | if (includeData.hasOwnProperty(fname)) { 34 | input = input.split(include).join(includeData[fname]); 35 | incCount--; 36 | if (incCount === 0) { 37 | return cb(null, input); 38 | } 39 | } 40 | 41 | var fullFname = path.resolve(path.dirname(inputFile), fname); 42 | fs.readFile(fullFname, 'utf8', function(er, inc) { 43 | if (errState) return; 44 | if (er) return cb(errState = er); 45 | preprocess(inputFile, inc, function(er, inc) { 46 | if (errState) return; 47 | if (er) return cb(errState = er); 48 | incCount--; 49 | includeData[fname] = inc; 50 | input = input.split(include+'\n').join(includeData[fname]+'\n'); 51 | if (incCount === 0) { 52 | return cb(null, input); 53 | } 54 | }); 55 | }); 56 | }); 57 | } 58 | 59 | --------------------------------------------------------------------------------