Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: migrate TSLint rules to ESLint equivalents #4158

Merged
merged 17 commits into from
May 29, 2020
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ if (process.env.LINT_SCRIPT) {
// in CI, we don't wan to run eslint-plugin-prettier because it has a ~50% performance penalty.
// instead, run yarn format-check at the root to ensure prettier formatting.
// also, run import/no-cycle only in CI because it is slow.
xtends.push("plugin:import/typescript");
plugins.push(
"import"
);
Expand All @@ -26,6 +25,23 @@ module.exports = {
plugins,
rules,
settings,
overrides: [
{
files: ["**/test/**/*.{ts,tsx}"],
env: {
browser: true,
mocha: true,
},
rules: {
// HACKHACK: many test assertions are written with this syntax
"@typescript-eslint/no-unused-expressions": "off",
// HACKHACK: test dependencies are only declared at root but used in all packages.
"import/no-extraneous-dependencies": "off",
// HACKHACK: many violations, should be fixed eventually
"import/no-internal-modules": "off"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be removed since I ended up re-enabling tslint no-submodule-imports

}
},
],
ignorePatterns: [
"node_modules",
"dist",
Expand Down
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ generated/
lib/
dist/
/site/
*.scss
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@
"cross-env": "^7.0.2",
"eslint": "^7.1.0",
"eslint-config-prettier": "^6.10.1",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-prettier": "^3.1.3",
"gh-pages": "^2.2.0",
"http-server": "^0.12.3",
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/blueprint-hi-contrast.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*!
/*

Copyright 2019-present Palantir Technologies, Inc. All rights reserved.
Licensed under the Apache License, Version 2.0.
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/blueprint.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*!
/*

Copyright 2015-present Palantir Technologies, Inc. All rights reserved.
Licensed under the Apache License, Version 2.0.
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/common/abstractComponent2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { isNodeEnv } from "./utils";
* An abstract component that Blueprint components can extend
* in order to add some common functionality like runtime props validation.
*/
// eslint-disable-next-line @typescript-eslint/ban-types
export abstract class AbstractComponent2<P, S = {}, SS = {}> extends React.Component<P, S, SS> {
// unsafe lifecycle methods
public componentWillUpdate: never;
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/common/abstractPureComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { isNodeEnv } from "./utils";
* in order to add some common functionality like runtime props validation.
* @deprecated componentWillReceiveProps is deprecated in React 16.9; use AbstractPureComponent2 instead
*/
// eslint-disable-next-line @typescript-eslint/ban-types
export abstract class AbstractPureComponent<P, S = {}> extends React.PureComponent<P, S> {
/** Component displayName should be `public static`. This property exists to prevent incorrect usage. */
protected displayName: never;
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/common/abstractPureComponent2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { isNodeEnv } from "./utils";
* An abstract component that Blueprint components can extend
* in order to add some common functionality like runtime props validation.
*/
// eslint-disable-next-line @typescript-eslint/ban-types
export abstract class AbstractPureComponent2<P, S = {}, SS = {}> extends React.PureComponent<P, S, SS> {
// unsafe lifecycle method
public componentWillUpdate: never;
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/common/configureDom4.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

if (typeof require !== "undefined" && typeof window !== "undefined" && typeof document !== "undefined") {
// we're in browser
// tslint:disable-next-line:no-var-requires
// eslint-disable-line @typescript-eslint/no-var-requires
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

invalid comment flag, should be removed

require("dom4"); // only import actual dom4 if we're in the browser (not server-compatible)
// we'll still need dom4 types for the TypeScript to compile, these are included in package.json
}
27 changes: 27 additions & 0 deletions packages/core/src/common/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2020 Palantir Technologies, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// simplified typings copied from @types/prop-types, to avoid that explicit dependency

export type Validator = (
props: { [key: string]: any },
propName: string,
componentName: string,
location: string,
propFullName: string,
) => Error | null;

export type ValidationMap<T> = { [K in keyof T]?: Validator };
50 changes: 27 additions & 23 deletions packages/core/src/common/utils/compareUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
* limitations under the License.
*/

// we use the empty object {} a lot in this public API
/* eslint-disable @typescript-eslint/ban-types */

export interface IKeyWhitelist<T> {
include: Array<keyof T>;
}
Expand Down Expand Up @@ -43,7 +46,7 @@ export function arraysEqual(arrA: any[], arrB: any[], compare = (a: any, b: any)
* of keys will be compared; otherwise, all keys will be compared.
* @returns true if items are equal.
*/
export function shallowCompareKeys<T extends object>(objA: T, objB: T, keys?: IKeyBlacklist<T> | IKeyWhitelist<T>) {
export function shallowCompareKeys<T extends {}>(objA: T, objB: T, keys?: IKeyBlacklist<T> | IKeyWhitelist<T>) {
// treat `null` and `undefined` as the same
if (objA == null && objB == null) {
return true;
Expand All @@ -52,13 +55,14 @@ export function shallowCompareKeys<T extends object>(objA: T, objB: T, keys?: IK
} else if (Array.isArray(objA) || Array.isArray(objB)) {
return false;
} else if (keys != null) {
return _shallowCompareKeys(objA, objB, keys);
return shallowCompareKeysImpl(objA, objB, keys);
} else {
// shallowly compare all keys from both objects
const keysA = Object.keys(objA) as Array<keyof T>;
const keysB = Object.keys(objB) as Array<keyof T>;
return (
_shallowCompareKeys(objA, objB, { include: keysA }) && _shallowCompareKeys(objA, objB, { include: keysB })
shallowCompareKeysImpl(objA, objB, { include: keysA }) &&
shallowCompareKeysImpl(objA, objB, { include: keysB })
);
}
}
Expand All @@ -78,10 +82,10 @@ export function deepCompareKeys(objA: any, objB: any, keys?: Array<string | numb
return false;
} else if (Array.isArray(objA) || Array.isArray(objB)) {
return arraysEqual(objA, objB, deepCompareKeys);
} else if (_isSimplePrimitiveType(objA) || _isSimplePrimitiveType(objB)) {
} else if (isSimplePrimitiveType(objA) || isSimplePrimitiveType(objB)) {
return objA === objB;
} else if (keys != null) {
return _deepCompareKeys(objA, objB, keys);
return deepCompareKeysImpl(objA, objB, keys);
} else if (objA.constructor !== objB.constructor) {
return false;
} else {
Expand All @@ -93,21 +97,21 @@ export function deepCompareKeys(objA: any, objB: any, keys?: Array<string | numb
if (keysA.length === 0 && keysB.length === 0) {
return true;
}
return arraysEqual(keysA, keysB) && _deepCompareKeys(objA, objB, keysA);
return arraysEqual(keysA, keysB) && deepCompareKeysImpl(objA, objB, keysA);
}
}

/**
* Returns a descriptive object for each key whose values are deeply unequal
* between two provided objects. Useful for debugging shouldComponentUpdate.
*/
export function getDeepUnequalKeyValues<T extends object>(
export function getDeepUnequalKeyValues<T extends {}>(
objA: T = ({} as any) as T,
objB: T = ({} as any) as T,
keys?: Array<keyof T>,
) {
const filteredKeys = keys == null ? _unionKeys(objA, objB) : keys;
return _getUnequalKeyValues(objA, objB, filteredKeys, (a, b, key) => {
const filteredKeys = keys == null ? unionKeys(objA, objB) : keys;
return getUnequalKeyValues(objA, objB, filteredKeys, (a, b, key) => {
return deepCompareKeys(a, b, [key]);
});
}
Expand All @@ -118,34 +122,34 @@ export function getDeepUnequalKeyValues<T extends object>(
/**
* Partial shallow comparison between objects using the given list of keys.
*/
function _shallowCompareKeys<T>(objA: T, objB: T, keys: IKeyBlacklist<T> | IKeyWhitelist<T>) {
return _filterKeys(objA, objB, keys).every(key => {
function shallowCompareKeysImpl<T>(objA: T, objB: T, keys: IKeyBlacklist<T> | IKeyWhitelist<T>) {
return filterKeys(objA, objB, keys).every(key => {
return objA.hasOwnProperty(key) === objB.hasOwnProperty(key) && objA[key] === objB[key];
});
}

/**
* Partial deep comparison between objects using the given list of keys.
*/
function _deepCompareKeys(objA: any, objB: any, keys: Array<string | number | symbol>): boolean {
function deepCompareKeysImpl(objA: any, objB: any, keys: Array<string | number | symbol>): boolean {
return keys.every(key => {
return objA.hasOwnProperty(key) === objB.hasOwnProperty(key) && deepCompareKeys(objA[key], objB[key]);
});
}

function _isSimplePrimitiveType(value: any) {
function isSimplePrimitiveType(value: any) {
return typeof value === "number" || typeof value === "string" || typeof value === "boolean";
}

function _filterKeys<T>(objA: T, objB: T, keys: IKeyBlacklist<T> | IKeyWhitelist<T>) {
if (_isWhitelist(keys)) {
function filterKeys<T>(objA: T, objB: T, keys: IKeyBlacklist<T> | IKeyWhitelist<T>) {
if (isWhitelist(keys)) {
return keys.include;
} else if (_isBlacklist(keys)) {
} else if (isBlacklist(keys)) {
const keysA = Object.keys(objA);
const keysB = Object.keys(objB);

// merge keys from both objects into a big set for quick access
const keySet = _arrayToObject(keysA.concat(keysB));
const keySet = arrayToObject(keysA.concat(keysB));

// delete blacklisted keys from the key set
keys.exclude.forEach(key => delete keySet[key]);
Expand All @@ -157,22 +161,22 @@ function _filterKeys<T>(objA: T, objB: T, keys: IKeyBlacklist<T> | IKeyWhitelist
return [];
}

function _isWhitelist<T>(keys: any): keys is IKeyWhitelist<T> {
function isWhitelist<T>(keys: any): keys is IKeyWhitelist<T> {
return keys != null && (keys as IKeyWhitelist<T>).include != null;
}

function _isBlacklist<T>(keys: any): keys is IKeyBlacklist<T> {
function isBlacklist<T>(keys: any): keys is IKeyBlacklist<T> {
return keys != null && (keys as IKeyBlacklist<T>).exclude != null;
}

function _arrayToObject(arr: any[]) {
function arrayToObject(arr: any[]) {
return arr.reduce((obj: any, element: any) => {
obj[element] = true;
return obj;
}, {});
}

function _getUnequalKeyValues<T extends object>(
function getUnequalKeyValues<T extends {}>(
objA: T,
objB: T,
keys: Array<keyof T>,
Expand All @@ -187,12 +191,12 @@ function _getUnequalKeyValues<T extends object>(
return unequalKeyValues;
}

function _unionKeys<T extends object>(objA: T, objB: T) {
function unionKeys<T extends {}>(objA: T, objB: T) {
const keysA = Object.keys(objA);
const keysB = Object.keys(objB);

const concatKeys = keysA.concat(keysB);
const keySet = _arrayToObject(concatKeys);
const keySet = arrayToObject(concatKeys);

return Object.keys(keySet) as Array<keyof T>;
}
12 changes: 6 additions & 6 deletions packages/core/src/common/utils/domUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function elementIsOrContains(element: HTMLElement, testElement: HTMLEleme
* @see https://developer.mozilla.org/en-US/docs/Web/Events/scroll
*/
export function throttleEvent(target: EventTarget, eventName: string, newEventName: string) {
const throttledFunc = _throttleHelper((event: Event) => {
const throttledFunc = throttleImpl((event: Event) => {
target.dispatchEvent(new CustomEvent(newEventName, event));
});
target.addEventListener(eventName, throttledFunc);
Expand All @@ -47,7 +47,7 @@ export function throttleReactEventCallback(
callback: (event: React.SyntheticEvent<any>, ...otherArgs: any[]) => any,
options: IThrottledReactEventOptions = {},
) {
const throttledFunc = _throttleHelper(
const throttledFunc = throttleImpl(
callback,
(event2: React.SyntheticEvent<any>) => {
if (options.preventDefault) {
Expand All @@ -64,13 +64,13 @@ export function throttleReactEventCallback(
* Throttle a method by wrapping it in a `requestAnimationFrame` call. Returns
* the throttled function.
*/
// tslint:disable-next-line:ban-types
// eslint-disable-next-line @typescript-eslint/ban-types
export function throttle<T extends Function>(method: T): T {
return _throttleHelper(method);
return throttleImpl(method);
}

// tslint:disable-next-line:ban-types
function _throttleHelper<T extends Function>(
// eslint-disable-next-line @typescript-eslint/ban-types
function throttleImpl<T extends Function>(
onAnimationFrameRequested: T,
onBeforeIsRunningCheck?: T,
onAfterIsRunningCheck?: T,
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/common/utils/functionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

/** Returns whether the value is a function. Acts as a type guard. */
// tslint:disable-next-line:ban-types
// eslint-disable-next-line @typescript-eslint/ban-types
export function isFunction(value: any): value is Function {
return typeof value === "function";
}
Expand All @@ -40,7 +40,7 @@ export function safeInvoke<A, B, C, D, R>(
arg3: C,
arg4: D,
): R | undefined;
// tslint:disable-next-line:ban-types
// eslint-disable-next-line @typescript-eslint/ban-types
export function safeInvoke(func: Function | undefined, ...args: any[]) {
if (isFunction(func)) {
return func(...args);
Expand Down Expand Up @@ -68,7 +68,7 @@ export function safeInvokeOrValue<A, B, C, D, R>(
arg3: C,
arg4: D,
): R;
// tslint:disable-next-line:ban-types
// eslint-disable-next-line @typescript-eslint/ban-types
export function safeInvokeOrValue(funcOrValue: Function | any | undefined, ...args: any[]) {
return isFunction(funcOrValue) ? funcOrValue(...args) : funcOrValue;
}
2 changes: 1 addition & 1 deletion packages/core/src/common/utils/jsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import { CLAMP_MIN_MAX } from "../errors";

// only accessible within this file, so use `Utils.isNodeEnv(env)` from the outside.
declare var process: { env: any };
declare let process: { env: any };

/** Returns whether `process.env.NODE_ENV` exists and equals `env`. */
export function isNodeEnv(env: string) {
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/common/utils/reactUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export function getDisplayName(ComponentClass: React.ComponentType | INamed) {
* @param element JSX element in question
* @param ComponentType desired component type of element
*/
// eslint-disable-next-line @typescript-eslint/ban-types
export function isElementOfType<P = {}>(
element: any,
ComponentType: React.ComponentType<P>,
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/common/utils/safeInvokeMember.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export function safeInvokeMember<
C,
R = void
>(obj: T | undefined, key: K, arg1: A, arg2: B, arg3: C): R | undefined;
// tslint:disable-next-line:ban-types
// eslint-disable-next-line @typescript-eslint/ban-types
export function safeInvokeMember<T extends { [P in K]?: Function }, K extends keyof T>(
obj: T | null | undefined,
key: K,
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/components/alert/alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export interface IAlertProps extends IOverlayLifecycleProps, IProps {
}

@polyfill
export class Alert extends AbstractPureComponent2<IAlertProps, {}> {
export class Alert extends AbstractPureComponent2<IAlertProps> {
public static defaultProps: IAlertProps = {
canEscapeKeyCancel: false,
canOutsideClickCancel: false,
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/components/button/buttons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

// HACKHACK: these components should go in separate files
// tslint:disable max-classes-per-file
/* eslint-disable max-classes-per-file */

import * as React from "react";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export interface ICollapsibleListProps extends IProps {
}

/** @deprecated use `<OverflowList>` for automatic overflow based on available space. */
export class CollapsibleList extends React.Component<ICollapsibleListProps, {}> {
export class CollapsibleList extends React.Component<ICollapsibleListProps> {
public static displayName = `${DISPLAYNAME_PREFIX}.CollapsibleList`;

public static defaultProps: ICollapsibleListProps = {
Expand Down
Loading