Lint and format src/compiler/parse/state/mustache.js

pull/8569/head
Simon Holthausen 3 years ago
parent d5e61674af
commit 072022ac9f

@ -12,26 +12,23 @@ import parser_errors from '../errors';
* @param {boolean} trim_after * @param {boolean} trim_after
*/ */
function trim_whitespace(block, trim_before, trim_after) { function trim_whitespace(block, trim_before, trim_after) {
if (!block.children || block.children.length === 0) if (!block.children || block.children.length === 0) return; // AwaitBlock
return; // AwaitBlock const first_child = block.children[0];
const first_child = block.children[0]; const last_child = block.children[block.children.length - 1];
const last_child = block.children[block.children.length - 1]; if (first_child.type === 'Text' && trim_before) {
if (first_child.type === 'Text' && trim_before) { first_child.data = trim_start(first_child.data);
first_child.data = trim_start(first_child.data); if (!first_child.data) block.children.shift();
if (!first_child.data) }
block.children.shift(); if (last_child.type === 'Text' && trim_after) {
} last_child.data = trim_end(last_child.data);
if (last_child.type === 'Text' && trim_after) { if (!last_child.data) block.children.pop();
last_child.data = trim_end(last_child.data); }
if (!last_child.data) if (block.else) {
block.children.pop(); trim_whitespace(block.else, trim_before, trim_after);
} }
if (block.else) { if (first_child.elseif) {
trim_whitespace(block.else, trim_before, trim_after); trim_whitespace(first_child, trim_before, trim_after);
} }
if (first_child.elseif) {
trim_whitespace(first_child, trim_before, trim_after);
}
} }
const regex_whitespace_with_closing_curly_brace = /^\s*}/; const regex_whitespace_with_closing_curly_brace = /^\s*}/;
@ -39,343 +36,331 @@ const regex_whitespace_with_closing_curly_brace = /^\s*}/;
* @param {Parser} parser * @param {Parser} parser
*/ */
export default function mustache(parser) { export default function mustache(parser) {
const start = parser.index; const start = parser.index;
parser.index += 1; parser.index += 1;
parser.allow_whitespace(); parser.allow_whitespace();
// {/if}, {/each}, {/await} or {/key} // {/if}, {/each}, {/await} or {/key}
if (parser.eat('/')) { if (parser.eat('/')) {
let block = parser.current(); let block = parser.current();
let expected; let expected;
if (closing_tag_omitted(block.name)) { if (closing_tag_omitted(block.name)) {
block.end = start; block.end = start;
parser.stack.pop(); parser.stack.pop();
block = parser.current(); block = parser.current();
} }
if (block.type === 'ElseBlock' || if (
block.type === 'PendingBlock' || block.type === 'ElseBlock' ||
block.type === 'ThenBlock' || block.type === 'PendingBlock' ||
block.type === 'CatchBlock') { block.type === 'ThenBlock' ||
block.end = start; block.type === 'CatchBlock'
parser.stack.pop(); ) {
block = parser.current(); block.end = start;
expected = 'await'; parser.stack.pop();
} block = parser.current();
if (block.type === 'IfBlock') { expected = 'await';
expected = 'if'; }
} if (block.type === 'IfBlock') {
else if (block.type === 'EachBlock') { expected = 'if';
expected = 'each'; } else if (block.type === 'EachBlock') {
} expected = 'each';
else if (block.type === 'AwaitBlock') { } else if (block.type === 'AwaitBlock') {
expected = 'await'; expected = 'await';
} } else if (block.type === 'KeyBlock') {
else if (block.type === 'KeyBlock') { expected = 'key';
expected = 'key'; } else {
} parser.error(parser_errors.unexpected_block_close);
else { }
parser.error(parser_errors.unexpected_block_close); parser.eat(expected, true);
} parser.allow_whitespace();
parser.eat(expected, true); parser.eat('}', true);
parser.allow_whitespace(); while (block.elseif) {
parser.eat('}', true); block.end = parser.index;
while (block.elseif) { parser.stack.pop();
block.end = parser.index; block = parser.current();
parser.stack.pop(); if (block.else) {
block = parser.current(); block.else.end = start;
if (block.else) { }
block.else.end = start; }
} // strip leading/trailing whitespace as necessary
} const char_before = parser.template[block.start - 1];
// strip leading/trailing whitespace as necessary const char_after = parser.template[parser.index];
const char_before = parser.template[block.start - 1]; const trim_before = !char_before || regex_whitespace.test(char_before);
const char_after = parser.template[parser.index]; const trim_after = !char_after || regex_whitespace.test(char_after);
const trim_before = !char_before || regex_whitespace.test(char_before); trim_whitespace(block, trim_before, trim_after);
const trim_after = !char_after || regex_whitespace.test(char_after); block.end = parser.index;
trim_whitespace(block, trim_before, trim_after); parser.stack.pop();
block.end = parser.index; } else if (parser.eat(':else')) {
parser.stack.pop(); if (parser.eat('if')) {
} parser.error(parser_errors.invalid_elseif);
else if (parser.eat(':else')) { }
if (parser.eat('if')) { parser.allow_whitespace();
parser.error(parser_errors.invalid_elseif); // :else if
} if (parser.eat('if')) {
parser.allow_whitespace(); const block = parser.current();
// :else if if (block.type !== 'IfBlock') {
if (parser.eat('if')) { parser.error(
const block = parser.current(); parser.stack.some((block) => block.type === 'IfBlock')
if (block.type !== 'IfBlock') { ? parser_errors.invalid_elseif_placement_unclosed_block(to_string(block))
parser.error(parser.stack.some((block) => block.type === 'IfBlock') : parser_errors.invalid_elseif_placement_outside_if
? parser_errors.invalid_elseif_placement_unclosed_block(to_string(block)) );
: parser_errors.invalid_elseif_placement_outside_if); }
} parser.require_whitespace();
parser.require_whitespace(); const expression = read_expression(parser);
const expression = read_expression(parser); parser.allow_whitespace();
parser.allow_whitespace(); parser.eat('}', true);
parser.eat('}', true); block.else = {
block.else = { start: parser.index,
start: parser.index, end: null,
end: null, type: 'ElseBlock',
type: 'ElseBlock', children: [
children: [ {
{ start: parser.index,
start: parser.index, end: null,
end: null, type: 'IfBlock',
type: 'IfBlock', elseif: true,
elseif: true, expression,
expression, children: []
children: [] }
} ]
] };
}; parser.stack.push(block.else.children[0]);
parser.stack.push(block.else.children[0]); } else {
} // :else
else { const block = parser.current();
// :else if (block.type !== 'IfBlock' && block.type !== 'EachBlock') {
const block = parser.current(); parser.error(
if (block.type !== 'IfBlock' && block.type !== 'EachBlock') { parser.stack.some((block) => block.type === 'IfBlock' || block.type === 'EachBlock')
parser.error(parser.stack.some((block) => block.type === 'IfBlock' || block.type === 'EachBlock') ? parser_errors.invalid_else_placement_unclosed_block(to_string(block))
? parser_errors.invalid_else_placement_unclosed_block(to_string(block)) : parser_errors.invalid_else_placement_outside_if
: parser_errors.invalid_else_placement_outside_if); );
} }
parser.allow_whitespace(); parser.allow_whitespace();
parser.eat('}', true); parser.eat('}', true);
block.else = { block.else = {
start: parser.index, start: parser.index,
end: null, end: null,
type: 'ElseBlock', type: 'ElseBlock',
children: [] children: []
}; };
parser.stack.push(block.else); parser.stack.push(block.else);
} }
} } else if (parser.match(':then') || parser.match(':catch')) {
else if (parser.match(':then') || parser.match(':catch')) { const block = parser.current();
const block = parser.current(); const is_then = parser.eat(':then') || !parser.eat(':catch');
const is_then = parser.eat(':then') || !parser.eat(':catch'); if (is_then) {
if (is_then) { if (block.type !== 'PendingBlock') {
if (block.type !== 'PendingBlock') { parser.error(
parser.error(parser.stack.some((block) => block.type === 'PendingBlock') parser.stack.some((block) => block.type === 'PendingBlock')
? parser_errors.invalid_then_placement_unclosed_block(to_string(block)) ? parser_errors.invalid_then_placement_unclosed_block(to_string(block))
: parser_errors.invalid_then_placement_without_await); : parser_errors.invalid_then_placement_without_await
} );
} }
else { } else {
if (block.type !== 'ThenBlock' && block.type !== 'PendingBlock') { if (block.type !== 'ThenBlock' && block.type !== 'PendingBlock') {
parser.error(parser.stack.some((block) => block.type === 'ThenBlock' || block.type === 'PendingBlock') parser.error(
? parser_errors.invalid_catch_placement_unclosed_block(to_string(block)) parser.stack.some((block) => block.type === 'ThenBlock' || block.type === 'PendingBlock')
: parser_errors.invalid_catch_placement_without_await); ? parser_errors.invalid_catch_placement_unclosed_block(to_string(block))
} : parser_errors.invalid_catch_placement_without_await
} );
block.end = start; }
parser.stack.pop(); }
const await_block = parser.current(); block.end = start;
if (!parser.eat('}')) { parser.stack.pop();
parser.require_whitespace(); const await_block = parser.current();
await_block[is_then ? 'value' : 'error'] = read_context(parser); if (!parser.eat('}')) {
parser.allow_whitespace(); parser.require_whitespace();
parser.eat('}', true); await_block[is_then ? 'value' : 'error'] = read_context(parser);
} parser.allow_whitespace();
const new_block = { parser.eat('}', true);
start, }
end: null, const new_block = {
type: is_then ? 'ThenBlock' : 'CatchBlock', start,
children: [], end: null,
skip: false type: is_then ? 'ThenBlock' : 'CatchBlock',
}; children: [],
await_block[is_then ? 'then' : 'catch'] = new_block; skip: false
parser.stack.push(new_block); };
} await_block[is_then ? 'then' : 'catch'] = new_block;
else if (parser.eat('#')) { parser.stack.push(new_block);
// {#if foo}, {#each foo} or {#await foo} } else if (parser.eat('#')) {
let type; // {#if foo}, {#each foo} or {#await foo}
if (parser.eat('if')) { let type;
type = 'IfBlock'; if (parser.eat('if')) {
} type = 'IfBlock';
else if (parser.eat('each')) { } else if (parser.eat('each')) {
type = 'EachBlock'; type = 'EachBlock';
} } else if (parser.eat('await')) {
else if (parser.eat('await')) { type = 'AwaitBlock';
type = 'AwaitBlock'; } else if (parser.eat('key')) {
} type = 'KeyBlock';
else if (parser.eat('key')) { } else {
type = 'KeyBlock'; parser.error(parser_errors.expected_block_type);
} }
else { parser.require_whitespace();
parser.error(parser_errors.expected_block_type); const expression = read_expression(parser);
} const block =
parser.require_whitespace(); type === 'AwaitBlock'
const expression = read_expression(parser); ? {
const block = type === 'AwaitBlock' start,
? { end: null,
start, type,
end: null, expression,
type, value: null,
expression, error: null,
value: null, pending: {
error: null, start: null,
pending: { end: null,
start: null, type: 'PendingBlock',
end: null, children: [],
type: 'PendingBlock', skip: true
children: [], },
skip: true then: {
}, start: null,
then: { end: null,
start: null, type: 'ThenBlock',
end: null, children: [],
type: 'ThenBlock', skip: true
children: [], },
skip: true catch: {
}, start: null,
catch: { end: null,
start: null, type: 'CatchBlock',
end: null, children: [],
type: 'CatchBlock', skip: true
children: [], }
skip: true }
} : {
} start,
: { end: null,
start, type,
end: null, expression,
type, children: []
expression, };
children: [] parser.allow_whitespace();
}; // {#each} blocks must declare a context {#each list as item}
parser.allow_whitespace(); if (type === 'EachBlock') {
// {#each} blocks must declare a context {#each list as item} parser.eat('as', true);
if (type === 'EachBlock') { parser.require_whitespace();
parser.eat('as', true); block.context = read_context(parser);
parser.require_whitespace(); parser.allow_whitespace();
block.context = read_context(parser); if (parser.eat(',')) {
parser.allow_whitespace(); parser.allow_whitespace();
if (parser.eat(',')) { block.index = parser.read_identifier();
parser.allow_whitespace(); if (!block.index) parser.error(parser_errors.expected_name);
block.index = parser.read_identifier(); parser.allow_whitespace();
if (!block.index) }
parser.error(parser_errors.expected_name); if (parser.eat('(')) {
parser.allow_whitespace(); parser.allow_whitespace();
} block.key = read_expression(parser);
if (parser.eat('(')) { parser.allow_whitespace();
parser.allow_whitespace(); parser.eat(')', true);
block.key = read_expression(parser); parser.allow_whitespace();
parser.allow_whitespace(); }
parser.eat(')', true); }
parser.allow_whitespace(); const await_block_shorthand = type === 'AwaitBlock' && parser.eat('then');
} if (await_block_shorthand) {
} if (parser.match_regex(regex_whitespace_with_closing_curly_brace)) {
const await_block_shorthand = type === 'AwaitBlock' && parser.eat('then'); parser.allow_whitespace();
if (await_block_shorthand) { } else {
if (parser.match_regex(regex_whitespace_with_closing_curly_brace)) { parser.require_whitespace();
parser.allow_whitespace(); block.value = read_context(parser);
} parser.allow_whitespace();
else { }
parser.require_whitespace(); }
block.value = read_context(parser); const await_block_catch_shorthand =
parser.allow_whitespace(); !await_block_shorthand && type === 'AwaitBlock' && parser.eat('catch');
} if (await_block_catch_shorthand) {
} if (parser.match_regex(regex_whitespace_with_closing_curly_brace)) {
const await_block_catch_shorthand = !await_block_shorthand && type === 'AwaitBlock' && parser.eat('catch'); parser.allow_whitespace();
if (await_block_catch_shorthand) { } else {
if (parser.match_regex(regex_whitespace_with_closing_curly_brace)) { parser.require_whitespace();
parser.allow_whitespace(); block.error = read_context(parser);
} parser.allow_whitespace();
else { }
parser.require_whitespace(); }
block.error = read_context(parser); parser.eat('}', true);
parser.allow_whitespace(); parser.current().children.push(block);
} parser.stack.push(block);
} if (type === 'AwaitBlock') {
parser.eat('}', true); let child_block;
parser.current().children.push(block); if (await_block_shorthand) {
parser.stack.push(block); block.then.skip = false;
if (type === 'AwaitBlock') { child_block = block.then;
let child_block; } else if (await_block_catch_shorthand) {
if (await_block_shorthand) { block.catch.skip = false;
block.then.skip = false; child_block = block.catch;
child_block = block.then; } else {
} block.pending.skip = false;
else if (await_block_catch_shorthand) { child_block = block.pending;
block.catch.skip = false; }
child_block = block.catch; child_block.start = parser.index;
} parser.stack.push(child_block);
else { }
block.pending.skip = false; } else if (parser.eat('@html')) {
child_block = block.pending; // {@html content} tag
} parser.require_whitespace();
child_block.start = parser.index; const expression = read_expression(parser);
parser.stack.push(child_block); parser.allow_whitespace();
} parser.eat('}', true);
} parser.current().children.push({
else if (parser.eat('@html')) { start,
// {@html content} tag end: parser.index,
parser.require_whitespace(); type: 'RawMustacheTag',
const expression = read_expression(parser); expression
parser.allow_whitespace(); });
parser.eat('}', true); } else if (parser.eat('@debug')) {
parser.current().children.push({ let identifiers;
start, // Implies {@debug} which indicates "debug all"
end: parser.index, if (parser.read(regex_whitespace_with_closing_curly_brace)) {
type: 'RawMustacheTag', identifiers = [];
expression } else {
}); const expression = read_expression(parser);
} identifiers =
else if (parser.eat('@debug')) { expression.type === 'SequenceExpression' ? expression.expressions : [expression];
let identifiers; identifiers.forEach((node) => {
// Implies {@debug} which indicates "debug all" if (node.type !== 'Identifier') {
if (parser.read(regex_whitespace_with_closing_curly_brace)) { parser.error(parser_errors.invalid_debug_args, node.start);
identifiers = []; }
} });
else { parser.allow_whitespace();
const expression = read_expression(parser); parser.eat('}', true);
identifiers = }
expression.type === 'SequenceExpression' ? expression.expressions : [expression]; parser.current().children.push({
identifiers.forEach((node) => { start,
if (node.type !== 'Identifier') { end: parser.index,
parser.error(parser_errors.invalid_debug_args, node.start); type: 'DebugTag',
} identifiers
}); });
parser.allow_whitespace(); } else if (parser.eat('@const')) {
parser.eat('}', true); // {@const a = b}
} parser.require_whitespace();
parser.current().children.push({ const expression = read_expression(parser);
start, if (!(expression.type === 'AssignmentExpression' && expression.operator === '=')) {
end: parser.index, parser.error(
type: 'DebugTag', {
identifiers code: 'invalid-const-args',
}); message: '{@const ...} must be an assignment.'
} },
else if (parser.eat('@const')) { start
// {@const a = b} );
parser.require_whitespace(); }
const expression = read_expression(parser); parser.allow_whitespace();
if (!(expression.type === 'AssignmentExpression' && expression.operator === '=')) { parser.eat('}', true);
parser.error({ parser.current().children.push({
code: 'invalid-const-args', start,
message: '{@const ...} must be an assignment.' end: parser.index,
}, start); type: 'ConstTag',
} expression
parser.allow_whitespace(); });
parser.eat('}', true); } else {
parser.current().children.push({ const expression = read_expression(parser);
start, parser.allow_whitespace();
end: parser.index, parser.eat('}', true);
type: 'ConstTag', parser.current().children.push({
expression start,
}); end: parser.index,
} type: 'MustacheTag',
else { expression
const expression = read_expression(parser); });
parser.allow_whitespace(); }
parser.eat('}', true);
parser.current().children.push({
start,
end: parser.index,
type: 'MustacheTag',
expression
});
}
} }

Loading…
Cancel
Save