|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import {factorySpace} from 'micromark-factory-space' |
|
import { |
|
asciiAlpha, |
|
asciiAlphanumeric, |
|
markdownLineEnding, |
|
markdownLineEndingOrSpace, |
|
markdownSpace |
|
} from 'micromark-util-character' |
|
import {codes} from 'micromark-util-symbol/codes.js' |
|
import {constants} from 'micromark-util-symbol/constants.js' |
|
import {types} from 'micromark-util-symbol/types.js' |
|
import {ok as assert} from 'uvu/assert' |
|
|
|
|
|
export const htmlText = {name: 'htmlText', tokenize: tokenizeHtmlText} |
|
|
|
|
|
|
|
|
|
|
|
function tokenizeHtmlText(effects, ok, nok) { |
|
const self = this |
|
|
|
let marker |
|
|
|
let index |
|
|
|
let returnState |
|
|
|
return start |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function start(code) { |
|
assert(code === codes.lessThan, 'expected `<`') |
|
effects.enter(types.htmlText) |
|
effects.enter(types.htmlTextData) |
|
effects.consume(code) |
|
return open |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function open(code) { |
|
if (code === codes.exclamationMark) { |
|
effects.consume(code) |
|
return declarationOpen |
|
} |
|
|
|
if (code === codes.slash) { |
|
effects.consume(code) |
|
return tagCloseStart |
|
} |
|
|
|
if (code === codes.questionMark) { |
|
effects.consume(code) |
|
return instruction |
|
} |
|
|
|
|
|
if (asciiAlpha(code)) { |
|
effects.consume(code) |
|
return tagOpen |
|
} |
|
|
|
return nok(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function declarationOpen(code) { |
|
if (code === codes.dash) { |
|
effects.consume(code) |
|
return commentOpenInside |
|
} |
|
|
|
if (code === codes.leftSquareBracket) { |
|
effects.consume(code) |
|
index = 0 |
|
return cdataOpenInside |
|
} |
|
|
|
if (asciiAlpha(code)) { |
|
effects.consume(code) |
|
return declaration |
|
} |
|
|
|
return nok(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function commentOpenInside(code) { |
|
if (code === codes.dash) { |
|
effects.consume(code) |
|
return commentEnd |
|
} |
|
|
|
return nok(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function comment(code) { |
|
if (code === codes.eof) { |
|
return nok(code) |
|
} |
|
|
|
if (code === codes.dash) { |
|
effects.consume(code) |
|
return commentClose |
|
} |
|
|
|
if (markdownLineEnding(code)) { |
|
returnState = comment |
|
return lineEndingBefore(code) |
|
} |
|
|
|
effects.consume(code) |
|
return comment |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function commentClose(code) { |
|
if (code === codes.dash) { |
|
effects.consume(code) |
|
return commentEnd |
|
} |
|
|
|
return comment(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function commentEnd(code) { |
|
return code === codes.greaterThan |
|
? end(code) |
|
: code === codes.dash |
|
? commentClose(code) |
|
: comment(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function cdataOpenInside(code) { |
|
const value = constants.cdataOpeningString |
|
|
|
if (code === value.charCodeAt(index++)) { |
|
effects.consume(code) |
|
return index === value.length ? cdata : cdataOpenInside |
|
} |
|
|
|
return nok(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function cdata(code) { |
|
if (code === codes.eof) { |
|
return nok(code) |
|
} |
|
|
|
if (code === codes.rightSquareBracket) { |
|
effects.consume(code) |
|
return cdataClose |
|
} |
|
|
|
if (markdownLineEnding(code)) { |
|
returnState = cdata |
|
return lineEndingBefore(code) |
|
} |
|
|
|
effects.consume(code) |
|
return cdata |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function cdataClose(code) { |
|
if (code === codes.rightSquareBracket) { |
|
effects.consume(code) |
|
return cdataEnd |
|
} |
|
|
|
return cdata(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function cdataEnd(code) { |
|
if (code === codes.greaterThan) { |
|
return end(code) |
|
} |
|
|
|
if (code === codes.rightSquareBracket) { |
|
effects.consume(code) |
|
return cdataEnd |
|
} |
|
|
|
return cdata(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function declaration(code) { |
|
if (code === codes.eof || code === codes.greaterThan) { |
|
return end(code) |
|
} |
|
|
|
if (markdownLineEnding(code)) { |
|
returnState = declaration |
|
return lineEndingBefore(code) |
|
} |
|
|
|
effects.consume(code) |
|
return declaration |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function instruction(code) { |
|
if (code === codes.eof) { |
|
return nok(code) |
|
} |
|
|
|
if (code === codes.questionMark) { |
|
effects.consume(code) |
|
return instructionClose |
|
} |
|
|
|
if (markdownLineEnding(code)) { |
|
returnState = instruction |
|
return lineEndingBefore(code) |
|
} |
|
|
|
effects.consume(code) |
|
return instruction |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function instructionClose(code) { |
|
return code === codes.greaterThan ? end(code) : instruction(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function tagCloseStart(code) { |
|
|
|
if (asciiAlpha(code)) { |
|
effects.consume(code) |
|
return tagClose |
|
} |
|
|
|
return nok(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function tagClose(code) { |
|
|
|
if (code === codes.dash || asciiAlphanumeric(code)) { |
|
effects.consume(code) |
|
return tagClose |
|
} |
|
|
|
return tagCloseBetween(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function tagCloseBetween(code) { |
|
if (markdownLineEnding(code)) { |
|
returnState = tagCloseBetween |
|
return lineEndingBefore(code) |
|
} |
|
|
|
if (markdownSpace(code)) { |
|
effects.consume(code) |
|
return tagCloseBetween |
|
} |
|
|
|
return end(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function tagOpen(code) { |
|
|
|
if (code === codes.dash || asciiAlphanumeric(code)) { |
|
effects.consume(code) |
|
return tagOpen |
|
} |
|
|
|
if ( |
|
code === codes.slash || |
|
code === codes.greaterThan || |
|
markdownLineEndingOrSpace(code) |
|
) { |
|
return tagOpenBetween(code) |
|
} |
|
|
|
return nok(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function tagOpenBetween(code) { |
|
if (code === codes.slash) { |
|
effects.consume(code) |
|
return end |
|
} |
|
|
|
|
|
if (code === codes.colon || code === codes.underscore || asciiAlpha(code)) { |
|
effects.consume(code) |
|
return tagOpenAttributeName |
|
} |
|
|
|
if (markdownLineEnding(code)) { |
|
returnState = tagOpenBetween |
|
return lineEndingBefore(code) |
|
} |
|
|
|
if (markdownSpace(code)) { |
|
effects.consume(code) |
|
return tagOpenBetween |
|
} |
|
|
|
return end(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function tagOpenAttributeName(code) { |
|
|
|
if ( |
|
code === codes.dash || |
|
code === codes.dot || |
|
code === codes.colon || |
|
code === codes.underscore || |
|
asciiAlphanumeric(code) |
|
) { |
|
effects.consume(code) |
|
return tagOpenAttributeName |
|
} |
|
|
|
return tagOpenAttributeNameAfter(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function tagOpenAttributeNameAfter(code) { |
|
if (code === codes.equalsTo) { |
|
effects.consume(code) |
|
return tagOpenAttributeValueBefore |
|
} |
|
|
|
if (markdownLineEnding(code)) { |
|
returnState = tagOpenAttributeNameAfter |
|
return lineEndingBefore(code) |
|
} |
|
|
|
if (markdownSpace(code)) { |
|
effects.consume(code) |
|
return tagOpenAttributeNameAfter |
|
} |
|
|
|
return tagOpenBetween(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function tagOpenAttributeValueBefore(code) { |
|
if ( |
|
code === codes.eof || |
|
code === codes.lessThan || |
|
code === codes.equalsTo || |
|
code === codes.greaterThan || |
|
code === codes.graveAccent |
|
) { |
|
return nok(code) |
|
} |
|
|
|
if (code === codes.quotationMark || code === codes.apostrophe) { |
|
effects.consume(code) |
|
marker = code |
|
return tagOpenAttributeValueQuoted |
|
} |
|
|
|
if (markdownLineEnding(code)) { |
|
returnState = tagOpenAttributeValueBefore |
|
return lineEndingBefore(code) |
|
} |
|
|
|
if (markdownSpace(code)) { |
|
effects.consume(code) |
|
return tagOpenAttributeValueBefore |
|
} |
|
|
|
effects.consume(code) |
|
return tagOpenAttributeValueUnquoted |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function tagOpenAttributeValueQuoted(code) { |
|
if (code === marker) { |
|
effects.consume(code) |
|
marker = undefined |
|
return tagOpenAttributeValueQuotedAfter |
|
} |
|
|
|
if (code === codes.eof) { |
|
return nok(code) |
|
} |
|
|
|
if (markdownLineEnding(code)) { |
|
returnState = tagOpenAttributeValueQuoted |
|
return lineEndingBefore(code) |
|
} |
|
|
|
effects.consume(code) |
|
return tagOpenAttributeValueQuoted |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function tagOpenAttributeValueUnquoted(code) { |
|
if ( |
|
code === codes.eof || |
|
code === codes.quotationMark || |
|
code === codes.apostrophe || |
|
code === codes.lessThan || |
|
code === codes.equalsTo || |
|
code === codes.graveAccent |
|
) { |
|
return nok(code) |
|
} |
|
|
|
if ( |
|
code === codes.slash || |
|
code === codes.greaterThan || |
|
markdownLineEndingOrSpace(code) |
|
) { |
|
return tagOpenBetween(code) |
|
} |
|
|
|
effects.consume(code) |
|
return tagOpenAttributeValueUnquoted |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function tagOpenAttributeValueQuotedAfter(code) { |
|
if ( |
|
code === codes.slash || |
|
code === codes.greaterThan || |
|
markdownLineEndingOrSpace(code) |
|
) { |
|
return tagOpenBetween(code) |
|
} |
|
|
|
return nok(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function end(code) { |
|
if (code === codes.greaterThan) { |
|
effects.consume(code) |
|
effects.exit(types.htmlTextData) |
|
effects.exit(types.htmlText) |
|
return ok |
|
} |
|
|
|
return nok(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function lineEndingBefore(code) { |
|
assert(returnState, 'expected return state') |
|
assert(markdownLineEnding(code), 'expected eol') |
|
effects.exit(types.htmlTextData) |
|
effects.enter(types.lineEnding) |
|
effects.consume(code) |
|
effects.exit(types.lineEnding) |
|
return lineEndingAfter |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function lineEndingAfter(code) { |
|
|
|
assert( |
|
self.parser.constructs.disable.null, |
|
'expected `disable.null` to be populated' |
|
) |
|
return markdownSpace(code) |
|
? factorySpace( |
|
effects, |
|
lineEndingAfterPrefix, |
|
types.linePrefix, |
|
self.parser.constructs.disable.null.includes('codeIndented') |
|
? undefined |
|
: constants.tabSize |
|
)(code) |
|
: lineEndingAfterPrefix(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function lineEndingAfterPrefix(code) { |
|
effects.enter(types.htmlTextData) |
|
return returnState(code) |
|
} |
|
} |
|
|