'use strict' var assign = require('../constant/assign.js') var chunkedSplice = require('./chunked-splice.js') var shallow = require('./shallow.js') function subtokenize(events) { var jumps = {} var index = -1 var event var lineIndex var otherIndex var otherEvent var parameters var subevents var more while (++index < events.length) { while (index in jumps) { index = jumps[index] } event = events[index] // Add a hook for the GFM tasklist extension, which needs to know if text // is in the first content of a list item. if ( index && event[1].type === 'chunkFlow' && events[index - 1][1].type === 'listItemPrefix' ) { subevents = event[1]._tokenizer.events otherIndex = 0 if ( otherIndex < subevents.length && subevents[otherIndex][1].type === 'lineEndingBlank' ) { otherIndex += 2 } if ( otherIndex < subevents.length && subevents[otherIndex][1].type === 'content' ) { while (++otherIndex < subevents.length) { if (subevents[otherIndex][1].type === 'content') { break } if (subevents[otherIndex][1].type === 'chunkText') { subevents[otherIndex][1].isInFirstContentOfListItem = true otherIndex++ } } } } // Enter. if (event[0] === 'enter') { if (event[1].contentType) { assign(jumps, subcontent(events, index)) index = jumps[index] more = true } } // Exit. else if (event[1]._container || event[1]._movePreviousLineEndings) { otherIndex = index lineIndex = undefined while (otherIndex--) { otherEvent = events[otherIndex] if ( otherEvent[1].type === 'lineEnding' || otherEvent[1].type === 'lineEndingBlank' ) { if (otherEvent[0] === 'enter') { if (lineIndex) { events[lineIndex][1].type = 'lineEndingBlank' } otherEvent[1].type = 'lineEnding' lineIndex = otherIndex } } else { break } } if (lineIndex) { // Fix position. event[1].end = shallow(events[lineIndex][1].start) // Switch container exit w/ line endings. parameters = events.slice(lineIndex, index) parameters.unshift(event) chunkedSplice(events, lineIndex, index - lineIndex + 1, parameters) } } } return !more } function subcontent(events, eventIndex) { var token = events[eventIndex][1] var context = events[eventIndex][2] var startPosition = eventIndex - 1 var startPositions = [] var tokenizer = token._tokenizer || context.parser[token.contentType](token.start) var childEvents = tokenizer.events var jumps = [] var gaps = {} var stream var previous var index var entered var end var adjust // Loop forward through the linked tokens to pass them in order to the // subtokenizer. while (token) { // Find the position of the event for this token. while (events[++startPosition][1] !== token) { // Empty. } startPositions.push(startPosition) if (!token._tokenizer) { stream = context.sliceStream(token) if (!token.next) { stream.push(null) } if (previous) { tokenizer.defineSkip(token.start) } if (token.isInFirstContentOfListItem) { tokenizer._gfmTasklistFirstContentOfListItem = true } tokenizer.write(stream) if (token.isInFirstContentOfListItem) { tokenizer._gfmTasklistFirstContentOfListItem = undefined } } // Unravel the next token. previous = token token = token.next } // Now, loop back through all events (and linked tokens), to figure out which // parts belong where. token = previous index = childEvents.length while (index--) { // Make sure we’ve at least seen something (final eol is part of the last // token). if (childEvents[index][0] === 'enter') { entered = true } else if ( // Find a void token that includes a break. entered && childEvents[index][1].type === childEvents[index - 1][1].type && childEvents[index][1].start.line !== childEvents[index][1].end.line ) { add(childEvents.slice(index + 1, end)) // Help GC. token._tokenizer = token.next = undefined token = token.previous end = index + 1 } } // Help GC. tokenizer.events = token._tokenizer = token.next = undefined // Do head: add(childEvents.slice(0, end)) index = -1 adjust = 0 while (++index < jumps.length) { gaps[adjust + jumps[index][0]] = adjust + jumps[index][1] adjust += jumps[index][1] - jumps[index][0] - 1 } return gaps function add(slice) { var start = startPositions.pop() jumps.unshift([start, start + slice.length - 1]) chunkedSplice(events, start, 2, slice) } } module.exports = subtokenize