diff --git a/Jakefile.js b/Jakefile.js index 595875dfc3248..5779d75022f50 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -945,7 +945,7 @@ task("generate-code-coverage", ["tests", builtLocalDirectory], function () { // Browser tests var nodeServerOutFile = "tests/webTestServer.js"; var nodeServerInFile = "tests/webTestServer.ts"; -compileFile(nodeServerOutFile, [nodeServerInFile], [builtLocalDirectory, tscFile], [], /*useBuiltCompiler:*/ true, { noOutFile: true }); +compileFile(nodeServerOutFile, [nodeServerInFile], [builtLocalDirectory, tscFile], [], /*useBuiltCompiler:*/ true, { noOutFile: true, lib: "es6" }); desc("Runs browserify on run.js to produce a file suitable for running tests in the browser"); task("browserify", ["tests", builtLocalDirectory, nodeServerOutFile], function() { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 83b4cb961a45a..02f1e203aec29 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1,4 +1,4 @@ -{ +{ "Unterminated string literal.": { "category": "Error", "code": 1002 @@ -3355,6 +3355,24 @@ "category": "Message", "code": 90017 }, + "Disable checking for this file.": { + "category": "Message", + "code": 90018 + }, + "Suppress this error message.": { + "category": "Message", + "code": 90019 + }, + "Initialize property '{0}' in the constructor.": { + "category": "Message", + "code": 90020 + }, + "Initialize static property '{0}'.": { + "category": "Message", + "code": 90021 + }, + + "Octal literal types must use ES2015 syntax. Use the syntax '{0}'.": { "category": "Error", "code": 8017 diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 67e9f62fe2db0..bdc8f76cf6049 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -4,6 +4,7 @@ namespace ts { const emptyArray: any[] = []; + const suppressDiagnosticCommentRegEx = /(^\s*$)|(^\s*\/\/\/?\s*(@ts-suppress)?)/; export function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean, configName = "tsconfig.json"): string { while (true) { @@ -923,10 +924,36 @@ namespace ts { const fileProcessingDiagnosticsInFile = fileProcessingDiagnostics.getDiagnostics(sourceFile.fileName); const programDiagnosticsInFile = programDiagnostics.getDiagnostics(sourceFile.fileName); - return bindDiagnostics.concat(checkDiagnostics, fileProcessingDiagnosticsInFile, programDiagnosticsInFile); + const diagnostics = bindDiagnostics.concat(checkDiagnostics, fileProcessingDiagnosticsInFile, programDiagnosticsInFile); + return isSourceFileJavaScript(sourceFile) + ? filter(diagnostics, shouldReportDiagnostic) + : diagnostics; }); } + /** + * Skip errors if previous line start with '// @ts-suppress' comment, not counting non-empty non-comment lines + */ + function shouldReportDiagnostic(diagnostic: Diagnostic) { + const { file, start } = diagnostic; + const lineStarts = getLineStarts(file); + let { line } = computeLineAndCharacterOfPosition(lineStarts, start); + while (line > 0) { + const previousLineText = file.text.slice(lineStarts[line - 1], lineStarts[line]); + const result = suppressDiagnosticCommentRegEx.exec(previousLineText); + if (!result) { + // non-empty line + return true; + } + if (result[3]) { + // @ts-suppress + return false; + } + line--; + } + return true; + } + function getJavaScriptSyntacticDiagnosticsForFile(sourceFile: SourceFile): Diagnostic[] { return runWithCancellationToken(() => { const diagnostics: Diagnostic[] = []; diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 0df9f4f4dd2bd..11103bf6e2d59 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -1,4 +1,4 @@ -// +// // Copyright (c) Microsoft Corporation. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -2550,6 +2550,11 @@ namespace FourSlash { } } + public printAvailableCodeFixes() { + const codeFixes = this.getCodeFixActions(this.activeFile.fileName); + Harness.IO.log(stringify(codeFixes)); + } + // Get the text of the entire line the caret is currently at private getCurrentLineContent() { const text = this.getFileContent(this.activeFile.fileName); @@ -3738,6 +3743,10 @@ namespace FourSlashInterface { this.state.printCompletionListMembers(); } + public printAvailableCodeFixes() { + this.state.printAvailableCodeFixes(); + } + public printBreakpointLocation(pos: number) { this.state.printBreakpointLocation(pos); } diff --git a/src/harness/tsconfig.json b/src/harness/tsconfig.json index 21622325368cc..9f0e30baa1c85 100644 --- a/src/harness/tsconfig.json +++ b/src/harness/tsconfig.json @@ -1,4 +1,4 @@ -{ +{ "extends": "../tsconfig-base", "compilerOptions": { "removeComments": false, @@ -81,6 +81,7 @@ "../services/codefixes/helpers.ts", "../services/codefixes/importFixes.ts", "../services/codefixes/unusedIdentifierFixes.ts", + "../services/codefixes/disableJsDiagnostics.ts", "harness.ts", "sourceMapRecorder.ts", diff --git a/src/services/codefixes/disableJsDiagnostics.ts b/src/services/codefixes/disableJsDiagnostics.ts new file mode 100644 index 0000000000000..c18c0153a0368 --- /dev/null +++ b/src/services/codefixes/disableJsDiagnostics.ts @@ -0,0 +1,74 @@ +/* @internal */ +namespace ts.codefix { + registerCodeFix({ + errorCodes: getApplicableDiagnosticCodes(), + getCodeActions: getDisableJsDiagnosticsCodeActions + }); + + function getApplicableDiagnosticCodes(): number[] { + const allDiagnostcs = >Diagnostics; + return Object.keys(allDiagnostcs) + .filter(d => allDiagnostcs[d] && allDiagnostcs[d].category === DiagnosticCategory.Error) + .map(d => allDiagnostcs[d].code); + } + + function shouldCheckJsFile(sourceFile: SourceFile, compilerOptions: CompilerOptions) { + return sourceFile.checkJsDirective ? sourceFile.checkJsDirective.enabled : compilerOptions.checkJs; + } + + function getSuppressCommentLocationForLocation(sourceFile: SourceFile, position: number, newLineCharacter: string) { + let { line } = getLineAndCharacterOfPosition(sourceFile, position); + const lineStartPosition = getStartPositionOfLine(line, sourceFile); + const startPosition = getFirstNonSpaceCharacterPosition(sourceFile.text, lineStartPosition); + + // First try to see if we can put the '// @ts-suppress' on the previous line. + // We need to make sure that we are not in the middle of a string literal or a comment. + // We also want to check if the previous line holds a comment for a node on the next line + // if so, we do not want to separate the node from its comment if we can. + if (!isInComment(sourceFile, startPosition) && !isInString(sourceFile, startPosition) && !isInTemplateString(sourceFile, startPosition)) { + const token = getTouchingToken(sourceFile, startPosition); + const tokenLeadingCommnets = getLeadingCommentRangesOfNode(token, sourceFile); + if (!tokenLeadingCommnets || !tokenLeadingCommnets.length || tokenLeadingCommnets[0].pos >= startPosition) { + return { + span: { start: startPosition, length: 0 }, + newText: `// @ts-suppress${newLineCharacter}` + }; + } + } + + // If all fails, add an extra new line immediatlly before the error span. + return { + span: { start: position, length: 0 }, + newText: `${position === startPosition ? "" : newLineCharacter}// @ts-suppress${newLineCharacter}` + }; + } + + function getDisableJsDiagnosticsCodeActions(context: CodeFixContext): CodeAction[] | undefined { + const { sourceFile, program, newLineCharacter, span } = context; + + if (!isInJavaScriptFile(sourceFile) || !shouldCheckJsFile(sourceFile, program.getCompilerOptions())) { + return undefined; + } + + return [{ + description: getLocaleSpecificMessage(Diagnostics.Suppress_this_error_message), + changes: [{ + fileName: sourceFile.fileName, + textChanges: [getSuppressCommentLocationForLocation(sourceFile, span.start, newLineCharacter)] + }] + }, + { + description: getLocaleSpecificMessage(Diagnostics.Disable_checking_for_this_file), + changes: [{ + fileName: sourceFile.fileName, + textChanges: [{ + span: { + start: sourceFile.checkJsDirective ? sourceFile.checkJsDirective.pos : 0, + length: sourceFile.checkJsDirective ? sourceFile.checkJsDirective.end - sourceFile.checkJsDirective.pos : 0 + }, + newText: `// @ts-nocheck${newLineCharacter}` + }] + }] + }]; + } +} \ No newline at end of file diff --git a/src/services/codefixes/fixAddMissingMember.ts b/src/services/codefixes/fixAddMissingMember.ts index 6ae2ba3f51c99..bc2ee6fe0f885 100644 --- a/src/services/codefixes/fixAddMissingMember.ts +++ b/src/services/codefixes/fixAddMissingMember.ts @@ -1,4 +1,4 @@ -/* @internal */ +/* @internal */ namespace ts.codefix { registerCodeFix({ errorCodes: [Diagnostics.Property_0_does_not_exist_on_type_1.code], @@ -13,55 +13,106 @@ namespace ts.codefix { // this.missing = 1; // ^^^^^^^ const token = getTokenAtPosition(sourceFile, start); - if (token.kind != SyntaxKind.Identifier) { return undefined; } - const classDeclaration = getContainingClass(token); - if (!classDeclaration) { + if (!isPropertyAccessExpression(token.parent) || token.parent.expression.kind !== SyntaxKind.ThisKeyword) { return undefined; } - if (!(token.parent && token.parent.kind === SyntaxKind.PropertyAccessExpression)) { + const classMemberDeclaration = getThisContainer(token, /*includeArrowFunctions*/ false); + if (!isClassElement(classMemberDeclaration)) { return undefined; } - if ((token.parent as PropertyAccessExpression).expression.kind !== SyntaxKind.ThisKeyword) { + const classDeclaration = classMemberDeclaration.parent; + if (!classDeclaration || !isClassLike(classDeclaration)) { return undefined; } - let typeString = "any"; + const isStatic = hasModifier(getThisContainer(token, /*includeArrowFunctions*/ false), ModifierFlags.Static); - if (token.parent.parent.kind === SyntaxKind.BinaryExpression) { - const binaryExpression = token.parent.parent as BinaryExpression; + return isInJavaScriptFile(sourceFile) ? getActionsForAddMissingMemberInJavaScriptFile() : getActionsForAddMissingMemberInTypeScriptFile(); - const checker = context.program.getTypeChecker(); - const widenedType = checker.getWidenedType(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(binaryExpression.right))); - typeString = checker.typeToString(widenedType); - } + function getActionsForAddMissingMemberInTypeScriptFile(): CodeAction[] | undefined { + let typeString = "any"; - const startPos = classDeclaration.members.pos; + if (token.parent.parent.kind === SyntaxKind.BinaryExpression) { + const binaryExpression = token.parent.parent as BinaryExpression; - return [{ - description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_declaration_for_missing_property_0), [token.getText()]), - changes: [{ - fileName: sourceFile.fileName, - textChanges: [{ - span: { start: startPos, length: 0 }, - newText: `${token.getFullText(sourceFile)}: ${typeString};` - }] - }] - }, - { - description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_index_signature_for_missing_property_0), [token.getText()]), - changes: [{ - fileName: sourceFile.fileName, - textChanges: [{ - span: { start: startPos, length: 0 }, - newText: `[name: string]: ${typeString};` + const checker = context.program.getTypeChecker(); + const widenedType = checker.getWidenedType(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(binaryExpression.right))); + typeString = checker.typeToString(widenedType); + } + + const startPos = classDeclaration.members.pos; + + const actions = [{ + description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_declaration_for_missing_property_0), [token.getText()]), + changes: [{ + fileName: sourceFile.fileName, + textChanges: [{ + span: { start: startPos, length: 0 }, + newText: `${isStatic ? "static " : ""}${token.getFullText(sourceFile)}: ${typeString};` + }] }] - }] - }]; + }]; + + if (!isStatic) { + actions.push({ + description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_index_signature_for_missing_property_0), [token.getText()]), + changes: [{ + fileName: sourceFile.fileName, + textChanges: [{ + span: { start: startPos, length: 0 }, + newText: `[x: string]: ${typeString};` + }] + }] + }); + } + + return actions; + } + + function getActionsForAddMissingMemberInJavaScriptFile(): CodeAction[] | undefined { + const memberName = token.getText(); + + if (isStatic) { + if (classDeclaration.kind === SyntaxKind.ClassExpression) { + return undefined; + } + + const className = classDeclaration.name.getText(); + + return [{ + description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Initialize_static_property_0), [memberName]), + changes: [{ + fileName: sourceFile.fileName, + textChanges: [{ + span: { start: classDeclaration.getEnd(), length: 0 }, + newText: `${context.newLineCharacter}${className}.${memberName} = undefined;${context.newLineCharacter}` + }] + }] + }]; + } + else { + const classConstructor = getFirstConstructorWithBody(classDeclaration); + if (!classConstructor) { + return undefined; + } + + return [{ + description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Initialize_property_0_in_the_constructor), [memberName]), + changes: [{ + fileName: sourceFile.fileName, + textChanges: [{ + span: { start: classConstructor.body.getEnd() - 1, length: 0 }, + newText: `this.${memberName} = undefined;${context.newLineCharacter}` + }] + }] + }]; + } + } } } \ No newline at end of file diff --git a/src/services/codefixes/fixes.ts b/src/services/codefixes/fixes.ts index 76be34c67cda5..ae1643dfa3baa 100644 --- a/src/services/codefixes/fixes.ts +++ b/src/services/codefixes/fixes.ts @@ -7,4 +7,5 @@ /// /// /// +/// /// diff --git a/src/services/codefixes/unusedIdentifierFixes.ts b/src/services/codefixes/unusedIdentifierFixes.ts index 61d48bdc3bc85..6c8bd0a9dbe7e 100644 --- a/src/services/codefixes/unusedIdentifierFixes.ts +++ b/src/services/codefixes/unusedIdentifierFixes.ts @@ -105,9 +105,10 @@ namespace ts.codefix { else { // import |d,| * as ns from './file' const start = importClause.name.getStart(); - let end = findFirstNonSpaceCharPosStarting(importClause.name.end); + const text = sourceFile.text; + let end = getFirstNonSpaceCharacterPosition(text, importClause.name.end); if (sourceFile.text.charCodeAt(end) === CharacterCodes.comma) { - end = findFirstNonSpaceCharPosStarting(end + 1); + end = getFirstNonSpaceCharacterPosition(text, end + 1); } return createCodeFix("", start, end - start); @@ -166,13 +167,6 @@ namespace ts.codefix { return createCodeFix("", start, end - start); } - function findFirstNonSpaceCharPosStarting(start: number) { - while (isWhiteSpace(sourceFile.text.charCodeAt(start))) { - start += 1; - } - return start; - } - function createCodeFix(newText: string, start: number, length: number): CodeAction[] { return [{ description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Remove_declaration_for_Colon_0), { 0: token.getText() }), diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index 93f861e80aa58..b97b3c509f8e7 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -90,6 +90,7 @@ "codefixes/fixes.ts", "codefixes/helpers.ts", "codefixes/importFixes.ts", - "codefixes/unusedIdentifierFixes.ts" + "codefixes/unusedIdentifierFixes.ts", + "codefixes/disableJsDiagnostics.ts" ] } \ No newline at end of file diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 7c5bf862fc8a0..c894df121f862 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1388,4 +1388,11 @@ namespace ts { // First token is the open curly, this is where we want to put the 'super' call. return constructor.body.getFirstToken(sourceFile).getEnd(); } + + export function getFirstNonSpaceCharacterPosition(text: string, position: number) { + while (isWhiteSpace(text.charCodeAt(position))) { + position += 1; + } + return position; + } } diff --git a/tests/baselines/reference/checkJsFiles_skipDiagnostics.symbols b/tests/baselines/reference/checkJsFiles_skipDiagnostics.symbols new file mode 100644 index 0000000000000..a0f2200048f25 --- /dev/null +++ b/tests/baselines/reference/checkJsFiles_skipDiagnostics.symbols @@ -0,0 +1,38 @@ +=== tests/cases/compiler/a.js === + +var x = 0; +>x : Symbol(x, Decl(a.js, 1, 3)) + + +/// @ts-suppress +x(); +>x : Symbol(x, Decl(a.js, 1, 3)) + +/// @ts-suppress +x(); +>x : Symbol(x, Decl(a.js, 1, 3)) + +/// @ts-suppress +x( +>x : Symbol(x, Decl(a.js, 1, 3)) + + 2, + 3); + + + +// @ts-suppress +// come comment +// some other comment + +// @anohter + +x(); +>x : Symbol(x, Decl(a.js, 1, 3)) + + + +// @ts-suppress: no call signature +x(); +>x : Symbol(x, Decl(a.js, 1, 3)) + diff --git a/tests/baselines/reference/checkJsFiles_skipDiagnostics.types b/tests/baselines/reference/checkJsFiles_skipDiagnostics.types new file mode 100644 index 0000000000000..69105a3112aa9 --- /dev/null +++ b/tests/baselines/reference/checkJsFiles_skipDiagnostics.types @@ -0,0 +1,47 @@ +=== tests/cases/compiler/a.js === + +var x = 0; +>x : number +>0 : 0 + + +/// @ts-suppress +x(); +>x() : any +>x : number + +/// @ts-suppress +x(); +>x() : any +>x : number + +/// @ts-suppress +x( +>x( 2, 3) : any +>x : number + + 2, +>2 : 2 + + 3); +>3 : 3 + + + +// @ts-suppress +// come comment +// some other comment + +// @anohter + +x(); +>x() : any +>x : number + + + +// @ts-suppress: no call signature +x(); +>x() : any +>x : number + diff --git a/tests/cases/compiler/checkJsFiles_skipDiagnostics.ts b/tests/cases/compiler/checkJsFiles_skipDiagnostics.ts new file mode 100644 index 0000000000000..bcbcc815e7c21 --- /dev/null +++ b/tests/cases/compiler/checkJsFiles_skipDiagnostics.ts @@ -0,0 +1,33 @@ +// @allowJs: true +// @checkJs: true +// @noEmit: true + +// @fileName: a.js +var x = 0; + + +/// @ts-suppress +x(); + +/// @ts-suppress +x(); + +/// @ts-suppress +x( + 2, + 3); + + + +// @ts-suppress +// come comment +// some other comment + +// @anohter + +x(); + + + +// @ts-suppress: no call signature +x(); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixAddMissingMember.ts b/tests/cases/fourslash/codeFixAddMissingMember.ts new file mode 100644 index 0000000000000..43c0bc3b765ec --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingMember.ts @@ -0,0 +1,14 @@ +/// + +////[|class C { +//// method() { +//// this.foo = 10; +//// } +////}|] + +verify.rangeAfterCodeFix(`class C { + foo: number; + method() { + this.foo = 10; + } +}`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 0); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixAddMissingMember2.ts b/tests/cases/fourslash/codeFixAddMissingMember2.ts new file mode 100644 index 0000000000000..7b64fde8c0109 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingMember2.ts @@ -0,0 +1,14 @@ +/// + +////[|class C { +//// method() { +//// this.foo = 10; +//// } +////}|] + +verify.rangeAfterCodeFix(`class C { + [x:string]: number; + method() { + this.foo = 10; + } +}`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 1); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixAddMissingMember3.ts b/tests/cases/fourslash/codeFixAddMissingMember3.ts new file mode 100644 index 0000000000000..5864c9c10297f --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingMember3.ts @@ -0,0 +1,14 @@ +/// + +////[|class C { +//// static method() { +//// this.foo = 10; +//// } +////}|] + +verify.rangeAfterCodeFix(`class C { + static foo: number; + static method() { + this.foo = 10; + } +}`); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixAddMissingMember4.ts b/tests/cases/fourslash/codeFixAddMissingMember4.ts new file mode 100644 index 0000000000000..08df9ccabc2ee --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingMember4.ts @@ -0,0 +1,22 @@ +/// + +// @checkJs: true +// @allowJs: true + +// @Filename: a.js +////[|class C { +//// constructor() { +//// } +//// method() { +//// this.foo === 10; +//// } +////}|] + +verify.rangeAfterCodeFix(`class C { + constructor() { + this.foo = undefined; +} + method() { + this.foo === 10; + } +}`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 0); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixAddMissingMember5.ts b/tests/cases/fourslash/codeFixAddMissingMember5.ts new file mode 100644 index 0000000000000..cbabc0ba6c58f --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingMember5.ts @@ -0,0 +1,19 @@ +/// + +// @checkJs: true +// @allowJs: true + +// @Filename: a.js +////[|class C { +//// static method() { +//// ()=>{ this.foo === 10 }; +//// } +////} +////|] + +verify.rangeAfterCodeFix(`class C { + static method() { + ()=>{ this.foo === 10 }; + } +} +C.foo = undefined;`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 0); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixAddMissingMember6.ts b/tests/cases/fourslash/codeFixAddMissingMember6.ts new file mode 100644 index 0000000000000..2f3911d779e05 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingMember6.ts @@ -0,0 +1,18 @@ +/// + +// @checkJs: true +// @allowJs: true + +// @Filename: a.js +////[|class C { +//// constructor() { +//// } +//// prop = ()=>{ this.foo === 10 }; +////}|] + +verify.rangeAfterCodeFix(`class C { + constructor() { + this.foo = undefined; + } + prop = ()=>{ this.foo === 10 }; +}`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 0); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixAddMissingMember7.ts b/tests/cases/fourslash/codeFixAddMissingMember7.ts new file mode 100644 index 0000000000000..0e937a3ab6e95 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingMember7.ts @@ -0,0 +1,15 @@ +/// + +// @checkJs: true +// @allowJs: true + +// @Filename: a.js +////[|class C { +//// static p = ()=>{ this.foo === 10 }; +////} +////|] + +verify.rangeAfterCodeFix(`class C { + static p = ()=>{ this.foo === 10 }; +} +C.foo = undefined;`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 2); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile.ts b/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile.ts new file mode 100644 index 0000000000000..070712c2523ea --- /dev/null +++ b/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile.ts @@ -0,0 +1,11 @@ +/// + +// @allowjs: true +// @noEmit: true + +// @Filename: a.js +////[|// @ts-check|] +////var x = ""; +////x = 1; + +verify.rangeAfterCodeFix("// @ts-nocheck", /*includeWhiteSpace*/ false, /*errorCode*/ undefined, /*index*/ 1); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile2.ts b/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile2.ts new file mode 100644 index 0000000000000..4a55f2ba44f92 --- /dev/null +++ b/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile2.ts @@ -0,0 +1,15 @@ +/// + +// @allowjs: true +// @noEmit: true +// @checkJs: true + +// @Filename: a.js +////[|var x = ""; +////x = 1;|] + +// Disable checking for the whole file +verify.rangeAfterCodeFix(`// @ts-nocheck +var x = ""; +x = 1;`, /*includeWhiteSpace*/ false, /*errorCode*/ undefined, /*index*/ 1); + diff --git a/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile3.ts b/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile3.ts new file mode 100644 index 0000000000000..f486a7e171bf5 --- /dev/null +++ b/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile3.ts @@ -0,0 +1,14 @@ +/// + +// @allowjs: true +// @noEmit: true +// @checkJs: true + +// @Filename: a.js +////[|var x = ""; +////x = 1;|] + +// Disable checking for next line +verify.rangeAfterCodeFix(`var x = ""; +// @ts-suppress +x = 1;`, /*includeWhiteSpace*/ false, /*errorCode*/ undefined, /*index*/ 0); diff --git a/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile4.ts b/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile4.ts new file mode 100644 index 0000000000000..cadbda2c27395 --- /dev/null +++ b/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile4.ts @@ -0,0 +1,18 @@ +/// + +// @allowjs: true +// @noEmit: true +// @checkJs: true + +// @Filename: a.js +////var x = ""; +//// +////[|"test \ +////"; x = 1;|] + +// Disable checking for next line +verify.rangeAfterCodeFix(`"test \\ +"; +// @ts-suppress +x = 1;`, /*includeWhiteSpace*/ false, /*errorCode*/ undefined, /*index*/ 0); + diff --git a/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile5.ts b/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile5.ts new file mode 100644 index 0000000000000..56b9fbf20d988 --- /dev/null +++ b/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile5.ts @@ -0,0 +1,17 @@ +/// + +// @allowjs: true +// @noEmit: true +// @checkJs: true + +// @Filename: a.js +////var x = ""; +//// +////[|/** comment */ +////x = 1;|] + +// Disable checking for next line +verify.rangeAfterCodeFix(`/** comment */ +// @ts-suppress +x = 1;`, /*includeWhiteSpace*/ false, /*errorCode*/ undefined, /*index*/ 0); + diff --git a/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile6.ts b/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile6.ts new file mode 100644 index 0000000000000..a0497b4deb9e5 --- /dev/null +++ b/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile6.ts @@ -0,0 +1,17 @@ +/// + +// @allowjs: true +// @noEmit: true +// @checkJs: true + +// @Filename: a.js +////var x = 0; +//// +////function f(_a) { +//// [|f(x());|] +////} + +// Disable checking for next line +verify.rangeAfterCodeFix(`// @ts-suppress + f(x());`, /*includeWhiteSpace*/ false, /*errorCode*/ undefined, /*index*/ 0); + diff --git a/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile7.ts b/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile7.ts new file mode 100644 index 0000000000000..ad8377e129de5 --- /dev/null +++ b/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile7.ts @@ -0,0 +1,17 @@ +/// + +// @allowjs: true +// @noEmit: true +// @checkJs: true + +// @Filename: a.js +////var x = 0; +//// +////function f(_a) { +//// [|x();|] +////} + +// Disable checking for next line +verify.rangeAfterCodeFix(`// @ts-suppress + x();`, /*includeWhiteSpace*/ false, /*errorCode*/ undefined, /*index*/ 0); + diff --git a/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile8.ts b/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile8.ts new file mode 100644 index 0000000000000..8ec350479af1e --- /dev/null +++ b/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile8.ts @@ -0,0 +1,19 @@ +/// + +// @allowjs: true +// @noEmit: true +// @checkJs: true + +// @Filename: a.js +////var x = 0; +//// +////function f(_a) { +//// /** comment for f */ +//// [|f(x());|] +////} + +// Disable checking for next line +verify.rangeAfterCodeFix(`f( + // @ts-suppress + x());`, /*includeWhiteSpace*/ false, /*errorCode*/ undefined, /*index*/ 0); + diff --git a/tests/cases/fourslash/codeFixUndeclaredIndexSignatureNumericLiteral.ts b/tests/cases/fourslash/codeFixUndeclaredIndexSignatureNumericLiteral.ts index 2e49a8184eb73..0a2b0ee799df3 100644 --- a/tests/cases/fourslash/codeFixUndeclaredIndexSignatureNumericLiteral.ts +++ b/tests/cases/fourslash/codeFixUndeclaredIndexSignatureNumericLiteral.ts @@ -8,7 +8,7 @@ verify.rangeAfterCodeFix(` class A { - [name: string]: number; + [x: string]: number; constructor() { this.x = 10; diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index ab83752d93bd0..418066fb6f93e 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -296,6 +296,7 @@ declare namespace FourSlashInterface { printCurrentQuickInfo(): void; printCurrentSignatureHelp(): void; printCompletionListMembers(): void; + printAvailableCodeFixes(): void; printBreakpointLocation(pos: number): void; printBreakpointAtCurrentLocation(): void; printNameOrDottedNameSpans(pos: number): void;