-
-
Notifications
You must be signed in to change notification settings - Fork 371
/
parser_block.js
165 lines (142 loc) · 4.49 KB
/
parser_block.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
import Ruler from './ruler';
import StateBlock from './rules_block/state_block';
import code from './rules_block/code';
import fences from './rules_block/fences';
import blockquote from './rules_block/blockquote';
import hr from './rules_block/hr';
import list from './rules_block/list';
import footnote from './rules_block/footnote';
import heading from './rules_block/heading';
import lheading from './rules_block/lheading';
import htmlblock from './rules_block/htmlblock';
import table from './rules_block/table';
import deflist from './rules_block/deflist';
import paragraph from './rules_block/paragraph';
/**
* Parser rules
*/
var _rules = [
[ 'code', code ],
[ 'fences', fences, [ 'paragraph', 'blockquote', 'list' ] ],
[ 'blockquote', blockquote, [ 'paragraph', 'blockquote', 'list' ] ],
[ 'hr', hr, [ 'paragraph', 'blockquote', 'list' ] ],
[ 'list', list, [ 'paragraph', 'blockquote' ] ],
[ 'footnote', footnote, [ 'paragraph' ] ],
[ 'heading', heading, [ 'paragraph', 'blockquote' ] ],
[ 'lheading', lheading ],
[ 'htmlblock', htmlblock, [ 'paragraph', 'blockquote' ] ],
[ 'table', table, [ 'paragraph' ] ],
[ 'deflist', deflist, [ 'paragraph' ] ],
[ 'paragraph', paragraph ]
];
/**
* Block Parser class
*
* @api private
*/
export default function ParserBlock() {
this.ruler = new Ruler();
for (var i = 0; i < _rules.length; i++) {
this.ruler.push(_rules[i][0], _rules[i][1], {
alt: (_rules[i][2] || []).slice()
});
}
}
/**
* Generate tokens for the given input range.
*
* @param {Object} `state` Has properties like `src`, `parser`, `options` etc
* @param {Number} `startLine`
* @param {Number} `endLine`
* @api private
*/
ParserBlock.prototype.tokenize = function (state, startLine, endLine) {
var rules = this.ruler.getRules('');
var len = rules.length;
var line = startLine;
var hasEmptyLines = false;
var ok, i;
while (line < endLine) {
var newLine = state.skipEmptyLines(line);
// save the emtpy lines info into state.env.emptyLines
if (state.options.emptyLines === true && newLine > line) {
state.env.emptyLines = state.env.emptyLines || {};
state.env.emptyLines[line] = newLine - line;
}
state.line = line = newLine;
if (line >= endLine) {
break;
}
if (line >= endLine) {
break;
}
// Termination condition for nested calls.
// Nested calls currently used for blockquotes & lists
if (state.tShift[line] < state.blkIndent) {
break;
}
// Try all possible rules.
// On success, rule should:
//
// - update `state.line`
// - update `state.tokens`
// - return true
for (i = 0; i < len; i++) {
ok = rules[i](state, line, endLine, false);
if (ok) {
break;
}
}
// set state.tight iff we had an empty line before current tag
// i.e. latest empty line should not count
state.tight = !hasEmptyLines;
// paragraph might "eat" one newline after it in nested lists
if (state.isEmpty(state.line - 1)) {
hasEmptyLines = true;
}
line = state.line;
if (line < endLine && state.isEmpty(line)) {
hasEmptyLines = true;
line++;
// two empty lines should stop the parser in list mode
if (line < endLine && state.parentType === 'list' && state.isEmpty(line)) { break; }
state.line = line;
}
}
};
var TABS_SCAN_RE = /[\n\t]/g;
var NEWLINES_RE = /\r[\n\u0085]|[\u2424\u2028\u0085]/g;
var SPACES_RE = /\u00a0/g;
/**
* Tokenize the given `str`.
*
* @param {String} `str` Source string
* @param {Object} `options`
* @param {Object} `env`
* @param {Array} `outTokens`
* @api private
*/
ParserBlock.prototype.parse = function (str, options, env, outTokens) {
var state, lineStart = 0, lastTabPos = 0;
if (!str) { return []; }
// Normalize spaces
str = str.replace(SPACES_RE, ' ');
// Normalize newlines
str = str.replace(NEWLINES_RE, '\n');
// Replace tabs with proper number of spaces (1..4)
if (str.indexOf('\t') >= 0) {
str = str.replace(TABS_SCAN_RE, function (match, offset) {
var result;
if (str.charCodeAt(offset) === 0x0A) {
lineStart = offset + 1;
lastTabPos = 0;
return match;
}
result = ' '.slice((offset - lineStart - lastTabPos) % 4);
lastTabPos = offset - lineStart + 1;
return result;
});
}
state = new StateBlock(str, this, options, env, outTokens);
this.tokenize(state, state.line, state.lineMax);
};