|
|
|
|
@ -8,7 +8,6 @@ import parser_errors from './errors';
|
|
|
|
|
const regex_position_indicator = / \(\d+:\d+\)$/;
|
|
|
|
|
/** */
|
|
|
|
|
export class Parser {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @readonly
|
|
|
|
|
* @type {string}
|
|
|
|
|
@ -89,10 +88,13 @@ export class Parser {
|
|
|
|
|
const current = this.current();
|
|
|
|
|
const type = current.type === 'Element' ? `<${current.name}>` : 'Block';
|
|
|
|
|
const slug = current.type === 'Element' ? 'element' : 'block';
|
|
|
|
|
this.error({
|
|
|
|
|
this.error(
|
|
|
|
|
{
|
|
|
|
|
code: `unclosed-${slug}`,
|
|
|
|
|
message: `${type} was left open`
|
|
|
|
|
}, current.start);
|
|
|
|
|
},
|
|
|
|
|
current.start
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
if (state !== fragment) {
|
|
|
|
|
this.error({
|
|
|
|
|
@ -102,15 +104,12 @@ export class Parser {
|
|
|
|
|
}
|
|
|
|
|
if (this.html.children.length) {
|
|
|
|
|
let start = this.html.children[0].start;
|
|
|
|
|
while (regex_whitespace.test(template[start]))
|
|
|
|
|
start += 1;
|
|
|
|
|
while (regex_whitespace.test(template[start])) start += 1;
|
|
|
|
|
let end = this.html.children[this.html.children.length - 1].end;
|
|
|
|
|
while (regex_whitespace.test(template[end - 1]))
|
|
|
|
|
end -= 1;
|
|
|
|
|
while (regex_whitespace.test(template[end - 1])) end -= 1;
|
|
|
|
|
this.html.start = start;
|
|
|
|
|
this.html.end = end;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
} else {
|
|
|
|
|
this.html.start = this.html.end = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -121,10 +120,13 @@ export class Parser {
|
|
|
|
|
/**
|
|
|
|
|
* @param {any} err */
|
|
|
|
|
acorn_error(err) {
|
|
|
|
|
this.error({
|
|
|
|
|
this.error(
|
|
|
|
|
{
|
|
|
|
|
code: 'parse-error',
|
|
|
|
|
message: err.message.replace(regex_position_indicator, '')
|
|
|
|
|
}, err.pos);
|
|
|
|
|
},
|
|
|
|
|
err.pos
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -150,10 +152,12 @@ export class Parser {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (required) {
|
|
|
|
|
this.error(error ||
|
|
|
|
|
this.error(
|
|
|
|
|
error ||
|
|
|
|
|
(this.index === this.template.length
|
|
|
|
|
? parser_errors.unexpected_eof_token(str)
|
|
|
|
|
: parser_errors.unexpected_token(str)));
|
|
|
|
|
: parser_errors.unexpected_token(str))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
@ -169,8 +173,7 @@ export class Parser {
|
|
|
|
|
*/
|
|
|
|
|
match_regex(pattern) {
|
|
|
|
|
const match = pattern.exec(this.template.slice(this.index));
|
|
|
|
|
if (!match || match.index !== 0)
|
|
|
|
|
return null;
|
|
|
|
|
if (!match || match.index !== 0) return null;
|
|
|
|
|
return match[0];
|
|
|
|
|
}
|
|
|
|
|
allow_whitespace() {
|
|
|
|
|
@ -184,29 +187,29 @@ export class Parser {
|
|
|
|
|
*/
|
|
|
|
|
read(pattern) {
|
|
|
|
|
const result = this.match_regex(pattern);
|
|
|
|
|
if (result)
|
|
|
|
|
this.index += result.length;
|
|
|
|
|
if (result) this.index += result.length;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
read_identifier(allow_reserved = false) {
|
|
|
|
|
const start = this.index;
|
|
|
|
|
let i = this.index;
|
|
|
|
|
const code = full_char_code_at(this.template, i);
|
|
|
|
|
if (!isIdentifierStart(code, true))
|
|
|
|
|
return null;
|
|
|
|
|
if (!isIdentifierStart(code, true)) return null;
|
|
|
|
|
i += code <= 0xffff ? 1 : 2;
|
|
|
|
|
while (i < this.template.length) {
|
|
|
|
|
const code = full_char_code_at(this.template, i);
|
|
|
|
|
if (!isIdentifierChar(code, true))
|
|
|
|
|
break;
|
|
|
|
|
if (!isIdentifierChar(code, true)) break;
|
|
|
|
|
i += code <= 0xffff ? 1 : 2;
|
|
|
|
|
}
|
|
|
|
|
const identifier = this.template.slice(this.index, (this.index = i));
|
|
|
|
|
if (!allow_reserved && reserved.has(identifier)) {
|
|
|
|
|
this.error({
|
|
|
|
|
this.error(
|
|
|
|
|
{
|
|
|
|
|
code: 'unexpected-reserved-word',
|
|
|
|
|
message: `'${identifier}' is a reserved word in JavaScript and cannot be used here`
|
|
|
|
|
}, start);
|
|
|
|
|
},
|
|
|
|
|
start
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return identifier;
|
|
|
|
|
}
|
|
|
|
|
@ -217,10 +220,12 @@ export class Parser {
|
|
|
|
|
*/
|
|
|
|
|
read_until(pattern, error_message) {
|
|
|
|
|
if (this.index >= this.template.length) {
|
|
|
|
|
this.error(error_message || {
|
|
|
|
|
this.error(
|
|
|
|
|
error_message || {
|
|
|
|
|
code: 'unexpected-eof',
|
|
|
|
|
message: 'Unexpected end of input'
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
const start = this.index;
|
|
|
|
|
const match = pattern.exec(this.template.slice(start));
|
|
|
|
|
@ -270,7 +275,6 @@ export default function parse(template, options = {}) {
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @typedef {(parser: Parser) => ParserState | void} ParserState */
|
|
|
|
|
|
|
|
|
|
/** @typedef {Object} LastAutoClosedTag
|
|
|
|
|
|