-
Notifications
You must be signed in to change notification settings - Fork 887
Update dependencies and lint for no-unsafe-any #2544
Conversation
1e9977f
to
d9faf67
Compare
src/language/formatter/formatter.ts
Outdated
@@ -46,6 +46,10 @@ export interface IFormatterMetadata { | |||
|
|||
export type ConsumerType = "human" | "machine"; | |||
|
|||
export interface FormatterStatic { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename to FormatterConstructor?
import { arrayify, camelize, dedent } from "./utils"; | ||
|
||
const moduleDirectory = path.dirname(module.filename); | ||
const CORE_RULES_DIRECTORY = path.resolve(moduleDirectory, ".", "rules"); | ||
const cachedRules = new Map<string, typeof AbstractRule | null>(); // null indicates that the rule was not found |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually I found this to be clearer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But rules aren't actually guaranteed to be implemented by AbstractRule
subclasses, are they?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that it's renamed to RuleConstructor
I'm fine with it.
src/language/rule/rule.ts
Outdated
@@ -20,6 +20,11 @@ import * as ts from "typescript"; | |||
import {arrayify, flatMap} from "../../utils"; | |||
import {IWalker} from "../walker"; | |||
|
|||
export interface RuleStatic { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also rename to RuleConstructor?
src/ruleLoader.ts
Outdated
@@ -153,9 +152,9 @@ function loadCachedRule(directory: string, ruleName: string, isCustomPath = fals | |||
} | |||
} | |||
|
|||
let Rule: typeof AbstractRule | null = null; | |||
let Rule: RuleStatic | null = null; | |||
if (absolutePath != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this comparison can be strict
@@ -87,7 +87,7 @@ class NoInferredEmptyObjectTypeRule extends Lint.ProgramAwareRuleWalker { | |||
let isAnonymous: boolean; | |||
if (ts.ObjectFlags == null) { | |||
// typescript 2.0.x specific code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this branch can be removed since support for ts 2.0.x was dropped in v5.0.0
@@ -44,7 +44,7 @@ export function objectify(arg: any): any { | |||
* E.g. "foo-bar" -> "fooBar" | |||
*/ | |||
export function camelize(stringWithHyphens: string): string { | |||
return stringWithHyphens.replace(/-(.)/g, (_, nextLetter) => nextLetter.toUpperCase()); | |||
return stringWithHyphens.replace(/-(.)/g, (_, nextLetter) => (nextLetter as string).toUpperCase()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
consider adding the type annotation to the parameter instead of asserting it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like that style since it behaves the same as a typecast but doesn't look like one. Was actually considering writing a lint rule for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
um, I don't think that's quite right @andy-hanson. type assertions (as string
) are generally less safe than typedefs, because the assignability checks for the latter are stricter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A type annotation in a callback is unsafe.
declare function f(cb: (x: {}) => void): void;
f((n: number) => { console.log(n + 1); }); // Huh, no error?
A type assertion is of course also unsafe, but it's more obvious that it is.
src/ruleLoader.ts
Outdated
return ruleModule.Rule; | ||
} | ||
} | ||
return undefined; | ||
return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why the switch to nulls? can't we use undefined?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We use cachedRules.set(fullPath, Rule);
, so if Rule
is undefined, it will look like we didn't cache a result at all. I actually already had to do this in #2369.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we should use a string literal like "not-found" or "load-error" instead of null
@@ -44,7 +44,7 @@ export function objectify(arg: any): any { | |||
* E.g. "foo-bar" -> "fooBar" | |||
*/ | |||
export function camelize(stringWithHyphens: string): string { | |||
return stringWithHyphens.replace(/-(.)/g, (_, nextLetter) => nextLetter.toUpperCase()); | |||
return stringWithHyphens.replace(/-(.)/g, (_, nextLetter) => (nextLetter as string).toUpperCase()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
um, I don't think that's quite right @andy-hanson. type assertions (as string
) are generally less safe than typedefs, because the assignability checks for the latter are stricter
@@ -193,8 +193,8 @@ export class Runner { | |||
try { | |||
this.processFiles(onComplete, files, program); | |||
} catch (error) { | |||
if (error.name === FatalError.NAME) { | |||
console.error(error.message); | |||
if ((error as FatalError).name === FatalError.NAME) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you use error: FatalError
on the line above instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, TS doesn't allow a type annotation there. It wouldn't be safe anyway since TS doesn't have checked exceptions.
src/rules/noUnsafeAnyRule.ts
Outdated
@@ -36,7 +36,7 @@ export class Rule extends Lint.Rules.TypedRule { | |||
}; | |||
/* tslint:enable:object-literal-sort-keys */ | |||
|
|||
public static FAILURE_STRING = "Unsafe use of expression of type 'any'."; | |||
public static FAILURE_STRING: string = "Unsafe use of expression of type 'any'."; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
surely this isn't necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoops, no idea why that got there!
} | ||
|
||
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { | ||
const limit: number = this.ruleArguments[0] || Rule.DEFAULT_ALLOWED_BLANKS; | ||
const limit = this.ruleArguments[0] as number | undefined || Rule.DEFAULT_ALLOWED_BLANKS; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why the switch from typedef to type assertion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A typedef const x: number = thisIsAny;
is flagged by the no-unsafe-any
rule, since it looks safe but isn't. const x = thisIsAny as number;
is OK since that's obviously an assertion.
src/configuration.ts
Outdated
@@ -252,7 +254,7 @@ export function extendConfigurationFile(targetConfig: IConfigurationFile, | |||
}; | |||
} | |||
|
|||
function getHomeDir() { | |||
function getHomeDir(): string | undefined { | |||
const environment = global.process.env; | |||
const paths = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prefer type annotation on paths
instead of the function return value. or both
src/ruleLoader.ts
Outdated
@@ -54,7 +53,7 @@ export function loadRules(ruleOptionsList: IOptions[], | |||
} else { | |||
const ruleSpecificList = enableDisableRules || []; | |||
ruleOptions.disabledIntervals = buildDisabledIntervalsFromSwitches(ruleSpecificList); | |||
rules.push(new (Rule as any)(ruleOptions)); | |||
rules.push(new (Rule as any)(ruleOptions) as IRule); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't need either cast
src/configuration.ts
Outdated
@@ -15,6 +15,8 @@ | |||
* limitations under the License. | |||
*/ | |||
|
|||
// tslint:disable no-unsafe-any (TODO) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this needed?
src/formatterLoader.ts
Outdated
const formatterPath = paths.reduce((p, c) => path.join(p, c), ""); | ||
const fullPath = path.resolve(moduleDirectory, formatterPath); | ||
|
||
if (fs.existsSync(`${fullPath}.js`)) { | ||
const formatterModule = require(fullPath); | ||
return formatterModule.Formatter; | ||
return formatterModule.Formatter; // tslint:disable-line no-unsafe-any |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of disabling rule, cast the require
to an interface like { Formatter: FormatterConstructor }
src/formatterLoader.ts
Outdated
let src: string; | ||
try { | ||
src = require.resolve(name); | ||
} catch (e) { | ||
return undefined; | ||
} | ||
return require(src).Formatter; | ||
return require(src).Formatter; // tslint:disable-line no-unsafe-any |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above comment
src/ruleLoader.ts
Outdated
return ruleModule.Rule; | ||
} | ||
} | ||
return undefined; | ||
return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we should use a string literal like "not-found" or "load-error" instead of null
src/ruleLoader.ts
Outdated
Rule = loadRule(absolutePath, ruleName); | ||
let Rule: RuleConstructor | null = null; | ||
if (absolutePath !== undefined) { | ||
Rule = loadRule(absolutePath, ruleName); // tslint:disable-line no-unsafe-any |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you need to disable the rule here
src/rules/memberOrderingRule.ts
Outdated
@@ -396,6 +396,7 @@ function getOptionsJson(allOptions: any[]): { order: MemberCategoryJson[], alpha | |||
return { order: convertFromOldStyleOptions(allOptions), alphabetize: false }; // presume allOptions to be string[] | |||
} | |||
|
|||
// tslint:disable-next-line no-unsafe-any | |||
return { order: categoryFromOption(firstOption[OPTION_ORDER]), alphabetize: !!firstOption[OPTION_ALPHABETIZE] }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of disabling, annotate firstOption
as type Options
, then call using firstOption.order
and firstOption.alphabetize
src/tslint-cli.ts
Outdated
@@ -15,6 +15,8 @@ | |||
* limitations under the License. | |||
*/ | |||
|
|||
// tslint:disable no-unsafe-any (TODO) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you need to disable the rule here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just some nits
src/configuration.ts
Outdated
@@ -143,7 +141,7 @@ export function findConfigurationPath(suppliedConfigFilePath: string | null, inp | |||
} | |||
} | |||
|
|||
/** | |||
/**findRule |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this here?
src/ruleLoader.ts
Outdated
import { arrayify, camelize, dedent } from "./utils"; | ||
|
||
const moduleDirectory = path.dirname(module.filename); | ||
const CORE_RULES_DIRECTORY = path.resolve(moduleDirectory, ".", "rules"); | ||
const cachedRules = new Map<string, typeof AbstractRule | null>(); // null indicates that the rule was not found | ||
const cachedRules = new Map<string, RuleConstructor | "not-found">(); // null indicates that the rule was not found |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can remove/update this comment
PR checklist
Overview of change:
The
no-unsafe-any
rule mostly just required appropriate casts, but in the case ofFormatterFunction
it seems to have discovered a bug -- formatters actually seem to have to be new-able. So created aFormatterStatic
instead. This is technically a breaking change, but code that compiled againstFormatterFunction
would have been wrong.