Markdown parser, done right. 100% CommonMark support, extensions, syntax plugins & high speed https://markdown-it.github.io/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

170 lines
4.1 KiB

/** internal
* class ParserInline
*
* Tokenizes paragraph content.
**/
'use strict';
var Ruler = require('./ruler');
var replaceEntities = require('./common/utils').replaceEntities;
////////////////////////////////////////////////////////////////////////////////
// Parser rules
var _rules = [
[ 'text', require('./rules_inline/text') ],
[ 'newline', require('./rules_inline/newline') ],
[ 'escape', require('./rules_inline/escape') ],
[ 'backtick', require('./rules_inline/backtick') ],
[ 'strikethrough', require('./rules_inline/strikethrough') ],
[ 'emphasis', require('./rules_inline/emphasis') ],
[ 'link', require('./rules_inline/link') ],
[ 'image', require('./rules_inline/image') ],
[ 'autolink', require('./rules_inline/autolink') ],
[ 'html_inline', require('./rules_inline/html_inline') ],
[ 'entity', require('./rules_inline/entity') ]
];
var BAD_PROTOCOLS = [ 'vbscript', 'javascript', 'file' ];
function validateLink(url) {
var str = url.trim().toLowerCase();
// Care about digital entities "javascript:alert(1)"
str = replaceEntities(str);
if (str.indexOf(':') >= 0 && BAD_PROTOCOLS.indexOf(str.split(':')[0]) >= 0) {
return false;
}
return true;
}
/**
* new ParserInline()
**/
function ParserInline() {
/**
* ParserInline#validateLink(url) -> Boolean
*
* Link validation function. CommonMark allows too much in links. By default
* we disable `javascript:` and `vbscript:` schemas. You can change this
* behaviour.
*
* ```javascript
* var md = require('markdown-it')();
* // enable everything
* md.inline.validateLink = function () { return true; }
* ```
**/
this.validateLink = validateLink;
/**
* ParserInline#ruler -> Ruler
*
* [[Ruler]] instance. Keep configuration of inline rules.
**/
this.ruler = new Ruler();
for (var i = 0; i < _rules.length; i++) {
this.ruler.push(_rules[i][0], _rules[i][1]);
}
}
// Skip single token by running all rules in validation mode;
// returns `true` if any rule reported success
//
ParserInline.prototype.skipToken = function (state) {
var i, cached_pos, pos = state.pos,
rules = this.ruler.getRules(''),
len = rules.length,
maxNesting = state.md.options.maxNesting;
if ((cached_pos = state.cacheGet(pos)) > 0) {
state.pos = cached_pos;
return;
}
if (state.level < maxNesting) {
for (i = 0; i < len; i++) {
if (rules[i](state, true)) {
state.cacheSet(pos, state.pos);
return;
}
}
state.pos++;
} else {
// If nesting level exceeded - skip tail to the end. That's not ordinary
// situation and we should not care about content.
state.pos = state.max;
}
state.cacheSet(pos, state.pos);
};
// Generate tokens for input range
//
ParserInline.prototype.tokenize = function (state) {
var ok, i,
rules = this.ruler.getRules(''),
len = rules.length,
end = state.posMax,
maxNesting = state.md.options.maxNesting;
while (state.pos < end) {
// If nesting level exceeded - skip tail to the end. That's not ordinary
// situation and we should not care about content.
if (state.level >= maxNesting) {
state.pos = end;
break;
}
// Try all possible rules.
// On success, rule should:
//
// - update `state.pos`
// - update `state.tokens`
// - return true
for (i = 0; i < len; i++) {
ok = rules[i](state, false);
if (ok) { break; }
}
if (ok) {
if (state.pos >= end) { break; }
continue;
}
state.pending += state.src[state.pos++];
}
if (state.pending) {
state.pushPending();
}
};
/**
10 years ago
* ParserInline.parse(str, md, env, outTokens)
*
* Process input string and push inline tokens into `outTokens`
**/
ParserInline.prototype.parse = function (str, md, env, outTokens) {
var state = new this.State(str, md, env, outTokens);
this.tokenize(state);
};
ParserInline.prototype.State = require('./rules_inline/state_inline');
module.exports = ParserInline;