diff --git a/package.json b/package.json index 509e0075fe5..22d58e42a8b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tslint", - "version": "5.12.0", + "version": "5.12.1", "description": "An extensible static analysis linter for the TypeScript language", "bin": { "tslint": "./bin/tslint" diff --git a/src/configs/latest.ts b/src/configs/latest.ts index f96fff8b091..7c489301d7b 100644 --- a/src/configs/latest.ts +++ b/src/configs/latest.ts @@ -65,6 +65,10 @@ export const rules = { "no-duplicate-switch-case": true, "no-implicit-dependencies": true, "no-return-await": true, + + // added in v5.12 + "function-constructor": true, + "unnecessary-bind": true, }; // tslint:enable object-literal-sort-keys diff --git a/src/configs/recommended.ts b/src/configs/recommended.ts index 7314eea224d..b918e6aa6e5 100644 --- a/src/configs/recommended.ts +++ b/src/configs/recommended.ts @@ -47,7 +47,6 @@ export const rules = { "cyclomatic-complexity": false, eofline: true, forin: true, - "function-constructor": true, "import-spacing": true, indent: { options: ["spaces"], diff --git a/src/linter.ts b/src/linter.ts index ab4ad44291a..5337a5b005b 100644 --- a/src/linter.ts +++ b/src/linter.ts @@ -42,7 +42,7 @@ import { arrayify, dedent, flatMap, mapDefined } from "./utils"; * Linter that can lint multiple files in consecutive runs. */ export class Linter { - public static VERSION = "5.12.0"; + public static VERSION = "5.12.1"; public static findConfiguration = findConfiguration; public static findConfigurationPath = findConfigurationPath; @@ -104,13 +104,16 @@ export class Linter { /** * Returns a list of source file names from a TypeScript program. This includes all referenced - * files and excludes declaration (".d.ts") files. + * files and excludes declaration (".d.ts") files, as well as JSON files, to avoid problems with + * `resolveJsonModule`. */ public static getFileNames(program: ts.Program): string[] { return mapDefined( program.getSourceFiles(), file => - file.fileName.endsWith(".d.ts") || program.isSourceFileFromExternalLibrary(file) + file.fileName.endsWith(".d.ts") || + file.fileName.endsWith(".json") || + program.isSourceFileFromExternalLibrary(file) ? undefined : file.fileName, ); diff --git a/src/rules/incrementDecrementRule.ts b/src/rules/incrementDecrementRule.ts index b697b33acf2..ac5e144f77d 100644 --- a/src/rules/incrementDecrementRule.ts +++ b/src/rules/incrementDecrementRule.ts @@ -80,7 +80,14 @@ function walk(context: Lint.WalkContext) { function complainOnNode(node: ts.PostfixUnaryExpression | ts.PrefixUnaryExpression) { const newOperatorText = node.operator === ts.SyntaxKind.PlusPlusToken ? "+= 1" : "-= 1"; - const replacement = createReplacement(node, newOperatorText); + let replacement: Lint.Replacement | undefined; + + if ( + tsutils.isPrefixUnaryExpression(node) || + node.parent.kind === ts.SyntaxKind.ExpressionStatement + ) { + replacement = createReplacement(node, newOperatorText); + } const failure = Rule.FAILURE_STRING_FACTORY(newOperatorText); diff --git a/src/rules/quotemarkRule.ts b/src/rules/quotemarkRule.ts index ddc0312f189..aef05c8c963 100644 --- a/src/rules/quotemarkRule.ts +++ b/src/rules/quotemarkRule.ts @@ -27,12 +27,12 @@ const OPTION_JSX_DOUBLE = "jsx-double"; const OPTION_AVOID_TEMPLATE = "avoid-template"; const OPTION_AVOID_ESCAPE = "avoid-escape"; -type QUOTE_MARK = "'" | '"' | "`"; -type JSX_QUOTE_MARK = "'" | '"'; +type QUOTEMARK = "'" | '"' | "`"; +type JSX_QUOTEMARK = "'" | '"'; interface Options { - quoteMark: QUOTE_MARK; - jsxQuoteMark: JSX_QUOTE_MARK; + quotemark: QUOTEMARK; + jsxQuotemark: JSX_QUOTEMARK; avoidEscape: boolean; avoidTemplate: boolean; } @@ -52,9 +52,11 @@ export class Rule extends Lint.Rules.AbstractRule { * \`"${OPTION_JSX_SINGLE}"\` enforces single quotes for JSX attributes. * \`"${OPTION_JSX_DOUBLE}"\` enforces double quotes for JSX attributes. * \`"${OPTION_AVOID_TEMPLATE}"\` forbids single-line untagged template strings that do not contain string interpolations. + Note that backticks may still be used if \`"${OPTION_AVOID_ESCAPE}"\` is enabled and both single and double quotes are + present in the string (the latter option takes precedence). * \`"${OPTION_AVOID_ESCAPE}"\` allows you to use the "other" quotemark in cases where escaping would normally be required. - For example, \`[true, "${OPTION_DOUBLE}", "${OPTION_AVOID_ESCAPE}"]\` would not report a failure on the string literal - \`'Hello "World"'\`.`, + For example, \`[true, "${OPTION_DOUBLE}", "${OPTION_AVOID_ESCAPE}"]\` would not report a failure on the string literal + \`'Hello "World"'\`.`, options: { type: "array", items: { @@ -87,15 +89,14 @@ export class Rule extends Lint.Rules.AbstractRule { public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { const args = this.ruleArguments; - - const quoteMark = getQuotemarkPreference(args); - const jsxQuoteMark = getJSXQuotemarkPreference(args); + const quotemark = getQuotemarkPreference(args); + const jsxQuotemark = getJSXQuotemarkPreference(args, quotemark); return this.applyWithFunction(sourceFile, walk, { avoidEscape: hasArg(OPTION_AVOID_ESCAPE), avoidTemplate: hasArg(OPTION_AVOID_TEMPLATE), - jsxQuoteMark, - quoteMark, + jsxQuotemark, + quotemark, }); function hasArg(name: string): boolean { @@ -114,19 +115,18 @@ function walk(ctx: Lint.WalkContext) { node.parent.kind !== ts.SyntaxKind.TaggedTemplateExpression && isSameLine(sourceFile, node.getStart(sourceFile), node.end)) ) { - const expectedQuoteMark = + const expectedQuotemark = node.parent.kind === ts.SyntaxKind.JsxAttribute - ? options.jsxQuoteMark - : options.quoteMark; - const actualQuoteMark = sourceFile.text[node.end - 1]; + ? options.jsxQuotemark + : options.quotemark; + const actualQuotemark = sourceFile.text[node.end - 1]; - if (actualQuoteMark === expectedQuoteMark) { + if (actualQuotemark === expectedQuotemark) { return; } - let fixQuoteMark = expectedQuoteMark; - - const needsQuoteEscapes = node.text.includes(expectedQuoteMark); + let fixQuotemark = expectedQuotemark; + const needsQuoteEscapes = node.text.includes(expectedQuotemark); // This string requires escapes to use the expected quote mark, but `avoid-escape` was passed if (needsQuoteEscapes && options.avoidEscape) { @@ -134,24 +134,25 @@ function walk(ctx: Lint.WalkContext) { return; } - // If we are expecting double quotes, use single quotes to avoid - // escaping. Otherwise, just use double quotes. - fixQuoteMark = expectedQuoteMark === '"' ? "'" : '"'; - - // It also includes the fixQuoteMark. Let's try to use single - // quotes instead, unless we originally expected single - // quotes, in which case we will try to use backticks. This - // means that we may use backtick even with avoid-template - // in trying to avoid escaping. What is the desired priority - // here? - if (node.text.includes(fixQuoteMark)) { - fixQuoteMark = expectedQuoteMark === "'" ? "`" : "'"; - - // It contains all of the other kinds of quotes. Escaping is - // unavoidable, sadly. - if (node.text.includes(fixQuoteMark)) { + // If we are expecting double quotes, use single quotes to avoid escaping. + // Otherwise, just use double quotes. + const alternativeFixQuotemark = expectedQuotemark === '"' ? "'" : '"'; + + if (node.text.includes(alternativeFixQuotemark)) { + // It also includes the alternative fix quote mark. Let's try to use single quotes instead, + // unless we originally expected single quotes, in which case we will try to use backticks. + // This means that we may use backtick even with avoid-template in trying to avoid escaping. + fixQuotemark = expectedQuotemark === "'" ? "`" : "'"; + + if (fixQuotemark === actualQuotemark) { + // We were already using the best quote mark for this scenario + return; + } else if (node.text.includes(fixQuotemark)) { + // It contains all of the other kinds of quotes. Escaping is unavoidable, sadly. return; } + } else { + fixQuotemark = alternativeFixQuotemark; } } @@ -159,37 +160,33 @@ function walk(ctx: Lint.WalkContext) { let text = sourceFile.text.substring(start + 1, node.end - 1); if (needsQuoteEscapes) { - text = text.replace(new RegExp(fixQuoteMark, "g"), `\\${fixQuoteMark}`); + text = text.replace(new RegExp(fixQuotemark, "g"), `\\${fixQuotemark}`); } - text = text.replace(new RegExp(`\\\\${actualQuoteMark}`, "g"), actualQuoteMark); + text = text.replace(new RegExp(`\\\\${actualQuotemark}`, "g"), actualQuotemark); return ctx.addFailure( start, node.end, - Rule.FAILURE_STRING(actualQuoteMark, fixQuoteMark), - new Lint.Replacement(start, node.end - start, fixQuoteMark + text + fixQuoteMark), + Rule.FAILURE_STRING(actualQuotemark, fixQuotemark), + new Lint.Replacement(start, node.end - start, fixQuotemark + text + fixQuotemark), ); } ts.forEachChild(node, cb); }); } -function getQuotemarkPreference(args: any[]): QUOTE_MARK { - type QUOTE_PREF = typeof OPTION_SINGLE | typeof OPTION_DOUBLE | typeof OPTION_BACKTICK; - - const quoteFromOption = { - [OPTION_SINGLE]: "'", - [OPTION_DOUBLE]: '"', - [OPTION_BACKTICK]: "`", - }; - - for (const arg of args) { +function getQuotemarkPreference(ruleArguments: any[]): QUOTEMARK { + for (const arg of ruleArguments) { switch (arg) { case OPTION_SINGLE: + return "'"; case OPTION_DOUBLE: + return '"'; case OPTION_BACKTICK: - return quoteFromOption[arg as QUOTE_PREF] as QUOTE_MARK; + return "`"; + default: + continue; } } @@ -197,25 +194,19 @@ function getQuotemarkPreference(args: any[]): QUOTE_MARK { return '"'; } -function getJSXQuotemarkPreference(args: any[]): JSX_QUOTE_MARK { - type JSX_QUOTE_PREF = typeof OPTION_JSX_SINGLE | typeof OPTION_JSX_DOUBLE; - - const jsxQuoteFromOption = { - [OPTION_JSX_SINGLE]: "'", - [OPTION_JSX_DOUBLE]: '"', - }; - - for (const arg of args) { +function getJSXQuotemarkPreference(ruleArguments: any[], regularQuotemarkPreference: QUOTEMARK): JSX_QUOTEMARK { + for (const arg of ruleArguments) { switch (arg) { case OPTION_JSX_SINGLE: + return "'"; case OPTION_JSX_DOUBLE: - return jsxQuoteFromOption[arg as JSX_QUOTE_PREF] as JSX_QUOTE_MARK; + return '"'; + default: + continue; } } // The JSX preference was not found, so try to use the regular preference. // If the regular pref is backtick, use double quotes instead. - const regularQuotemark = getQuotemarkPreference(args); - - return regularQuotemark !== "`" ? regularQuotemark : '"'; + return regularQuotemarkPreference !== "`" ? regularQuotemarkPreference : '"'; } diff --git a/src/rules/strictTypePredicatesRule.ts b/src/rules/strictTypePredicatesRule.ts index bd07d69bd58..2a878137f2a 100644 --- a/src/rules/strictTypePredicatesRule.ts +++ b/src/rules/strictTypePredicatesRule.ts @@ -99,7 +99,12 @@ function walk(ctx: Lint.WalkContext, checker: ts.TypeChecker): void { const exprType = checker.getTypeAtLocation(exprPred.expression); // TODO: could use checker.getBaseConstraintOfType to help with type parameters, but it's not publicly exposed. - if (isTypeFlagSet(exprType, ts.TypeFlags.Any | ts.TypeFlags.TypeParameter)) { + if ( + isTypeFlagSet( + exprType, + ts.TypeFlags.Any | ts.TypeFlags.TypeParameter | ts.TypeFlags.Unknown, + ) + ) { return; } diff --git a/src/test.ts b/src/test.ts index 25fd19233ae..0cb9dd4eccf 100644 --- a/src/test.ts +++ b/src/test.ts @@ -205,8 +205,16 @@ export function runTest(testDirectory: string, rulesDirectory?: string | string[ errorsFromMarkup, fixesFromLinter: newFileText, fixesFromMarkup: fixedFileText, - markupFromLinter: parse.createMarkupFromErrors(fileTextWithoutMarkup, errorsFromMarkup), - markupFromMarkup: parse.createMarkupFromErrors(fileTextWithoutMarkup, errorsFromLinter), + markupFromLinter: parse.createMarkupFromErrors( + fileToLint, + fileTextWithoutMarkup, + errorsFromMarkup, + ), + markupFromMarkup: parse.createMarkupFromErrors( + fileToLint, + fileTextWithoutMarkup, + errorsFromLinter, + ), skipped: false, }; } diff --git a/src/verify/lines.ts b/src/verify/lines.ts index ea21ac16e55..47e1f865d21 100644 --- a/src/verify/lines.ts +++ b/src/verify/lines.ts @@ -87,14 +87,17 @@ export function parseLine(text: string): Line { * Maps a Line object to a matching line of text that could be in a .lint file. * This is almost the inverse of parseLine. * If you ran `printLine(parseLine(someText), code)`, the whitespace in the result may be different than in someText + * @param fileName - File name containing the line and code. * @param line - A Line object to convert to text * @param code - If line represents error markup, this is the line of code preceding the markup. * Otherwise, this parameter is not required. */ -export function printLine(line: Line, code?: string): string | undefined { +export function printLine(fileName: string, line: Line, code?: string): string | undefined { if (line instanceof ErrorLine) { if (code === undefined) { - throw new Error("Must supply argument for code parameter when line is an ErrorLine"); + throw new Error( + `${fileName}: Must supply argument for code parameter when line is an ErrorLine`, + ); } const leadingSpaces = " ".repeat(line.startCol); @@ -111,7 +114,7 @@ export function printLine(line: Line, code?: string): string | undefined { let tildes = "~".repeat(line.endCol - line.startCol); if (code.length < line.endCol) { // Better than crashing in String.repeat - throw new Error(`Bad error marker at ${JSON.stringify(line)}`); + throw new Error(`Bad error marker in ${fileName} at ${JSON.stringify(line)}`); } let endSpaces = " ".repeat(code.length - line.endCol); if (tildes.length === 0) { diff --git a/src/verify/parse.ts b/src/verify/parse.ts index a505ce01f1d..ef7998af602 100644 --- a/src/verify/parse.ts +++ b/src/verify/parse.ts @@ -255,7 +255,7 @@ function parseFormatArguments(text: string): string[] | undefined { return result.length === 0 ? undefined : result; } -export function createMarkupFromErrors(code: string, lintErrors: LintError[]) { +export function createMarkupFromErrors(fileName: string, code: string, lintErrors: LintError[]) { lintErrors.sort(errorComparator); const codeText = code.split("\n"); @@ -281,7 +281,7 @@ export function createMarkupFromErrors(code: string, lintErrors: LintError[]) { return flatMap(codeText, (line, i) => [ line, - ...mapDefined(errorLinesForCodeText[i], err => printLine(err, line)), + ...mapDefined(errorLinesForCodeText[i], err => printLine(fileName, err, line)), ]).join("\n"); } /* tslint:enable:object-literal-sort-keys */ diff --git a/test/executable/executableTests.ts b/test/executable/executableTests.ts index 64ea241b654..b4f89b89382 100644 --- a/test/executable/executableTests.ts +++ b/test/executable/executableTests.ts @@ -19,8 +19,10 @@ import * as cp from "child_process"; import * as fs from "fs"; import * as os from "os"; import * as path from "path"; +import * as semver from "semver"; import { Logger, Options, run, Status } from "../../src/runner"; import { denormalizeWinPath } from "../../src/utils"; +import { getNormalizedTypescriptVersion } from "../../src/verify/parse"; import { createTempFile } from "../utils"; // when tests are run with mocha from npm scripts CWD points to project root @@ -41,6 +43,8 @@ describe("Executable", function(this: Mocha.ISuiteCallbackContext) { this.slow(3000); // the executable is JIT-ed each time it runs; avoid showing slowness warnings this.timeout(10000); + const tsVersion = getNormalizedTypescriptVersion(); + describe("Files", () => { it("exits with code 1 if no arguments passed", done => { execCli([], (err, stdout, stderr) => { @@ -596,6 +600,13 @@ describe("Executable", function(this: Mocha.ISuiteCallbackContext) { fs.readFileSync("test/files/project-multiple-fixes/after.test.ts", "utf-8"), ); }).timeout(8000); + + if (semver.satisfies(tsVersion, ">=2.9")) { + it("does not try to parse JSON files with --resolveJsonModule with TS >= 2.9", async () => { + const status = await execRunner({project: "test/files/tsconfig-resolve-json-module/tsconfig.json"}); + assert.equal(status, Status.Ok, "process should exit without an error"); + }); + } }); describe("--type-check", () => { diff --git a/test/files/tsconfig-resolve-json-module/index.ts b/test/files/tsconfig-resolve-json-module/index.ts new file mode 100644 index 00000000000..8a3502284d4 --- /dev/null +++ b/test/files/tsconfig-resolve-json-module/index.ts @@ -0,0 +1,3 @@ +import settings from "./test.json"; +// tslint:disable-next-line:no-console +console.log(settings.dry); diff --git a/test/files/tsconfig-resolve-json-module/test.json b/test/files/tsconfig-resolve-json-module/test.json new file mode 100644 index 00000000000..a6696097cc2 --- /dev/null +++ b/test/files/tsconfig-resolve-json-module/test.json @@ -0,0 +1,4 @@ +{ + "dry": false, + "debug": false +} \ No newline at end of file diff --git a/test/files/tsconfig-resolve-json-module/tsconfig.json b/test/files/tsconfig-resolve-json-module/tsconfig.json new file mode 100644 index 00000000000..708459a0a56 --- /dev/null +++ b/test/files/tsconfig-resolve-json-module/tsconfig.json @@ -0,0 +1,8 @@ +{ + "include": ["index.ts"], + "compilerOptions": { + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true + } +} diff --git a/test/files/tsconfig-resolve-json-module/tslint.json b/test/files/tsconfig-resolve-json-module/tslint.json new file mode 100644 index 00000000000..d3216dbe2ea --- /dev/null +++ b/test/files/tsconfig-resolve-json-module/tslint.json @@ -0,0 +1,5 @@ +{ + "extends": [ + "tslint:latest" + ] +} diff --git a/test/rule-tester/linesTests.ts b/test/rule-tester/linesTests.ts index 3ba29992ef6..b086460f1ac 100644 --- a/test/rule-tester/linesTests.ts +++ b/test/rule-tester/linesTests.ts @@ -24,24 +24,43 @@ describe("Rule Test Lines", () => { const code1 = "this is a line of code"; const errorLine1 = new lines.MultilineErrorLine(2); const errorMarkup1 = " ~~~~~~~~~~~~~~~~~~~~"; - assert.strictEqual(lines.printLine(errorLine1, code1), errorMarkup1); + assert.strictEqual(lines.printLine("fileName.ts", errorLine1, code1), errorMarkup1); const code2 = "another line of code here"; const errorLine2 = new lines.EndErrorLine(0, code2.length, "foo"); const errorMarkup2 = "~~~~~~~~~~~~~~~~~~~~~~~~~ [foo]"; - assert.strictEqual(lines.printLine(errorLine2, code2), errorMarkup2); + assert.strictEqual(lines.printLine("fileName.ts", errorLine2, code2), errorMarkup2); }); it("should correctly create strings with empty lines of code", () => { const code1 = ""; const errorLine1 = new lines.MultilineErrorLine(0); const errorMarkup1 = lines.ZERO_LENGTH_ERROR; - assert.strictEqual(lines.printLine(errorLine1, code1), errorMarkup1); + assert.strictEqual(lines.printLine("fileName.ts", errorLine1, code1), errorMarkup1); const code2 = ""; const errorLine2 = new lines.EndErrorLine(0, 0, "foo"); const errorMarkup2 = `${lines.ZERO_LENGTH_ERROR} [foo]`; - assert.strictEqual(lines.printLine(errorLine2, code2), errorMarkup2); + assert.strictEqual(lines.printLine("fileName.ts", errorLine2, code2), errorMarkup2); + }); + + it("should correctly throw an error when code is not supplied", () => { + const errorLine = new lines.EndErrorLine(0, 0, "foo"); + assert.throws( + () => lines.printLine("fileName.ts", errorLine), + Error, + "fileName.ts: Must supply argument for code parameter when line is an ErrorLine", + ); + }); + + it("should correctly throw an when the error marker is off", () => { + const code = ""; + const errorLine = new lines.EndErrorLine(0, 2, "foo"); + assert.throws( + () => lines.printLine("fileName.ts", errorLine, code), + Error, + `Bad error marker in fileName.ts at {"startCol":0,"endCol":2,"message":"foo"}`, + ); }); }); }); diff --git a/test/rule-tester/parseTests.ts b/test/rule-tester/parseTests.ts index 99142d8404a..a5398b3a0f5 100644 --- a/test/rule-tester/parseTests.ts +++ b/test/rule-tester/parseTests.ts @@ -67,14 +67,22 @@ describe("Rule Test Parse", () => { describe("createMarkupFromErrors", () => { it("should generate correct markup", () => { assert.strictEqual( - parse.createMarkupFromErrors(testData.codeStr5, testData.resultErrs5), + parse.createMarkupFromErrors( + "fileName.ts", + testData.codeStr5, + testData.resultErrs5, + ), testData.lintStr5, ); }); it("should generate correct markup with nil-length errors", () => { assert.strictEqual( - parse.createMarkupFromErrors(testData.codeStr7, testData.resultErrs7), + parse.createMarkupFromErrors( + "fileName.ts", + testData.codeStr7, + testData.resultErrs7, + ), testData.lintStr7, ); }); diff --git a/test/rules/increment-decrement/default/test.ts.fix b/test/rules/increment-decrement/default/test.ts.fix index f69f47c9056..245a116d30f 100644 --- a/test/rules/increment-decrement/default/test.ts.fix +++ b/test/rules/increment-decrement/default/test.ts.fix @@ -14,13 +14,16 @@ x - 1; 1 - x; x + (x += 1); -x + (x += 1); +x + x++; x - (x -= 1); -x - (x -= 1); +x - x--; (x += 1) + x; -(x += 1) + x; +x++ + x; (x -= 1) - x; -(x -= 1) - x; +x-- - x; + +expect(x++) +expect(x += 1) diff --git a/test/rules/increment-decrement/default/test.ts.lint b/test/rules/increment-decrement/default/test.ts.lint index 203f22a705f..19f39bb99b0 100644 --- a/test/rules/increment-decrement/default/test.ts.lint +++ b/test/rules/increment-decrement/default/test.ts.lint @@ -38,3 +38,8 @@ x-- - x; ~~~ [minus] [plus]: Use an explicit += 1 operator. [minus]: Use an explicit -= 1 operator. + +expect(x++) + ~~~ [plus] +expect(++x) + ~~~ [plus] diff --git a/test/rules/quotemark/avoid-template/tslint.json b/test/rules/quotemark/avoid-template/tslint.json deleted file mode 100644 index 11c3fd965d7..00000000000 --- a/test/rules/quotemark/avoid-template/tslint.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rules": { - "quotemark": [true, "avoid-escape", "double", "avoid-template"] - } -} diff --git a/test/rules/quotemark/avoid-template/test.ts.fix b/test/rules/quotemark/double-avoid-template/test.ts.fix similarity index 75% rename from test/rules/quotemark/avoid-template/test.ts.fix rename to test/rules/quotemark/double-avoid-template/test.ts.fix index 2c73dc1dd0c..df3dfeacb23 100644 --- a/test/rules/quotemark/avoid-template/test.ts.fix +++ b/test/rules/quotemark/double-avoid-template/test.ts.fix @@ -16,3 +16,5 @@ bar foo``; `${foo}`; +this.toastCtrl.present('Please tick "Yes" to confirm'); + diff --git a/test/rules/quotemark/avoid-template/test.ts.lint b/test/rules/quotemark/double-avoid-template/test.ts.lint similarity index 69% rename from test/rules/quotemark/avoid-template/test.ts.lint rename to test/rules/quotemark/double-avoid-template/test.ts.lint index ff3d80dbcb2..eb0d6f9481f 100644 --- a/test/rules/quotemark/avoid-template/test.ts.lint +++ b/test/rules/quotemark/double-avoid-template/test.ts.lint @@ -19,5 +19,8 @@ bar foo``; `${foo}`; +this.toastCtrl.present(`Please tick "Yes" to confirm`); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [1] + [0]: ` should be " [1]: ` should be ' diff --git a/test/rules/quotemark/double-avoid-template/tslint.json b/test/rules/quotemark/double-avoid-template/tslint.json new file mode 100644 index 00000000000..dbeffb1d574 --- /dev/null +++ b/test/rules/quotemark/double-avoid-template/tslint.json @@ -0,0 +1,5 @@ +{ + "rules": { + "quotemark": [true, "double", "avoid-escape", "avoid-template"] + } +} diff --git a/test/rules/quotemark/single-avoid-escape/tslint.json b/test/rules/quotemark/single-avoid-escape/tslint.json index 03b9fbbe5bb..c360887f9d7 100644 --- a/test/rules/quotemark/single-avoid-escape/tslint.json +++ b/test/rules/quotemark/single-avoid-escape/tslint.json @@ -1,5 +1,5 @@ { "rules": { - "quotemark": [true, "avoid-escape", "single"] + "quotemark": [true, "single", "avoid-escape"] } } diff --git a/test/rules/quotemark/single-avoid-template/test.ts.fix b/test/rules/quotemark/single-avoid-template/test.ts.fix new file mode 100644 index 00000000000..5f26f410553 --- /dev/null +++ b/test/rules/quotemark/single-avoid-template/test.ts.fix @@ -0,0 +1,20 @@ +'fo`o'; + +"a 'quote'"; + +'a "quote"'; + +`a "quote" 'quote'`; + +// Allow multi-line templates +` +foo +bar +`; + +// Allow tagged templates and templates with substitutions +foo``; +`${foo}`; + +this.toastCtrl.present('Please tick "Yes" to confirm'); + diff --git a/test/rules/quotemark/single-avoid-template/test.ts.lint b/test/rules/quotemark/single-avoid-template/test.ts.lint new file mode 100644 index 00000000000..8bf33978e84 --- /dev/null +++ b/test/rules/quotemark/single-avoid-template/test.ts.lint @@ -0,0 +1,26 @@ +`fo\`o`; +~~~~~~~ [0] + +`a 'quote'`; +~~~~~~~~~~~ [1] + +`a "quote"`; +~~~~~~~~~~~ [0] + +`a "quote" 'quote'`; + +// Allow multi-line templates +` +foo +bar +`; + +// Allow tagged templates and templates with substitutions +foo``; +`${foo}`; + +this.toastCtrl.present(`Please tick "Yes" to confirm`); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0] + +[0]: ` should be ' +[1]: ` should be " diff --git a/test/rules/quotemark/single-avoid-template/tslint.json b/test/rules/quotemark/single-avoid-template/tslint.json new file mode 100644 index 00000000000..f5eb55e4f0c --- /dev/null +++ b/test/rules/quotemark/single-avoid-template/tslint.json @@ -0,0 +1,5 @@ +{ + "rules": { + "quotemark": [true, "single", "avoid-escape", "avoid-template"] + } +} diff --git a/test/rules/strict-type-predicates/strict-null-checks/test.ts.lint b/test/rules/strict-type-predicates/strict-null-checks/test.ts.lint index 57c624c8a4d..2f45d333a2f 100644 --- a/test/rules/strict-type-predicates/strict-null-checks/test.ts.lint +++ b/test/rules/strict-type-predicates/strict-null-checks/test.ts.lint @@ -194,6 +194,9 @@ declare function get(): T; typeof get() === `stirng`; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [typeof] + typeof get() === "unknown"; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [typeof] + let a: string, b: string; typeof a === typeof b; typeof a === b; diff --git a/test/rules/strict-type-predicates/unknown/test.ts.lint b/test/rules/strict-type-predicates/unknown/test.ts.lint new file mode 100644 index 00000000000..40dd5d0da99 --- /dev/null +++ b/test/rules/strict-type-predicates/unknown/test.ts.lint @@ -0,0 +1,42 @@ +[typescript]: >= 3.0.0 + +declare function get(): T; + +// typeof +{ + typeof get() === "undefined"; + typeof get() === "boolean"; + typeof get() === "number"; + typeof get() === "string"; + typeof get() === "symbol"; + typeof get() === "function"; + typeof get() === "object"; +} + +// negation +{ + get() !== null; + get() !== undefined; +} + +// reverse left/right +{ + "string" === typeof get(); + + undefined === get(); +} + +// type parameters +{ + function f(t: T) { + typeof t === "boolean"; + } +} + +const body: unknown = 'test'; +if (typeof body === 'object') + console.log('a'); + +let test: unknown = undefined; +if (test !== undefined) + console.log('b'); diff --git a/test/rules/strict-type-predicates/unknown/tsconfig.json b/test/rules/strict-type-predicates/unknown/tsconfig.json new file mode 100644 index 00000000000..1cc3bc85ee9 --- /dev/null +++ b/test/rules/strict-type-predicates/unknown/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "strictNullChecks": true + } +} \ No newline at end of file diff --git a/test/rules/strict-type-predicates/unknown/tslint.json b/test/rules/strict-type-predicates/unknown/tslint.json new file mode 100644 index 00000000000..bb5f9231e91 --- /dev/null +++ b/test/rules/strict-type-predicates/unknown/tslint.json @@ -0,0 +1,5 @@ +{ + "rules": { + "strict-type-predicates": true + } +}