Skip to content

Commit b619d69

Browse files
crisbetothePunderWoman
authored andcommitted
fix(compiler): produce less noisy errors when parsing control flow (#57711)
Currently several parsing errors in the new control flow (e.g. missing `track` expression) produce errors whose span targets the entire block. This can be really noisy in the IDE where the error can span many lines in the template. These changes switch to highlighting just the start of the block. PR Close #57711
1 parent 0a86b49 commit b619d69

File tree

1 file changed

+22
-12
lines changed

1 file changed

+22
-12
lines changed

packages/compiler/src/render3/r3_control_flow.ts

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ export function createForLoop(
183183
if (params.trackBy === null) {
184184
// TODO: We should not fail here, and instead try to produce some AST for the language
185185
// service.
186-
errors.push(new ParseError(ast.sourceSpan, '@for loop must have a "track" expression'));
186+
errors.push(new ParseError(ast.startSourceSpan, '@for loop must have a "track" expression'));
187187
} else {
188188
// The `for` block has a main span that includes the `empty` branch. For only the span of the
189189
// main `for` body, use `mainSourceSpan`.
@@ -284,7 +284,7 @@ function parseForLoopParameters(
284284
bindingParser: BindingParser,
285285
) {
286286
if (block.parameters.length === 0) {
287-
errors.push(new ParseError(block.sourceSpan, '@for loop does not have an expression'));
287+
errors.push(new ParseError(block.startSourceSpan, '@for loop does not have an expression'));
288288
return null;
289289
}
290290

@@ -372,7 +372,9 @@ function parseForLoopParameters(
372372
} else {
373373
const expression = parseBlockParameterToBinding(param, bindingParser, trackMatch[1]);
374374
if (expression.ast instanceof EmptyExpr) {
375-
errors.push(new ParseError(param.sourceSpan, '@for loop must have a "track" expression'));
375+
errors.push(
376+
new ParseError(block.startSourceSpan, '@for loop must have a "track" expression'),
377+
);
376378
}
377379
const keywordSpan = new ParseSourceSpan(
378380
param.sourceSpan.start,
@@ -481,18 +483,20 @@ function validateIfConnectedBlocks(connectedBlocks: html.Block[]): ParseError[]
481483

482484
if (block.name === 'else') {
483485
if (hasElse) {
484-
errors.push(new ParseError(block.sourceSpan, 'Conditional can only have one @else block'));
486+
errors.push(
487+
new ParseError(block.startSourceSpan, 'Conditional can only have one @else block'),
488+
);
485489
} else if (connectedBlocks.length > 1 && i < connectedBlocks.length - 1) {
486490
errors.push(
487-
new ParseError(block.sourceSpan, '@else block must be last inside the conditional'),
491+
new ParseError(block.startSourceSpan, '@else block must be last inside the conditional'),
488492
);
489493
} else if (block.parameters.length > 0) {
490-
errors.push(new ParseError(block.sourceSpan, '@else block cannot have parameters'));
494+
errors.push(new ParseError(block.startSourceSpan, '@else block cannot have parameters'));
491495
}
492496
hasElse = true;
493497
} else if (!ELSE_IF_PATTERN.test(block.name)) {
494498
errors.push(
495-
new ParseError(block.sourceSpan, `Unrecognized conditional block @${block.name}`),
499+
new ParseError(block.startSourceSpan, `Unrecognized conditional block @${block.name}`),
496500
);
497501
}
498502
}
@@ -506,7 +510,9 @@ function validateSwitchBlock(ast: html.Block): ParseError[] {
506510
let hasDefault = false;
507511

508512
if (ast.parameters.length !== 1) {
509-
errors.push(new ParseError(ast.sourceSpan, '@switch block must have exactly one parameter'));
513+
errors.push(
514+
new ParseError(ast.startSourceSpan, '@switch block must have exactly one parameter'),
515+
);
510516
return errors;
511517
}
512518

@@ -530,14 +536,16 @@ function validateSwitchBlock(ast: html.Block): ParseError[] {
530536
if (node.name === 'default') {
531537
if (hasDefault) {
532538
errors.push(
533-
new ParseError(node.sourceSpan, '@switch block can only have one @default block'),
539+
new ParseError(node.startSourceSpan, '@switch block can only have one @default block'),
534540
);
535541
} else if (node.parameters.length > 0) {
536-
errors.push(new ParseError(node.sourceSpan, '@default block cannot have parameters'));
542+
errors.push(new ParseError(node.startSourceSpan, '@default block cannot have parameters'));
537543
}
538544
hasDefault = true;
539545
} else if (node.name === 'case' && node.parameters.length !== 1) {
540-
errors.push(new ParseError(node.sourceSpan, '@case block must have exactly one parameter'));
546+
errors.push(
547+
new ParseError(node.startSourceSpan, '@case block must have exactly one parameter'),
548+
);
541549
}
542550
}
543551

@@ -586,7 +594,9 @@ function parseConditionalBlockParameters(
586594
bindingParser: BindingParser,
587595
) {
588596
if (block.parameters.length === 0) {
589-
errors.push(new ParseError(block.sourceSpan, 'Conditional block does not have an expression'));
597+
errors.push(
598+
new ParseError(block.startSourceSpan, 'Conditional block does not have an expression'),
599+
);
590600
return null;
591601
}
592602

0 commit comments

Comments
 (0)