module.exports = create var classifyCharacter = require('micromark/dist/util/classify-character') var chunkedSplice = require('micromark/dist/util/chunked-splice') var resolveAll = require('micromark/dist/util/resolve-all') var shallow = require('micromark/dist/util/shallow') function create(options) { var settings = options || {} var single = settings.singleTilde var tokenizer = { tokenize: tokenizeStrikethrough, resolveAll: resolveAllStrikethrough } if (single === null || single === undefined) { single = true } return {text: {126: tokenizer}, insideSpan: {null: tokenizer}} // Take events and resolve strikethrough. function resolveAllStrikethrough(events, context) { var index = -1 var strikethrough var text var open var nextEvents // Walk through all events. while (++index < events.length) { // Find a token that can close. if ( events[index][0] === 'enter' && events[index][1].type === 'strikethroughSequenceTemporary' && events[index][1]._close ) { open = index // Now walk back to find an opener. while (open--) { // Find a token that can open the closer. if ( events[open][0] === 'exit' && events[open][1].type === 'strikethroughSequenceTemporary' && events[open][1]._open && // If the sizes are the same: events[index][1].end.offset - events[index][1].start.offset === events[open][1].end.offset - events[open][1].start.offset ) { events[index][1].type = 'strikethroughSequence' events[open][1].type = 'strikethroughSequence' strikethrough = { type: 'strikethrough', start: shallow(events[open][1].start), end: shallow(events[index][1].end) } text = { type: 'strikethroughText', start: shallow(events[open][1].end), end: shallow(events[index][1].start) } // Opening. nextEvents = [ ['enter', strikethrough, context], ['enter', events[open][1], context], ['exit', events[open][1], context], ['enter', text, context] ] // Between. chunkedSplice( nextEvents, nextEvents.length, 0, resolveAll( context.parser.constructs.insideSpan.null, events.slice(open + 1, index), context ) ) // Closing. chunkedSplice(nextEvents, nextEvents.length, 0, [ ['exit', text, context], ['enter', events[index][1], context], ['exit', events[index][1], context], ['exit', strikethrough, context] ]) chunkedSplice(events, open - 1, index - open + 3, nextEvents) index = open + nextEvents.length - 2 break } } } } return removeRemainingSequences(events) } function removeRemainingSequences(events) { var index = -1 var length = events.length while (++index < length) { if (events[index][1].type === 'strikethroughSequenceTemporary') { events[index][1].type = 'data' } } return events } function tokenizeStrikethrough(effects, ok, nok) { var previous = this.previous var events = this.events var size = 0 return start function start(code) { if ( code !== 126 || (previous === 126 && events[events.length - 1][1].type !== 'characterEscape') ) { return nok(code) } effects.enter('strikethroughSequenceTemporary') return more(code) } function more(code) { var before = classifyCharacter(previous) var token var after if (code === 126) { // If this is the third marker, exit. if (size > 1) return nok(code) effects.consume(code) size++ return more } if (size < 2 && !single) return nok(code) token = effects.exit('strikethroughSequenceTemporary') after = classifyCharacter(code) token._open = !after || (after === 2 && before) token._close = !before || (before === 2 && after) return ok(code) } } }