|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export const resolver = { |
|
resolveAll: createResolver() |
|
} |
|
export const string = initializeFactory('string') |
|
export const text = initializeFactory('text') |
|
|
|
|
|
|
|
|
|
|
|
function initializeFactory(field) { |
|
return { |
|
tokenize: initializeText, |
|
resolveAll: createResolver( |
|
field === 'text' ? resolveAllLineSuffixes : undefined |
|
) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function initializeText(effects) { |
|
const self = this |
|
const constructs = this.parser.constructs[field] |
|
const text = effects.attempt(constructs, start, notText) |
|
return start |
|
|
|
|
|
function start(code) { |
|
return atBreak(code) ? text(code) : notText(code) |
|
} |
|
|
|
|
|
function notText(code) { |
|
if (code === null) { |
|
effects.consume(code) |
|
return |
|
} |
|
effects.enter('data') |
|
effects.consume(code) |
|
return data |
|
} |
|
|
|
|
|
function data(code) { |
|
if (atBreak(code)) { |
|
effects.exit('data') |
|
return text(code) |
|
} |
|
|
|
|
|
effects.consume(code) |
|
return data |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function atBreak(code) { |
|
if (code === null) { |
|
return true |
|
} |
|
const list = constructs[code] |
|
let index = -1 |
|
if (list) { |
|
|
|
|
|
while (++index < list.length) { |
|
const item = list[index] |
|
if (!item.previous || item.previous.call(self, self.previous)) { |
|
return true |
|
} |
|
} |
|
} |
|
return false |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function createResolver(extraResolver) { |
|
return resolveAllText |
|
|
|
|
|
function resolveAllText(events, context) { |
|
let index = -1 |
|
|
|
let enter |
|
|
|
|
|
|
|
while (++index <= events.length) { |
|
if (enter === undefined) { |
|
if (events[index] && events[index][1].type === 'data') { |
|
enter = index |
|
index++ |
|
} |
|
} else if (!events[index] || events[index][1].type !== 'data') { |
|
|
|
if (index !== enter + 2) { |
|
events[enter][1].end = events[index - 1][1].end |
|
events.splice(enter + 2, index - enter - 2) |
|
index = enter + 2 |
|
} |
|
enter = undefined |
|
} |
|
} |
|
return extraResolver ? extraResolver(events, context) : events |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function resolveAllLineSuffixes(events, context) { |
|
let eventIndex = 0 |
|
|
|
while (++eventIndex <= events.length) { |
|
if ( |
|
(eventIndex === events.length || |
|
events[eventIndex][1].type === 'lineEnding') && |
|
events[eventIndex - 1][1].type === 'data' |
|
) { |
|
const data = events[eventIndex - 1][1] |
|
const chunks = context.sliceStream(data) |
|
let index = chunks.length |
|
let bufferIndex = -1 |
|
let size = 0 |
|
|
|
let tabs |
|
while (index--) { |
|
const chunk = chunks[index] |
|
if (typeof chunk === 'string') { |
|
bufferIndex = chunk.length |
|
while (chunk.charCodeAt(bufferIndex - 1) === 32) { |
|
size++ |
|
bufferIndex-- |
|
} |
|
if (bufferIndex) break |
|
bufferIndex = -1 |
|
} |
|
|
|
else if (chunk === -2) { |
|
tabs = true |
|
size++ |
|
} else if (chunk === -1) { |
|
|
|
} else { |
|
|
|
index++ |
|
break |
|
} |
|
} |
|
if (size) { |
|
const token = { |
|
type: |
|
eventIndex === events.length || tabs || size < 2 |
|
? 'lineSuffix' |
|
: 'hardBreakTrailing', |
|
start: { |
|
line: data.end.line, |
|
column: data.end.column - size, |
|
offset: data.end.offset - size, |
|
_index: data.start._index + index, |
|
_bufferIndex: index |
|
? bufferIndex |
|
: data.start._bufferIndex + bufferIndex |
|
}, |
|
end: Object.assign({}, data.end) |
|
} |
|
data.end = Object.assign({}, token.start) |
|
if (data.start.offset === data.end.offset) { |
|
Object.assign(data, token) |
|
} else { |
|
events.splice( |
|
eventIndex, |
|
0, |
|
['enter', token, context], |
|
['exit', token, context] |
|
) |
|
eventIndex += 2 |
|
} |
|
} |
|
eventIndex++ |
|
} |
|
} |
|
return events |
|
} |
|
|