From 8ed749101013623ebe49f3c3d9cdc0725066456d Mon Sep 17 00:00:00 2001 From: Alexander T Date: Tue, 17 Mar 2020 14:55:37 +0200 Subject: [PATCH] feat(37409): add fix all quick fix to fixInvalidJsxCharacters --- src/compiler/diagnosticMessages.json | 10 +++++- src/services/codeFixProvider.ts | 6 +++- .../codefixes/fixInvalidJsxCharacters.ts | 34 +++++++++++-------- .../fourslash/codeFixInvalidJsxCharacters1.ts | 13 ++++--- .../codeFixInvalidJsxCharacters10.ts | 13 +++++++ .../fourslash/codeFixInvalidJsxCharacters2.ts | 13 ++++--- .../fourslash/codeFixInvalidJsxCharacters3.ts | 13 ++++--- .../fourslash/codeFixInvalidJsxCharacters4.ts | 13 ++++--- .../fourslash/codeFixInvalidJsxCharacters5.ts | 13 ++++--- .../fourslash/codeFixInvalidJsxCharacters6.ts | 13 ++++--- .../fourslash/codeFixInvalidJsxCharacters7.ts | 17 ++++++++++ .../fourslash/codeFixInvalidJsxCharacters8.ts | 17 ++++++++++ .../fourslash/codeFixInvalidJsxCharacters9.ts | 13 +++++++ 13 files changed, 130 insertions(+), 58 deletions(-) create mode 100644 tests/cases/fourslash/codeFixInvalidJsxCharacters10.ts create mode 100644 tests/cases/fourslash/codeFixInvalidJsxCharacters7.ts create mode 100644 tests/cases/fourslash/codeFixInvalidJsxCharacters8.ts create mode 100644 tests/cases/fourslash/codeFixInvalidJsxCharacters9.ts diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 07a90e3772949..121b4116ae8a1 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -5513,10 +5513,18 @@ "category": "Message", "code": 95100 }, - "Wrap invalid character in an expression container": { + "Convert all invalid characters to HTML entity code": { "category": "Message", "code": 95101 }, + "Wrap invalid character in an expression container": { + "category": "Message", + "code": 95102 + }, + "Wrap all invalid characters in an expression container": { + "category": "Message", + "code": 95103 + }, "No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": { "category": "Error", diff --git a/src/services/codeFixProvider.ts b/src/services/codeFixProvider.ts index e50477358eda3..ab88aa97a3d7e 100644 --- a/src/services/codeFixProvider.ts +++ b/src/services/codeFixProvider.ts @@ -90,6 +90,10 @@ namespace ts.codefix { } function getDiagnostics({ program, sourceFile, cancellationToken }: CodeFixContextBase) { - return program.getSemanticDiagnostics(sourceFile, cancellationToken).concat(computeSuggestionDiagnostics(sourceFile, program, cancellationToken)); + return [ + ...program.getSemanticDiagnostics(sourceFile, cancellationToken), + ...program.getSyntacticDiagnostics(sourceFile, cancellationToken), + ...computeSuggestionDiagnostics(sourceFile, program, cancellationToken) + ]; } } diff --git a/src/services/codefixes/fixInvalidJsxCharacters.ts b/src/services/codefixes/fixInvalidJsxCharacters.ts index f765c3558dc76..67ce26efd6519 100644 --- a/src/services/codefixes/fixInvalidJsxCharacters.ts +++ b/src/services/codefixes/fixInvalidJsxCharacters.ts @@ -1,42 +1,48 @@ /* @internal */ namespace ts.codefix { - const fixIdHtmlEntity = "invalidJsxCharactersConvertToHtmlEntity"; - const fixIdExpression = "invalidJsxCharactersConvertToExpression"; + const fixIdExpression = "fixInvalidJsxCharacters_expression"; + const fixIdHtmlEntity = "fixInvalidJsxCharacters_htmlEntity"; - const errorCodes = [Diagnostics.Unexpected_token_Did_you_mean_or_gt.code, Diagnostics.Unexpected_token_Did_you_mean_or_rbrace.code]; + const errorCodes = [ + Diagnostics.Unexpected_token_Did_you_mean_or_gt.code, + Diagnostics.Unexpected_token_Did_you_mean_or_rbrace.code + ]; registerCodeFix({ errorCodes, - getCodeActions: context => { - const { sourceFile, span } = context; - const changeToExpression = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, span.start, /* useHtmlEntity */ false)); - const changeToHtmlEntity = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, span.start, /* useHtmlEntity */ true)); + fixIds: [fixIdExpression, fixIdHtmlEntity], + getCodeActions(context) { + const { sourceFile, preferences, span } = context; + const changeToExpression = textChanges.ChangeTracker.with(context, t => doChange(t, preferences, sourceFile, span.start, /* useHtmlEntity */ false)); + const changeToHtmlEntity = textChanges.ChangeTracker.with(context, t => doChange(t, preferences, sourceFile, span.start, /* useHtmlEntity */ true)); + return [ - createCodeFixActionWithoutFixAll(fixIdExpression, changeToExpression, Diagnostics.Wrap_invalid_character_in_an_expression_container), - createCodeFixAction(fixIdHtmlEntity, changeToHtmlEntity, Diagnostics.Convert_invalid_character_to_its_html_entity_code, fixIdHtmlEntity, Diagnostics.Convert_invalid_character_to_its_html_entity_code), + createCodeFixAction(fixIdExpression, changeToExpression, Diagnostics.Wrap_invalid_character_in_an_expression_container, fixIdExpression, Diagnostics.Wrap_all_invalid_characters_in_an_expression_container), + createCodeFixAction(fixIdHtmlEntity, changeToHtmlEntity, Diagnostics.Convert_invalid_character_to_its_html_entity_code, fixIdHtmlEntity, Diagnostics.Convert_all_invalid_characters_to_HTML_entity_code) ]; }, - fixIds: [fixIdExpression, fixIdHtmlEntity], + getAllCodeActions(context) { + return codeFixAll(context, errorCodes, (changes, diagnostic) => doChange(changes, context.preferences, diagnostic.file, diagnostic.start, context.fixId === fixIdHtmlEntity)); + } }); const htmlEntity = { ">": ">", "}": "}", }; + function isValidCharacter(character: string): character is keyof typeof htmlEntity { return hasProperty(htmlEntity, character); } - function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, start: number, useHtmlEntity: boolean) { + function doChange(changes: textChanges.ChangeTracker, preferences: UserPreferences, sourceFile: SourceFile, start: number, useHtmlEntity: boolean) { const character = sourceFile.getText()[start]; // sanity check if (!isValidCharacter(character)) { return; } - const replacement = useHtmlEntity - ? htmlEntity[character] - : `{'${character}'}`; + const replacement = useHtmlEntity ? htmlEntity[character] : `{${quote(character, preferences)}}`; changes.replaceRangeWithText(sourceFile, { pos: start, end: start + 1 }, replacement); } } diff --git a/tests/cases/fourslash/codeFixInvalidJsxCharacters1.ts b/tests/cases/fourslash/codeFixInvalidJsxCharacters1.ts index 60495c8b8142a..7610e6cc78bdf 100644 --- a/tests/cases/fourslash/codeFixInvalidJsxCharacters1.ts +++ b/tests/cases/fourslash/codeFixInvalidJsxCharacters1.ts @@ -3,17 +3,16 @@ // @jsx: react // @filename: main.tsx -//// let x1 =
}
; +//// let foo =
}
; verify.codeFix({ - description: "Wrap invalid character in an expression container", - newFileContent: -`let x1 =
{'}'}
;`, + description: ts.Diagnostics.Wrap_invalid_character_in_an_expression_container.message, + newFileContent: `let foo =
{"}"}
;`, index: 0, }); + verify.codeFix({ - description: "Convert invalid character to its html entity code", - newFileContent: -`let x1 =
}
;`, + description: ts.Diagnostics.Convert_invalid_character_to_its_html_entity_code.message, + newFileContent: `let foo =
}
;`, index: 1, }); diff --git a/tests/cases/fourslash/codeFixInvalidJsxCharacters10.ts b/tests/cases/fourslash/codeFixInvalidJsxCharacters10.ts new file mode 100644 index 0000000000000..63ad5a9b15743 --- /dev/null +++ b/tests/cases/fourslash/codeFixInvalidJsxCharacters10.ts @@ -0,0 +1,13 @@ +/// + +// @jsx: react +// @filename: main.tsx + +//// let foo =
>
; + +verify.codeFix({ + index: 0, + description: ts.Diagnostics.Wrap_invalid_character_in_an_expression_container.message, + newFileContent: `let foo =
{">"}
;`, + preferences: { quotePreference: "double" } +}); diff --git a/tests/cases/fourslash/codeFixInvalidJsxCharacters2.ts b/tests/cases/fourslash/codeFixInvalidJsxCharacters2.ts index ef8747d48652d..db8a0b14be270 100644 --- a/tests/cases/fourslash/codeFixInvalidJsxCharacters2.ts +++ b/tests/cases/fourslash/codeFixInvalidJsxCharacters2.ts @@ -3,17 +3,16 @@ // @jsx: react // @filename: main.tsx -//// let x2 =
>
; +//// let foo =
>
; verify.codeFix({ - description: "Wrap invalid character in an expression container", - newFileContent: -`let x2 =
{'>'}
;`, + description: ts.Diagnostics.Wrap_invalid_character_in_an_expression_container.message, + newFileContent: `let foo =
{">"}
;`, index: 0, }); + verify.codeFix({ - description: "Convert invalid character to its html entity code", - newFileContent: -`let x2 =
>
;`, + description: ts.Diagnostics.Convert_invalid_character_to_its_html_entity_code.message, + newFileContent: `let foo =
>
;`, index: 1, }); diff --git a/tests/cases/fourslash/codeFixInvalidJsxCharacters3.ts b/tests/cases/fourslash/codeFixInvalidJsxCharacters3.ts index d9d97c0bec282..9684ddb697b1b 100644 --- a/tests/cases/fourslash/codeFixInvalidJsxCharacters3.ts +++ b/tests/cases/fourslash/codeFixInvalidJsxCharacters3.ts @@ -3,17 +3,16 @@ // @jsx: react // @filename: main.tsx -//// let x3 =
{"foo"}}
; +//// let foo =
{"foo"}}
; verify.codeFix({ - description: "Wrap invalid character in an expression container", - newFileContent: -`let x3 =
{"foo"}{'}'}
;`, + description: ts.Diagnostics.Wrap_invalid_character_in_an_expression_container.message, + newFileContent: `let foo =
{"foo"}{"}"}
;`, index: 0, }); + verify.codeFix({ - description: "Convert invalid character to its html entity code", - newFileContent: -`let x3 =
{"foo"}}
;`, + description: ts.Diagnostics.Convert_invalid_character_to_its_html_entity_code.message, + newFileContent: `let foo =
{"foo"}}
;`, index: 1, }); diff --git a/tests/cases/fourslash/codeFixInvalidJsxCharacters4.ts b/tests/cases/fourslash/codeFixInvalidJsxCharacters4.ts index cbb0e01d29377..517e830f6e822 100644 --- a/tests/cases/fourslash/codeFixInvalidJsxCharacters4.ts +++ b/tests/cases/fourslash/codeFixInvalidJsxCharacters4.ts @@ -3,17 +3,16 @@ // @jsx: react // @filename: main.tsx -//// let x4 =
{"foo"}>
; +//// let foo =
{"foo"}>
; verify.codeFix({ - description: "Wrap invalid character in an expression container", - newFileContent: -`let x4 =
{"foo"}{'>'}
;`, + description: ts.Diagnostics.Wrap_invalid_character_in_an_expression_container.message, + newFileContent: `let foo =
{"foo"}{">"}
;`, index: 0, }); + verify.codeFix({ - description: "Convert invalid character to its html entity code", - newFileContent: -`let x4 =
{"foo"}>
;`, + description: ts.Diagnostics.Convert_invalid_character_to_its_html_entity_code.message, + newFileContent: `let foo =
{"foo"}>
;`, index: 1, }); diff --git a/tests/cases/fourslash/codeFixInvalidJsxCharacters5.ts b/tests/cases/fourslash/codeFixInvalidJsxCharacters5.ts index abc3e7ba16e1c..e660bb0126366 100644 --- a/tests/cases/fourslash/codeFixInvalidJsxCharacters5.ts +++ b/tests/cases/fourslash/codeFixInvalidJsxCharacters5.ts @@ -3,17 +3,16 @@ // @jsx: react // @filename: main.tsx -//// let x5 =
}{"foo"}
; +//// let foo =
}{"foo"}
; verify.codeFix({ - description: "Wrap invalid character in an expression container", - newFileContent: -`let x5 =
{'}'}{"foo"}
;`, + description: ts.Diagnostics.Wrap_invalid_character_in_an_expression_container.message, + newFileContent: `let foo =
{"}"}{"foo"}
;`, index: 0, }); + verify.codeFix({ - description: "Convert invalid character to its html entity code", - newFileContent: -`let x5 =
}{"foo"}
;`, + description: ts.Diagnostics.Convert_invalid_character_to_its_html_entity_code.message, + newFileContent: `let foo =
}{"foo"}
;`, index: 1, }); diff --git a/tests/cases/fourslash/codeFixInvalidJsxCharacters6.ts b/tests/cases/fourslash/codeFixInvalidJsxCharacters6.ts index f29e9ed2b8b2c..c34c9acd33c70 100644 --- a/tests/cases/fourslash/codeFixInvalidJsxCharacters6.ts +++ b/tests/cases/fourslash/codeFixInvalidJsxCharacters6.ts @@ -3,17 +3,16 @@ // @jsx: react // @filename: main.tsx -//// let x6 =
>{"foo"}
; +//// let foo =
>{"foo"}
; verify.codeFix({ - description: "Wrap invalid character in an expression container", - newFileContent: -`let x6 =
{'>'}{"foo"}
;`, + description: ts.Diagnostics.Wrap_invalid_character_in_an_expression_container.message, + newFileContent: `let foo =
{">"}{"foo"}
;`, index: 0, }); + verify.codeFix({ - description: "Convert invalid character to its html entity code", - newFileContent: -`let x6 =
>{"foo"}
;`, + description: ts.Diagnostics.Convert_invalid_character_to_its_html_entity_code.message, + newFileContent: `let foo =
>{"foo"}
;`, index: 1, }); diff --git a/tests/cases/fourslash/codeFixInvalidJsxCharacters7.ts b/tests/cases/fourslash/codeFixInvalidJsxCharacters7.ts new file mode 100644 index 0000000000000..a2d3c0d09d884 --- /dev/null +++ b/tests/cases/fourslash/codeFixInvalidJsxCharacters7.ts @@ -0,0 +1,17 @@ +/// + +// @jsx: react +// @filename: main.tsx + +////let a =
>{"foo"}
; +////let b =
>{"foo"}
; +////let c =
>{"foo"}
; + +verify.codeFixAll({ + fixId: "fixInvalidJsxCharacters_htmlEntity", + fixAllDescription: ts.Diagnostics.Convert_all_invalid_characters_to_HTML_entity_code.message, + newFileContent: +`let a =
>{"foo"}
; +let b =
>{"foo"}
; +let c =
>{"foo"}
;` +}); diff --git a/tests/cases/fourslash/codeFixInvalidJsxCharacters8.ts b/tests/cases/fourslash/codeFixInvalidJsxCharacters8.ts new file mode 100644 index 0000000000000..511a96e9e3c96 --- /dev/null +++ b/tests/cases/fourslash/codeFixInvalidJsxCharacters8.ts @@ -0,0 +1,17 @@ +/// + +// @jsx: react +// @filename: main.tsx + +////let a =
>{"foo"}
; +////let b =
>{"foo"}
; +////let c =
>{"foo"}
; + +verify.codeFixAll({ + fixId: "fixInvalidJsxCharacters_expression", + fixAllDescription: ts.Diagnostics.Wrap_all_invalid_characters_in_an_expression_container.message, + newFileContent: +`let a =
{">"}{"foo"}
; +let b =
{">"}{"foo"}
; +let c =
{">"}{"foo"}
;` +}); diff --git a/tests/cases/fourslash/codeFixInvalidJsxCharacters9.ts b/tests/cases/fourslash/codeFixInvalidJsxCharacters9.ts new file mode 100644 index 0000000000000..58179e84f43c3 --- /dev/null +++ b/tests/cases/fourslash/codeFixInvalidJsxCharacters9.ts @@ -0,0 +1,13 @@ +/// + +// @jsx: react +// @filename: main.tsx + +//// let foo =
>
; + +verify.codeFix({ + index: 0, + description: ts.Diagnostics.Wrap_invalid_character_in_an_expression_container.message, + newFileContent: `let foo =
{'>'}
;`, + preferences: { quotePreference: "single" } +});