htmljs-parser
Version:
An HTML parser recognizes content and string placeholders and allows JavaScript expressions as attribute values
1,715 lines (1,701 loc) • 81.4 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
ErrorCode: () => ErrorCode,
TagType: () => TagType,
createParser: () => createParser,
getLines: () => getLines,
getLocation: () => getLocation,
getPosition: () => getPosition
});
module.exports = __toCommonJS(src_exports);
// src/util/constants.ts
var ErrorCode = /* @__PURE__ */ ((ErrorCode3) => {
ErrorCode3[ErrorCode3["EXTRA_CLOSING_TAG"] = 0] = "EXTRA_CLOSING_TAG";
ErrorCode3[ErrorCode3["INVALID_ATTRIBUTE_ARGUMENT"] = 1] = "INVALID_ATTRIBUTE_ARGUMENT";
ErrorCode3[ErrorCode3["INVALID_ATTRIBUTE_NAME"] = 2] = "INVALID_ATTRIBUTE_NAME";
ErrorCode3[ErrorCode3["INVALID_ATTRIBUTE_VALUE"] = 3] = "INVALID_ATTRIBUTE_VALUE";
ErrorCode3[ErrorCode3["INVALID_CHARACTER"] = 4] = "INVALID_CHARACTER";
ErrorCode3[ErrorCode3["INVALID_CODE_AFTER_SEMICOLON"] = 5] = "INVALID_CODE_AFTER_SEMICOLON";
ErrorCode3[ErrorCode3["INVALID_EXPRESSION"] = 6] = "INVALID_EXPRESSION";
ErrorCode3[ErrorCode3["INVALID_INDENTATION"] = 7] = "INVALID_INDENTATION";
ErrorCode3[ErrorCode3["INVALID_LINE_START"] = 8] = "INVALID_LINE_START";
ErrorCode3[ErrorCode3["INVALID_REGULAR_EXPRESSION"] = 9] = "INVALID_REGULAR_EXPRESSION";
ErrorCode3[ErrorCode3["INVALID_STRING"] = 10] = "INVALID_STRING";
ErrorCode3[ErrorCode3["INVALID_TAG_ARGUMENT"] = 11] = "INVALID_TAG_ARGUMENT";
ErrorCode3[ErrorCode3["INVALID_TAG_SHORTHAND"] = 12] = "INVALID_TAG_SHORTHAND";
ErrorCode3[ErrorCode3["INVALID_TEMPLATE_STRING"] = 13] = "INVALID_TEMPLATE_STRING";
ErrorCode3[ErrorCode3["MALFORMED_CDATA"] = 14] = "MALFORMED_CDATA";
ErrorCode3[ErrorCode3["MALFORMED_CLOSE_TAG"] = 15] = "MALFORMED_CLOSE_TAG";
ErrorCode3[ErrorCode3["MALFORMED_COMMENT"] = 16] = "MALFORMED_COMMENT";
ErrorCode3[ErrorCode3["MALFORMED_DECLARATION"] = 17] = "MALFORMED_DECLARATION";
ErrorCode3[ErrorCode3["MALFORMED_DOCUMENT_TYPE"] = 18] = "MALFORMED_DOCUMENT_TYPE";
ErrorCode3[ErrorCode3["MALFORMED_OPEN_TAG"] = 19] = "MALFORMED_OPEN_TAG";
ErrorCode3[ErrorCode3["MALFORMED_PLACEHOLDER"] = 20] = "MALFORMED_PLACEHOLDER";
ErrorCode3[ErrorCode3["MISMATCHED_CLOSING_TAG"] = 21] = "MISMATCHED_CLOSING_TAG";
ErrorCode3[ErrorCode3["MISSING_END_TAG"] = 22] = "MISSING_END_TAG";
ErrorCode3[ErrorCode3["MISSING_TAG_VARIABLE"] = 23] = "MISSING_TAG_VARIABLE";
ErrorCode3[ErrorCode3["RESERVED_TAG_NAME"] = 24] = "RESERVED_TAG_NAME";
ErrorCode3[ErrorCode3["ROOT_TAG_ONLY"] = 25] = "ROOT_TAG_ONLY";
ErrorCode3[ErrorCode3["INVALID_TAG_PARAMS"] = 26] = "INVALID_TAG_PARAMS";
ErrorCode3[ErrorCode3["INVALID_TAG_TYPES"] = 27] = "INVALID_TAG_TYPES";
ErrorCode3[ErrorCode3["INVALID_ATTR_TYPE_PARAMS"] = 28] = "INVALID_ATTR_TYPE_PARAMS";
return ErrorCode3;
})(ErrorCode || {});
var TagType = /* @__PURE__ */ ((TagType2) => {
TagType2[TagType2["html"] = 0] = "html";
TagType2[TagType2["text"] = 1] = "text";
TagType2[TagType2["void"] = 2] = "void";
TagType2[TagType2["statement"] = 3] = "statement";
return TagType2;
})(TagType || {});
// src/util/util.ts
function isWhitespaceCode(code) {
return code <= 32 /* SPACE */;
}
function isIndentCode(code) {
return code === 9 /* TAB */ || code === 32 /* SPACE */;
}
function getLocation(lines, startOffset, endOffset) {
const start = getPosition(lines, startOffset);
const end = startOffset === endOffset ? start : getPosAfterLine(lines, start.line, endOffset);
return { start, end };
}
function getPosition(lines, offset) {
return getPosAfterLine(lines, 0, offset);
}
function getLines(src) {
const lines = [0];
for (let i = 0; i < src.length; i++) {
if (src.charCodeAt(i) === 10 /* NEWLINE */) {
lines.push(i + 1);
}
}
return lines;
}
function htmlEOF() {
this.endText();
while (this.activeTag) {
if (this.activeTag.concise) {
this.closeTagEnd(this.pos, this.pos, void 0);
} else {
return this.emitError(
this.activeTag,
22 /* MISSING_END_TAG */,
'Missing ending "' + this.read(this.activeTag.tagName) + '" tag'
);
}
}
}
function matchesCloseAngleBracket(code) {
return code === 62 /* CLOSE_ANGLE_BRACKET */;
}
function matchesCloseParen(code) {
return code === 41 /* CLOSE_PAREN */;
}
function matchesCloseCurlyBrace(code) {
return code === 125 /* CLOSE_CURLY_BRACE */;
}
function matchesPipe(code) {
return code === 124 /* PIPE */;
}
function getPosAfterLine(lines, startLine, index) {
let max = lines.length - 1;
let line = startLine;
while (line < max) {
const mid = 1 + line + max >>> 1;
if (lines[mid] <= index) {
line = mid;
} else {
max = mid - 1;
}
}
return {
line,
character: index - lines[line]
};
}
// src/core/Parser.ts
var Parser = class {
// Keeps track of line indexes to provide line/column info.
constructor(options) {
this.options = options;
}
read(range) {
return this.data.slice(range.start, range.end);
}
positionAt(offset) {
return getPosition(
this.lines || (this.lines = getLines(this.data)),
offset
);
}
locationAt(range) {
return getLocation(
this.lines || (this.lines = getLines(this.data)),
range.start,
range.end
);
}
enterState(state) {
this.activeState = state;
return this.activeRange = state.enter.call(
this,
this.activeRange,
this.pos
);
}
exitState() {
const { activeRange, activeState } = this;
const parent = this.activeRange = activeRange.parent;
this.activeState = parent.state;
this.forward = 0;
activeRange.end = this.pos;
activeState.exit.call(this, activeRange);
this.activeState.return.call(this, activeRange, parent);
}
/**
* Compare a position in the source to either another position, or a string.
*/
matchAtPos(a, b) {
const aPos = a.start;
const aLen = a.end - aPos;
let bPos = 0;
let bLen = 0;
let bSource = this.data;
if (typeof b === "string") {
bLen = b.length;
bSource = b;
} else {
bPos = b.start;
bLen = b.end - bPos;
}
if (aLen !== bLen)
return false;
for (let i = 0; i < aLen; i++) {
if (this.data.charAt(aPos + i) !== bSource.charAt(bPos + i)) {
return false;
}
}
return true;
}
matchAnyAtPos(a, list) {
for (const item of list) {
if (this.matchAtPos(a, item))
return true;
}
return false;
}
/**
* Look ahead to see if the given str matches the substring sequence
* beyond
*/
lookAheadFor(str, startPos = this.pos + 1) {
let i = str.length;
if (startPos + i <= this.maxPos) {
const { data } = this;
for (; i--; ) {
if (str[i] !== data[startPos + i]) {
return void 0;
}
}
return str;
}
}
lookAtCharCodeAhead(offset, startPos = this.pos) {
return this.data.charCodeAt(startPos + offset);
}
startText() {
if (this.textPos === -1) {
this.textPos = this.pos;
}
}
endText() {
var _a, _b;
const start = this.textPos;
if (start !== -1) {
(_b = (_a = this.options).onText) == null ? void 0 : _b.call(_a, { start, end: this.pos });
this.textPos = -1;
}
}
/**
* This is used to enter into "HTML" parsing mode instead
* of concise HTML. We push a block on to the stack so that we know when
* return back to the previous parsing mode and to ensure that all
* tags within a block are properly closed.
*/
beginHtmlBlock(delimiter, singleLine) {
var _a;
const content = this.enterState(
((_a = this.activeTag) == null ? void 0 : _a.type) === 1 /* text */ ? states_exports.PARSED_TEXT_CONTENT : states_exports.HTML_CONTENT
);
content.singleLine = singleLine;
content.delimiter = delimiter;
content.indent = this.indent;
}
emitError(range, code, message) {
var _a, _b;
let start, end;
if (typeof range === "number") {
start = end = range;
} else {
start = range.start;
end = range.end;
}
(_b = (_a = this.options).onError) == null ? void 0 : _b.call(_a, {
start,
end,
code,
message
});
this.pos = this.maxPos + 1;
}
closeTagEnd(start, end, name) {
var _a, _b, _c, _d;
const { beginMixedMode, parentTag } = this.activeTag;
if (beginMixedMode)
this.endingMixedModeAtEOL = true;
this.activeTag = parentTag;
if (name)
(_b = (_a = this.options).onCloseTagName) == null ? void 0 : _b.call(_a, name);
(_d = (_c = this.options).onCloseTagEnd) == null ? void 0 : _d.call(_c, { start, end });
}
// --------------------------
consumeWhitespaceIfBefore(str, start = 0) {
const { pos, data } = this;
let cur = pos + start;
while (isWhitespaceCode(data.charCodeAt(cur)))
cur++;
if (this.lookAheadFor(str, cur)) {
this.pos = cur;
if (this.forward > 1)
this.forward = 1;
return true;
}
return false;
}
getPreviousNonWhitespaceCharCode(start = -1) {
let behind = start;
while (isWhitespaceCode(this.lookAtCharCodeAhead(behind)))
behind--;
return this.lookAtCharCodeAhead(behind);
}
onlyWhitespaceRemainsOnLine(start = 1) {
const maxOffset = this.maxPos - this.pos;
let ahead = start;
while (ahead < maxOffset) {
const code = this.lookAtCharCodeAhead(ahead);
if (isWhitespaceCode(code)) {
switch (code) {
case 13 /* CARRIAGE_RETURN */:
case 10 /* NEWLINE */:
return true;
}
} else {
return false;
}
ahead++;
}
return true;
}
consumeWhitespaceOnLine(start = 1) {
const maxOffset = this.maxPos - this.pos;
let ahead = start;
while (ahead < maxOffset) {
const code = this.lookAtCharCodeAhead(ahead);
if (isWhitespaceCode(code)) {
switch (code) {
case 13 /* CARRIAGE_RETURN */:
case 10 /* NEWLINE */:
this.pos += ahead;
return true;
}
} else {
this.pos += ahead;
return false;
}
ahead++;
}
this.pos = this.maxPos;
return true;
}
consumeWhitespace() {
const maxOffset = this.maxPos - this.pos;
let ahead = 0;
while (ahead < maxOffset && isWhitespaceCode(this.lookAtCharCodeAhead(ahead))) {
ahead++;
}
this.pos += ahead;
}
parse(data) {
const maxPos = this.maxPos = data.length;
this.data = data;
this.indent = "";
this.textPos = -1;
this.forward = 1;
this.isConcise = true;
this.beginMixedMode = this.endingMixedModeAtEOL = false;
this.lines = this.activeTag = this.activeAttr = void 0;
this.pos = data.charCodeAt(0) === 65279 ? 1 : 0;
this.enterState(states_exports.CONCISE_HTML_CONTENT);
while (this.pos < maxPos) {
const code = data.charCodeAt(this.pos);
if (code === 10 /* NEWLINE */) {
this.forward = 1;
this.activeState.eol.call(this, 1, this.activeRange);
} else if (code === 13 /* CARRIAGE_RETURN */ && data.charCodeAt(this.pos + 1) === 10 /* NEWLINE */) {
this.forward = 2;
this.activeState.eol.call(this, 2, this.activeRange);
} else {
this.forward = 1;
this.activeState.char.call(this, code, this.activeRange);
}
this.pos += this.forward;
}
while (this.pos === this.maxPos) {
this.forward = 1;
this.activeState.eof.call(this, this.activeRange);
if (this.forward !== 0)
break;
}
}
};
// src/states/index.ts
var states_exports = {};
__export(states_exports, {
ATTRIBUTE: () => ATTRIBUTE,
BEGIN_DELIMITED_HTML_BLOCK: () => BEGIN_DELIMITED_HTML_BLOCK,
CDATA: () => CDATA,
CLOSE_TAG: () => CLOSE_TAG,
CONCISE_HTML_CONTENT: () => CONCISE_HTML_CONTENT,
DECLARATION: () => DECLARATION,
DTD: () => DTD,
EXPRESSION: () => EXPRESSION,
HTML_COMMENT: () => HTML_COMMENT,
HTML_CONTENT: () => HTML_CONTENT,
INLINE_SCRIPT: () => INLINE_SCRIPT,
JS_COMMENT_BLOCK: () => JS_COMMENT_BLOCK,
JS_COMMENT_LINE: () => JS_COMMENT_LINE,
OPEN_TAG: () => OPEN_TAG,
PARSED_STRING: () => PARSED_STRING,
PARSED_TEXT_CONTENT: () => PARSED_TEXT_CONTENT,
PLACEHOLDER: () => PLACEHOLDER,
REGULAR_EXPRESSION: () => REGULAR_EXPRESSION,
STRING: () => STRING,
TAG_NAME: () => TAG_NAME,
TAG_STAGE: () => TAG_STAGE,
TEMPLATE_STRING: () => TEMPLATE_STRING,
checkForCDATA: () => checkForCDATA,
checkForClosingTag: () => checkForClosingTag,
checkForPlaceholder: () => checkForPlaceholder,
handleDelimitedEOL: () => handleDelimitedEOL
});
// src/states/OPEN_TAG.ts
var TAG_STAGE = /* @__PURE__ */ ((TAG_STAGE2) => {
TAG_STAGE2[TAG_STAGE2["UNKNOWN"] = 0] = "UNKNOWN";
TAG_STAGE2[TAG_STAGE2["VAR"] = 1] = "VAR";
TAG_STAGE2[TAG_STAGE2["ARGUMENT"] = 2] = "ARGUMENT";
TAG_STAGE2[TAG_STAGE2["TYPES"] = 3] = "TYPES";
TAG_STAGE2[TAG_STAGE2["PARAMS"] = 4] = "PARAMS";
TAG_STAGE2[TAG_STAGE2["ATTR_GROUP"] = 5] = "ATTR_GROUP";
return TAG_STAGE2;
})(TAG_STAGE || {});
var OPEN_TAG = {
name: "OPEN_TAG",
enter(parent, start) {
const tag = this.activeTag = {
state: OPEN_TAG,
type: 0 /* html */,
parent,
start,
end: start,
stage: 0 /* UNKNOWN */,
parentTag: this.activeTag,
nestedIndent: void 0,
indent: this.indent,
hasShorthandId: false,
hasArgs: false,
hasAttrs: false,
hasParams: false,
typeParams: void 0,
selfClosed: false,
shorthandEnd: -1,
tagName: void 0,
concise: this.isConcise,
beginMixedMode: this.beginMixedMode || this.endingMixedModeAtEOL
};
this.beginMixedMode = false;
this.endingMixedModeAtEOL = false;
this.endText();
return tag;
},
exit(tag) {
var _a, _b;
const { selfClosed } = tag;
(_b = (_a = this.options).onOpenTagEnd) == null ? void 0 : _b.call(_a, {
start: this.pos - (this.isConcise ? 0 : selfClosed ? 2 : 1),
end: this.pos,
selfClosed
});
switch (selfClosed ? 2 /* void */ : tag.type) {
case 2 /* void */:
case 3 /* statement */: {
if (tag.beginMixedMode)
this.endingMixedModeAtEOL = true;
this.activeTag = tag.parentTag;
break;
}
case 1 /* text */:
if (this.isConcise) {
this.enterState(states_exports.CONCISE_HTML_CONTENT);
} else {
this.enterState(states_exports.PARSED_TEXT_CONTENT);
}
break;
}
},
eol(_, tag) {
if (this.isConcise && tag.stage !== 5 /* ATTR_GROUP */ && !this.consumeWhitespaceIfBefore(",")) {
this.exitState();
}
},
eof(tag) {
if (this.isConcise) {
if (tag.stage === 5 /* ATTR_GROUP */) {
this.emitError(
tag,
19 /* MALFORMED_OPEN_TAG */,
'EOF reached while within an attribute group (e.g. "[ ... ]").'
);
return;
}
this.exitState();
} else {
this.emitError(
tag,
19 /* MALFORMED_OPEN_TAG */,
"EOF reached while parsing open tag"
);
}
},
char(code, tag) {
if (this.isConcise) {
if (code === 59 /* SEMICOLON */) {
this.pos++;
this.exitState();
if (!this.consumeWhitespaceOnLine(0)) {
switch (this.lookAtCharCodeAhead(0)) {
case 47 /* FORWARD_SLASH */:
switch (this.lookAtCharCodeAhead(1)) {
case 47 /* FORWARD_SLASH */:
this.enterState(states_exports.JS_COMMENT_LINE);
this.pos += 2;
return;
case 42 /* ASTERISK */:
this.enterState(states_exports.JS_COMMENT_BLOCK);
this.pos += 2;
return;
}
break;
case 60 /* OPEN_ANGLE_BRACKET */:
if (this.lookAheadFor("!--")) {
this.enterState(states_exports.HTML_COMMENT);
this.pos += 4;
return;
}
break;
}
this.emitError(
this.pos,
5 /* INVALID_CODE_AFTER_SEMICOLON */,
"A semicolon indicates the end of a line. Only comments may follow it."
);
}
return;
}
if (code === 45 /* HYPHEN */) {
if (this.lookAtCharCodeAhead(1) !== 45 /* HYPHEN */) {
this.emitError(
tag,
19 /* MALFORMED_OPEN_TAG */,
'"-" not allowed as first character of attribute name'
);
return;
}
if (tag.stage === 5 /* ATTR_GROUP */) {
this.emitError(
this.pos,
19 /* MALFORMED_OPEN_TAG */,
"Attribute group was not properly ended"
);
return;
}
this.exitState();
const maxPos = this.maxPos;
let curPos = this.pos + 1;
while (curPos < maxPos && this.data.charCodeAt(++curPos) !== 10 /* NEWLINE */)
;
const indentStart = ++curPos;
while (curPos < maxPos) {
if (isIndentCode(this.data.charCodeAt(curPos))) {
curPos++;
} else {
break;
}
}
const indentSize = curPos - indentStart;
if (indentSize > this.indent.length) {
this.indent = this.data.slice(indentStart, curPos);
}
this.enterState(states_exports.BEGIN_DELIMITED_HTML_BLOCK);
return;
} else if (code === 91 /* OPEN_SQUARE_BRACKET */) {
if (tag.stage === 5 /* ATTR_GROUP */) {
this.emitError(
this.pos,
19 /* MALFORMED_OPEN_TAG */,
'Unexpected "[" character within open tag.'
);
return;
}
tag.stage = 5 /* ATTR_GROUP */;
return;
} else if (code === 93 /* CLOSE_SQUARE_BRACKET */) {
if (tag.stage !== 5 /* ATTR_GROUP */) {
this.emitError(
this.pos,
19 /* MALFORMED_OPEN_TAG */,
'Unexpected "]" character within open tag.'
);
return;
}
tag.stage = 0 /* UNKNOWN */;
return;
}
} else if (code === 62 /* CLOSE_ANGLE_BRACKET */) {
this.pos++;
this.exitState();
return;
} else if (code === 47 /* FORWARD_SLASH */ && this.lookAtCharCodeAhead(1) === 62 /* CLOSE_ANGLE_BRACKET */) {
tag.selfClosed = true;
this.pos += 2;
this.exitState();
return;
}
if (code === 47 /* FORWARD_SLASH */) {
switch (this.lookAtCharCodeAhead(1)) {
case 47 /* FORWARD_SLASH */:
this.enterState(states_exports.JS_COMMENT_LINE);
this.pos++;
return;
case 42 /* ASTERISK */:
this.enterState(states_exports.JS_COMMENT_BLOCK);
this.pos++;
return;
}
}
if (isWhitespaceCode(code)) {
} else if (code === 44 /* COMMA */) {
this.pos++;
this.forward = 0;
this.consumeWhitespace();
} else {
this.forward = 0;
if (tag.hasAttrs) {
this.enterState(states_exports.ATTRIBUTE);
} else if (tag.tagName) {
switch (code) {
case 47 /* FORWARD_SLASH */: {
tag.stage = 1 /* VAR */;
this.pos++;
if (isWhitespaceCode(this.lookAtCharCodeAhead(0))) {
return this.emitError(
this.pos,
23 /* MISSING_TAG_VARIABLE */,
"A slash was found that was not followed by a variable name or lhs expression"
);
}
const expr = this.enterState(states_exports.EXPRESSION);
expr.operators = true;
expr.terminatedByWhitespace = true;
expr.shouldTerminate = this.isConcise ? shouldTerminateConciseTagVar : shouldTerminateHtmlTagVar;
break;
}
case 40 /* OPEN_PAREN */:
if (tag.hasArgs) {
this.emitError(
this.pos,
11 /* INVALID_TAG_ARGUMENT */,
"A tag can only have one argument"
);
return;
}
tag.hasArgs = true;
tag.stage = 2 /* ARGUMENT */;
this.pos++;
this.enterState(states_exports.EXPRESSION).shouldTerminate = matchesCloseParen;
break;
case 124 /* PIPE */:
if (tag.hasParams) {
this.emitError(
this.pos,
26 /* INVALID_TAG_PARAMS */,
"A tag can only specify parameters once"
);
return;
}
tag.hasParams = true;
tag.stage = 4 /* PARAMS */;
this.pos++;
this.enterState(states_exports.EXPRESSION).shouldTerminate = matchesPipe;
break;
case 60 /* OPEN_ANGLE_BRACKET */: {
tag.stage = 3 /* TYPES */;
this.pos++;
const expr = this.enterState(states_exports.EXPRESSION);
expr.inType = true;
expr.forceType = true;
expr.shouldTerminate = matchesCloseAngleBracket;
break;
}
default:
tag.hasAttrs = true;
this.enterState(states_exports.ATTRIBUTE);
}
} else {
this.enterState(states_exports.TAG_NAME);
}
}
},
return(child, tag) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
if (child.state !== states_exports.EXPRESSION)
return;
switch (tag.stage) {
case 1 /* VAR */: {
if (child.start === child.end) {
return this.emitError(
child,
23 /* MISSING_TAG_VARIABLE */,
"A slash was found that was not followed by a variable name or lhs expression"
);
}
(_b = (_a = this.options).onTagVar) == null ? void 0 : _b.call(_a, {
start: child.start - 1,
// include /,
end: child.end,
value: {
start: child.start,
end: child.end
}
});
break;
}
case 2 /* ARGUMENT */: {
const { typeParams } = tag;
const start = child.start - 1;
const end = ++this.pos;
const value = {
start: child.start,
end: child.end
};
if (this.consumeWhitespaceIfBefore("{")) {
const attr = this.enterState(states_exports.ATTRIBUTE);
if (typeParams) {
attr.start = typeParams.start;
attr.typeParams = typeParams;
} else {
attr.start = start;
}
attr.args = { start, end, value };
this.forward = 0;
tag.hasAttrs = true;
} else {
if (typeParams) {
this.emitError(
child,
27 /* INVALID_TAG_TYPES */,
"Unexpected types. Type arguments must directly follow a tag name and type paremeters must precede a method or tag parameters."
);
break;
}
(_d = (_c = this.options).onTagArgs) == null ? void 0 : _d.call(_c, {
start,
end,
value
});
}
break;
}
case 3 /* TYPES */: {
const { typeParams, hasParams, hasArgs } = tag;
const end = ++this.pos;
const types = {
start: child.start - 1,
// include <
end,
value: {
start: child.start,
end: child.end
}
};
if (tag.tagName.end === types.start) {
(_f = (_e = this.options).onTagTypeArgs) == null ? void 0 : _f.call(_e, types);
break;
}
this.consumeWhitespace();
const nextCode = this.lookAtCharCodeAhead(0);
if (nextCode === 124 /* PIPE */ && !hasParams) {
(_h = (_g = this.options).onTagTypeParams) == null ? void 0 : _h.call(_g, types);
} else if (nextCode === 40 /* OPEN_PAREN */ && !(typeParams || hasParams || hasArgs)) {
tag.typeParams = types;
} else {
this.emitError(
child,
27 /* INVALID_TAG_TYPES */,
"Unexpected types. Type arguments must directly follow a tag name and type paremeters must precede a method or tag parameters."
);
}
break;
}
case 4 /* PARAMS */: {
const end = ++this.pos;
(_j = (_i = this.options).onTagParams) == null ? void 0 : _j.call(_i, {
start: child.start - 1,
end,
value: {
start: child.start,
end: child.end
}
});
break;
}
}
}
};
function shouldTerminateConciseTagVar(code, data, pos, expression) {
switch (code) {
case 44 /* COMMA */:
case 61 /* EQUAL */:
case 124 /* PIPE */:
case 40 /* OPEN_PAREN */:
case 59 /* SEMICOLON */:
return true;
case 60 /* OPEN_ANGLE_BRACKET */:
return !expression.inType;
case 45 /* HYPHEN */:
return data.charCodeAt(pos + 1) === 45 /* HYPHEN */;
case 58 /* COLON */:
return data.charCodeAt(pos + 1) === 61 /* EQUAL */;
default:
return false;
}
}
function shouldTerminateHtmlTagVar(code, data, pos, expression) {
switch (code) {
case 124 /* PIPE */:
case 44 /* COMMA */:
case 61 /* EQUAL */:
case 40 /* OPEN_PAREN */:
case 62 /* CLOSE_ANGLE_BRACKET */:
return true;
case 60 /* OPEN_ANGLE_BRACKET */:
return !expression.inType;
case 58 /* COLON */:
return data.charCodeAt(pos + 1) === 61 /* EQUAL */;
case 47 /* FORWARD_SLASH */:
return data.charCodeAt(pos + 1) === 62 /* CLOSE_ANGLE_BRACKET */;
default:
return false;
}
}
// src/states/ATTRIBUTE.ts
var ATTRIBUTE = {
name: "ATTRIBUTE",
enter(parent, start) {
return this.activeAttr = {
state: ATTRIBUTE,
parent,
start,
end: start,
valueStart: start,
stage: 0 /* UNKNOWN */,
name: void 0,
args: false,
typeParams: void 0,
bound: false,
spread: false
};
},
exit() {
this.activeAttr = void 0;
},
char(code, attr) {
if (isWhitespaceCode(code)) {
return;
} else if (code === 61 /* EQUAL */ || code === 58 /* COLON */ && this.lookAtCharCodeAhead(1) === 61 /* EQUAL */ || code === 46 /* PERIOD */ && this.lookAheadFor("..")) {
attr.valueStart = this.pos;
this.forward = 0;
if (code === 58 /* COLON */) {
ensureAttrName(this, attr);
attr.bound = true;
this.pos += 2;
this.consumeWhitespace();
} else if (code === 46 /* PERIOD */) {
attr.spread = true;
this.pos += 3;
} else {
ensureAttrName(this, attr);
this.pos++;
this.consumeWhitespace();
}
attr.stage = 2 /* VALUE */;
const expr = this.enterState(states_exports.EXPRESSION);
expr.operators = true;
expr.terminatedByWhitespace = true;
expr.shouldTerminate = this.isConcise ? this.activeTag.stage === 5 /* ATTR_GROUP */ ? shouldTerminateConciseGroupedAttrValue : shouldTerminateConciseAttrValue : shouldTerminateHtmlAttrValue;
} else if (code === 40 /* OPEN_PAREN */) {
ensureAttrName(this, attr);
attr.stage = 3 /* ARGUMENT */;
this.pos++;
this.forward = 0;
this.enterState(states_exports.EXPRESSION).shouldTerminate = matchesCloseParen;
} else if (code === 60 /* OPEN_ANGLE_BRACKET */ && attr.stage === 1 /* NAME */) {
attr.stage = 4 /* TYPE_PARAMS */;
this.pos++;
this.forward = 0;
const expr = this.enterState(states_exports.EXPRESSION);
expr.inType = true;
expr.forceType = true;
expr.shouldTerminate = matchesCloseAngleBracket;
} else if (code === 123 /* OPEN_CURLY_BRACE */ && attr.args) {
ensureAttrName(this, attr);
attr.stage = 5 /* BLOCK */;
this.pos++;
this.forward = 0;
this.enterState(states_exports.EXPRESSION).shouldTerminate = matchesCloseCurlyBrace;
} else if (attr.stage === 0 /* UNKNOWN */) {
if (code === 60 /* OPEN_ANGLE_BRACKET */) {
return this.emitError(
this.pos,
2 /* INVALID_ATTRIBUTE_NAME */,
'Invalid attribute name. Attribute name cannot begin with the "<" character.'
);
}
attr.stage = 1 /* NAME */;
this.forward = 0;
const expr = this.enterState(states_exports.EXPRESSION);
expr.terminatedByWhitespace = true;
expr.shouldTerminate = this.isConcise ? this.activeTag.stage === 5 /* ATTR_GROUP */ ? shouldTerminateConciseGroupedAttrName : shouldTerminateConciseAttrName : shouldTerminateHtmlAttrName;
} else {
this.exitState();
}
},
eol() {
if (this.isConcise) {
this.exitState();
}
},
eof(attr) {
if (this.isConcise) {
this.exitState();
} else {
this.emitError(
attr,
19 /* MALFORMED_OPEN_TAG */,
'EOF reached while parsing attribute "' + (attr.name ? this.read(attr.name) : "default") + '" for the "' + this.read(this.activeTag.tagName) + '" tag'
);
}
},
return(child, attr) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
switch (attr.stage) {
case 1 /* NAME */: {
attr.name = {
start: child.start,
end: child.end
};
(_b = (_a = this.options).onAttrName) == null ? void 0 : _b.call(_a, attr.name);
break;
}
case 3 /* ARGUMENT */: {
if (attr.args) {
this.emitError(
child,
1 /* INVALID_ATTRIBUTE_ARGUMENT */,
"An attribute can only have one set of arguments"
);
return;
}
const start = child.start - 1;
const end = ++this.pos;
const value = {
start: child.start,
end: child.end
};
if (this.consumeWhitespaceIfBefore("{")) {
attr.args = {
start,
end,
value
};
} else if (attr.typeParams) {
this.emitError(
child,
1 /* INVALID_ATTRIBUTE_ARGUMENT */,
"An attribute cannot have both type parameters and arguments"
);
} else {
attr.args = true;
(_d = (_c = this.options).onAttrArgs) == null ? void 0 : _d.call(_c, {
start,
end,
value
});
}
break;
}
case 5 /* BLOCK */: {
const params = attr.args;
const end = ++this.pos;
const { typeParams } = attr;
const start = typeParams ? typeParams.start : params.start;
(_f = (_e = this.options).onAttrMethod) == null ? void 0 : _f.call(_e, {
start,
end,
params,
typeParams,
body: {
start: child.start - 1,
// include {
end,
value: {
start: child.start,
end: child.end
}
}
});
this.exitState();
break;
}
case 4 /* TYPE_PARAMS */: {
const start = child.start - 1;
const end = ++this.pos;
if (!this.consumeWhitespaceIfBefore("(")) {
return this.emitError(
child,
28 /* INVALID_ATTR_TYPE_PARAMS */,
"Attribute cannot contain type parameters unless it is a shorthand method"
);
}
attr.typeParams = {
start,
end,
value: {
start: child.start,
end: child.end
}
};
break;
}
case 2 /* VALUE */: {
if (child.start === child.end) {
return this.emitError(
child,
3 /* INVALID_ATTRIBUTE_VALUE */,
"Missing value for attribute"
);
}
if (attr.spread) {
(_h = (_g = this.options).onAttrSpread) == null ? void 0 : _h.call(_g, {
start: attr.valueStart,
end: child.end,
value: {
start: child.start,
end: child.end
}
});
} else {
(_j = (_i = this.options).onAttrValue) == null ? void 0 : _j.call(_i, {
start: attr.valueStart,
end: child.end,
bound: attr.bound,
value: {
start: child.start,
end: child.end
}
});
}
this.exitState();
break;
}
}
}
};
function ensureAttrName(parser, attr) {
var _a, _b;
if (!attr.name) {
(_b = (_a = parser.options).onAttrName) == null ? void 0 : _b.call(_a, {
start: attr.start,
end: attr.start
});
}
}
function shouldTerminateHtmlAttrName(code, data, pos) {
switch (code) {
case 44 /* COMMA */:
case 61 /* EQUAL */:
case 40 /* OPEN_PAREN */:
case 62 /* CLOSE_ANGLE_BRACKET */:
case 60 /* OPEN_ANGLE_BRACKET */:
return true;
case 58 /* COLON */:
return data.charCodeAt(pos + 1) === 61 /* EQUAL */;
case 47 /* FORWARD_SLASH */:
return data.charCodeAt(pos + 1) === 62 /* CLOSE_ANGLE_BRACKET */;
default:
return false;
}
}
function shouldTerminateHtmlAttrValue(code, data, pos) {
switch (code) {
case 44 /* COMMA */:
return true;
case 47 /* FORWARD_SLASH */:
return data.charCodeAt(pos + 1) === 62 /* CLOSE_ANGLE_BRACKET */;
case 62 /* CLOSE_ANGLE_BRACKET */:
return pos === this.start || data.charCodeAt(pos - 1) !== 61 /* EQUAL */;
default:
return false;
}
}
function shouldTerminateConciseAttrName(code, data, pos) {
switch (code) {
case 44 /* COMMA */:
case 61 /* EQUAL */:
case 40 /* OPEN_PAREN */:
case 59 /* SEMICOLON */:
case 60 /* OPEN_ANGLE_BRACKET */:
return true;
case 58 /* COLON */:
return data.charCodeAt(pos + 1) === 61 /* EQUAL */;
case 45 /* HYPHEN */:
return data.charCodeAt(pos + 1) === 45 /* HYPHEN */ && isWhitespaceCode(data.charCodeAt(pos - 1));
default:
return false;
}
}
function shouldTerminateConciseAttrValue(code, data, pos) {
switch (code) {
case 44 /* COMMA */:
case 59 /* SEMICOLON */:
return true;
case 45 /* HYPHEN */:
return data.charCodeAt(pos + 1) === 45 /* HYPHEN */ && isWhitespaceCode(data.charCodeAt(pos - 1));
default:
return false;
}
}
function shouldTerminateConciseGroupedAttrName(code, data, pos) {
switch (code) {
case 44 /* COMMA */:
case 61 /* EQUAL */:
case 40 /* OPEN_PAREN */:
case 93 /* CLOSE_SQUARE_BRACKET */:
case 60 /* OPEN_ANGLE_BRACKET */:
return true;
case 58 /* COLON */:
return data.charCodeAt(pos + 1) === 61 /* EQUAL */;
default:
return false;
}
}
function shouldTerminateConciseGroupedAttrValue(code) {
switch (code) {
case 44 /* COMMA */:
case 93 /* CLOSE_SQUARE_BRACKET */:
return true;
default:
return false;
}
}
// src/states/BEGIN_DELIMITED_HTML_BLOCK.ts
var BEGIN_DELIMITED_HTML_BLOCK = {
name: "BEGIN_DELIMITED_HTML_BLOCK",
enter(parent, start) {
return {
state: BEGIN_DELIMITED_HTML_BLOCK,
parent,
start,
end: start,
indent: this.indent,
delimiter: ""
};
},
exit() {
},
char(code, block) {
if (code === 45 /* HYPHEN */) {
block.delimiter += "-";
} else {
const startPos = this.pos;
if (!this.consumeWhitespaceOnLine()) {
this.pos = startPos + 1;
this.forward = 0;
this.beginHtmlBlock(void 0, true);
}
}
},
eol(len, block) {
this.beginHtmlBlock(block.delimiter, false);
handleDelimitedBlockEOL(this, len, block);
},
eof: htmlEOF,
return() {
}
};
function handleDelimitedEOL(parser, newLineLength, content) {
if (content.singleLine) {
parser.endText();
parser.exitState();
parser.exitState();
return true;
}
if (content.delimiter) {
handleDelimitedBlockEOL(parser, newLineLength, content);
return true;
}
return false;
}
function handleDelimitedBlockEOL(parser, newLineLength, {
indent,
delimiter
}) {
const endHtmlBlockLookahead = indent + delimiter;
if (parser.lookAheadFor(endHtmlBlockLookahead, parser.pos + newLineLength)) {
parser.startText();
parser.pos += newLineLength;
parser.endText();
parser.pos += endHtmlBlockLookahead.length;
if (parser.consumeWhitespaceOnLine(0)) {
parser.exitState();
parser.exitState();
} else {
parser.emitError(
parser.pos,
4 /* INVALID_CHARACTER */,
"A concise mode closing block delimiter can only be followed by whitespace."
);
}
} else if (parser.lookAheadFor(indent, parser.pos + newLineLength)) {
parser.startText();
parser.pos += indent.length;
} else if (indent && !parser.onlyWhitespaceRemainsOnLine(newLineLength)) {
parser.endText();
parser.exitState();
parser.exitState();
} else if (parser.pos + newLineLength !== parser.maxPos) {
parser.startText();
}
}
// src/states/CDATA.ts
var CDATA = {
name: "CDATA",
enter(parent, start) {
return {
state: CDATA,
parent,
start,
end: start
};
},
exit(cdata) {
var _a, _b;
(_b = (_a = this.options).onCDATA) == null ? void 0 : _b.call(_a, {
start: cdata.start,
end: cdata.end,
value: {
start: cdata.start + 9,
// strip <![CDATA[
end: cdata.end - 3
// strip ]]>
}
});
},
char(code) {
if (code === 93 /* CLOSE_SQUARE_BRACKET */ && this.lookAheadFor("]>")) {
this.pos += 3;
this.exitState();
return;
}
},
eol() {
},
eof(cdata) {
this.emitError(
cdata,
14 /* MALFORMED_CDATA */,
"EOF reached while parsing CDATA"
);
},
return() {
}
};
function checkForCDATA(parser) {
if (parser.lookAheadFor("![CDATA[")) {
parser.endText();
parser.enterState(CDATA);
parser.pos += 8;
return true;
}
return false;
}
// src/states/CLOSE_TAG.ts
var CLOSE_TAG = {
name: "CLOSE_TAG",
enter(parent, start) {
this.endText();
return {
state: CLOSE_TAG,
parent,
start,
end: start
};
},
exit() {
},
char(code, closeTag) {
if (code === 62 /* CLOSE_ANGLE_BRACKET */) {
this.pos++;
this.exitState();
ensureExpectedCloseTag(this, closeTag);
}
},
eol() {
},
eof(closeTag) {
this.emitError(
closeTag,
15 /* MALFORMED_CLOSE_TAG */,
"EOF reached while parsing closing tag"
);
},
return() {
}
};
function checkForClosingTag(parser) {
var _a, _b;
const curPos = parser.pos + 1;
let match = !!parser.lookAheadFor("/>");
let skip = 3;
if (!match) {
const { tagName } = parser.activeTag;
const tagNameLen = tagName.end - tagName.start;
if (tagNameLen) {
skip += tagNameLen;
match = parser.lookAheadFor("/", curPos) && parser.lookAheadFor(">", 1 + curPos + tagNameLen) && parser.matchAtPos(tagName, {
start: 1 + curPos,
end: 1 + curPos + tagNameLen
}) || false;
}
}
if (match) {
parser.endText();
(_b = (_a = parser.options).onCloseTagStart) == null ? void 0 : _b.call(_a, {
start: curPos - 1,
end: curPos + 1
});
if (ensureExpectedCloseTag(parser, {
start: parser.pos,
end: parser.pos += skip
})) {
parser.exitState();
}
return true;
}
return false;
}
function ensureExpectedCloseTag(parser, closeTag) {
const activeTag = parser.activeTag;
const closeTagNameStart = closeTag.start + 2;
const closeTagNameEnd = closeTag.end - 1;
if (!activeTag) {
parser.emitError(
closeTag,
0 /* EXTRA_CLOSING_TAG */,
'The closing "' + parser.read({ start: closeTagNameStart, end: closeTagNameEnd }) + '" tag was not expected'
);
return false;
}
const closeTagNamePos = {
start: closeTagNameStart,
end: closeTagNameEnd
};
if (closeTagNameStart < closeTagNameEnd) {
if (!parser.matchAtPos(
closeTagNamePos,
activeTag.tagName.end > activeTag.tagName.start ? activeTag.tagName : "div"
)) {
if (activeTag.shorthandEnd === void 0 || !parser.matchAtPos(closeTagNamePos, {
start: activeTag.tagName.start,
end: activeTag.shorthandEnd
})) {
parser.emitError(
closeTag,
21 /* MISMATCHED_CLOSING_TAG */,
'The closing "' + parser.read(closeTagNamePos) + '" tag does not match the corresponding opening "' + (parser.read(activeTag.tagName) || "div") + '" tag'
);
return false;
}
}
}
parser.closeTagEnd(closeTagNameEnd, closeTag.end, closeTagNamePos);
return true;
}
// src/states/CONCISE_HTML_CONTENT.ts
var CONCISE_HTML_CONTENT = {
name: "CONCISE_HTML_CONTENT",
enter(parent, start) {
this.isConcise = true;
this.indent = "";
return {
state: CONCISE_HTML_CONTENT,
parent,
start,
end: start
};
},
exit() {
},
char(code) {
if (isWhitespaceCode(code)) {
this.indent += this.data[this.pos];
} else {
const curIndent = this.indent.length;
const indentStart = this.pos - curIndent - 1;
let parentTag = this.activeTag;
while (parentTag && parentTag.indent.length >= curIndent) {
this.closeTagEnd(indentStart, indentStart, void 0);
parentTag = this.activeTag;
}
if (!parentTag && curIndent) {
if (code !== 47 /* FORWARD_SLASH */) {
this.emitError(
this.pos,
7 /* INVALID_INDENTATION */,
"Line has extra indentation at the beginning"
);
return;
}
}
if (parentTag) {
if (parentTag.type === 1 /* text */ && code !== 45 /* HYPHEN */) {
this.emitError(
this.pos,
8 /* INVALID_LINE_START */,
'A line within a tag that only allows text content must begin with a "-" character'
);
return;
}
if (parentTag.nestedIndent === void 0) {
parentTag.nestedIndent = this.indent;
} else if (parentTag.nestedIndent !== this.indent) {
this.emitError(
this.pos,
7 /* INVALID_INDENTATION */,
"Line indentation does match indentation of previous line"
);
return;
}
}
switch (code) {
case 60 /* OPEN_ANGLE_BRACKET */:
this.beginMixedMode = true;
this.pos--;
this.beginHtmlBlock(void 0, false);
return;
case 36 /* DOLLAR */:
if (isWhitespaceCode(this.lookAtCharCodeAhead(1))) {
this.pos++;
this.enterState(states_exports.INLINE_SCRIPT);
return;
}
break;
case 45 /* HYPHEN */:
if (this.lookAtCharCodeAhead(1) === 45 /* HYPHEN */) {
this.enterState(states_exports.BEGIN_DELIMITED_HTML_BLOCK);
this.pos--;
} else {
this.emitError(
this.pos,
8 /* INVALID_LINE_START */,
'A line in concise mode cannot start with a single hyphen. Use "--" instead. See: https://github.com/marko-js/htmljs-parser/issues/43'
);
}
return;
case 47 /* FORWARD_SLASH */:
switch (this.lookAtCharCodeAhead(1)) {
case 47 /* FORWARD_SLASH */:
this.enterState(states_exports.JS_COMMENT_LINE);
this.pos++;
return;
case 42 /* ASTERISK */:
this.enterState(states_exports.JS_COMMENT_BLOCK);
this.pos++;
return;
default:
this.emitError(
this.pos,
8 /* INVALID_LINE_START */,
'A line in concise mode cannot start with "/" unless it starts a "//" or "/*" comment'
);
return;
}
}
this.enterState(states_exports.OPEN_TAG);
this.forward = 0;
}
},
eol() {
this.indent = "";
},
eof: htmlEOF,
return(child) {
var _a, _b, _c, _d;
this.indent = "";
this.isConcise = true;
switch (child.state) {
case states_exports.JS_COMMENT_LINE:
(_b = (_a = this.options).onComment) == null ? void 0 : _b.call(_a, {
start: child.start,
end: child.end,
value: {
start: child.start + 2,
// strip //
end: child.end
}
});
break;
case states_exports.JS_COMMENT_BLOCK: {
(_d = (_c = this.options).onComment) == null ? void 0 : _d.call(_c, {
start: child.start,
end: child.end,
value: {
start: child.start + 2,
// strip /*
end: child.end - 2
// strip */,
}
});
if (!this.consumeWhitespaceOnLine(0)) {
this.emitError(
this.pos,
4 /* INVALID_CHARACTER */,
"In concise mode a javascript comment block can only be followed by whitespace characters and a newline."
);
}
break;
}
}
}
};
// src/states/DECLARATION.ts
var DECLARATION = {
name: "DECLARATION",
enter(parent, start) {
this.endText();
return {
state: DECLARATION,
parent,
start,
end: start
};
},
exit() {
},
char(code, declaration) {
if (code === 63 /* QUESTION */) {
if (this.lookAtCharCodeAhead(1) === 62 /* CLOSE_ANGLE_BRACKET */) {
exitDeclaration(this, declaration, 2);
}
} else if (code === 62 /* CLOSE_ANGLE_BRACKET */) {
exitDeclaration(this, declaration, 1);
}
},
eol() {
},
eof(declaration) {
this.emitError(
declaration,
17 /* MALFORMED_DECLARATION */,
"EOF reached while parsing declaration"
);
},
return() {
}
};
function exitDeclaration(parser, declaration, closeOffset) {
var _a, _b;
parser.pos += closeOffset;
parser.exitState();
(_b = (_a = parser.options).onDeclaration) == null ? void 0 : _b.call(_a, {
start: declaration.start,
end: declaration.end,
value: {
start: declaration.start + 2,
// strip <?
end: declaration.end - closeOffset
// > or ?>
}
});
}
// src/states/DTD.ts
var DTD = {
name: "DTD",
enter(parent, start) {
this.endText();
return {
state: DTD,
parent,
start,
end: start
};
},
exit(documentType) {
var _a, _b;
(_b = (_a = this.options).onDoctype) == null ? void 0 : _b.call(_a, {
start: documentType.start,
end: documentType.end,
value: {
start: documentType.start + 2,
// strip <!
end: documentType.end - 1
// strip >
}
});
},
char(code) {
if (code === 62 /* CLOSE_ANGLE_BRACKET */) {
this.pos++;
this.exitState();
}
},
eol() {
},
eof(documentType) {
this.emitError(
documentType,
18 /* MALFORMED_DOCUMENT_TYPE */,
"EOF reached while parsing document type"
);
},
return() {
}
};
// src/states/EXPRESSION.ts
var shouldTerminate = () => false;
var unaryKeywords = [
"async",
"await",
"class",
"function",
"new",
"typeof",
"void"
];
var tsUnaryKeywords = [
...unaryKeywords,
"asserts",
"infer",
"is",
"keyof",
"readonly",
"unique"
];
var binaryKeywords = [
"as",
"extends",
"instanceof",
// Note: instanceof must be checked before `in`
"in",
"satisfies"
];
var EXPRESSION = {
name: "EXPRESSION",
enter(parent, start) {
return {
state: EXPRESSION,
parent,
start,
end: start,
groupStack: [],
shouldTerminate,
operators: false,
wasComment: false,
inType: false,
forceType: false,
ternaryDepth: 0,
terminatedByEOL: false,
terminatedByWhitespace: false,
consumeIndentedContent: false
};
},
exit() {
},
char(code, expression) {
if (!expression.groupStack.length) {
if (expression.terminatedByWhitespace && isWhitespaceCode(code)) {
if (!checkForOperators(this, expression, false)) {
this.exitState();
}
return;
}
if (expression.shouldTerminate(code, this.data, this.pos, expression)) {
let wasExpression = false;
if (expression.operators) {
const prevNonWhitespacePos = lookBehindWhile(
isWhitespaceCode,
this.data,
this.pos - 1
);
if (prevNonWhitespacePos > expression.start) {
wasExpression = lookBehindForOperator(
expression,
this.data,
prevNonWhitespacePos
) !== -1;
}
}
if (!wasExpression) {
this.exitState();
return;
}
}
}
switch (code) {
case 34 /* DOUBLE_QUOTE */:
this.enterState(states_exports.STRING);
break;
case 39 /* SINGLE_QUOTE */:
this.enterState(states_exports.STRING).quoteCharCode = code;
break;
case 96 /* BACKTICK */:
this.enterState(states_exports.TEMPLATE_STRIN