mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-06 22:40:14 -05:00
replace custom showdown fork with markdown-it (#8451)
refs https://github.com/TryGhost/Ghost-Admin/pull/690, closes #1501, closes #2093, closes #4592, closes #4627, closes #4659, closes #5039, closes #5237, closes #5587, closes #5625, closes #5632, closes #5822, closes #5939, closes #6840, closes #7183, closes #7536 - replace custom showdown fork with markdown-it - swaps showdown for markdown-it when rendering markdown - match existing header ID behaviour - allow headers without a space after the #s - add duplicate header ID handling - remove legacy markdown spec - move markdown-it setup into markdown-converter util - update mobiledoc specs to match markdown-it newline behaviour - update data-generator HTML to match markdown-it newline behaviour - fix Post "converts html to plaintext" test - update rss spec to match markdown-it newline behaviour - close almost all related showdown bugs
This commit is contained in:
parent
3bae41ccff
commit
5d868d14ad
11 changed files with 94 additions and 648 deletions
|
@ -1,7 +1,6 @@
|
||||||
var SimpleDom = require('simple-dom'),
|
var SimpleDom = require('simple-dom'),
|
||||||
tokenizer = require('simple-html-tokenizer').tokenize,
|
tokenizer = require('simple-html-tokenizer').tokenize,
|
||||||
Showdown = require('showdown-ghost'),
|
markdownConverter = require('../../../utils/markdown-converter'),
|
||||||
converter = new Showdown.converter({extensions: ['ghostgfm', 'footnotes', 'highlight']}),
|
|
||||||
parser;
|
parser;
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
@ -9,6 +8,10 @@ module.exports = {
|
||||||
type: 'dom',
|
type: 'dom',
|
||||||
render(opts) {
|
render(opts) {
|
||||||
parser = new SimpleDom.HTMLParser(tokenizer, opts.env.dom, SimpleDom.voidMap);
|
parser = new SimpleDom.HTMLParser(tokenizer, opts.env.dom, SimpleDom.voidMap);
|
||||||
return parser.parse('<div class="kg-card-markdown">' + converter.makeHtml(opts.payload.markdown || '') + '</div>');
|
return parser.parse(''
|
||||||
|
+ '<div class="kg-card-markdown">'
|
||||||
|
+ markdownConverter.render(opts.payload.markdown || '')
|
||||||
|
+ '</div>'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,6 +15,6 @@ describe('Markdown card', function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
var serializer = new SimpleDom.HTMLSerializer([]);
|
var serializer = new SimpleDom.HTMLSerializer([]);
|
||||||
serializer.serialize(card.render(opts)).should.match('<div class="kg-card-markdown"><h1 id="heading">HEADING</h1>\n\n<ul>\n<li>list</li>\n<li>items</li>\n</ul></div>');
|
serializer.serialize(card.render(opts)).should.match('<div class="kg-card-markdown"><h1 id="heading">HEADING</h1>\n<ul>\n<li>list</li>\n<li>items</li>\n</ul>\n</div>');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,8 +5,7 @@ var _ = require('lodash'),
|
||||||
Promise = require('bluebird'),
|
Promise = require('bluebird'),
|
||||||
sequence = require('../utils/sequence'),
|
sequence = require('../utils/sequence'),
|
||||||
errors = require('../errors'),
|
errors = require('../errors'),
|
||||||
Showdown = require('showdown-ghost'),
|
legacyConverter = require('../utils/markdown-converter'),
|
||||||
legacyConverter = new Showdown.converter({extensions: ['ghostgfm', 'footnotes', 'highlight']}),
|
|
||||||
htmlToText = require('html-to-text'),
|
htmlToText = require('html-to-text'),
|
||||||
ghostBookshelf = require('./base'),
|
ghostBookshelf = require('./base'),
|
||||||
events = require('../events'),
|
events = require('../events'),
|
||||||
|
@ -234,11 +233,11 @@ Post = ghostBookshelf.Model.extend({
|
||||||
if (mobiledoc) {
|
if (mobiledoc) {
|
||||||
this.set('html', utils.mobiledocConverter.render(JSON.parse(mobiledoc)));
|
this.set('html', utils.mobiledocConverter.render(JSON.parse(mobiledoc)));
|
||||||
} else {
|
} else {
|
||||||
// legacy showdown mode
|
// legacy markdown mode
|
||||||
this.set('html', legacyConverter.makeHtml(_.toString(this.get('markdown'))));
|
this.set('html', legacyConverter.render(_.toString(this.get('markdown'))));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.hasChanged('html')) {
|
if (this.hasChanged('html') || !this.get('plaintext')) {
|
||||||
this.set('plaintext', htmlToText.fromString(this.get('html'), {
|
this.set('plaintext', htmlToText.fromString(this.get('html'), {
|
||||||
wordwrap: 80,
|
wordwrap: 80,
|
||||||
ignoreImage: true,
|
ignoreImage: true,
|
||||||
|
|
|
@ -112,7 +112,8 @@ utils = {
|
||||||
tokens: require('./tokens'),
|
tokens: require('./tokens'),
|
||||||
sequence: require('./sequence'),
|
sequence: require('./sequence'),
|
||||||
ghostVersion: require('./ghost-version'),
|
ghostVersion: require('./ghost-version'),
|
||||||
mobiledocConverter: require('./mobiledoc-converter')
|
mobiledocConverter: require('./mobiledoc-converter'),
|
||||||
|
markdownConverter: require('./markdown-converter')
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = utils;
|
module.exports = utils;
|
||||||
|
|
26
core/server/utils/markdown-converter.js
Normal file
26
core/server/utils/markdown-converter.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
var MarkdownIt = require('markdown-it'),
|
||||||
|
converter = new MarkdownIt({
|
||||||
|
html: true,
|
||||||
|
breaks: true,
|
||||||
|
linkify: true
|
||||||
|
})
|
||||||
|
.use(require('markdown-it-footnote'))
|
||||||
|
.use(require('markdown-it-lazy-headers'))
|
||||||
|
.use(require('markdown-it-mark'))
|
||||||
|
.use(require('markdown-it-named-headers'), {
|
||||||
|
// match legacy Showdown IDs otherwise default is github style dasherized
|
||||||
|
slugify: function (inputString, usedHeaders) {
|
||||||
|
var slug = inputString.replace(/[^\w]/g, '').toLowerCase();
|
||||||
|
if (usedHeaders[slug]) {
|
||||||
|
usedHeaders[slug] += 1;
|
||||||
|
slug += usedHeaders[slug];
|
||||||
|
}
|
||||||
|
return slug;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
render: function (markdown) {
|
||||||
|
return converter.render(markdown);
|
||||||
|
}
|
||||||
|
};
|
|
@ -167,7 +167,7 @@ describe('RSS', function () {
|
||||||
// item tags
|
// item tags
|
||||||
xmlData.should.match(/<title><!\[CDATA\[Short and Sweet\]\]>/);
|
xmlData.should.match(/<title><!\[CDATA\[Short and Sweet\]\]>/);
|
||||||
xmlData.should.match(/<description><!\[CDATA\[test stuff/);
|
xmlData.should.match(/<description><!\[CDATA\[test stuff/);
|
||||||
xmlData.should.match(/<content:encoded><!\[CDATA\[<h2 id="testing">testing<\/h2>\n\n/);
|
xmlData.should.match(/<content:encoded><!\[CDATA\[<h2 id="testing">testing<\/h2>\n/);
|
||||||
xmlData.should.match(/<img src="http:\/\/placekitten.com\/500\/200"/);
|
xmlData.should.match(/<img src="http:\/\/placekitten.com\/500\/200"/);
|
||||||
xmlData.should.match(/<media:content url="http:\/\/placekitten.com\/500\/200" medium="image"\/>/);
|
xmlData.should.match(/<media:content url="http:\/\/placekitten.com\/500\/200" medium="image"\/>/);
|
||||||
xmlData.should.match(/<category><!\[CDATA\[public\]\]/);
|
xmlData.should.match(/<category><!\[CDATA\[public\]\]/);
|
||||||
|
@ -197,7 +197,7 @@ describe('RSS', function () {
|
||||||
// special/optional tags
|
// special/optional tags
|
||||||
xmlData.should.match(/<title><!\[CDATA\[Short and Sweet\]\]>/);
|
xmlData.should.match(/<title><!\[CDATA\[Short and Sweet\]\]>/);
|
||||||
xmlData.should.match(/<description><!\[CDATA\[test stuff/);
|
xmlData.should.match(/<description><!\[CDATA\[test stuff/);
|
||||||
xmlData.should.match(/<content:encoded><!\[CDATA\[<h2 id="testing">testing<\/h2>\n\n/);
|
xmlData.should.match(/<content:encoded><!\[CDATA\[<h2 id="testing">testing<\/h2>\n/);
|
||||||
xmlData.should.match(/<img src="http:\/\/placekitten.com\/500\/200"/);
|
xmlData.should.match(/<img src="http:\/\/placekitten.com\/500\/200"/);
|
||||||
xmlData.should.match(/<media:content url="http:\/\/placekitten.com\/500\/200" medium="image"\/>/);
|
xmlData.should.match(/<media:content url="http:\/\/placekitten.com\/500\/200" medium="image"\/>/);
|
||||||
|
|
||||||
|
|
|
@ -1,628 +0,0 @@
|
||||||
/**
|
|
||||||
* Client showdown integration tests
|
|
||||||
*
|
|
||||||
* Ensures that the final output from showdown + client extensions is as expected
|
|
||||||
*/
|
|
||||||
|
|
||||||
var should = require('should'), // jshint ignore:line
|
|
||||||
|
|
||||||
// Stuff we are testing
|
|
||||||
Showdown = require('showdown-ghost'),
|
|
||||||
converter = new Showdown.converter({extensions: ['ghostimagepreview', 'ghostgfm', 'footnotes', 'highlight']});
|
|
||||||
|
|
||||||
describe('Showdown client side converter', function () {
|
|
||||||
/*jslint regexp: true */
|
|
||||||
|
|
||||||
it('should replace showdown strike through with html', function () {
|
|
||||||
var testPhrase = {input: '~~foo_bar~~', output: /^<p><del>foo_bar<\/del><\/p>$/},
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
|
|
||||||
// The image is the entire markup, so the image box should be too
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should honour escaped tildes', function () {
|
|
||||||
var testPhrase = {input: '\\~\\~foo_bar\\~\\~', output: /^<p>~~foo_bar~~<\/p>$/},
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
|
|
||||||
// The image is the entire markup, so the image box should be too
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not touch single underscores inside words', function () {
|
|
||||||
var testPhrase = {input: 'foo_bar', output: /^<p>foo_bar<\/p>$/},
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Currently failing - fixing this causes other issues
|
|
||||||
// it('should not create italic words between lines', function () {
|
|
||||||
// var testPhrase = {input: 'foo_bar\nbar_foo', output: /^<p>foo_bar <br \/>\nbar_foo<\/p>$/},
|
|
||||||
// processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
|
|
||||||
// processedMarkup.should.match(testPhrase.output);
|
|
||||||
// });
|
|
||||||
|
|
||||||
it('should not touch underscores in code blocks', function () {
|
|
||||||
var testPhrase = {input: ' foo_bar_baz', output: /^<pre><code>foo_bar_baz\n<\/code><\/pre>$/},
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not touch underscores in pre blocks', function () {
|
|
||||||
var testPhrases = [
|
|
||||||
{input: '<pre>\nfoo_bar_baz\n</pre>', output: /^<pre>\nfoo_bar_baz\n<\/pre>$/},
|
|
||||||
{input: '<pre>foo_bar_baz</pre>', output: /^<pre>foo_bar_baz<\/pre>$/}
|
|
||||||
],
|
|
||||||
processedMarkup;
|
|
||||||
|
|
||||||
testPhrases.forEach(function (testPhrase) {
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not escape double underscores at the beginning of a line', function () {
|
|
||||||
var testPhrases = [
|
|
||||||
{input: '\n__test__\n', output: /^<p><strong>test<\/strong><\/p>$/}
|
|
||||||
],
|
|
||||||
processedMarkup;
|
|
||||||
|
|
||||||
testPhrases.forEach(function (testPhrase) {
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not treat pre blocks with pre-text differently', function () {
|
|
||||||
var testPhrases = [
|
|
||||||
{
|
|
||||||
input: '<pre>\nthis is `a\\_test` and this\\_too and finally_this_is\n</pre>',
|
|
||||||
output: /^<pre>\nthis is `a\\_test` and this\\_too and finally_this_is\n<\/pre>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: 'hmm<pre>\nthis is `a\\_test` and this\\_too and finally_this_is\n</pre>',
|
|
||||||
output: /^<p>hmm<\/p>\n\n<pre>\nthis is `a\\_test` and this\\_too and finally_this_is\n<\/pre>$/
|
|
||||||
}
|
|
||||||
],
|
|
||||||
processedMarkup;
|
|
||||||
|
|
||||||
testPhrases.forEach(function (testPhrase) {
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should escape two or more underscores inside words', function () {
|
|
||||||
var testPhrases = [
|
|
||||||
{input: 'foo_bar_baz', output: /^<p>foo_bar_baz<\/p>$/},
|
|
||||||
{input: 'foo_bar_baz_bat', output: /^<p>foo_bar_baz_bat<\/p>$/},
|
|
||||||
{input: 'foo_bar_baz_bat_boo', output: /^<p>foo_bar_baz_bat_boo<\/p>$/},
|
|
||||||
{input: 'FOO_BAR', output: /^<p>FOO_BAR<\/p>$/},
|
|
||||||
{input: 'FOO_BAR_BAZ', output: /^<p>FOO_BAR_BAZ<\/p>$/},
|
|
||||||
{input: 'FOO_bar_BAZ_bat', output: /^<p>FOO_bar_BAZ_bat<\/p>$/},
|
|
||||||
{input: 'FOO_bar_BAZ_bat_BOO', output: /^<p>FOO_bar_BAZ_bat_BOO<\/p>$/},
|
|
||||||
{input: 'foo_BAR_baz_BAT_boo', output: /^<p>foo_BAR_baz_BAT_boo<\/p>$/}
|
|
||||||
],
|
|
||||||
processedMarkup;
|
|
||||||
|
|
||||||
testPhrases.forEach(function (testPhrase) {
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should turn newlines into br tags in simple cases', function () {
|
|
||||||
var testPhrases = [
|
|
||||||
{input: 'fizz\nbuzz', output: /^<p>fizz <br \/>\nbuzz<\/p>$/},
|
|
||||||
{input: 'Hello world\nIt is a fine day', output: /^<p>Hello world <br \/>\nIt is a fine day<\/p>$/},
|
|
||||||
{input: '\'first\nsecond', output: /^<p>\'first <br \/>\nsecond<\/p>$/},
|
|
||||||
{input: '\'first\nsecond', output: /^<p>\'first <br \/>\nsecond<\/p>$/}
|
|
||||||
],
|
|
||||||
processedMarkup;
|
|
||||||
|
|
||||||
testPhrases.forEach(function (testPhrase) {
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should convert newlines in all groups', function () {
|
|
||||||
var testPhrases = [
|
|
||||||
{
|
|
||||||
input: 'ruby\npython\nerlang',
|
|
||||||
output: /^<p>ruby <br \/>\npython <br \/>\nerlang<\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: 'Hello world\nIt is a fine day\nout',
|
|
||||||
output: /^<p>Hello world <br \/>\nIt is a fine day <br \/>\nout<\/p>$/
|
|
||||||
}
|
|
||||||
],
|
|
||||||
processedMarkup;
|
|
||||||
|
|
||||||
testPhrases.forEach(function (testPhrase) {
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should convert newlines in even long groups', function () {
|
|
||||||
var testPhrases = [
|
|
||||||
{
|
|
||||||
input: 'ruby\npython\nerlang\ngo',
|
|
||||||
output: /^<p>ruby <br \/>\npython <br \/>\nerlang <br \/>\ngo<\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: 'Hello world\nIt is a fine day\noutside\nthe window',
|
|
||||||
output: /^<p>Hello world <br \/>\nIt is a fine day <br \/>\noutside <br \/>\nthe window<\/p>$/
|
|
||||||
}
|
|
||||||
],
|
|
||||||
processedMarkup;
|
|
||||||
|
|
||||||
testPhrases.forEach(function (testPhrase) {
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not convert newlines in lists', function () {
|
|
||||||
var testPhrases = [
|
|
||||||
{
|
|
||||||
input: '#fizz\n# buzz\n### baz',
|
|
||||||
output: /^<h1 id="fizz">fizz<\/h1>\n\n<h1 id="buzz">buzz<\/h1>\n\n<h3 id="baz">baz<\/h3>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '* foo\n* bar',
|
|
||||||
output: /^<ul>\n<li>foo<\/li>\n<li>bar<\/li>\n<\/ul>$/
|
|
||||||
}
|
|
||||||
],
|
|
||||||
processedMarkup;
|
|
||||||
|
|
||||||
testPhrases.forEach(function (testPhrase) {
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should auto-link URL in text with markdown syntax', function () {
|
|
||||||
var testPhrases = [
|
|
||||||
{
|
|
||||||
input: 'http://google.co.uk',
|
|
||||||
output: /^<p><a href="http:\/\/google.co.uk">http:\/\/google.co.uk<\/a><\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: 'https://atest.com/fizz/buzz?baz=fizzbuzz',
|
|
||||||
output: /^<p><a href="https:\/\/atest.com\/fizz\/buzz\?baz=fizzbuzz">https:\/\/atest.com\/fizz\/buzz\?baz=fizzbuzz<\/a><\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: 'Some [ text (http://www.google.co.uk) some other text',
|
|
||||||
output: /^<p>Some \[ text \(<a href="http:\/\/www.google.co.uk">http:\/\/www.google.co.uk<\/a>\) some other text<\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '>http://google.co.uk',
|
|
||||||
output: /^<blockquote>\n <p><a href="http:\/\/google.co.uk">http:\/\/google.co.uk<\/a><\/p>\n<\/blockquote>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '> http://google.co.uk',
|
|
||||||
output: /^<blockquote>\n <p><a href="http:\/\/google.co.uk">http:\/\/google.co.uk<\/a><\/p>\n<\/blockquote>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '<>>> http://google.co.uk',
|
|
||||||
output: /^<p><>>> <a href="http:\/\/google.co.uk">http:\/\/google.co.uk<\/a><\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '<strong>http://google.co.uk',
|
|
||||||
output: /^<p><strong><a href="http:\/\/google.co.uk">http:\/\/google.co.uk<\/a><\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '# http://google.co.uk',
|
|
||||||
output: /^<h1 id="httpgooglecouk"><a href="http:\/\/google.co.uk">http:\/\/google.co.uk<\/a><\/h1>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '* http://google.co.uk',
|
|
||||||
output: /^<ul>\n<li><a href="http:\/\/google.co.uk">http:\/\/google.co.uk<\/a><\/li>\n<\/ul>$/
|
|
||||||
}
|
|
||||||
],
|
|
||||||
processedMarkup;
|
|
||||||
|
|
||||||
testPhrases.forEach(function (testPhrase) {
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should convert reference format URL', function () {
|
|
||||||
var testPhrases = [
|
|
||||||
{
|
|
||||||
input: '[Google][1]\n\n[1]: http://google.co.uk',
|
|
||||||
output: /^<p><a href="http:\/\/google.co.uk">Google<\/a><\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '[Google][1]\n\n[1]: http://google.co.uk \"some text\"',
|
|
||||||
output: /^<p><a href="http:\/\/google.co.uk" title="some text">Google<\/a><\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '[http://google.co.uk]: http://google.co.uk\n\n[Hello][http://google.co.uk]',
|
|
||||||
output: /^<p><a href="http:\/\/google.co.uk">Hello<\/a><\/p>$/
|
|
||||||
}
|
|
||||||
],
|
|
||||||
processedMarkup;
|
|
||||||
|
|
||||||
testPhrases.forEach(function (testPhrase) {
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/* No ref-style for now
|
|
||||||
it('should convert reference format image', function () {
|
|
||||||
var testPhrases = [
|
|
||||||
{
|
|
||||||
input: '![Google][1]\n\n[1]: http://dsurl.stuff/something.jpg',
|
|
||||||
output: /^<section.*?<img.*?src="http:\/\/dsurl.stuff\/something.jpg"\/>.*?<\/section>$/,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '![Google][1]\n\n[1]: http://dsurl.stuff/something.jpg \"some text\"',
|
|
||||||
output: /^<section.*?<img.*?src="http:\/\/dsurl.stuff\/something.jpg"\/>.*?<\/section>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '[http://www.google.co.uk]: http://www.google.co.uk\n\n![Hello][http://www.google.co.uk]',
|
|
||||||
output: /^<section.*?<img.*?src="http:\/\/www.google.co.uk"\/>.*?<\/section>$/
|
|
||||||
}
|
|
||||||
],
|
|
||||||
processedMarkup;
|
|
||||||
|
|
||||||
testPhrases.forEach(function (testPhrase) {
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
|
|
||||||
it('should NOT auto-link URL in HTML', function () {
|
|
||||||
var testPhrases = [
|
|
||||||
{
|
|
||||||
input: '<img src="http://placekitten.com/50">',
|
|
||||||
output: /^<p><img src=\"http:\/\/placekitten.com\/50\"><\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '<img src="http://placekitten.com/50" />',
|
|
||||||
output: /^<p><img src=\"http:\/\/placekitten.com\/50\" \/><\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '<script type="text/javascript" src="http://google.co.uk"></script>',
|
|
||||||
output: /^<script type=\"text\/javascript\" src=\"http:\/\/google.co.uk\"><\/script>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '<a href="http://facebook.com">http://google.co.uk</a>',
|
|
||||||
output: /^<p><a href=\"http:\/\/facebook.com\">http:\/\/google.co.uk<\/a><\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '<a href="http://facebook.com">test</a> http://google.co.uk',
|
|
||||||
output: /^<p><a href=\"http:\/\/facebook.com\">test<\/a> <a href="http:\/\/google.co.uk">http:\/\/google.co.uk<\/a><\/p>$/
|
|
||||||
}
|
|
||||||
],
|
|
||||||
processedMarkup;
|
|
||||||
|
|
||||||
testPhrases.forEach(function (testPhrase) {
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should NOT escape underscore inside of code/pre blocks', function () {
|
|
||||||
var testPhrase = {
|
|
||||||
input: '```\n_____\n```',
|
|
||||||
output: /^<pre><code>_____ \n<\/code><\/pre>$/
|
|
||||||
},
|
|
||||||
processedMarkup;
|
|
||||||
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should NOT auto-link URLS inside of code/pre blocks', function () {
|
|
||||||
var testPhrases = [
|
|
||||||
{
|
|
||||||
input: '```\nurl: http://google.co.uk\n```',
|
|
||||||
output: /^<pre><code>url: http:\/\/google.co.uk \n<\/code><\/pre>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '`url: http://google.co.uk`',
|
|
||||||
output: /^<p><code>url: http:\/\/google.co.uk<\/code><\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: 'Hello type some `url: http://google.co.uk` stuff',
|
|
||||||
output: /^<p>Hello type some <code>url: http:\/\/google.co.uk<\/code> stuff<\/p>$/
|
|
||||||
}
|
|
||||||
|
|
||||||
],
|
|
||||||
processedMarkup;
|
|
||||||
|
|
||||||
testPhrases.forEach(function (testPhrase) {
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not display anything for reference URL', function () {
|
|
||||||
var testPhrases = [
|
|
||||||
{
|
|
||||||
input: '[1]: http://www.google.co.uk',
|
|
||||||
output: /^$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '[http://www.google.co.uk]: http://www.google.co.uk',
|
|
||||||
output: /^$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '[1]: http://dsurl.stuff/something.jpg',
|
|
||||||
output: /^$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '[1]:http://www.google.co.uk',
|
|
||||||
output: /^$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ' [1]:http://www.google.co.uk',
|
|
||||||
output: /^$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '',
|
|
||||||
output: /^$/
|
|
||||||
}
|
|
||||||
],
|
|
||||||
processedMarkup;
|
|
||||||
|
|
||||||
testPhrases.forEach(function (testPhrase) {
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show placeholder for image markdown', function () {
|
|
||||||
var testPhrases = [
|
|
||||||
{input: '![image and another,/ image](http://dsurl stuff)', output: /^<section.*?section>\n*$/},
|
|
||||||
{input: '![image and another,/ image]', output: /^<section.*?section>\n*$/},
|
|
||||||
{input: '![]()', output: /^<section.*?section>\n*$/},
|
|
||||||
{input: '![]', output: /^<section.*?section>\n*$/}
|
|
||||||
],
|
|
||||||
processedMarkup;
|
|
||||||
|
|
||||||
testPhrases.forEach(function (testPhrase) {
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should have placeholder with image ONLY if image URL is present and valid', function () {
|
|
||||||
var testPhrases = [
|
|
||||||
{
|
|
||||||
input: '![image stuff](http://dsurl.stuff/something.jpg)',
|
|
||||||
output: /^<section.*?<img class="js-upload-target.*?<\/section>$/
|
|
||||||
},
|
|
||||||
{input: '![]', output: /<img class="js-upload-target"/, not: true},
|
|
||||||
{input: '![]', output: /^<section.*?<\/section>$/},
|
|
||||||
{input: '![]()', output: /<img class="js-upload-target"/, not: true},
|
|
||||||
{input: '![]()', output: /^<section.*?<\/section>$/},
|
|
||||||
{input: '![]', output: /<img class="js-upload-target"/, not: true},
|
|
||||||
{input: '![]', output: /^<section.*?<\/section>$/}
|
|
||||||
],
|
|
||||||
processedMarkup;
|
|
||||||
|
|
||||||
testPhrases.forEach(function (testPhrase) {
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
if (testPhrase.not) {
|
|
||||||
processedMarkup.should.not.match(testPhrase.output);
|
|
||||||
} else {
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/* No ref-style for now
|
|
||||||
it('should have placeholder with image if image reference is present', function () {
|
|
||||||
var testPhrases = [
|
|
||||||
{
|
|
||||||
input: '![alt][id]\n\n[id]: http://dsurl.stuff/something.jpg',
|
|
||||||
output: /^<section.*?<img class="js-upload-target.*?<\/section>$/
|
|
||||||
},
|
|
||||||
{input: '![][]', output: /^<section.*?<\/section>$/},
|
|
||||||
{input: '![][]', output: /<img class="js-upload-target"/, not: true},
|
|
||||||
{input: '![][id]', output: /^<section.*?<\/section>$/},
|
|
||||||
{input: '![][id]', output: /<img class="js-upload-target"/, not: true}
|
|
||||||
],
|
|
||||||
processedMarkup;
|
|
||||||
|
|
||||||
testPhrases.forEach(function (testPhrase) {
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
if (testPhrase.not) {
|
|
||||||
processedMarkup.should.not.match(testPhrase.output);
|
|
||||||
} else {
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
|
|
||||||
it('should correctly output link and image markdown without autolinks', function () {
|
|
||||||
var testPhrases = [
|
|
||||||
{
|
|
||||||
input: '[1](http://google.co.uk)',
|
|
||||||
output: /^<p><a href="http:\/\/google.co.uk">1<\/a><\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ' [1](http://google.co.uk)',
|
|
||||||
output: /^<p><a href="http:\/\/google.co.uk">1<\/a><\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '[http://google.co.uk](http://google.co.uk)',
|
|
||||||
output: /^<p><a href="http:\/\/google.co.uk">http:\/\/google.co.uk<\/a><\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '[http://google.co.uk][id]\n\n[id]: http://google.co.uk',
|
|
||||||
output: /^<p><a href="http:\/\/google.co.uk">http:\/\/google.co.uk<\/a><\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '![http://google.co.uk/kitten.jpg](http://google.co.uk/kitten.jpg)',
|
|
||||||
output: /^<section.*?((?!<a href="http:\/\/google.co.uk\/kitten.jpg").)*<\/section>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '![image stuff](http://dsurl.stuff/something)',
|
|
||||||
output: /^<section.*?((?!<a href="http:\/\/dsurl.stuff\/something").)*<\/section>$/
|
|
||||||
}
|
|
||||||
],
|
|
||||||
processedMarkup;
|
|
||||||
|
|
||||||
testPhrases.forEach(function (testPhrase) {
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should output block HTML untouched', function () {
|
|
||||||
var testPhrases = [
|
|
||||||
{
|
|
||||||
input: '<table class=\"test\">\n <tr>\n <td>Foo</td>\n </tr>\n <tr>\n <td>Bar</td>\n </tr>\n</table>',
|
|
||||||
output: /^<table class=\"test\"> \n <tr>\n <td>Foo<\/td>\n <\/tr>\n <tr>\n <td>Bar<\/td>\n <\/tr>\n<\/table>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '<hr />',
|
|
||||||
output: /^<hr \/>$/
|
|
||||||
},
|
|
||||||
{ // audio isn't counted as a block tag by showdown so gets wrapped in <p></p>
|
|
||||||
input: '<audio class=\"podcastplayer\" controls>\n <source src=\"foobar.mp3\" type=\"audio/mp3\" preload=\"none\"></source>\n <source src=\"foobar.off\" type=\"audio/ogg\" preload=\"none\"></source>\n</audio>',
|
|
||||||
output: /^<audio class=\"podcastplayer\" controls> \n <source src=\"foobar.mp3\" type=\"audio\/mp3\" preload=\"none\"><\/source>\n <source src=\"foobar.off\" type=\"audio\/ogg\" preload=\"none\"><\/source>\n<\/audio>$/
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
testPhrases.forEach(function (testPhrase) {
|
|
||||||
var processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should treat ![^n] as footnote unless it occurs on a new line', function () {
|
|
||||||
var testPhrases = [
|
|
||||||
{
|
|
||||||
input: 'Foo![^1](bar)',
|
|
||||||
output: '<p>Foo!<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup>(bar)</p>'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
input: '![^1](bar)',
|
|
||||||
output: '<section class="js-drop-zone image-uploader"><img class="js-upload-target" src="bar"/><div class="description">Add image of <strong>^1</strong></div><input data-url="upload" class="js-fileupload main fileupload" type="file" name="uploadimage"></section>'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
testPhrases.forEach(function (testPhrase) {
|
|
||||||
var processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should replace showdown highlight with html', function () {
|
|
||||||
var testPhrases = [
|
|
||||||
{
|
|
||||||
input: '==foo_bar==',
|
|
||||||
output: /^<p><mark>foo_bar<\/mark><\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: 'My stuff that has a ==highlight== in the middle.',
|
|
||||||
output: /^<p>My stuff that has a <mark>highlight<\/mark> in the middle.<\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: 'My stuff that has a ==multiple word highlight== in the middle.',
|
|
||||||
output: /^<p>My stuff that has a <mark>multiple word highlight<\/mark> in the middle.<\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: 'My stuff that has a ==multiple word **bold** highlight== in the middle.',
|
|
||||||
output: /^<p>My stuff that has a <mark>multiple word <strong>bold<\/strong> highlight<\/mark> in the middle.<\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: 'My stuff that has a ==multiple word and\n line broken highlight== in the middle.',
|
|
||||||
output: /^<p>My stuff that has a <mark>multiple word and <br \/>\n line broken highlight<\/mark> in the middle.<\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: 'Test ==Highlighting with a [link](https://ghost.org) in the middle== of it.',
|
|
||||||
output: /^<p>Test <mark>Highlighting with a <a href="https:\/\/ghost.org">link<\/a> in the middle<\/mark> of it.<\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '==[link](http://ghost.org)==',
|
|
||||||
output: /^<p><mark><a href="http:\/\/ghost.org">link<\/a><\/mark><\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '[==link==](http://ghost.org)',
|
|
||||||
output: /^<p><a href="http:\/\/ghost.org"><mark>link<\/mark><\/a><\/p>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: '====test==test==test====test',
|
|
||||||
output: /^<p><mark>==test<\/mark>test<mark>test<\/mark>==test<\/p>$/
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
testPhrases.forEach(function (testPhrase) {
|
|
||||||
var processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not effect pre tags', function () {
|
|
||||||
var testPhrase = {
|
|
||||||
input: '```javascript\n' +
|
|
||||||
'var foo = "bar";\n' +
|
|
||||||
'if (foo === "bar") {\n' +
|
|
||||||
' return true;\n' +
|
|
||||||
'} else if (foo === "baz") {\n' +
|
|
||||||
' return "magic happened";\n' +
|
|
||||||
'}\n' +
|
|
||||||
'```',
|
|
||||||
output: /^<mark><\/mark>$/
|
|
||||||
},
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
|
|
||||||
// this does not get mark tags
|
|
||||||
processedMarkup.should.not.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should ignore multiple equals', function () {
|
|
||||||
var testPhrase = {input: '=====', output: /^<p>=====<\/p>$/},
|
|
||||||
processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should still handle headers correctly', function () {
|
|
||||||
var testPhrases = [
|
|
||||||
{
|
|
||||||
input: 'Header\n==',
|
|
||||||
output: /^<h1 id="header">Header <\/h1>$/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: 'First Header\n==\nSecond Header\n==',
|
|
||||||
output: /^<h1 id="firstheader">First Header <\/h1>\n\n<h1 id="secondheader">Second Header <\/h1>$/
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
testPhrases.forEach(function (testPhrase) {
|
|
||||||
var processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
processedMarkup.should.match(testPhrase.output);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Waiting for showdown typography to be updated
|
|
||||||
// it('should correctly convert quotes to curly quotes', function () {
|
|
||||||
// var testPhrases = [
|
|
||||||
// {
|
|
||||||
// input: 'Hello world\nIt's a fine day\nout',
|
|
||||||
// output: /^<p>Hello world <br \/>\nIt’s a fine day <br \/>\nout<\/p>$/}
|
|
||||||
// ];
|
|
||||||
|
|
||||||
// testPhrases.forEach(function (testPhrase) {
|
|
||||||
// processedMarkup = converter.makeHtml(testPhrase.input);
|
|
||||||
// processedMarkup.should.match(testPhrase.output);
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
});
|
|
|
@ -29,6 +29,6 @@ describe('Convert mobiledoc to HTML ', function () {
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
it('Converts a mobiledoc to HTML', function () {
|
it('Converts a mobiledoc to HTML', function () {
|
||||||
converter.render(mobiledoc).should.match('<p>test</p><div class="kg-card-markdown"><h1 id="heading">heading</h1>\n\n<ul>\n<li>list one</li>\n<li>list two</li>\n<li>list three</li>\n</ul></div><div class="kg-card-html"><p>HTML CARD</p></div>');
|
converter.render(mobiledoc).should.match('<p>test</p><div class="kg-card-markdown"><h1 id="heading">heading</h1>\n<ul>\n<li>list one</li>\n<li>list two</li>\n<li>list three</li>\n</ul>\n</div><div class="kg-card-html"><p>HTML CARD</p></div>');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -28,7 +28,7 @@ DataGenerator.Content = {
|
||||||
title: "Short and Sweet",
|
title: "Short and Sweet",
|
||||||
slug: "short-and-sweet",
|
slug: "short-and-sweet",
|
||||||
markdown: "## testing\n\nmctesters\n\n- test\n- line\n- items",
|
markdown: "## testing\n\nmctesters\n\n- test\n- line\n- items",
|
||||||
html: "<h2 id=\"testing\">testing</h2>\n\n<p>mctesters</p>\n\n<ul>\n<li>test</li>\n<li>line</li>\n<li>items</li>\n</ul>",
|
html: "<h2 id=\"testing\">testing</h2>\n<p>mctesters</p>\n<ul>\n<li>test</li>\n<li>line</li>\n<li>items</li>\n</ul>\n",
|
||||||
feature_image: "http://placekitten.com/500/200",
|
feature_image: "http://placekitten.com/500/200",
|
||||||
meta_description: "test stuff",
|
meta_description: "test stuff",
|
||||||
published_at: new Date("2015-01-03"),
|
published_at: new Date("2015-01-03"),
|
||||||
|
|
|
@ -62,6 +62,11 @@
|
||||||
"knex": "0.13.0",
|
"knex": "0.13.0",
|
||||||
"knex-migrator": "2.0.16",
|
"knex-migrator": "2.0.16",
|
||||||
"lodash": "4.17.4",
|
"lodash": "4.17.4",
|
||||||
|
"markdown-it": "8.3.1",
|
||||||
|
"markdown-it-footnote": "3.0.1",
|
||||||
|
"markdown-it-lazy-headers": "0.1.3",
|
||||||
|
"markdown-it-mark": "2.0.0",
|
||||||
|
"markdown-it-named-headers": "0.0.4",
|
||||||
"mobiledoc-dom-renderer": "0.6.5",
|
"mobiledoc-dom-renderer": "0.6.5",
|
||||||
"moment": "2.18.1",
|
"moment": "2.18.1",
|
||||||
"moment-timezone": "0.5.13",
|
"moment-timezone": "0.5.13",
|
||||||
|
@ -79,7 +84,6 @@
|
||||||
"rss": "1.2.2",
|
"rss": "1.2.2",
|
||||||
"sanitize-html": "1.14.1",
|
"sanitize-html": "1.14.1",
|
||||||
"semver": "5.3.0",
|
"semver": "5.3.0",
|
||||||
"showdown-ghost": "0.3.6",
|
|
||||||
"simple-dom": "0.3.2",
|
"simple-dom": "0.3.2",
|
||||||
"simple-html-tokenizer": "0.4.1",
|
"simple-html-tokenizer": "0.4.1",
|
||||||
"superagent": "3.5.2",
|
"superagent": "3.5.2",
|
||||||
|
@ -130,7 +134,6 @@
|
||||||
"ignore": [
|
"ignore": [
|
||||||
"glob",
|
"glob",
|
||||||
"nodemailer",
|
"nodemailer",
|
||||||
"showdown-ghost",
|
|
||||||
"grunt",
|
"grunt",
|
||||||
"grunt-bg-shell",
|
"grunt-bg-shell",
|
||||||
"grunt-cli",
|
"grunt-cli",
|
||||||
|
|
50
yarn.lock
50
yarn.lock
|
@ -2959,6 +2959,12 @@ liftoff@~2.2.0:
|
||||||
rechoir "^0.6.2"
|
rechoir "^0.6.2"
|
||||||
resolve "^1.1.7"
|
resolve "^1.1.7"
|
||||||
|
|
||||||
|
linkify-it@^2.0.0:
|
||||||
|
version "2.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f"
|
||||||
|
dependencies:
|
||||||
|
uc.micro "^1.0.1"
|
||||||
|
|
||||||
livereload-js@^2.2.0:
|
livereload-js@^2.2.0:
|
||||||
version "2.2.2"
|
version "2.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.2.2.tgz#6c87257e648ab475bc24ea257457edcc1f8d0bc2"
|
resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.2.2.tgz#6c87257e648ab475bc24ea257457edcc1f8d0bc2"
|
||||||
|
@ -3255,6 +3261,34 @@ map-obj@^1.0.0, map-obj@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
|
resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
|
||||||
|
|
||||||
|
markdown-it-footnote@3.0.1:
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/markdown-it-footnote/-/markdown-it-footnote-3.0.1.tgz#7f3730747cacc86e2fe0bf8a17a710f34791517a"
|
||||||
|
|
||||||
|
markdown-it-lazy-headers@0.1.3:
|
||||||
|
version "0.1.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/markdown-it-lazy-headers/-/markdown-it-lazy-headers-0.1.3.tgz#e70dd4da79c87a9ce82ca4701b8b7c0e2d72297b"
|
||||||
|
|
||||||
|
markdown-it-mark@2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/markdown-it-mark/-/markdown-it-mark-2.0.0.tgz#46a1aa947105aed8188978e0a016179e404f42c7"
|
||||||
|
|
||||||
|
markdown-it-named-headers@0.0.4:
|
||||||
|
version "0.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/markdown-it-named-headers/-/markdown-it-named-headers-0.0.4.tgz#82efc28324240a6b1e77b9aae501771d5f351c1f"
|
||||||
|
dependencies:
|
||||||
|
string "^3.0.1"
|
||||||
|
|
||||||
|
markdown-it@8.3.1:
|
||||||
|
version "8.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.3.1.tgz#2f4b622948ccdc193d66f3ca2d43125ac4ac7323"
|
||||||
|
dependencies:
|
||||||
|
argparse "^1.0.7"
|
||||||
|
entities "~1.1.1"
|
||||||
|
linkify-it "^2.0.0"
|
||||||
|
mdurl "^1.0.1"
|
||||||
|
uc.micro "^1.0.3"
|
||||||
|
|
||||||
matchdep@1.0.1:
|
matchdep@1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/matchdep/-/matchdep-1.0.1.tgz#a57a33804491fbae208aba8f68380437abc2dca5"
|
resolved "https://registry.yarnpkg.com/matchdep/-/matchdep-1.0.1.tgz#a57a33804491fbae208aba8f68380437abc2dca5"
|
||||||
|
@ -3277,6 +3311,10 @@ maxmin@^1.1.0:
|
||||||
gzip-size "^1.0.0"
|
gzip-size "^1.0.0"
|
||||||
pretty-bytes "^1.0.0"
|
pretty-bytes "^1.0.0"
|
||||||
|
|
||||||
|
mdurl@^1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
|
||||||
|
|
||||||
media-typer@0.3.0:
|
media-typer@0.3.0:
|
||||||
version "0.3.0"
|
version "0.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
||||||
|
@ -4807,10 +4845,6 @@ should@11.2.1:
|
||||||
should-type-adaptors "^1.0.1"
|
should-type-adaptors "^1.0.1"
|
||||||
should-util "^1.0.0"
|
should-util "^1.0.0"
|
||||||
|
|
||||||
showdown-ghost@0.3.6:
|
|
||||||
version "0.3.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/showdown-ghost/-/showdown-ghost-0.3.6.tgz#ec73685cc5b4790352b00ed9e2cb26efc337d2f1"
|
|
||||||
|
|
||||||
sigmund@^1.0.1, sigmund@~1.0.0:
|
sigmund@^1.0.1, sigmund@~1.0.0:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590"
|
resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590"
|
||||||
|
@ -4981,6 +5015,10 @@ string-width@^1.0.1:
|
||||||
is-fullwidth-code-point "^1.0.0"
|
is-fullwidth-code-point "^1.0.0"
|
||||||
strip-ansi "^3.0.0"
|
strip-ansi "^3.0.0"
|
||||||
|
|
||||||
|
string@^3.0.1:
|
||||||
|
version "3.3.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/string/-/string-3.3.3.tgz#5ea211cd92d228e184294990a6cc97b366a77cb0"
|
||||||
|
|
||||||
string_decoder@~0.10.x:
|
string_decoder@~0.10.x:
|
||||||
version "0.10.31"
|
version "0.10.31"
|
||||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
|
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
|
||||||
|
@ -5234,6 +5272,10 @@ typedarray@~0.0.5:
|
||||||
version "0.0.6"
|
version "0.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||||
|
|
||||||
|
uc.micro@^1.0.1, uc.micro@^1.0.3:
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192"
|
||||||
|
|
||||||
uglify-js@^2.6, uglify-js@~2.7.0:
|
uglify-js@^2.6, uglify-js@~2.7.0:
|
||||||
version "2.7.5"
|
version "2.7.5"
|
||||||
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8"
|
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8"
|
||||||
|
|
Loading…
Reference in a new issue