Merge branch 'master' into update-templates

This commit is contained in:
Josh Bruce 2018-02-25 11:46:47 -05:00
commit a14ac2e2d0
9 changed files with 1856 additions and 274 deletions

27
.eslintrc.json Normal file
View File

@ -0,0 +1,27 @@
{
"extends": "standard",
"plugins": [
"standard"
],
"parserOptions": { "ecmaVersion": 5 },
"rules": {
"semi": "off",
"indent": ["warn", 2, {
"VariableDeclarator": { "var": 2 },
"SwitchCase": 1,
"outerIIFEBody": 0
}],
"space-before-function-paren": "off",
"operator-linebreak": ["error", "before", { "overrides": { "=": "after" } }],
"no-cond-assign": "off",
"no-useless-escape": "off",
"no-return-assign": "off",
"one-var": "off",
"no-control-regex": "off"
},
"env": {
"node": true,
"browser": true,
"amd": true
}
}

View File

@ -1,5 +1,16 @@
language: node_js
node_js:
- "0.10"
- "0.8"
- "0.6"
- "4"
- "lts/*"
- "node"
script: |
if [ `node --version | cut -d . -f 1,2` = "v0.10" ]; then
sed -i s/0o755/0755/ test/index.js;
npm test;
else
npm run lint && npm test;
fi
cache:
directories:
- node_modules

View File

