Skip to content

Commit

Permalink
refactor: tidy up conditional imports importing
Browse files Browse the repository at this point in the history
  • Loading branch information
RebeccaStevens committed Aug 30, 2021
1 parent 374bdf3 commit 5fd2cc1
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 53 deletions.
2 changes: 2 additions & 0 deletions packages/experimental-utils/src/conditional-imports/index.ts
@@ -0,0 +1,2 @@
export * from './tsutils';
export * from './typescript';
@@ -1,12 +1,12 @@
import type * as tsutils from 'tsutils';
import type * as tsutilsType from 'tsutils';

// Conditionally loaded tsutils but only if it is available.
const conditionalTsutils = ((): typeof tsutils | Error => {
const tsutils = ((): typeof tsutilsType | Error => {
try {
return require('tsutils') as typeof tsutils;
return require('tsutils') as typeof tsutilsType;
} catch {
return new Error('Cannot find local tsutils peer depenancy.');
}
})();

export { conditionalTsutils };
export { tsutils };
@@ -1,12 +1,12 @@
import type * as ts from 'typescript';
import type * as tsType from 'typescript';

// Conditionally loaded TypeScript but only if it is available.
const conditionalTypeScript = ((): typeof ts | Error => {
const ts = ((): typeof tsType | Error => {
try {
return require('typescript') as typeof ts;
return require('typescript') as typeof tsType;
} catch {
return new Error('Cannot find local typescript peer depenancy.');
}
})();

export { conditionalTypeScript };
export { ts };
67 changes: 31 additions & 36 deletions packages/experimental-utils/src/eslint-utils/isTypeReadonly.ts
@@ -1,8 +1,7 @@
import assert from 'assert';
import type * as ts from 'typescript';
import type * as tsTypes from 'typescript';

import { conditionalTypeScript } from '../conditional-imports/typescript';
import { conditionalTsutils } from '../conditional-imports/tsutils';
import { ts, tsutils } from '../conditional-imports';

import { getTypeOfPropertyOfType } from './propertyTypes';
import { nullThrows, NullThrowsReasons } from './nullThrows';
Expand All @@ -17,11 +16,11 @@ const enum Readonlyness {
}

function isTypeReadonlyArrayOrTuple(
checker: ts.TypeChecker,
type: ts.Type,
seenTypes: Set<ts.Type>,
checker: tsTypes.TypeChecker,
type: tsTypes.Type,
seenTypes: Set<tsTypes.Type>,
): Readonlyness {
function checkTypeArguments(arrayType: ts.TypeReference): Readonlyness {
function checkTypeArguments(arrayType: tsTypes.TypeReference): Readonlyness {
const typeArguments =
// getTypeArguments was only added in TS3.7
checker.getTypeArguments
Expand Down Expand Up @@ -73,14 +72,14 @@ function isTypeReadonlyArrayOrTuple(
}

function isTypeReadonlyObject(
checker: ts.TypeChecker,
type: ts.Type,
seenTypes: Set<ts.Type>,
checker: tsTypes.TypeChecker,
type: tsTypes.Type,
seenTypes: Set<tsTypes.Type>,
): Readonlyness {
assert(!(conditionalTypeScript instanceof Error));
assert(!(conditionalTsutils instanceof Error));
assert(!(ts instanceof Error));
assert(!(tsutils instanceof Error));

function checkIndexSignature(kind: ts.IndexKind): Readonlyness {
function checkIndexSignature(kind: tsTypes.IndexKind): Readonlyness {
const indexInfo = checker.getIndexInfoOfType(type, kind);
if (indexInfo) {
return indexInfo.isReadonly
Expand All @@ -96,7 +95,7 @@ function isTypeReadonlyObject(
// ensure the properties are marked as readonly
for (const property of properties) {
if (
!conditionalTsutils.isPropertyReadonlyInType(
!tsutils.isPropertyReadonlyInType(
type,
property.getEscapedName(),
checker,
Expand Down Expand Up @@ -133,16 +132,12 @@ function isTypeReadonlyObject(
}
}

const isStringIndexSigReadonly = checkIndexSignature(
conditionalTypeScript.IndexKind.String,
);
const isStringIndexSigReadonly = checkIndexSignature(ts.IndexKind.String);
if (isStringIndexSigReadonly === Readonlyness.Mutable) {
return isStringIndexSigReadonly;
}

const isNumberIndexSigReadonly = checkIndexSignature(
conditionalTypeScript.IndexKind.Number,
);
const isNumberIndexSigReadonly = checkIndexSignature(ts.IndexKind.Number);
if (isNumberIndexSigReadonly === Readonlyness.Mutable) {
return isNumberIndexSigReadonly;
}
Expand All @@ -152,18 +147,18 @@ function isTypeReadonlyObject(

// a helper function to ensure the seenTypes map is always passed down, except by the external caller
function isTypeReadonlyRecurser(
checker: ts.TypeChecker,
type: ts.Type,
seenTypes: Set<ts.Type>,
checker: tsTypes.TypeChecker,
type: tsTypes.Type,
seenTypes: Set<tsTypes.Type>,
): Readonlyness.Readonly | Readonlyness.Mutable {
assert(!(conditionalTypeScript instanceof Error));
assert(!(conditionalTsutils instanceof Error));
assert(!(ts instanceof Error));
assert(!(tsutils instanceof Error));

seenTypes.add(type);

if (conditionalTsutils.isUnionType(type)) {
if (tsutils.isUnionType(type)) {
// all types in the union must be readonly
const result = conditionalTsutils
const result = tsutils
.unionTypeParts(type)
.every(t => isTypeReadonlyRecurser(checker, t, seenTypes));
const readonlyness = result ? Readonlyness.Readonly : Readonlyness.Mutable;
Expand All @@ -172,10 +167,7 @@ function isTypeReadonlyRecurser(

// all non-object, non-intersection types are readonly.
// this should only be primitive types
if (
!conditionalTsutils.isObjectType(type) &&
!conditionalTsutils.isUnionOrIntersectionType(type)
) {
if (!tsutils.isObjectType(type) && !tsutils.isUnionOrIntersectionType(type)) {
return Readonlyness.Readonly;
}

Expand Down Expand Up @@ -205,12 +197,15 @@ function isTypeReadonlyRecurser(
/**
* Checks if the given type is readonly
*/
function isTypeReadonly(checker: ts.TypeChecker, type: ts.Type): boolean {
if (conditionalTypeScript instanceof Error) {
throw conditionalTypeScript;
function isTypeReadonly(
checker: tsTypes.TypeChecker,
type: tsTypes.Type,
): boolean {
if (ts instanceof Error) {
throw ts;
}
if (conditionalTsutils instanceof Error) {
throw conditionalTsutils;
if (tsutils instanceof Error) {
throw tsutils;
}

return (
Expand Down
18 changes: 9 additions & 9 deletions packages/experimental-utils/src/eslint-utils/propertyTypes.ts
@@ -1,11 +1,11 @@
import type * as ts from 'typescript';
import type * as tsType from 'typescript';

export function getTypeOfPropertyOfName(
checker: ts.TypeChecker,
type: ts.Type,
checker: tsType.TypeChecker,
type: tsType.Type,
name: string,
escapedName?: ts.__String,
): ts.Type | undefined {
escapedName?: tsType.__String,
): tsType.Type | undefined {
// Most names are directly usable in the checker and aren't different from escaped names
if (!escapedName || !name.startsWith('__')) {
return checker.getTypeOfPropertyOfType(type, name);
Expand All @@ -23,10 +23,10 @@ export function getTypeOfPropertyOfName(
}

export function getTypeOfPropertyOfType(
checker: ts.TypeChecker,
type: ts.Type,
property: ts.Symbol,
): ts.Type | undefined {
checker: tsType.TypeChecker,
type: tsType.Type,
property: tsType.Symbol,
): tsType.Type | undefined {
return getTypeOfPropertyOfName(
checker,
type,
Expand Down

0 comments on commit 5fd2cc1

Please sign in to comment.