|
|
|
|
@ -12,19 +12,16 @@ import parser_errors from '../errors';
|
|
|
|
|
* @param {boolean} trim_after
|
|
|
|
|
*/
|
|
|
|
|
function trim_whitespace(block, trim_before, trim_after) {
|
|
|
|
|
if (!block.children || block.children.length === 0)
|
|
|
|
|
return; // AwaitBlock
|
|
|
|
|
if (!block.children || block.children.length === 0) return; // AwaitBlock
|
|
|
|
|
const first_child = block.children[0];
|
|
|
|
|
const last_child = block.children[block.children.length - 1];
|
|
|
|
|
if (first_child.type === 'Text' && trim_before) {
|
|
|
|
|
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.data)
|
|
|
|
|
block.children.pop();
|
|
|
|
|
if (!last_child.data) block.children.pop();
|
|
|
|
|
}
|
|
|
|
|
if (block.else) {
|
|
|
|
|
trim_whitespace(block.else, trim_before, trim_after);
|
|
|
|
|
@ -51,10 +48,12 @@ export default function mustache(parser) {
|
|
|
|
|
parser.stack.pop();
|
|
|
|
|
block = parser.current();
|
|
|
|
|
}
|
|
|
|
|
if (block.type === 'ElseBlock' ||
|
|
|
|
|
if (
|
|
|
|
|
block.type === 'ElseBlock' ||
|
|
|
|
|
block.type === 'PendingBlock' ||
|
|
|
|
|
block.type === 'ThenBlock' ||
|
|
|
|
|
block.type === 'CatchBlock') {
|
|
|
|
|
block.type === 'CatchBlock'
|
|
|
|
|
) {
|
|
|
|
|
block.end = start;
|
|
|
|
|
parser.stack.pop();
|
|
|
|
|
block = parser.current();
|
|
|
|
|
@ -62,17 +61,13 @@ export default function mustache(parser) {
|
|
|
|
|
}
|
|
|
|
|
if (block.type === 'IfBlock') {
|
|
|
|
|
expected = 'if';
|
|
|
|
|
}
|
|
|
|
|
else if (block.type === 'EachBlock') {
|
|
|
|
|
} else if (block.type === 'EachBlock') {
|
|
|
|
|
expected = 'each';
|
|
|
|
|
}
|
|
|
|
|
else if (block.type === 'AwaitBlock') {
|
|
|
|
|
} else if (block.type === 'AwaitBlock') {
|
|
|
|
|
expected = 'await';
|
|
|
|
|
}
|
|
|
|
|
else if (block.type === 'KeyBlock') {
|
|
|
|
|
} else if (block.type === 'KeyBlock') {
|
|
|
|
|
expected = 'key';
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
} else {
|
|
|
|
|
parser.error(parser_errors.unexpected_block_close);
|
|
|
|
|
}
|
|
|
|
|
parser.eat(expected, true);
|
|
|
|
|
@ -94,8 +89,7 @@ export default function mustache(parser) {
|
|
|
|
|
trim_whitespace(block, trim_before, trim_after);
|
|
|
|
|
block.end = parser.index;
|
|
|
|
|
parser.stack.pop();
|
|
|
|
|
}
|
|
|
|
|
else if (parser.eat(':else')) {
|
|
|
|
|
} else if (parser.eat(':else')) {
|
|
|
|
|
if (parser.eat('if')) {
|
|
|
|
|
parser.error(parser_errors.invalid_elseif);
|
|
|
|
|
}
|
|
|
|
|
@ -104,9 +98,11 @@ export default function mustache(parser) {
|
|
|
|
|
if (parser.eat('if')) {
|
|
|
|
|
const block = parser.current();
|
|
|
|
|
if (block.type !== 'IfBlock') {
|
|
|
|
|
parser.error(parser.stack.some((block) => block.type === 'IfBlock')
|
|
|
|
|
parser.error(
|
|
|
|
|
parser.stack.some((block) => block.type === 'IfBlock')
|
|
|
|
|
? parser_errors.invalid_elseif_placement_unclosed_block(to_string(block))
|
|
|
|
|
: parser_errors.invalid_elseif_placement_outside_if);
|
|
|
|
|
: parser_errors.invalid_elseif_placement_outside_if
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
parser.require_whitespace();
|
|
|
|
|
const expression = read_expression(parser);
|
|
|
|
|
@ -128,14 +124,15 @@ export default function mustache(parser) {
|
|
|
|
|
]
|
|
|
|
|
};
|
|
|
|
|
parser.stack.push(block.else.children[0]);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
} else {
|
|
|
|
|
// :else
|
|
|
|
|
const block = parser.current();
|
|
|
|
|
if (block.type !== 'IfBlock' && block.type !== 'EachBlock') {
|
|
|
|
|
parser.error(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_outside_if);
|
|
|
|
|
: parser_errors.invalid_else_placement_outside_if
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
parser.allow_whitespace();
|
|
|
|
|
parser.eat('}', true);
|
|
|
|
|
@ -147,22 +144,24 @@ export default function mustache(parser) {
|
|
|
|
|
};
|
|
|
|
|
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 is_then = parser.eat(':then') || !parser.eat(':catch');
|
|
|
|
|
if (is_then) {
|
|
|
|
|
if (block.type !== 'PendingBlock') {
|
|
|
|
|
parser.error(parser.stack.some((block) => block.type === 'PendingBlock')
|
|
|
|
|
parser.error(
|
|
|
|
|
parser.stack.some((block) => block.type === 'PendingBlock')
|
|
|
|
|
? 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') {
|
|
|
|
|
parser.error(parser.stack.some((block) => block.type === 'ThenBlock' || block.type === 'PendingBlock')
|
|
|
|
|
parser.error(
|
|
|
|
|
parser.stack.some((block) => block.type === 'ThenBlock' || block.type === 'PendingBlock')
|
|
|
|
|
? parser_errors.invalid_catch_placement_unclosed_block(to_string(block))
|
|
|
|
|
: parser_errors.invalid_catch_placement_without_await);
|
|
|
|
|
: parser_errors.invalid_catch_placement_without_await
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
block.end = start;
|
|
|
|
|
@ -183,28 +182,24 @@ export default function mustache(parser) {
|
|
|
|
|
};
|
|
|
|
|
await_block[is_then ? 'then' : 'catch'] = new_block;
|
|
|
|
|
parser.stack.push(new_block);
|
|
|
|
|
}
|
|
|
|
|
else if (parser.eat('#')) {
|
|
|
|
|
} else if (parser.eat('#')) {
|
|
|
|
|
// {#if foo}, {#each foo} or {#await foo}
|
|
|
|
|
let type;
|
|
|
|
|
if (parser.eat('if')) {
|
|
|
|
|
type = 'IfBlock';
|
|
|
|
|
}
|
|
|
|
|
else if (parser.eat('each')) {
|
|
|
|
|
} else if (parser.eat('each')) {
|
|
|
|
|
type = 'EachBlock';
|
|
|
|
|
}
|
|
|
|
|
else if (parser.eat('await')) {
|
|
|
|
|
} else if (parser.eat('await')) {
|
|
|
|
|
type = 'AwaitBlock';
|
|
|
|
|
}
|
|
|
|
|
else if (parser.eat('key')) {
|
|
|
|
|
} else if (parser.eat('key')) {
|
|
|
|
|
type = 'KeyBlock';
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
} else {
|
|
|
|
|
parser.error(parser_errors.expected_block_type);
|
|
|
|
|
}
|
|
|
|
|
parser.require_whitespace();
|
|
|
|
|
const expression = read_expression(parser);
|
|
|
|
|
const block = type === 'AwaitBlock'
|
|
|
|
|
const block =
|
|
|
|
|
type === 'AwaitBlock'
|
|
|
|
|
? {
|
|
|
|
|
start,
|
|
|
|
|
end: null,
|
|
|
|
|
@ -251,8 +246,7 @@ export default function mustache(parser) {
|
|
|
|
|
if (parser.eat(',')) {
|
|
|
|
|
parser.allow_whitespace();
|
|
|
|
|
block.index = parser.read_identifier();
|
|
|
|
|
if (!block.index)
|
|
|
|
|
parser.error(parser_errors.expected_name);
|
|
|
|
|
if (!block.index) parser.error(parser_errors.expected_name);
|
|
|
|
|
parser.allow_whitespace();
|
|
|
|
|
}
|
|
|
|
|
if (parser.eat('(')) {
|
|
|
|
|
@ -267,19 +261,18 @@ export default function mustache(parser) {
|
|
|
|
|
if (await_block_shorthand) {
|
|
|
|
|
if (parser.match_regex(regex_whitespace_with_closing_curly_brace)) {
|
|
|
|
|
parser.allow_whitespace();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
} else {
|
|
|
|
|
parser.require_whitespace();
|
|
|
|
|
block.value = read_context(parser);
|
|
|
|
|
parser.allow_whitespace();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const await_block_catch_shorthand = !await_block_shorthand && type === 'AwaitBlock' && parser.eat('catch');
|
|
|
|
|
const await_block_catch_shorthand =
|
|
|
|
|
!await_block_shorthand && type === 'AwaitBlock' && parser.eat('catch');
|
|
|
|
|
if (await_block_catch_shorthand) {
|
|
|
|
|
if (parser.match_regex(regex_whitespace_with_closing_curly_brace)) {
|
|
|
|
|
parser.allow_whitespace();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
} else {
|
|
|
|
|
parser.require_whitespace();
|
|
|
|
|
block.error = read_context(parser);
|
|
|
|
|
parser.allow_whitespace();
|
|
|
|
|
@ -293,20 +286,17 @@ export default function mustache(parser) {
|
|
|
|
|
if (await_block_shorthand) {
|
|
|
|
|
block.then.skip = false;
|
|
|
|
|
child_block = block.then;
|
|
|
|
|
}
|
|
|
|
|
else if (await_block_catch_shorthand) {
|
|
|
|
|
} else if (await_block_catch_shorthand) {
|
|
|
|
|
block.catch.skip = false;
|
|
|
|
|
child_block = block.catch;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
} else {
|
|
|
|
|
block.pending.skip = false;
|
|
|
|
|
child_block = block.pending;
|
|
|
|
|
}
|
|
|
|
|
child_block.start = parser.index;
|
|
|
|
|
parser.stack.push(child_block);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (parser.eat('@html')) {
|
|
|
|
|
} else if (parser.eat('@html')) {
|
|
|
|
|
// {@html content} tag
|
|
|
|
|
parser.require_whitespace();
|
|
|
|
|
const expression = read_expression(parser);
|
|
|
|
|
@ -318,14 +308,12 @@ export default function mustache(parser) {
|
|
|
|
|
type: 'RawMustacheTag',
|
|
|
|
|
expression
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
else if (parser.eat('@debug')) {
|
|
|
|
|
} else if (parser.eat('@debug')) {
|
|
|
|
|
let identifiers;
|
|
|
|
|
// Implies {@debug} which indicates "debug all"
|
|
|
|
|
if (parser.read(regex_whitespace_with_closing_curly_brace)) {
|
|
|
|
|
identifiers = [];
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
} else {
|
|
|
|
|
const expression = read_expression(parser);
|
|
|
|
|
identifiers =
|
|
|
|
|
expression.type === 'SequenceExpression' ? expression.expressions : [expression];
|
|
|
|
|
@ -343,16 +331,18 @@ export default function mustache(parser) {
|
|
|
|
|
type: 'DebugTag',
|
|
|
|
|
identifiers
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
else if (parser.eat('@const')) {
|
|
|
|
|
} else if (parser.eat('@const')) {
|
|
|
|
|
// {@const a = b}
|
|
|
|
|
parser.require_whitespace();
|
|
|
|
|
const expression = read_expression(parser);
|
|
|
|
|
if (!(expression.type === 'AssignmentExpression' && expression.operator === '=')) {
|
|
|
|
|
parser.error({
|
|
|
|
|
parser.error(
|
|
|
|
|
{
|
|
|
|
|
code: 'invalid-const-args',
|
|
|
|
|
message: '{@const ...} must be an assignment.'
|
|
|
|
|
}, start);
|
|
|
|
|
},
|
|
|
|
|
start
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
parser.allow_whitespace();
|
|
|
|
|
parser.eat('}', true);
|
|
|
|
|
@ -362,8 +352,7 @@ export default function mustache(parser) {
|
|
|
|
|
type: 'ConstTag',
|
|
|
|
|
expression
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
} else {
|
|
|
|
|
const expression = read_expression(parser);
|
|
|
|
|
parser.allow_whitespace();
|
|
|
|
|
parser.eat('}', true);
|
|
|
|
|
@ -375,7 +364,3 @@ export default function mustache(parser) {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|