diff --git a/package.json b/package.json index cd35b89..f45f2f3 100644 --- a/package.json +++ b/package.json @@ -14,9 +14,8 @@ "node": ">=6" }, "scripts": { - "lint": "tslint --format stylish --project .", "build": "del dist && tsc", - "test": "npm run lint && ava", + "test": "xo && ava", "prepublishOnly": "npm run build" }, "files": [ @@ -47,20 +46,19 @@ "types" ], "devDependencies": { - "@sindresorhus/tsconfig": "^0.2.0", - "@types/jsdom": "^11.12.0", - "@types/node": "^10.12.21", + "@sindresorhus/tsconfig": "^0.3.0", + "@types/jsdom": "^12.2.3", + "@types/node": "^11.12.2", "@types/tempy": "^0.2.0", "@types/zen-observable": "^0.8.0", - "ava": "^1.2.0", + "@typescript-eslint/eslint-plugin": "^1.5.0", + "ava": "^1.4.1", "del-cli": "^1.1.0", "jsdom": "^11.6.2", "rxjs": "^6.4.0", "tempy": "^0.2.1", - "ts-node": "^8.0.2", - "tslint": "^5.9.1", - "tslint-xo": "^0.10.0", - "typescript": "^3.3.1", + "ts-node": "^8.0.3", + "typescript": "^3.4.1", "zen-observable": "^0.8.8" }, "types": "dist", @@ -74,5 +72,14 @@ "require": [ "ts-node/register" ] + }, + "xo": { + "extends": "xo-typescript", + "extensions": [ + "ts" + ], + "rules": { + "@typescript-eslint/explicit-function-return-type": "off" + } } } diff --git a/source/index.ts b/source/index.ts index cfd16ed..64943ab 100644 --- a/source/index.ts +++ b/source/index.ts @@ -4,10 +4,10 @@ /// // TODO: Use the `URL` global when targeting Node.js 10 -// tslint:disable-next-line +// eslint-disable-next-line @typescript-eslint/no-require-imports const URLGlobal = typeof URL === 'undefined' ? require('url').URL : URL; -export type Class = new(...args: any[]) => T; +export type Class = new (...args: any[]) => T; export const enum TypeName { null = 'null', @@ -46,7 +46,7 @@ export const enum TypeName { URL = 'URL' } -const toString = Object.prototype.toString; +const {toString} = Object.prototype; const isOfType = (type: string) => (value: unknown): value is T => typeof value === type; const getObjectType = (value: unknown): TypeName | undefined => { @@ -55,12 +55,11 @@ const getObjectType = (value: unknown): TypeName | undefined => { return objectName as TypeName; } - return; + return undefined; }; const isObjectOfType = (type: TypeName) => (value: unknown): value is T => getObjectType(value) === type; -// tslint:disable-next-line: no-use-before-declare function is(value: unknown): TypeName { switch (value) { case null: @@ -111,14 +110,15 @@ function is(value: unknown): TypeName { return TypeName.Object; } -// tslint:disable-next-line: strict-type-predicates const isObject = (value: unknown): value is object => typeof value === 'object'; is.undefined = isOfType('undefined'); is.string = isOfType('string'); is.number = isOfType('number'); + +// eslint-disable-next-line @typescript-eslint/ban-types is.function_ = isOfType('function'); -// tslint:disable-next-line: strict-type-predicates + is.null_ = (value: unknown): value is null => value === null; is.class_ = (value: unknown): value is Class => is.function_(value) && value.toString().startsWith('class '); is.boolean = (value: unknown): value is boolean => value === true || value === false; @@ -133,7 +133,10 @@ is.buffer = (value: unknown): value is Buffer => !is.nullOrUndefined(value) && ! is.nullOrUndefined = (value: unknown): value is null | undefined => is.null_(value) || is.undefined(value); is.object = (value: unknown): value is object => !is.nullOrUndefined(value) && (is.function_(value) || isObject(value)); is.iterable = (value: unknown): value is IterableIterator => !is.nullOrUndefined(value) && is.function_((value as IterableIterator)[Symbol.iterator]); + +// eslint-disable-next-line no-use-extend-native/no-use-extend-native is.asyncIterable = (value: unknown): value is AsyncIterableIterator => !is.nullOrUndefined(value) && is.function_((value as AsyncIterableIterator)[Symbol.asyncIterator]); + is.generator = (value: unknown): value is Generator => is.iterable(value) && is.function_(value.next) && is.function_(value.throw); is.nativePromise = (value: unknown): value is Promise => @@ -148,7 +151,11 @@ const hasPromiseAPI = (value: unknown): value is Promise => is.promise = (value: unknown): value is Promise => is.nativePromise(value) || hasPromiseAPI(value); is.generatorFunction = isObjectOfType(TypeName.GeneratorFunction); + +// eslint-disable-next-line @typescript-eslint/ban-types is.asyncFunction = isObjectOfType(TypeName.AsyncFunction); + +// eslint-disable-next-line no-prototype-builtins, @typescript-eslint/ban-types is.boundFunction = (value: unknown): value is Function => is.function_(value) && !value.hasOwnProperty('prototype'); is.regExp = isObjectOfType(TypeName.RegExp); @@ -182,7 +189,7 @@ is.urlString = (value: unknown): value is string => { } try { - new URLGlobal(value); // tslint:disable-line no-unused-expression + new URLGlobal(value); // eslint-disable-line no-new return true; } catch { return false; @@ -215,11 +222,13 @@ is.safeInteger = (value: unknown): value is number => Number.isSafeInteger(value is.plainObject = (value: unknown): value is {[key: string]: unknown} => { // From: https://github.com/sindresorhus/is-plain-obj/blob/master/index.js - let prototype; + if (getObjectType(value) !== TypeName.Object) { + return false; + } - return getObjectType(value) === TypeName.Object && - (prototype = Object.getPrototypeOf(value), prototype === null || // tslint:disable-line:ban-comma-operator - prototype === Object.getPrototypeOf({})); + const prototype = Object.getPrototypeOf(value); + + return prototype === null || prototype === Object.getPrototypeOf({}); }; const typedArrayTypes = new Set([ @@ -250,7 +259,7 @@ export interface ArrayLike { readonly [index: number]: T; } -const isValidLength = (value: unknown) => is.safeInteger(value) && value >= 0; +const isValidLength = (value: unknown): value is number => is.safeInteger(value) && value >= 0; is.arrayLike = (value: unknown): value is ArrayLike => !is.nullOrUndefined(value) && !is.function_(value) && isValidLength((value as ArrayLike).length); is.inRange = (value: number, range: number | number[]): value is number => { @@ -287,6 +296,7 @@ is.observable = (value: unknown): value is ObservableLike => { return false; } + // eslint-disable-next-line no-use-extend-native/no-use-extend-native if ((value as any)[Symbol.observable] && value === (value as any)[Symbol.observable]()) { return true; } @@ -298,13 +308,14 @@ is.observable = (value: unknown): value is ObservableLike => { return false; }; +// eslint-disable-next-line @typescript-eslint/ban-types export type NodeStream = object & {readonly pipe: Function}; is.nodeStream = (value: unknown): value is NodeStream => !is.nullOrUndefined(value) && isObject(value) as unknown && is.function_((value as NodeStream).pipe) && !is.observable(value); is.infinite = (value: unknown): value is number => value === Infinity || value === -Infinity; -const isAbsoluteMod2 = (rem: number) => (value: number): value is number => is.integer(value) && Math.abs(value % 2) === rem; +const isAbsoluteMod2 = (remainder: number) => (value: number): value is number => is.integer(value) && Math.abs(value % 2) === remainder; is.evenInteger = isAbsoluteMod2(0); is.oddInteger = isAbsoluteMod2(1); @@ -316,7 +327,7 @@ is.emptyString = (value: unknown): value is '' => is.string(value) && value.leng // TODO: Use `not ''` when the `not` operator is available. is.nonEmptyString = (value: unknown): value is string => is.string(value) && value.length > 0; -const isWhiteSpaceString = (value: unknown) => is.string(value) && /\S/.test(value) === false; +const isWhiteSpaceString = (value: unknown): value is string => is.string(value) && /\S/.test(value) === false; is.emptyStringOrWhitespace = (value: unknown): value is string => is.emptyString(value) || isWhiteSpaceString(value); is.emptyObject = (value: unknown): value is {[key: string]: never} => is.object(value) && !is.map(value) && !is.set(value) && Object.keys(value).length === 0; @@ -347,10 +358,8 @@ const predicateOnArray = (method: ArrayMethod, predicate: Predicate, values: unk return method.call(values, predicate); }; -// tslint:disable variable-name is.any = (predicate: Predicate, ...values: unknown[]): boolean => predicateOnArray(Array.prototype.some, predicate, values); is.all = (predicate: Predicate, ...values: unknown[]): boolean => predicateOnArray(Array.prototype.every, predicate, values); -// tslint:enable variable-name // Some few keywords are reserved, but we'll populate them for Node.js users // See https://github.com/Microsoft/TypeScript/issues/2536 diff --git a/test/test.ts b/test/test.ts index 4097b4a..d25d28b 100644 --- a/test/test.ts +++ b/test/test.ts @@ -2,8 +2,8 @@ import fs from 'fs'; import net from 'net'; import Stream from 'stream'; import util from 'util'; -import tempy from 'tempy'; import {URL} from 'url'; +import tempy from 'tempy'; import test, {ExecutionContext} from 'ava'; import {JSDOM} from 'jsdom'; import {Subject, Observable} from 'rxjs'; @@ -88,26 +88,24 @@ const types = new Map([ is: is.array, fixtures: [ [1, 2], - new Array(2) // tslint:disable-line:prefer-array-literal + new Array(2) ] }], ['emptyArray', { is: is.emptyArray, fixtures: [ [], - new Array() + new Array() // eslint-disable-line @typescript-eslint/no-array-constructor ] }], ['function', { is: is.function_, fixtures: [ - // tslint:disable:no-unused no-empty no-unused-variable only-arrow-functions no-function-expression - function foo() {}, + function foo() {}, // eslint-disable-line func-names function () {}, () => {}, async function () {}, function * (): unknown {} - // tslint:enable:no-unused no-empty no-unused-variable only-arrow-functions no-function-expression ] }], ['buffer', { @@ -153,7 +151,7 @@ const types = new Map([ ['promise', { is: is.promise, fixtures: [ - {then() {}, catch() {}} // tslint:disable-line:no-empty + {then() {}, catch() {}} ] }], ['generator', { @@ -175,27 +173,27 @@ const types = new Map([ ['asyncFunction', { is: is.asyncFunction, fixtures: [ - async function () {}, // tslint:disable-line:no-empty only-arrow-functions no-function-expression - async () => {} // tslint:disable-line:no-empty + async function () {}, + async () => {} ] }], ['boundFunction', { is: is.boundFunction, fixtures: [ - () => {}, // tslint:disable-line:no-empty - function () {}.bind(null), // tslint:disable-line:no-empty only-arrow-functions + () => {}, + function () {}.bind(null) // eslint-disable-line no-extra-bind ] }], ['map', { is: is.map, fixtures: [ - new Map([['one', '1']]), + new Map([['one', '1']]) ] }], ['emptyMap', { is: is.emptyMap, fixtures: [ - new Map(), + new Map() ] }], ['set', { @@ -207,7 +205,7 @@ const types = new Map([ ['emptySet', { is: is.emptySet, fixtures: [ - new Set(), + new Set() ] }], ['weakSet', { @@ -307,7 +305,7 @@ const types = new Map([ fixtures: [ {x: 1}, Object.create(null), - new Object() + new Object() // eslint-disable-line no-new-object ] }], ['integer', { @@ -319,8 +317,8 @@ const types = new Map([ ['safeInteger', { is: is.safeInteger, fixtures: [ - Math.pow(2, 53) - 1, - -Math.pow(2, 53) + 1 + (2 ** 53) - 1, + -(2 ** 53) + 1 ] }], ['domElement', { @@ -332,8 +330,8 @@ const types = new Map([ 'img', 'canvas', 'script' - ].map(createDomElement) } - ], + ].map(createDomElement) + }], ['non-domElements', { is: value => !is.domElement(value), fixtures: [ @@ -350,7 +348,7 @@ const types = new Map([ fixtures: [ new Observable(), new Subject(), - new ZenObservable(() => {}) // tslint:disable-line:no-empty + new ZenObservable(() => {}) ] }], ['nodeStream', { @@ -449,7 +447,7 @@ test('is.function', t => { }); test('is.boundFunction', t => { - t.false(is.boundFunction(function () {})); // tslint:disable-line:no-empty only-arrow-functions + t.false(is.boundFunction(function () {})); // eslint-disable-line prefer-arrow-callback }); test('is.buffer', t => { @@ -491,9 +489,11 @@ if (isNode8orHigher) { testType(t, 'promise', ['nativePromise']); }); - /*test('is.asyncFunction', t => { + /*- + test('is.asyncFunction', t => { testType(t, 'asyncFunction', ['function']); - });*/ + }); + */ } test('is.generator', t => { @@ -642,8 +642,8 @@ test('is.integer', t => { test('is.safeInteger', t => { testType(t, 'safeInteger', ['number', 'integer']); - t.false(is.safeInteger(Math.pow(2, 53))); - t.false(is.safeInteger(-Math.pow(2, 53))); + t.false(is.safeInteger(2 ** 53)); + t.false(is.safeInteger(-(2 ** 53))); }); test('is.plainObject', t => { @@ -665,7 +665,7 @@ test('is.iterable', t => { if (isNode10orHigher) { test('is.asyncIterable', t => { t.true(is.asyncIterable({ - [Symbol.asyncIterator]: () => {} // tslint:disable-line:no-empty + [Symbol.asyncIterator]: () => {} })); t.false(is.asyncIterable(null)); @@ -678,14 +678,15 @@ if (isNode10orHigher) { } test('is.class', t => { - class Foo {} // tslint:disable-line + class Foo {} // eslint-disable-line @typescript-eslint/no-extraneous-class + const classDeclarations = [ Foo, - class Bar extends Foo {} // tslint:disable-line + class Bar extends Foo {} ]; - for (const x of classDeclarations) { - t.true(is.class_(x)); + for (const classDeclaration of classDeclarations) { + t.true(is.class_(classDeclaration)); } }); @@ -714,14 +715,15 @@ test('is.typedArray', t => { }); test('is.arrayLike', t => { - (function () { // tslint:disable-line:only-arrow-functions - t.true(is.arrayLike(arguments)); + (function () { + t.true(is.arrayLike(arguments)); // eslint-disable-line prefer-rest-params })(); + t.true(is.arrayLike([])); t.true(is.arrayLike('unicorn')); t.false(is.arrayLike({})); - t.false(is.arrayLike(() => {})); // tslint:disable-line:no-empty + t.false(is.arrayLike(() => {})); t.false(is.arrayLike(new Map())); }); @@ -800,7 +802,7 @@ test('is.emptyArray', t => { test('is.nonEmptyArray', t => { t.true(is.nonEmptyArray([1, 2, 3])); t.false(is.nonEmptyArray([])); - t.false(is.nonEmptyArray(new Array())); + t.false(is.nonEmptyArray(new Array())); // eslint-disable-line @typescript-eslint/no-array-constructor }); test('is.emptyString', t => { @@ -823,7 +825,7 @@ test('is.emptyStringOrWhitespace', t => { test('is.emptyObject', t => { t.true(is.emptyObject({})); - t.true(is.emptyObject(new Object())); + t.true(is.emptyObject(new Object())); // eslint-disable-line no-new-object t.false(is.emptyObject({unicorn: '🦄'})); }); @@ -832,7 +834,7 @@ test('is.nonEmptyObject', t => { is.nonEmptyObject(foo); t.false(is.nonEmptyObject({})); - t.false(is.nonEmptyObject(new Object())); + t.false(is.nonEmptyObject(new Object())); // eslint-disable-line no-new-object t.true(is.nonEmptyObject({unicorn: '🦄'})); }); diff --git a/tslint.json b/tslint.json deleted file mode 100644 index 6f6ad0e..0000000 --- a/tslint.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "tslint-xo", - "rules": { - "interface-over-type-literal": false - } -}