diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 58e7202..47919d5 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -4,6 +4,7 @@ module.exports = { extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended', + 'plugin:@typescript-eslint/stylistic-type-checked', 'prettier', ], overrides: [ @@ -25,6 +26,7 @@ module.exports = { 'error', { allow: ['/package\\.json$'] }, ], + '@typescript-eslint/array-type': ['error', { default: 'generic' }], }, }, // Tests diff --git a/src/__tests__/package-json-file-service.test.ts b/src/__tests__/package-json-file-service.test.ts index 7981cfe..d9c963e 100644 --- a/src/__tests__/package-json-file-service.test.ts +++ b/src/__tests__/package-json-file-service.test.ts @@ -91,6 +91,8 @@ async function _writeFixture(withTrailingNewline = false): Promise { return file } -function cleanup(...files: string[]): Promise { - return Promise.all(files.map((f) => fsp.unlink(f))) +async function cleanup(...files: Array): Promise { + await Promise.all(files.map((f) => fsp.unlink(f))) + + return } diff --git a/src/__tests__/type-syncer.test.ts b/src/__tests__/type-syncer.test.ts index 7ef1712..3c724b1 100644 --- a/src/__tests__/type-syncer.test.ts +++ b/src/__tests__/type-syncer.test.ts @@ -13,7 +13,7 @@ import type { IWorkspaceResolverService, } from '../workspace-resolver' -const descriptors: IPackageTypingDescriptor[] = [ +const descriptors: Array = [ { typingsName: 'package1', codePackageName: 'package1', diff --git a/src/__tests__/versioning.test.ts b/src/__tests__/versioning.test.ts index 116363d..237c84b 100644 --- a/src/__tests__/versioning.test.ts +++ b/src/__tests__/versioning.test.ts @@ -5,7 +5,7 @@ import { describe('getClosestMatchingVersion', () => { it('returns the closest matching version', () => { - const inputVersions: IPackageVersionInfo[] = [ + const inputVersions: Array = [ { containsInternalTypings: false, version: '1.16.0', diff --git a/src/cli.ts b/src/cli.ts index be4876f..91c3857 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -33,8 +33,8 @@ export async function startCli() { typeSyncer: asFunction(createTypeSyncer), }) await run(container.resolve('typeSyncer')) - } catch (err: any) { - C.error(err) + } catch (err) { + C.error(err as any) process.exitCode = 1 } } @@ -109,7 +109,7 @@ function renderSyncedFile(file: ISyncedFile) { : chalk`{green.bold (${file.newTypings.length.toString()} new typings added)}` const dirName = path.basename(path.dirname(path.resolve(file.filePath))) - const title = chalk`📦 ${file.package.name || dirName} {gray.italic — ${ + const title = chalk`📦 ${file.package.name ?? dirName} {gray.italic — ${ file.filePath }} ${badge}` diff --git a/src/config-service.ts b/src/config-service.ts index 714bb55..87dc36c 100644 --- a/src/config-service.ts +++ b/src/config-service.ts @@ -40,7 +40,7 @@ function readCliConfig(flags: ICLIArguments['flags']): ISyncOptions { const readValues = ( key: string, validator?: (value: string) => boolean, - ): T[] | undefined => { + ): Array | undefined => { const values = flags[key] return typeof values === 'string' ? values diff --git a/src/fs-utils.ts b/src/fs-utils.ts index 4dc666e..8dbda87 100644 --- a/src/fs-utils.ts +++ b/src/fs-utils.ts @@ -12,14 +12,15 @@ async function assertFile(filePath: string) { } async function existsAsync(filePath: string): Promise { - return stat(filePath) - .then(() => true) - .catch((err) => { - /* istanbul ignore else */ - if (err.code === 'ENOENT') { - return false - } - /* istanbul ignore next */ - throw err - }) + try { + await stat(filePath) + return true + } catch (err) { + /* istanbul ignore else */ + if ((err as { code: string }).code === 'ENOENT') { + return false + } + /* istanbul ignore next */ + throw err + } } diff --git a/src/package-json-file-service.ts b/src/package-json-file-service.ts index 927e3ee..41a49f8 100644 --- a/src/package-json-file-service.ts +++ b/src/package-json-file-service.ts @@ -26,9 +26,7 @@ export function createPackageJSONFileService(): IPackageJSONService { writePackageFile: async (filePath, fileContent) => { const contents = await readFileContents(filePath) const { indent } = detectIndent(contents) - const trailingNewline = contents.length - ? contents[contents.length - 1] === '\n' - : false + const trailingNewline = contents.length ? contents.endsWith('\n') : false const data = JSON.stringify( fileContent, null, diff --git a/src/package-source.ts b/src/package-source.ts index 9f8b88a..342eb7a 100644 --- a/src/package-source.ts +++ b/src/package-source.ts @@ -11,7 +11,7 @@ export interface IPackageSource { * * @param packageName */ - fetch(packageName: string): Promise + fetch(this: void, packageName: string): Promise } /** @@ -33,7 +33,7 @@ export function createPackageSource(): IPackageSource { * Fetches info about a package, or `null` if not found. */ fetch: async (name) => { - const response = await fetch(encodeURI(name)).catch((err: any) => { + const response = await fetch(encodeURI(name)).catch((err) => { if (err.statusCode === 404) { return null } diff --git a/src/type-syncer.ts b/src/type-syncer.ts index 770f68f..561fa0c 100644 --- a/src/type-syncer.ts +++ b/src/type-syncer.ts @@ -86,7 +86,7 @@ export function createTypeSyncer( const { ignoreDeps, ignorePackages } = opts const packageFile = - file || (await packageJSONService.readPackageFile(filePath)) + file ?? (await packageJSONService.readPackageFile(filePath)) const allLocalPackages = Object.values(IDependencySection) .map((dep) => { const section = getDependenciesBySection(packageFile, dep) @@ -241,14 +241,15 @@ function getPackageScope(packageName: string): [string, string] | null { function getPackagesFromSection( section: IDependenciesSection, ignoredSection?: boolean, - ignorePackages?: string[], -): IPackageVersion[] { + ignorePackages?: Array, +): Array { return filterMap(Object.keys(section), (name) => { const isTyping = name.startsWith('@types/') // Never ignore `@types` packages. if (!isTyping) { // If it's not a `@types` package, check whether the section or package is ignored. + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- We want to check for false as well. if (ignoredSection || ignorePackages?.includes(name)) { return false } diff --git a/src/types.ts b/src/types.ts index 96b3c7b..30324f4 100644 --- a/src/types.ts +++ b/src/types.ts @@ -14,11 +14,11 @@ export interface ISyncOptions { /** * Ignore certain deps. */ - ignoreDeps?: IDependencySection[] + ignoreDeps?: Array /** * Ignore certain packages. */ - ignorePackages?: string[] + ignorePackages?: Array } /** @@ -37,9 +37,7 @@ export interface IPackageFile { /** * Section in package.json representing dependencies. */ -export interface IDependenciesSection { - [packageName: string]: string -} +export type IDependenciesSection = Record /** * Package + version record, collected from the {"package": "^1.2.3"} sections. @@ -107,6 +105,6 @@ export enum IDependencySection { * CLI arguments. */ export interface ICLIArguments { - flags: { [key: string]: boolean | string | undefined } + flags: Record args: Array } diff --git a/src/util.ts b/src/util.ts index 2ab304b..e9b5d82 100644 --- a/src/util.ts +++ b/src/util.ts @@ -53,7 +53,7 @@ export function shrinkObject(source: T): Required { * @param source An array of objects to merge. */ export function mergeObjects(source: Array): T { - return source.reduce((accum: any, next: any) => ({ ...accum, ...next }), {}) + return source.reduce((accum, next) => ({ ...accum, ...next }), {} as T) } /** @@ -91,13 +91,14 @@ export function untyped(name: string): string { * Orders an object. * @param source */ -export function orderObject< - T extends Record, ->(source: T, comparer?: (a: string, b: string) => number): T { +export function orderObject, U>( + source: T, + comparer?: (a: string, b: string) => number, +): T { const keys = Object.keys(source).sort(comparer) - const result: any = {} + const result: Record = {} for (const key of keys) { - result[key] = (source as any)[key] + result[key] = source[key] } return result as T @@ -108,10 +109,10 @@ export function orderObject< * * @param fn */ -export function memoizeAsync( +export function memoizeAsync, V, W>( fn: (...args: U) => Promise, ) { - const cache = new Map>() + const cache = new Map>() async function run(...args: U): Promise { try { diff --git a/src/versioning.ts b/src/versioning.ts index e1fc3c4..8ff523e 100644 --- a/src/versioning.ts +++ b/src/versioning.ts @@ -15,7 +15,7 @@ export interface IPackageVersionInfo { * @param version */ export function getClosestMatchingVersion( - availableVersions: IPackageVersionInfo[], + availableVersions: Array, version: string, ) { const parsedVersion = parseVersion(version) @@ -40,7 +40,7 @@ export function getClosestMatchingVersion( return true }) - return bestMatch || availableVersions[0] + return bestMatch ?? availableVersions[0] } /** diff --git a/src/workspace-resolver.ts b/src/workspace-resolver.ts index 31da5a8..ab0cd6e 100644 --- a/src/workspace-resolver.ts +++ b/src/workspace-resolver.ts @@ -37,7 +37,7 @@ export type IWorkspacesArray = Array * - 'packages/*' * ``` */ -export type IWorkspacesObject = { +export interface IWorkspacesObject { packages: IWorkspacesArray } @@ -61,7 +61,7 @@ type NpmWorkspacesConfig = IWorkspacesArray */ type YarnWorkspacesConfig = | IWorkspacesArray - | (IWorkspacesObject & { nohoist?: string[] }) + | (IWorkspacesObject & { nohoist?: Array }) /** * The contents of a `pnpm-workspace.yaml` file.