Improve error message for JSXExpressions that are comma expressions

This commit is contained in:
Andrew Branch 2019-05-21 14:21:44 -07:00
parent 77a76c157b
commit feaef9c829
No known key found for this signature in database
GPG key ID: 22CCA4B120C427D2
7 changed files with 46 additions and 1 deletions

View file

@ -19850,6 +19850,7 @@ namespace ts {
}
function checkJsxExpression(node: JsxExpression, checkMode?: CheckMode) {
checkGrammarJsxExpression(node);
if (node.expression) {
const type = checkExpression(node.expression, checkMode);
if (node.dotDotDotToken && type !== anyType && !isArrayType(type)) {
@ -31658,6 +31659,12 @@ namespace ts {
}
}
function checkGrammarJsxExpression(node: JsxExpression) {
if (node.expression && isCommaSequence(node.expression)) {
return grammarErrorOnNode(node.expression, Diagnostics.JSX_expressions_may_not_use_the_comma_operator_Did_you_mean_to_write_an_array);
}
}
function checkGrammarForInOrForOfStatement(forInOrOfStatement: ForInOrOfStatement): boolean {
if (checkGrammarStatementInAmbientContext(forInOrOfStatement)) {
return true;

View file

@ -4986,5 +4986,9 @@
"Classes may not have a field named 'constructor'.": {
"category": "Error",
"code": 18006
},
"JSX expressions may not use the comma operator. Did you mean to write an array?": {
"category": "Error",
"code": 18007
}
}

View file

@ -4430,7 +4430,10 @@ namespace ts {
if (token() !== SyntaxKind.CloseBraceToken) {
node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
node.expression = parseAssignmentExpressionOrHigher();
// Only an AssignmentExpression is valid here per the JSX spec,
// but we can unambiguously parse a comma sequence and provide
// a better error message in grammar checking.
node.expression = parseExpression();
}
if (inExpressionContext) {
parseExpected(SyntaxKind.CloseBraceToken);

View file

@ -582,6 +582,20 @@ namespace FourSlash {
});
}
public verifyErrorExistsAtRange(range: Range, code: number) {
const span = ts.createTextSpanFromRange(range);
const hasMatchingError = ts.some(
this.getDiagnostics(range.fileName),
({ code, start, length }) =>
code === code &&
ts.isNumber(start) && ts.isNumber(length) &&
ts.textSpansEqual(span, { start, length }));
if (!hasMatchingError) {
this.raiseError(`No error with code ${code} found at provided range.`);
}
}
public verifyNumberOfErrorsInCurrentFile(expected: number) {
const errors = this.getDiagnostics(this.activeFile.fileName);
const actual = errors.length;
@ -3968,6 +3982,10 @@ namespace FourSlashInterface {
this.state.verifyNoErrors();
}
public errorExistsAtRange(range: FourSlash.Range, code: number) {
this.state.verifyErrorExistsAtRange(range, code);
}
public numberOfErrorsInCurrentFile(expected: number) {
this.state.verifyNumberOfErrorsInCurrentFile(expected);
}

View file

@ -238,6 +238,7 @@ declare namespace FourSlashInterface {
signatureHelp(...options: VerifySignatureHelpOptions[], ): void;
// Checks that there are no compile errors.
noErrors(): void;
errorExistsAtRange(range: Range, code: number): void;
numberOfErrorsInCurrentFile(expected: number): void;
baselineCurrentFileBreakpointLocations(): void;
baselineCurrentFileNameOrDottedNameSpans(): void;

View file

@ -4,6 +4,7 @@
////declare var React: any;
////declare var x: string;
////const a = <div>{<div />[|x|]}</div>
////const b = <div x={<div />[|x|]} />
const range = test.ranges()[0];
verify.getSyntacticDiagnostics([{

View file

@ -0,0 +1,11 @@
/// <reference path="fourslash.ts" />
//@Filename: jsxExpressionWithCommaExpression.tsx
//@jsx: react
////declare var React: any;
////declare var x: string;
////const a = <div x={[|x, x|]} />
////const b = <div>{[|x, x|]}</div>
verify.getSyntacticDiagnostics([]);
test.ranges().forEach(range => verify.errorExistsAtRange(range, 18006));