@ -4,7 +4,7 @@
* https://github.com/chjj/marked
*/
;(function() {
;(function(root) {
'use strict';
/**
@ -30,45 +30,45 @@ var block = {
block._label = /(?:\\[\[\]]|[^\[\]])+/;
block._title = /(?:"(?:\\"|[^"]|"[^"\n]*")*"|'\n?(?:[^'\n]+\n?)*'|\([^()]*\))/;
block.def = replace(block.def)
('label', block._label)
('title', block._title)
();
block.def = edit(block.def)
.replace('label', block._label)
.replace('title', block._title)
.getRegex();
block.bullet = /(?:[*+-]|\d+\.)/;
block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
block.item = replace(block.item, 'gm')
(/bull/g, block.bullet)
();
block.item = edit(block.item, 'gm')
.replace(/bull/g, block.bullet)
.getRegex();
block.list = replace(block.list)
(/bull/g, block.bullet)
('hr', '\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))')
('def', '\\n+(?=' + block.def.source + ')')
();
block.list = edit(block.list)
.replace(/bull/g, block.bullet)
.replace('hr', '\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))')
.replace('def', '\\n+(?=' + block.def.source + ')')
.getRegex();
block._tag = '(?!(?:'
+ 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
+ '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
+ '|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b';
block.html = replace(block.html)
('comment', /<!--[\s\S]*?-->/)
('closed', /<(tag)[\s\S]+?<\/\1>/)
('closing', /<tag(?:"[^"]*"|'[^']*'|\s[^'"\/>]*)*?\/?>/)
(/tag/g, block._tag)
();
block.html = edit(block.html)
.replace('comment', /<!--[\s\S]*?-->/)
.replace('closed', /<(tag)[\s\S]+?<\/\1>/)
.replace('closing', /<tag(?:"[^"]*"|'[^']*'|\s[^'"\/>]*)*?\/?>/)
.replace(/tag/g, block._tag)
.getRegex();
block.paragraph = replace(block.paragraph)
('hr', block.hr)
('heading', block.heading)
('lheading', block.lheading)
('tag', '<' + block._tag)
();
block.paragraph = edit(block.paragraph)
.replace('hr', block.hr)
.replace('heading', block.heading)
.replace('lheading', block.lheading)
.replace('tag', '<' + block._tag)
.getRegex();
block.blockquote = replace(block.blockquote)
('paragraph', block.paragraph)
();
block.blockquote = edit(block.blockquote)
.replace('paragraph', block.paragraph)
.getRegex();
/**
* Normal Block Grammar
@ -86,11 +86,11 @@ block.gfm = merge({}, block.normal, {
heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
});
block.gfm.paragraph = replace(block.paragraph)
('(?!', '(?!'
block.gfm.paragraph = edit(block.paragraph)
.replace('(?!', '(?!'
+ block.gfm.fences.source.replace('\\1', '\\2') + '|'
+ block.list.source.replace('\\1', '\\3') + '|')
();
.getRegex();
/**
* GFM + Tables Block Grammar
@ -154,17 +154,17 @@ Lexer.prototype.lex = function(src) {
*/
Lexer.prototype.token = function(src, top) {
var src = src.replace(/^ +$/gm, '')
, next
, loose
, cap
, bull
, b
, item
, space
, i
, tag
, l;
src = src.replace(/^ +$/gm, '');
var next,
loose,
cap,
bull,
b,
item,
space,
i,
tag,
l;
while (src) {
// newline
@ -446,8 +446,7 @@ Lexer.prototype.token = function(src, top) {
}
if (src) {
throw new
Error('Infinite loop on byte: ' + src.charCodeAt(0));
throw new Error('Infinite loop on byte: ' + src.charCodeAt(0));
}
}
@ -477,22 +476,22 @@ var inline = {
inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
inline._email = /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/;
inline.autolink = replace(inline.autolink)
('scheme', inline._scheme)
('email', inline._email)
()
inline.autolink = edit(inline.autolink)
.replace('scheme', inline._scheme)
.replace('email', inline._email)
.getRegex()
inline._inside = /(?:\[[^\]]*\]|\\[\[\]]|[^\[\]]|\](?=[^\[]*\]))*/;
inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
inline.link = replace(inline.link)
('inside', inline._inside)
('href', inline._href)
();
inline.link = edit(inline.link)
.replace('inside', inline._inside)
.replace('href', inline._href)
.getRegex();
inline.reflink = replace(inline.reflink)
('inside', inline._inside)
();
inline.reflink = edit(inline.reflink)
.replace('inside', inline._inside)
.getRegex();
/**
* Normal Inline Grammar
@ -514,16 +513,16 @@ inline.pedantic = merge({}, inline.normal, {
*/
inline.gfm = merge({}, inline.normal, {
escape: replace(inline.escape)('])', '~|])')(),
url: replace(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/)
('email', inline._email)
(),
escape: edit(inline.escape).replace('])', '~|])').getRegex(),
url: edit(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/)
.replace('email', inline._email)
.getRegex(),
_backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,
del: /^~~(?=\S)([\s\S]*?\S)~~/,
text: replace(inline.text)
(']|', '~]|')
('|', '|https?://|ftp://|www\\.|[a-zA-Z0-9.!#$%&\'*+/=?^_`{\\|}~-]+@|')
()
text: edit(inline.text)
.replace(']|', '~]|')
.replace('|', '|https?://|ftp://|www\\.|[a-zA-Z0-9.!#$%&\'*+/=?^_`{\\|}~-]+@|')
.getRegex()
});
/**
@ -531,8 +530,8 @@ inline.gfm = merge({}, inline.normal, {
*/
inline.breaks = merge({}, inline.gfm, {
br: replace(inline.br)('{2,}', '*')(),
text: replace(inline.gfm.text)('{2,}', '*')()
br: edit(inline.br).replace('{2,}', '*').getRegex(),
text: edit(inline.gfm.text).replace('{2,}', '*').getRegex()
});
/**
@ -543,12 +542,11 @@ function InlineLexer(links, options) {
this.options = options || marked.defaults;
this.links = links;
this.rules = inline.normal;
this.renderer = this.options.renderer || new Renderer;
this.renderer = this.options.renderer || new Renderer();
this.renderer.options = this.options;
if (!this.links) {
throw new
Error('Tokens array requires a `links` property.');
throw new Error('Tokens array requires a `links` property.');
}
if (this.options.gfm) {
@ -582,11 +580,11 @@ InlineLexer.output = function(src, links, options) {
*/
InlineLexer.prototype.output = function(src) {
var out = ''
, link
, text
, href
, cap;
var out = '',
link,
text,
href,
cap;
while (src) {
// escape
@ -717,8 +715,7 @@ InlineLexer.prototype.output = function(src) {
}
if (src) {
throw new
Error('Infinite loop on byte: ' + src.charCodeAt(0));
throw new Error('Infinite loop on byte: ' + src.charCodeAt(0));
}
}
@ -730,8 +727,8 @@ InlineLexer.prototype.output = function(src) {
*/
InlineLexer.prototype.outputLink = function(cap, link) {
var href = escape(link.href)
, title = link.title ? escape(link.title) : null;
var href = escape(link.href),
title = link.title ? escape(link.title) : null;
return cap[0].charAt(0) !== '!'
? this.renderer.link(href, title, this.output(cap[1]))
@ -767,10 +764,10 @@ InlineLexer.prototype.smartypants = function(text) {
InlineLexer.prototype.mangle = function(text) {
if (!this.options.mangle) return text;
var out = ''
, l = text.length
, i = 0
, ch;
var out = '',
l = text.length,
i = 0,
ch;
for (; i < l; i++) {
ch = text.charCodeAt(i);
@ -970,7 +967,7 @@ function Parser(options) {
this.tokens = [];
this.token = null;
this.options = options || marked.defaults;
this.options.renderer = this.options.renderer || new Renderer;
this.options.renderer = this.options.renderer || new Renderer();
this.renderer = this.options.renderer;
this.renderer.options = this.options;
}
@ -991,7 +988,10 @@ Parser.parse = function(src, options) {
Parser.prototype.parse = function(src) {
this.inline = new InlineLexer(src.links, this.options);
// use an InlineLexer with a TextRenderer to extract pure text
this.inlineText = new InlineLexer(src.links, merge({}, this.options, {renderer: new TextRenderer}));
this.inlineText = new InlineLexer(
src.links,
merge({}, this.options, {renderer: new TextRenderer()})
);
this.tokens = src.reverse();
var out = '';
@ -1056,12 +1056,12 @@ Parser.prototype.tok = function() {
this.token.escaped);
}
case 'table': {
var header = ''
, body = ''
, i
, row
, cell
, j;
var header = '',
body = '',
i,
row,
cell,
j;
// header
cell = '';
@ -1089,7 +1089,7 @@ Parser.prototype.tok = function() {
return this.renderer.table(header, body);
}
case 'blockquote_start': {
var body = '';
body = '';
while (this.next().type !== 'blockquote_end') {
body += this.tok();
@ -1098,8 +1098,8 @@ Parser.prototype.tok = function() {
return this.renderer.blockquote(body);
}
case 'list_start': {
var body = ''
, ordered = this.token.ordered;
body = '';
var ordered = this.token.ordered;
while (this.next().type !== 'list_end') {
body += this.tok();
@ -1108,7 +1108,7 @@ Parser.prototype.tok = function() {
return this.renderer.list(body, ordered);
}
case 'list_item_start': {
var body = '';
body = '';
while (this.next().type !== 'list_item_end') {
body += this.token.type === 'text'
@ -1119,7 +1119,7 @@ Parser.prototype.tok = function() {
return this.renderer.listitem(body);
}
case 'loose_item_start': {
var body = '';
body = '';
while (this.next().type !== 'list_item_end') {
body += this.tok();
@ -1169,15 +1169,19 @@ function unescape(html) {
});
}
function replace(regex, opt) {
function edit(regex, opt) {
regex = regex.source;
opt = opt || '';
return function self(name, val) {
if (!name) return new RegExp(regex, opt);
return {
replace: function(name, val) {
val = val.source || val;
val = val.replace(/(^|[^\[])\^/g, '$1');
regex = regex.replace(name, val);
return self;
return this;
},
getRegex: function() {
return new RegExp(regex, opt);
}
};
}
@ -1209,9 +1213,9 @@ function noop() {}
noop.exec = noop;
function merge(obj) {
var i = 1
, target
, key;
var i = 1,
target,
key;
for (; i < arguments.length; i++) {
target = arguments[i];
@ -1225,19 +1229,19 @@ function merge(obj) {
return obj;
}
/**
* Marked
*/
function marked(src, opt, callback) {
// throw error in case of non string input
if (typeof src == 'undefined' || src === null)
if (typeof src === 'undefined' || src === null) {
throw new Error('marked(): input parameter is undefined or null');
if (typeof src != 'string')
throw new Error('marked(): input parameter is of type ' +
Object.prototype.toString.call(src) + ', string expected');
}
if (typeof src !== 'string') {
throw new Error('marked(): input parameter is of type '
+ Object.prototype.toString.call(src) + ', string expected');
}
if (callback || typeof opt === 'function') {
if (!callback) {
@ -1247,10 +1251,10 @@ function marked(src, opt, callback) {
opt = merge({}, marked.defaults, opt || {});
var highlight = opt.highlight
, tokens
, pending
, i = 0;
var highlight = opt.highlight,
tokens,
pending,
i = 0;
try {
tokens = Lexer.lex(src, opt)
@ -1346,7 +1350,7 @@ marked.defaults = {
langPrefix: 'lang-',
smartypants: false,
headerPrefix: '',
renderer: new Renderer,
renderer: new Renderer(),
xhtml: false,
baseUrl: null
};
@ -1374,9 +1378,6 @@ if (typeof module !== 'undefined' && typeof exports === 'object') {
} else if (typeof define === 'function' && define.amd) {
define(function() { return marked; });
} else {
this.marked = marked;
root.marked = marked;
}
}).call(function() {
return this || (typeof window !== 'undefined' ? window : global);
}());
})(this || (typeof window !== 'undefined' ? window : global));

2
marked.min.js vendored

File diff suppressed because one or more lines are too long

1542
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -23,17 +23,27 @@
"html"
],
"devDependencies": {
"markdown": "*",
"showdown": "*",
"markdown-it": "*",
"eslint": "^4.15.0",
"eslint-config-standard": "^11.0.0-beta.0",
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-node": "^5.2.1",
"eslint-plugin-promise": "^3.6.0",
"eslint-plugin-standard": "^3.0.1",
"front-matter": "^2.3.0",
"glob-to-regexp": "0.3.0",
"markdown": "*",
"markdown-it": "*",
"showdown": "*",
"uglify-js": "^3.3.10"
},
"scripts": {
"test": "node test",
"bench": "node test --bench",
"lint": "eslint --fix lib/marked.js test/index.js",
"build": "uglifyjs lib/marked.js -cm --comments /Copyright/ -o marked.min.js",
"preversion": "npm run build && (git diff --quiet || git commit -am 'minify')"
},
"engines": {
"node": ">=0.10.0"
}
}

View File

@ -1,11 +1,13 @@
var fs = require('fs');
var fs = require('fs'),
path = require('path');
var test = require('../')
, runTests = test.runTests
, load = test.load;
var testMod = require('../'),
load = testMod.load;
var express = require('express')
, app = express();
var express = require('express'),
app = express();
var files = load();
app.use(function(req, res, next) {
var setHeader = res.setHeader;
@ -21,21 +23,17 @@ app.use(function(req, res, next) {
next();
});
var dir = __dirname + '/../tests'
, files = {};
app.get('/test.js', function(req, res, next) {
var test = fs.readFileSync(__dirname + '/test.js', 'utf8')
, files = load();
test = test.replace('__TESTS__', JSON.stringify(files));
test = test.replace('__MAIN__', runTests + '');
var test = fs.readFileSync(path.join(__dirname, 'test.js'), 'utf8');
var testScript = test.replace('__TESTS__', JSON.stringify(files))
.replace('__MAIN__', testMod.runTests + '')
.replace('__LIBS__', testMod.testFile + '');
res.contentType('.js');
res.send(test);
res.send(testScript);
});
app.use(express.static(__dirname + '/../../lib'));
app.use(express.static(path.join(__dirname, '/../../lib'))) ;
app.use(express.static(__dirname));
app.listen(8080);

View File

@ -57,6 +57,8 @@ function escape(html, encode) {
.replace(/'/g, '&#39;');
}
__LIBS__;
(__MAIN__)();
}).call(this);

171
test/index.js vendored
View File

@ -10,30 +10,28 @@
* Modules
*/
var fs = require('fs')
, path = require('path')
, fm = require('front-matter')
, g2r = require('glob-to-regexp')
, marked = require('../')
, markedMin = require('../marked.min.js');
var fs = require('fs'),
path = require('path'),
fm = require('front-matter'),
g2r = require('glob-to-regexp'),
marked = require('../'),
markedMin = require('../marked.min.js');
/**
* Load Tests
*/
function load(options) {
var dir = __dirname + '/compiled_tests'
, files = {}
, list
, file
, name
, content
, regex
, skip
, glob = g2r(options.glob || "*", { extended: true })
, i
, j
, l;
options = options || {};
var dir = path.join(__dirname, 'compiled_tests'),
files = {},
list,
file,
name,
content,
glob = g2r(options.glob || '*', { extended: true }),
i,
l;
list = fs
.readdirSync(dir)
@ -45,7 +43,7 @@ function load(options) {
l = list.length;
for (i = 0; i < l; i++) {
name = path.basename(list[i], ".md");
name = path.basename(list[i], '.md');
if (glob.test(name)) {
file = path.join(dir, list[i]);
content = fm(fs.readFileSync(file, 'utf8'));
@ -62,7 +60,7 @@ function load(options) {
if (!options.glob) {
// Change certain tests to allow
// comparison to older benchmark times.
fs.readdirSync(__dirname + '/new').forEach(function(name) {
fs.readdirSync(path.join(__dirname, 'new')).forEach(function(name) {
if (path.extname(name) === '.html') return;
if (name === 'main.md') return;
delete files[name];
@ -93,32 +91,52 @@ function runTests(engine, options) {
engine = null;
}
var engine = engine || marked
, options = options || {}
, files = options.files || load(options)
, complete = 0
, failed = 0
, failures = []
, keys = Object.keys(files)
, i = 0
, len = keys.length
, filename
, file
, opts
, text
, html
, j
, l;
engine = engine || marked;
options = options || {};
var succeeded = 0,
failed = 0,
files = options.files || load(options),
filenames = Object.keys(files),
len = filenames.length,
success,
i,
filename,
file;
if (options.marked) {
marked.setOptions(options.marked);
}
main:
for (; i < len; i++) {
filename = keys[i];
for (i = 0; i < len; i++) {
filename = filenames[i];
file = files[filename];
opts = Object.keys(file.options);
success = testFile(engine, file, filename, i + 1);
if (success) {
succeeded++;
} else {
failed++;
if (options.stop) {
break;
}
}
}
console.log('%d/%d tests completed successfully.', succeeded, len);
if (failed) console.log('%d/%d tests failed.', failed, len);
return !failed;
}
/**
* Test a file
*/
function testFile(engine, file, filename, index) {
var opts = Object.keys(file.options),
text,
html,
j,
l;
if (marked._original) {
marked.defaults = marked._original;
@ -146,45 +164,31 @@ main:
throw e;
}
j = 0;
l = html.length;
for (; j < l; j++) {
for (j = 0; j < l; j++) {
if (text[j] !== html[j]) {
failed++;
failures.push(filename);
text = text.substring(
Math.max(j - 30, 0),
Math.min(j + 30, text.length));
html = html.substring(
Math.max(j - 30, 0),
Math.min(j + 30, html.length));
Math.min(j + 30, l));
console.log(
'\n#%d. %s failed at offset %d. Near: "%s".\n',
i + 1, filename, j, text);
index, filename, j, text);
console.log('\nGot:\n%s\n', text.trim() || text);
console.log('\nExpected:\n%s\n', html.trim() || html);
if (options.stop) {
break main;
}
continue main;
return false;
}
}
complete++;
console.log('#%d. %s completed.', i + 1, filename);
}
console.log('%d/%d tests completed successfully.', complete, len);
if (failed) console.log('%d/%d tests failed.', failed, len);
return !failed;
console.log('#%d. %s completed.', index, filename);
return true
}
/**
@ -192,13 +196,13 @@ main:
*/
function bench(name, files, func) {
var start = Date.now()
, times = 1000
, keys = Object.keys(files)
, i
, l = keys.length
, filename
, file;
var start = Date.now(),
times = 1000,
keys = Object.keys(files),
i,
l = keys.length,
filename,
file;
while (times--) {
for (i = 0; i < l; i++) {
@ -216,8 +220,8 @@ function bench(name, files, func) {
*/
function runBench(options) {
var options = options || {}
, files = load(options);
options = options || {};
var files = load(options);
// Non-GFM, Non-pedantic
marked.setOptions({
@ -314,8 +318,8 @@ function runBench(options) {
*/
function time(options) {
var options = options || {}
, files = load(options);
options = options || {};
var files = load(options);
if (options.marked) {
marked.setOptions(options.marked);
}
@ -360,13 +364,13 @@ function fix() {
});
// node fix.js
var dir = __dirname + '/compiled_tests';
var dir = path.join(__dirname, 'compiled_tests');
fs.readdirSync(dir).filter(function(file) {
return path.extname(file) === '.html';
}).forEach(function(file) {
var file = path.join(dir, file)
, html = fs.readFileSync(file, 'utf8');
file = path.join(dir, file);
var html = fs.readFileSync(file, 'utf8');
// fix unencoded quotes
html = html
@ -386,7 +390,7 @@ function fix() {
.replace(/&lt;/g, '<')
.replace(/&amp;/g, '&');
id = id.toLowerCase().replace(/[^\w]+/g, '-');
id = id.toLowerCase().replace(/[^\w]+/g, '-');
return '<' + h + ' id="' + id + '">' + text + '</' + h + '>';
});
@ -396,8 +400,8 @@ function fix() {
// turn <hr /> into <hr>
fs.readdirSync(dir).forEach(function(file) {
var file = path.join(dir, file)
, text = fs.readFileSync(file, 'utf8');
file = path.join(dir, file);
var text = fs.readFileSync(file, 'utf8');
text = text.replace(/(<|&lt;)hr\s*\/(>|&gt;)/g, '$1hr$2');
@ -425,12 +429,12 @@ function fix() {
* Argument Parsing
*/
function parseArg(argv) {
var argv = process.argv.slice(2)
, options = {}
, opt = ""
, orphans = []
, arg;
function parseArg() {
var argv = process.argv.slice(2),
options = {},
opt = '',
orphans = [],
arg;
function getarg() {
var arg = argv.shift();
@ -571,6 +575,7 @@ if (!module.parent) {
exports = main;
exports.main = main;
exports.runTests = runTests;
exports.testFile = testFile;
exports.runBench = runBench;
exports.load = load;
exports.bench = bench;