From 572e6f4932e2fb18a17b7fe60892855a21e6ec65 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 22 Aug 2022 21:07:26 -0700 Subject: [PATCH 1/8] Add rules from recommended set that triggered good lints --- .eslintrc.json | 12 +++++++++++- src/.eslintrc.json | 3 ++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 789725d782835..df14e61ace91d 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -2,7 +2,6 @@ "parser": "@typescript-eslint/parser", "parserOptions": { "warnOnUnsupportedTypeScriptVersion": false, - "ecmaVersion": 6, "sourceType": "module" }, "env": { @@ -25,6 +24,17 @@ { "files": ["*.ts"] } ], "rules": { + // TODO(jakebailey): organize + "no-useless-escape": "error", + "no-prototype-builtins": "error", + "no-self-assign": "error", + "no-dupe-else-if": "error", + "@typescript-eslint/no-extra-semi": "error", + "@typescript-eslint/prefer-as-const": "error", + "@typescript-eslint/no-extra-non-null-assertion": "off", // TODO(jakebailey): reenable + "@typescript-eslint/no-non-null-asserted-optional-chain": "off", // TODO(jakebailey): reenable + "@typescript-eslint/no-array-constructor": "error", + "@typescript-eslint/adjacent-overload-signatures": "error", "@typescript-eslint/array-type": "error", diff --git a/src/.eslintrc.json b/src/.eslintrc.json index f7ec4c8a8f555..94b2ab745807d 100644 --- a/src/.eslintrc.json +++ b/src/.eslintrc.json @@ -6,7 +6,8 @@ }, "rules": { "@typescript-eslint/no-unnecessary-qualifier": "error", - "@typescript-eslint/no-unnecessary-type-assertion": "error" + "@typescript-eslint/no-unnecessary-type-assertion": "error", + "@typescript-eslint/restrict-plus-operands": "error" }, "overrides": [ { From cff4cff0b397ab0a2d4bdf7041fd50da8ed54df6 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 22 Aug 2022 21:27:51 -0700 Subject: [PATCH 2/8] Fix autofixable --- src/compiler/checker.ts | 4 ++-- src/compiler/parser.ts | 2 +- src/compiler/program.ts | 2 +- src/compiler/scanner.ts | 2 +- src/compiler/tracing.ts | 2 +- src/compiler/tsbuildPublic.ts | 2 +- src/compiler/utilities.ts | 2 +- src/executeCommandLine/executeCommandLine.ts | 2 +- src/harness/fourslashImpl.ts | 2 +- src/harness/fourslashInterfaceImpl.ts | 4 ++-- src/harness/harnessIO.ts | 2 +- src/server/session.ts | 2 +- src/services/completions.ts | 4 ++-- src/services/refactors/convertExport.ts | 2 +- src/services/refactors/convertToOptionalChainExpression.ts | 4 ++-- src/services/refactors/helpers.ts | 2 +- src/services/refactors/moveToNewFile.ts | 2 +- src/testRunner/unittests/tsbuild/outputPaths.ts | 2 +- src/testRunner/unittests/tsserver/helpers.ts | 2 +- src/testRunner/unittests/tsserver/projects.ts | 2 +- 20 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8472c8b38e7e5..19f8ab3cc0002 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9198,7 +9198,7 @@ namespace ts { if (container && (container.kind === SyntaxKind.Constructor || isJSConstructor(container))) { return container as ConstructorDeclaration; } - }; + } } /** Create a synthetic property access flow node after the last statement of the file */ @@ -29739,7 +29739,7 @@ namespace ts { return !!s && getMinArgumentCount(s) >= 1 && isTypeAssignableTo(keyedType, getTypeAtPosition(s, 0)); } return false; - }; + } const suggestedMethod = isAssignmentTarget(expr) ? "set" : "get"; if (!hasProp(suggestedMethod)) { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 1b82ae4d9a335..b29f2688e9075 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -739,7 +739,7 @@ namespace ts { return visitNodes(cbNode, cbNodes, node.typeParameters) || visitNodes(cbNode, cbNodes, node.parameters) || visitNode(cbNode, node.type); - }; + } function forEachChildInUnionOrIntersectionType(node: UnionTypeNode | IntersectionTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { return visitNodes(cbNode, cbNodes, node.types); diff --git a/src/compiler/program.ts b/src/compiler/program.ts index e7c0f363ea8df..6d863142a8359 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -503,7 +503,7 @@ namespace ts { /* @internal */ imports: SourceFile["imports"]; /* @internal */ moduleAugmentations: SourceFile["moduleAugmentations"]; impliedNodeFormat?: SourceFile["impliedNodeFormat"]; - }; + } /** * Calculates the resulting resolution mode for some reference in some file - this is generally the explicitly diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 107ff3a143efa..e5ca88d8e1278 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -359,7 +359,7 @@ namespace ts { /* @internal */ export function computeLineStarts(text: string): number[] { - const result: number[] = new Array(); + const result: number[] = []; let pos = 0; let lineStart = 0; while (pos < text.length) { diff --git a/src/compiler/tracing.ts b/src/compiler/tracing.ts index 3fe7e335c7b35..0e629052c4e63 100644 --- a/src/compiler/tracing.ts +++ b/src/compiler/tracing.ts @@ -25,7 +25,7 @@ namespace ts { // eslint-disable-line local/one-namespace-per-file // The actual constraint is that JSON.stringify be able to serialize it without throwing. interface Args { [key: string]: string | number | boolean | null | undefined | Args | readonly (string | number | boolean | null | undefined | Args)[]; - }; + } /** Starts tracing for the given project. */ export function startTracing(tracingMode: Mode, traceDir: string, configFilePath?: string) { diff --git a/src/compiler/tsbuildPublic.ts b/src/compiler/tsbuildPublic.ts index 2b9d97f324ee2..cef7d432f8892 100644 --- a/src/compiler/tsbuildPublic.ts +++ b/src/compiler/tsbuildPublic.ts @@ -487,7 +487,7 @@ namespace ts { // TODO(rbuckton): Should be a `Set`, but that requires changing the code below that uses `mutateMapSkippingNewValues` const currentProjects = new Map( getBuildOrderFromAnyBuildOrder(buildOrder).map( - resolved => [toResolvedConfigFilePath(state, resolved), true as true]) + resolved => [toResolvedConfigFilePath(state, resolved), true as const]) ); const noopOnDelete = { onDeleteValue: noop }; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 62a941df1f79f..f76ea33851664 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -563,7 +563,7 @@ namespace ts { interface ScriptTargetFeatures { [key: string]: { [key: string]: string[] | undefined }; - }; + } export function getScriptTargetFeatures(): ScriptTargetFeatures { return { diff --git a/src/executeCommandLine/executeCommandLine.ts b/src/executeCommandLine/executeCommandLine.ts index cb3ba0575a146..5a891ad05c580 100644 --- a/src/executeCommandLine/executeCommandLine.ts +++ b/src/executeCommandLine/executeCommandLine.ts @@ -431,7 +431,7 @@ namespace ts { function getHeader(sys: System, message: string) { const colors = createColors(sys); const header: string[] = []; - const terminalWidth = sys.getWidthOfTerminal?.() ?? 0;; + const terminalWidth = sys.getWidthOfTerminal?.() ?? 0; const tsIconLength = 5; const tsIconFirstLine = colors.blueBackground(padLeft("", tsIconLength)); diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 46d2bc242e772..72ceb827adf95 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -2737,7 +2737,7 @@ namespace FourSlash { const identifier = this.classificationToIdentifier(a.classificationType as number); const text = this.activeFile.content.slice(a.textSpan.start, a.textSpan.start + a.textSpan.length); replacement.push(` c2.semanticToken("${identifier}", "${text}"), `); - }; + } replacement.push(");"); throw new Error("You need to change the source code of fourslash test to use replaceWithSemanticClassifications"); diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index 93508a079ab5a..053a232f4f619 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -1895,11 +1895,11 @@ namespace FourSlashInterface { }; export interface DiagnosticIgnoredInterpolations { template: string - }; + } export type RenameLocationOptions = FourSlash.Range | { readonly range: FourSlash.Range, readonly prefixText?: string, readonly suffixText?: string }; export interface RenameOptions { readonly findInStrings?: boolean; readonly findInComments?: boolean; readonly providePrefixAndSuffixTextForRename?: boolean; - }; + } } diff --git a/src/harness/harnessIO.ts b/src/harness/harnessIO.ts index 2786498d41e1f..90c09505b7a33 100644 --- a/src/harness/harnessIO.ts +++ b/src/harness/harnessIO.ts @@ -1496,7 +1496,7 @@ namespace Harness { export function getConfigNameFromFileName(filename: string): "tsconfig.json" | "jsconfig.json" | undefined { const flc = ts.getBaseFileName(filename).toLowerCase(); - return ts.find(["tsconfig.json" as "tsconfig.json", "jsconfig.json" as "jsconfig.json"], x => x === flc); + return ts.find(["tsconfig.json" as const, "jsconfig.json" as const], x => x === flc); } if (Error) (Error as any).stackTraceLimit = 100; diff --git a/src/server/session.ts b/src/server/session.ts index a541463063c5c..9f21e99915f1f 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -297,7 +297,7 @@ namespace ts.server { interface ProjectNavigateToItems { project: Project; navigateToItems: readonly NavigateToItem[]; - }; + } function createDocumentSpanSet(): Set { return createSet(({textSpan}) => textSpan.start + 100003 * textSpan.length, documentSpansEqual); diff --git a/src/services/completions.ts b/src/services/completions.ts index c24bc8dcaf165..46f2300e3cedf 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -1107,7 +1107,7 @@ namespace ts.Completions { return { isSnippet, insertText, labelDetails }; - }; + } function createObjectLiteralMethod( symbol: Symbol, @@ -4328,7 +4328,7 @@ namespace ts.Completions { function isArrowFunctionBody(node: Node) { return node.parent && isArrowFunction(node.parent) && node.parent.body === node; - }; + } /** True if symbol is a type or a module containing at least one type. */ function symbolCanBeReferencedAtTypeLocation(symbol: Symbol, checker: TypeChecker, seenModules = new Map()): boolean { diff --git a/src/services/refactors/convertExport.ts b/src/services/refactors/convertExport.ts index cb79dd2672fa4..ffde52b9571ab 100644 --- a/src/services/refactors/convertExport.ts +++ b/src/services/refactors/convertExport.ts @@ -54,7 +54,7 @@ namespace ts.refactor { readonly exportName: Identifier; // This is exportNode.name except for VariableStatement_s. readonly wasDefault: boolean; readonly exportingModuleSymbol: Symbol; - }; + } function getInfo(context: RefactorContext, considerPartialSpans = true): ExportInfo | RefactorErrorInfo | undefined { const { file, program } = context; diff --git a/src/services/refactors/convertToOptionalChainExpression.ts b/src/services/refactors/convertToOptionalChainExpression.ts index ba40ec6a5e553..a8c13e42f94fc 100644 --- a/src/services/refactors/convertToOptionalChainExpression.ts +++ b/src/services/refactors/convertToOptionalChainExpression.ts @@ -51,7 +51,7 @@ namespace ts.refactor.convertToOptionalChainExpression { finalExpression: PropertyAccessExpression | ElementAccessExpression | CallExpression, occurrences: Occurrence[], expression: ValidExpression, - }; + } type ValidExpressionOrStatement = ValidExpression | ValidStatement; @@ -119,7 +119,7 @@ namespace ts.refactor.convertToOptionalChainExpression { function getBinaryInfo(expression: BinaryExpression): OptionalChainInfo | RefactorErrorInfo | undefined { if (expression.operatorToken.kind !== SyntaxKind.AmpersandAmpersandToken) { return { error: getLocaleSpecificMessage(Diagnostics.Can_only_convert_logical_AND_access_chains) }; - }; + } const finalExpression = getFinalExpressionInChain(expression.right); if (!finalExpression) return { error: getLocaleSpecificMessage(Diagnostics.Could_not_find_convertible_access_expression) }; diff --git a/src/services/refactors/helpers.ts b/src/services/refactors/helpers.ts index e86229af915d1..25fcc1a3f5bc1 100644 --- a/src/services/refactors/helpers.ts +++ b/src/services/refactors/helpers.ts @@ -5,7 +5,7 @@ namespace ts.refactor { */ export interface RefactorErrorInfo { error: string; - }; + } /** * Checks if some refactor info has refactor error info. diff --git a/src/services/refactors/moveToNewFile.ts b/src/services/refactors/moveToNewFile.ts index 287178169e6c1..b01218a95ba5a 100644 --- a/src/services/refactors/moveToNewFile.ts +++ b/src/services/refactors/moveToNewFile.ts @@ -97,7 +97,7 @@ namespace ts.refactor { // Filters imports and prologue directives out of the range of statements to move. // Imports will be copied to the new file anyway, and may still be needed in the old file. // Prologue directives will be copied to the new file and should be left in the old file. - return !isPureImport(statement) && !isPrologueDirective(statement);; + return !isPureImport(statement) && !isPrologueDirective(statement); } function isPureImport(node: Node): boolean { diff --git a/src/testRunner/unittests/tsbuild/outputPaths.ts b/src/testRunner/unittests/tsbuild/outputPaths.ts index 72374f846115f..3bcad56dd68ab 100644 --- a/src/testRunner/unittests/tsbuild/outputPaths.ts +++ b/src/testRunner/unittests/tsbuild/outputPaths.ts @@ -19,7 +19,7 @@ namespace ts { it("verify getOutputFileNames", () => { const sys = new fakes.System(input.fs().makeReadonly(), { executingFilePath: "/lib/tsc" }) as TscCompileSystem; - ; + assert.deepEqual( getOutputFileNames( parseConfigFileWithSystem("/src/tsconfig.json", {}, /*extendedConfigCache*/ undefined, {}, sys, noop)!, diff --git a/src/testRunner/unittests/tsserver/helpers.ts b/src/testRunner/unittests/tsserver/helpers.ts index f87355f7491f9..0628d85dfb27a 100644 --- a/src/testRunner/unittests/tsserver/helpers.ts +++ b/src/testRunner/unittests/tsserver/helpers.ts @@ -738,7 +738,7 @@ namespace ts.projectSystem { checkAllErrors(request); } - interface SkipErrors { semantic?: true; suggestion?: true }; + interface SkipErrors { semantic?: true; suggestion?: true } export interface CheckAllErrors extends VerifyGetErrRequestBase { files: readonly any[]; skip?: readonly (SkipErrors | undefined)[]; diff --git a/src/testRunner/unittests/tsserver/projects.ts b/src/testRunner/unittests/tsserver/projects.ts index 7bd5af3fa4f34..3223bb3222a58 100644 --- a/src/testRunner/unittests/tsserver/projects.ts +++ b/src/testRunner/unittests/tsserver/projects.ts @@ -567,7 +567,7 @@ namespace ts.projectSystem { path: "/a/b/file1.js", content: "var x = 10;", fileName: "/a/b/file1.js", - scriptKind: "JS" as "JS" + scriptKind: "JS" as const }; const host = createServerHost([]); From 77a2b745b0e63f0a8ad3876b34bb544395931e7a Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 22 Aug 2022 21:54:18 -0700 Subject: [PATCH 3/8] Fix a bunch of lints --- .eslintrc.json | 2 +- scripts/word2md.ts | 2 +- src/.eslintrc.json | 3 +-- src/compiler/commandLineParser.ts | 2 +- src/compiler/debug.ts | 4 ++-- src/compiler/factory/nodeFactory.ts | 2 +- src/compiler/utilities.ts | 2 +- src/compiler/utilitiesPublic.ts | 2 +- src/harness/harnessIO.ts | 2 +- src/harness/harnessUtils.ts | 2 +- src/harness/vfsUtil.ts | 3 +-- src/loggedIO/loggedIO.ts | 2 +- src/server/editorServices.ts | 2 +- src/services/formatting/rules.ts | 10 +++++----- src/services/stringCompletions.ts | 2 +- 15 files changed, 20 insertions(+), 22 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index df14e61ace91d..5c31d08131c26 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -25,7 +25,7 @@ ], "rules": { // TODO(jakebailey): organize - "no-useless-escape": "error", + "no-useless-escape": "off", // appears to be wrong in some instances "no-prototype-builtins": "error", "no-self-assign": "error", "no-dupe-else-if": "error", diff --git a/scripts/word2md.ts b/scripts/word2md.ts index ed0338617d8be..472699156bb8b 100644 --- a/scripts/word2md.ts +++ b/scripts/word2md.ts @@ -185,7 +185,7 @@ function convertDocumentToMarkdown(doc: Word.Document): string { function setProperties(target: any, properties: any) { for (const name in properties) { - if (properties.hasOwnProperty(name)) { + if (Object.prototype.hasOwnProperty.call(properties, name)) { const value = properties[name]; if (typeof value === "object") { setProperties(target[name], value); diff --git a/src/.eslintrc.json b/src/.eslintrc.json index 94b2ab745807d..f7ec4c8a8f555 100644 --- a/src/.eslintrc.json +++ b/src/.eslintrc.json @@ -6,8 +6,7 @@ }, "rules": { "@typescript-eslint/no-unnecessary-qualifier": "error", - "@typescript-eslint/no-unnecessary-type-assertion": "error", - "@typescript-eslint/restrict-plus-operands": "error" + "@typescript-eslint/no-unnecessary-type-assertion": "error" }, "overrides": [ { diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 370461abd8559..cea4931949406 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -3705,7 +3705,7 @@ namespace ts { export function convertCompilerOptionsForTelemetry(opts: CompilerOptions): CompilerOptions { const out: CompilerOptions = {}; for (const key in opts) { - if (opts.hasOwnProperty(key)) { + if (hasProperty(opts, key)) { const type = getOptionFromName(key); if (type !== undefined) { // Ignore unknown options out[key] = getOptionValueWithEmptyStrings(opts[key], type); diff --git a/src/compiler/debug.ts b/src/compiler/debug.ts index d6edd94b3dc49..70893ceb29bc1 100644 --- a/src/compiler/debug.ts +++ b/src/compiler/debug.ts @@ -279,7 +279,7 @@ namespace ts { if (typeof func !== "function") { return ""; } - else if (func.hasOwnProperty("name")) { + else if (hasProperty(func, "name")) { return (func as any).name; } else { @@ -625,7 +625,7 @@ namespace ts { ]; for (const ctor of nodeConstructors) { - if (!ctor.prototype.hasOwnProperty("__debugKind")) { + if (!hasProperty(ctor, "__debugKind")) { Object.defineProperties(ctor.prototype, { // for use with vscode-js-debug's new customDescriptionGenerator in launch.json __tsDebuggerDisplay: { diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index 399dfd9d64640..5c9c3dd9ebc9e 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -5572,7 +5572,7 @@ namespace ts { setOriginalNode(clone, node); for (const key in node) { - if (clone.hasOwnProperty(key) || !node.hasOwnProperty(key)) { + if (hasProperty(clone, key) || !hasProperty(node, key)) { continue; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index f76ea33851664..90b8ff5456e2e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -5548,7 +5548,7 @@ namespace ts { export function isWatchSet(options: CompilerOptions) { // Firefox has Object.prototype.watch - return options.watch && options.hasOwnProperty("watch"); + return options.watch && hasProperty(options, "watch"); } export function closeFileWatcher(watcher: FileWatcher) { diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index 229620a1191b9..1a8f322765056 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -1121,7 +1121,7 @@ namespace ts { /* @internal */ export function isNodeArray(array: readonly T[]): array is NodeArray { - return array.hasOwnProperty("pos") && array.hasOwnProperty("end"); + return hasProperty(array, "pos") && hasProperty(array, "end"); } // Literals diff --git a/src/harness/harnessIO.ts b/src/harness/harnessIO.ts index 90c09505b7a33..87148c13492a7 100644 --- a/src/harness/harnessIO.ts +++ b/src/harness/harnessIO.ts @@ -335,7 +335,7 @@ namespace Harness { export function setCompilerOptionsFromHarnessSetting(settings: TestCaseParser.CompilerSettings, options: ts.CompilerOptions & HarnessOptions): void { for (const name in settings) { - if (settings.hasOwnProperty(name)) { + if (ts.hasProperty(settings, name)) { const value = settings[name]; if (value === undefined) { throw new Error(`Cannot have undefined value for compiler option '${name}'.`); diff --git a/src/harness/harnessUtils.ts b/src/harness/harnessUtils.ts index 97da7e0e3ec99..5ac968035346d 100644 --- a/src/harness/harnessUtils.ts +++ b/src/harness/harnessUtils.ts @@ -314,7 +314,7 @@ namespace Utils { function findChildName(parent: any, child: any) { for (const name in parent) { - if (parent.hasOwnProperty(name) && parent[name] === child) { + if (ts.hasProperty(parent, name) && parent[name] === child) { return name; } } diff --git a/src/harness/vfsUtil.ts b/src/harness/vfsUtil.ts index 63a3d6963d55e..f102bb0ddb63a 100644 --- a/src/harness/vfsUtil.ts +++ b/src/harness/vfsUtil.ts @@ -916,7 +916,6 @@ namespace vfs { if (this._shadowRoot) { this._copyShadowLinks(this._shadowRoot._getRootLinks(), this._lazy.links); } - this._lazy.links = this._lazy.links; } return this._lazy.links; } @@ -1578,7 +1577,7 @@ namespace vfs { const entry = normalizeFileSetEntry(container[name]); const file = dirname ? vpath.combine(dirname, name) : name; // eslint-disable-next-line no-null/no-null - if (entry === null || entry === undefined || entry instanceof Unlink || entry instanceof Rmdir) { + if (entry === null || entry === undefined || entry instanceof Unlink) { text += `//// [${file}] unlink\r\n`; } else if (entry instanceof Rmdir) { diff --git a/src/loggedIO/loggedIO.ts b/src/loggedIO/loggedIO.ts index 24b3f815f605e..5a0a658330b19 100644 --- a/src/loggedIO/loggedIO.ts +++ b/src/loggedIO/loggedIO.ts @@ -94,7 +94,7 @@ namespace Playback { // eslint-disable-line local/one-namespace-per-file function memoize(func: (s: string) => T): Memoized { let lookup: { [s: string]: T } = {}; const run: Memoized = ((s: string) => { - if (lookup.hasOwnProperty(s)) return lookup[s]; + if (Object.prototype.hasOwnProperty.call(lookup, s)) return lookup[s]; return lookup[s] = func(s); }) as Memoized; run.reset = () => { diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index c6d1513c0771f..b9a7249ecef42 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -940,7 +940,7 @@ namespace ts.server { // raw is now fixed and ready this.safelist = raw.typesMap; for (const key in raw.simpleMap) { - if (raw.simpleMap.hasOwnProperty(key)) { + if (hasProperty(raw.simpleMap, key)) { this.legacySafelist.set(key, raw.simpleMap[key].toLowerCase()); } } diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts index 76cd5aa6e4f8e..45a8abb6a2ce0 100644 --- a/src/services/formatting/rules.ts +++ b/src/services/formatting/rules.ts @@ -410,23 +410,23 @@ namespace ts.formatting { } function isOptionEnabled(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { - return (context) => context.options && context.options.hasOwnProperty(optionName) && !!context.options[optionName]; + return (context) => context.options && hasProperty(context.options, optionName) && !!context.options[optionName]; } function isOptionDisabled(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { - return (context) => context.options && context.options.hasOwnProperty(optionName) && !context.options[optionName]; + return (context) => context.options && hasProperty(context.options, optionName) && !context.options[optionName]; } function isOptionDisabledOrUndefined(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { - return (context) => !context.options || !context.options.hasOwnProperty(optionName) || !context.options[optionName]; + return (context) => !context.options || !hasProperty(context.options, optionName) || !context.options[optionName]; } function isOptionDisabledOrUndefinedOrTokensOnSameLine(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { - return (context) => !context.options || !context.options.hasOwnProperty(optionName) || !context.options[optionName] || context.TokensAreOnSameLine(); + return (context) => !context.options || !hasProperty(context.options, optionName) || !context.options[optionName] || context.TokensAreOnSameLine(); } function isOptionEnabledOrUndefined(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { - return (context) => !context.options || !context.options.hasOwnProperty(optionName) || !!context.options[optionName]; + return (context) => !context.options || !hasProperty(context.options, optionName) || !!context.options[optionName]; } function isForContext(context: FormattingContext): boolean { diff --git a/src/services/stringCompletions.ts b/src/services/stringCompletions.ts index cb7260f6d8068..6327cbcbc19ee 100644 --- a/src/services/stringCompletions.ts +++ b/src/services/stringCompletions.ts @@ -936,7 +936,7 @@ namespace ts.Completions.StringCompletions { const dependencies: object | undefined = (contents as any)[key]; if (!dependencies) continue; for (const dep in dependencies) { - if (dependencies.hasOwnProperty(dep) && !startsWith(dep, "@types/")) { + if (hasProperty(dependencies, dep) && !startsWith(dep, "@types/")) { result.push(dep); } } From 6316ac8b95faa8b3e546bd5404e555d728488f89 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 23 Aug 2022 12:05:54 -0700 Subject: [PATCH 4/8] Use ts.hasProperty --- src/loggedIO/loggedIO.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/loggedIO/loggedIO.ts b/src/loggedIO/loggedIO.ts index 5a0a658330b19..6018ee1026e3d 100644 --- a/src/loggedIO/loggedIO.ts +++ b/src/loggedIO/loggedIO.ts @@ -94,7 +94,7 @@ namespace Playback { // eslint-disable-line local/one-namespace-per-file function memoize(func: (s: string) => T): Memoized { let lookup: { [s: string]: T } = {}; const run: Memoized = ((s: string) => { - if (Object.prototype.hasOwnProperty.call(lookup, s)) return lookup[s]; + if (ts.hasProperty(lookup, s)) return lookup[s]; return lookup[s] = func(s); }) as Memoized; run.reset = () => { From ba00330382abf02f841fb58a2957d10b28d76f75 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 23 Aug 2022 13:25:34 -0700 Subject: [PATCH 5/8] Move rules --- .eslintrc.json | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 5c31d08131c26..624e2a045e890 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -24,19 +24,9 @@ { "files": ["*.ts"] } ], "rules": { - // TODO(jakebailey): organize - "no-useless-escape": "off", // appears to be wrong in some instances - "no-prototype-builtins": "error", - "no-self-assign": "error", - "no-dupe-else-if": "error", - "@typescript-eslint/no-extra-semi": "error", - "@typescript-eslint/prefer-as-const": "error", - "@typescript-eslint/no-extra-non-null-assertion": "off", // TODO(jakebailey): reenable - "@typescript-eslint/no-non-null-asserted-optional-chain": "off", // TODO(jakebailey): reenable - "@typescript-eslint/no-array-constructor": "error", - "@typescript-eslint/adjacent-overload-signatures": "error", "@typescript-eslint/array-type": "error", + "@typescript-eslint/no-array-constructor": "error", "brace-style": "off", "@typescript-eslint/brace-style": ["error", "stroustrup", { "allowSingleLine": true }], @@ -72,12 +62,14 @@ "@typescript-eslint/prefer-for-of": "error", "@typescript-eslint/prefer-function-type": "error", "@typescript-eslint/prefer-namespace-keyword": "error", + "@typescript-eslint/prefer-as-const": "error", "quotes": "off", "@typescript-eslint/quotes": ["error", "double", { "avoidEscape": true, "allowTemplateLiterals": true }], "semi": "off", "@typescript-eslint/semi": "error", + "@typescript-eslint/no-extra-semi": "error", "space-before-function-paren": "off", "@typescript-eslint/space-before-function-paren": ["error", { @@ -90,6 +82,9 @@ "@typescript-eslint/type-annotation-spacing": "error", "@typescript-eslint/unified-signatures": "error", + "@typescript-eslint/no-extra-non-null-assertion": "off", // TODO(jakebailey): reenable + "@typescript-eslint/no-non-null-asserted-optional-chain": "off", // TODO(jakebailey): reenable + // scripts/eslint/rules "local/object-literal-surrounding-space": "error", "local/no-type-assertion-whitespace": "error", @@ -153,6 +148,9 @@ "quote-props": ["error", "consistent-as-needed"], "space-in-parens": "error", "unicode-bom": ["error", "never"], - "use-isnan": "error" + "use-isnan": "error", + "no-prototype-builtins": "error", + "no-self-assign": "error", + "no-dupe-else-if": "error" } } From 4650c81858ca689840df6f544b412484a0679ae3 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 23 Aug 2022 13:59:25 -0700 Subject: [PATCH 6/8] Reenable other good lints to do with null assertion --- .eslintrc.json | 4 ++-- src/compiler/binder.ts | 9 ++++++--- src/compiler/checker.ts | 4 ++-- src/compiler/transformers/declarations.ts | 4 ++-- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 624e2a045e890..737b0cb319c5d 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -82,8 +82,8 @@ "@typescript-eslint/type-annotation-spacing": "error", "@typescript-eslint/unified-signatures": "error", - "@typescript-eslint/no-extra-non-null-assertion": "off", // TODO(jakebailey): reenable - "@typescript-eslint/no-non-null-asserted-optional-chain": "off", // TODO(jakebailey): reenable + "@typescript-eslint/no-extra-non-null-assertion": "error", + "@typescript-eslint/no-non-null-asserted-optional-chain": "error", // scripts/eslint/rules "local/object-literal-surrounding-space": "error", diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 6ffe3a7ef526e..9dd2d363cf009 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -3041,8 +3041,11 @@ namespace ts { return; } const rootExpr = getLeftmostAccessExpression(node.left); - if (isIdentifier(rootExpr) && lookupSymbolForName(container, rootExpr.escapedText)!?.flags & SymbolFlags.Alias) { - return; + if (isIdentifier(rootExpr)) { + const symbol = lookupSymbolForName(container, rootExpr.escapedText); + if (symbol && symbol.flags & SymbolFlags.Alias) { + return; + } } // Fix up parent pointers since we're going to use these nodes before we bind into them setParent(node.left, node); @@ -3074,7 +3077,7 @@ namespace ts { } function bindPotentiallyMissingNamespaces(namespaceSymbol: Symbol | undefined, entityName: BindableStaticNameExpression, isToplevel: boolean, isPrototypeProperty: boolean, containerIsClass: boolean) { - if (namespaceSymbol?.flags! & SymbolFlags.Alias) { + if (namespaceSymbol && namespaceSymbol.flags & SymbolFlags.Alias) { return namespaceSymbol; } if (isToplevel && !isPrototypeProperty) { diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 19f8ab3cc0002..9beb57bdae6d6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5837,8 +5837,8 @@ namespace ts { } function preserveCommentsOn(node: T) { - if (some(propertySymbol.declarations, d => d.kind === SyntaxKind.JSDocPropertyTag)) { - const d = propertySymbol.declarations?.find(d => d.kind === SyntaxKind.JSDocPropertyTag)! as JSDocPropertyTag; + const d = propertySymbol.declarations?.find(d => d.kind === SyntaxKind.JSDocPropertyTag) as JSDocPropertyTag | undefined; + if (d) { const commentText = getTextOfJSDocComment(d.comment); if (commentText) { setSyntheticLeadingComments(node, [{ kind: SyntaxKind.MultiLineCommentTrivia, text: "*\n * " + commentText.replace(/\n/g, "\n * ") + "\n ", pos: -1, end: -1, hasTrailingNewLine: true }]); diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index d64c14b2e0b2c..e453b77a3bff2 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -218,9 +218,9 @@ namespace ts { } function reportNonlocalAugmentation(containingFile: SourceFile, parentSymbol: Symbol, symbol: Symbol) { - const primaryDeclaration = parentSymbol.declarations?.find(d => getSourceFileOfNode(d) === containingFile)!; + const primaryDeclaration = parentSymbol.declarations?.find(d => getSourceFileOfNode(d) === containingFile); const augmentingDeclarations = filter(symbol.declarations, d => getSourceFileOfNode(d) !== containingFile); - if (augmentingDeclarations) { + if (primaryDeclaration && augmentingDeclarations) { for (const augmentations of augmentingDeclarations) { context.addDiagnostic(addRelatedInfo( createDiagnosticForNode(augmentations, Diagnostics.Declaration_augments_declaration_in_another_file_This_cannot_be_serialized), From d2d6c579feb7a9854f1b3ccb9f27b6fce865c8bb Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 19 Sep 2022 14:38:45 -0700 Subject: [PATCH 7/8] Revert undefined bitwise and change --- .eslintrc.json | 1 - src/compiler/binder.ts | 9 +++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index b7e0e9331fd16..1711f8592ab18 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -83,7 +83,6 @@ "@typescript-eslint/unified-signatures": "error", "@typescript-eslint/no-extra-non-null-assertion": "error", - "@typescript-eslint/no-non-null-asserted-optional-chain": "error", // scripts/eslint/rules "local/object-literal-surrounding-space": "error", diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 93d497b5ee65e..4c3eac092b45a 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -3044,11 +3044,8 @@ namespace ts { return; } const rootExpr = getLeftmostAccessExpression(node.left); - if (isIdentifier(rootExpr)) { - const symbol = lookupSymbolForName(container, rootExpr.escapedText); - if (symbol && symbol.flags & SymbolFlags.Alias) { - return; - } + if (isIdentifier(rootExpr) && lookupSymbolForName(container, rootExpr.escapedText)?.flags! & SymbolFlags.Alias) { + return; } // Fix up parent pointers since we're going to use these nodes before we bind into them setParent(node.left, node); @@ -3080,7 +3077,7 @@ namespace ts { } function bindPotentiallyMissingNamespaces(namespaceSymbol: Symbol | undefined, entityName: BindableStaticNameExpression, isToplevel: boolean, isPrototypeProperty: boolean, containerIsClass: boolean) { - if (namespaceSymbol && namespaceSymbol.flags & SymbolFlags.Alias) { + if (namespaceSymbol?.flags! & SymbolFlags.Alias) { return namespaceSymbol; } if (isToplevel && !isPrototypeProperty) { From 9a4f3e2471df3815cceb719334646eac27226fb9 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 19 Sep 2022 14:40:30 -0700 Subject: [PATCH 8/8] Another revert --- src/compiler/checker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6df4719e94943..afac9b5a1ae85 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5868,8 +5868,8 @@ namespace ts { } function preserveCommentsOn(node: T) { - const d = propertySymbol.declarations?.find(d => d.kind === SyntaxKind.JSDocPropertyTag) as JSDocPropertyTag | undefined; - if (d) { + if (some(propertySymbol.declarations, d => d.kind === SyntaxKind.JSDocPropertyTag)) { + const d = propertySymbol.declarations?.find(d => d.kind === SyntaxKind.JSDocPropertyTag)! as JSDocPropertyTag; const commentText = getTextOfJSDocComment(d.comment); if (commentText) { setSyntheticLeadingComments(node, [{ kind: SyntaxKind.MultiLineCommentTrivia, text: "*\n * " + commentText.replace(/\n/g, "\n * ") + "\n ", pos: -1, end: -1, hasTrailingNewLine: true }]);