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.
129 lines
3.3 KiB
129 lines
3.3 KiB
var setextUnderline = { |
|
name: 'setextUnderline', |
|
tokenize: tokenizeSetextUnderline, |
|
resolveTo: resolveToSetextUnderline |
|
} |
|
export default setextUnderline |
|
|
|
import assert from 'assert' |
|
import codes from '../character/codes.mjs' |
|
import markdownLineEnding from '../character/markdown-line-ending.mjs' |
|
import types from '../constant/types.mjs' |
|
import shallow from '../util/shallow.mjs' |
|
import spaceFactory from './factory-space.mjs' |
|
|
|
function resolveToSetextUnderline(events, context) { |
|
var index = events.length |
|
var content |
|
var text |
|
var definition |
|
var heading |
|
|
|
// Find the opening of the content. |
|
// It’ll always exist: we don’t tokenize if it isn’t there. |
|
while (index--) { |
|
if (events[index][0] === 'enter') { |
|
if (events[index][1].type === types.content) { |
|
content = index |
|
break |
|
} |
|
|
|
if (events[index][1].type === types.paragraph) { |
|
text = index |
|
} |
|
} |
|
// Exit |
|
else { |
|
if (events[index][1].type === types.content) { |
|
// Remove the content end (if needed we’ll add it later) |
|
events.splice(index, 1) |
|
} |
|
|
|
if (!definition && events[index][1].type === types.definition) { |
|
definition = index |
|
} |
|
} |
|
} |
|
|
|
heading = { |
|
type: types.setextHeading, |
|
start: shallow(events[text][1].start), |
|
end: shallow(events[events.length - 1][1].end) |
|
} |
|
|
|
// Change the paragraph to setext heading text. |
|
events[text][1].type = types.setextHeadingText |
|
|
|
// If we have definitions in the content, we’ll keep on having content, |
|
// but we need move it. |
|
if (definition) { |
|
events.splice(text, 0, ['enter', heading, context]) |
|
events.splice(definition + 1, 0, ['exit', events[content][1], context]) |
|
events[content][1].end = shallow(events[definition][1].end) |
|
} else { |
|
events[content][1] = heading |
|
} |
|
|
|
// Add the heading exit at the end. |
|
events.push(['exit', heading, context]) |
|
|
|
return events |
|
} |
|
|
|
function tokenizeSetextUnderline(effects, ok, nok) { |
|
var self = this |
|
var index = self.events.length |
|
var marker |
|
var paragraph |
|
|
|
// Find an opening. |
|
while (index--) { |
|
// Skip enter/exit of line ending, line prefix, and content. |
|
// We can now either have a definition or a paragraph. |
|
if ( |
|
self.events[index][1].type !== types.lineEnding && |
|
self.events[index][1].type !== types.linePrefix && |
|
self.events[index][1].type !== types.content |
|
) { |
|
paragraph = self.events[index][1].type === types.paragraph |
|
break |
|
} |
|
} |
|
|
|
return start |
|
|
|
function start(code) { |
|
assert( |
|
code === codes.dash || code === codes.equalsTo, |
|
'expected `=` or `-`' |
|
) |
|
|
|
if (!self.lazy && (self.interrupt || paragraph)) { |
|
effects.enter(types.setextHeadingLine) |
|
effects.enter(types.setextHeadingLineSequence) |
|
marker = code |
|
return closingSequence(code) |
|
} |
|
|
|
return nok(code) |
|
} |
|
|
|
function closingSequence(code) { |
|
if (code === marker) { |
|
effects.consume(code) |
|
return closingSequence |
|
} |
|
|
|
effects.exit(types.setextHeadingLineSequence) |
|
return spaceFactory(effects, closingSequenceEnd, types.lineSuffix)(code) |
|
} |
|
|
|
function closingSequenceEnd(code) { |
|
if (code === codes.eof || markdownLineEnding(code)) { |
|
effects.exit(types.setextHeadingLine) |
|
return ok(code) |
|
} |
|
|
|
return nok(code) |
|
} |
|
}
|
|
|