refactor: Enable ts/no-explicit-any rule

This commit is contained in:
Joachim Van Herwegen 2024-03-13 10:44:51 +01:00
parent 331f83d659
commit b381a9c926
67 changed files with 167 additions and 135 deletions

View File

@ -101,6 +101,7 @@ module.exports = {
'ts/explicit-member-accessibility': 'error',
'ts/method-signature-style': 'error',
'ts/no-confusing-non-null-assertion': 'error',
'ts/no-explicit-any': 'error',
'ts/no-extraneous-class': [ 'error', {
allowConstructorOnly: false,
allowEmpty: false,

View File

@ -32,6 +32,7 @@ module.exports = {
'test/prefer-lowercase-title': 'off',
'ts/naming-convention': 'off',
'ts/no-explicit-any': 'off',
'ts/no-unsafe-argument': 'off',
'ts/no-unsafe-assignment': 'off',
'ts/no-unsafe-call': 'off',

View File

@ -62,8 +62,8 @@ export class ConvertingErrorHandler extends ErrorHandler {
private async extractErrorDetails({ error, request }: ErrorHandlerArgs): Promise<PreparedArguments> {
if (!this.showStackTrace) {
delete error.stack;
// eslint-disable-next-line ts/no-unsafe-member-access
delete (error as any).cause;
// Cheating here to delete a readonly field
delete (error as { cause: unknown }).cause;
}
const representation = new BasicRepresentation([ error ], error.metadata, INTERNAL_ERROR, false);
const identifier = { path: representation.metadata.identifier.value };

View File

@ -35,7 +35,7 @@ export class BasicRepresentation implements Representation {
* @param binary - Whether the representation is a binary or object stream
*/
public constructor(
data: Guarded<Readable> | Readable | any[] | string,
data: Guarded<Readable> | Readable | unknown[] | string,
metadata: RepresentationMetadata | MetadataRecord,
binary?: boolean,
);
@ -47,7 +47,7 @@ export class BasicRepresentation implements Representation {
* @param binary - Whether the representation is a binary or object stream
*/
public constructor(
data: Guarded<Readable> | Readable | any[] | string,
data: Guarded<Readable> | Readable | unknown[] | string,
metadata: RepresentationMetadata | MetadataRecord,
contentType?: string,
binary?: boolean,
@ -59,7 +59,7 @@ export class BasicRepresentation implements Representation {
* @param binary - Whether the representation is a binary or object stream
*/
public constructor(
data: Guarded<Readable> | Readable | any[] | string,
data: Guarded<Readable> | Readable | unknown[] | string,
contentType: string,
binary?: boolean,
);
@ -71,7 +71,7 @@ export class BasicRepresentation implements Representation {
* @param binary - Whether the representation is a binary or object stream
*/
public constructor(
data: Guarded<Readable> | Readable | any[] | string,
data: Guarded<Readable> | Readable | unknown[] | string,
identifier: MetadataIdentifier,
metadata?: MetadataRecord,
binary?: boolean,
@ -84,14 +84,14 @@ export class BasicRepresentation implements Representation {
* @param binary - Whether the representation is a binary or object stream
*/
public constructor(
data: Guarded<Readable> | Readable | any[] | string,
data: Guarded<Readable> | Readable | unknown[] | string,
identifier: MetadataIdentifier,
contentType?: string,
binary?: boolean,
);
public constructor(
data?: Readable | any[] | string,
data?: Readable | unknown[] | string,
metadata?: RepresentationMetadata | MetadataRecord | MetadataIdentifier | string,
metadataRest?: MetadataRecord | string | boolean,
binary?: boolean,
@ -109,8 +109,7 @@ export class BasicRepresentation implements Representation {
}
if (!isRepresentationMetadata(metadata) || typeof metadataRest === 'string') {
// This combination will always match with a valid overload
// eslint-disable-next-line ts/no-unsafe-argument
metadata = new RepresentationMetadata(metadata as any, metadataRest as any);
metadata = new RepresentationMetadata(metadata as RepresentationMetadata, metadataRest as string);
}
this.metadata = metadata;

View File

@ -15,7 +15,7 @@ export type MetadataGraph = NamedNode | BlankNode | DefaultGraph | string;
/**
* Determines whether the object is a `RepresentationMetadata`.
*/
export function isRepresentationMetadata(object: any): object is RepresentationMetadata {
export function isRepresentationMetadata(object: unknown): object is RepresentationMetadata {
return typeof (object as RepresentationMetadata)?.setMetadata === 'function';
}
@ -240,7 +240,7 @@ export class RepresentationMetadata {
* @param graph - Optional graph of where to add the values to.
*/
public add(predicate: NamedNode, object: MetadataValue, graph?: MetadataGraph): this {
return this.forQuads(predicate, object, (pred, obj): any => this.addQuad(this.id, pred, obj, graph));
return this.forQuads(predicate, object, (pred, obj): unknown => this.addQuad(this.id, pred, obj, graph));
}
/**
@ -250,7 +250,7 @@ export class RepresentationMetadata {
* @param graph - Optional graph of where to remove the values from.
*/
public remove(predicate: NamedNode, object: MetadataValue, graph?: MetadataGraph): this {
return this.forQuads(predicate, object, (pred, obj): any => this.removeQuad(this.id, pred, obj, graph));
return this.forQuads(predicate, object, (pred, obj): unknown => this.removeQuad(this.id, pred, obj, graph));
}
/**
@ -290,8 +290,12 @@ export class RepresentationMetadata {
): boolean {
// This works with N3.js but at the time of writing the typings have not been updated yet.
// If you see this line of code check if the typings are already correct and update this if so.
// eslint-disable-next-line ts/no-unsafe-call
return (this.store.has as any)(this.id, predicate, object, graph) as boolean;
return (this.store as unknown as {
has: (subject: Term,
predicate: Term | string | null,
object: Term | string | null,
graph: Term | string | null) => boolean;
}).has(this.id, predicate, object, graph) as boolean;
}
/**

View File

@ -187,14 +187,20 @@ export class IdentityProviderFactory implements ProviderFactory {
provider.use(async(ctx, next): Promise<void> => {
const accepts = ctx.accepts.bind(ctx);
// Using `any` typings to make sure we support all different versions of `ctx.accepts`
ctx.accepts = (...types): any => {
// This is how you get the correct typing for an overloaded function
type AcceptFn = {
(): string[];
(...types: string[]): string | false;
(types: string[]): string | false;
};
ctx.accepts = ((...types): string[] | string | false => {
// Make sure we only override our specific case
if (types.length === 2 && types[0] === 'json' && types[1] === 'html') {
return 'html';
}
return accepts(...types as string[]);
};
}) as AcceptFn;
return next();
});
@ -257,7 +263,7 @@ export class IdentityProviderFactory implements ProviderFactory {
* Checks if the given token is an access token.
* The AccessToken interface is not exported, so we have to access it like this.
*/
private isAccessToken(token: any): token is KoaContextWithOIDC['oidc']['accessToken'] {
private isAccessToken(token: unknown): token is KoaContextWithOIDC['oidc']['accessToken'] {
return (token as KoaContextWithOIDC['oidc']['accessToken'])?.kind === 'AccessToken';
}
@ -270,7 +276,7 @@ export class IdentityProviderFactory implements ProviderFactory {
// Some fields are still missing, see https://github.com/CommunitySolidServer/CommunitySolidServer/issues/1154#issuecomment-1040233385
config.findAccount = async(ctx: KoaContextWithOIDC, sub: string): Promise<Account> => ({
accountId: sub,
async claims(): Promise<{ sub: string; [key: string]: any }> {
async claims(): Promise<{ sub: string; [key: string]: unknown }> {
return { sub, webid: sub, azp: ctx.oidc.client?.clientId };
},
});

View File

@ -1,5 +1,6 @@
import type { Json } from '../../util/Json';
import { ACCOUNT_ID_KEY } from './account/AccountIdRoute';
import type { Json, JsonRepresentation } from './InteractionUtil';
import type { JsonRepresentation } from './InteractionUtil';
import type { JsonInteractionHandlerInput } from './JsonInteractionHandler';
import { JsonInteractionHandler } from './JsonInteractionHandler';
import type { InteractionRoute } from './routing/InteractionRoute';

View File

@ -3,16 +3,12 @@ import type Provider from '../../../templates/types/oidc-provider';
import type { RepresentationMetadata } from '../../http/representation/RepresentationMetadata';
import { getLoggerFor } from '../../logging/LogUtil';
import { BadRequestHttpError } from '../../util/errors/BadRequestHttpError';
import type { Json } from '../../util/Json';
import type { Interaction } from './InteractionHandler';
import Dict = NodeJS.Dict;
const logger = getLoggerFor('AccountUtil');
/**
* A JSON object.
*/
export type Json = string | number | boolean | Dict<Json> | Json[];
/**
* Contains a JSON object and any associated metadata.
* Similar to a {@link Representation} but with all the data in memory instead of as a stream

View File

@ -3,10 +3,10 @@ import type { Representation } from '../../http/representation/Representation';
import { RepresentationMetadata } from '../../http/representation/RepresentationMetadata';
import type { RepresentationConverter } from '../../storage/conversion/RepresentationConverter';
import { APPLICATION_JSON } from '../../util/ContentTypes';
import type { Json } from '../../util/Json';
import { readJsonStream } from '../../util/StreamUtil';
import type { InteractionHandlerInput } from './InteractionHandler';
import { InteractionHandler } from './InteractionHandler';
import type { Json } from './InteractionUtil';
import type { JsonInteractionHandler, JsonInteractionHandlerInput } from './JsonInteractionHandler';
/**

View File

@ -1,8 +1,9 @@
import type { RepresentationMetadata } from '../../http/representation/RepresentationMetadata';
import type { ResourceIdentifier } from '../../http/representation/ResourceIdentifier';
import { AsyncHandler } from '../../util/handlers/AsyncHandler';
import type { Json } from '../../util/Json';
import type { Interaction } from './InteractionHandler';
import type { Json, JsonRepresentation } from './InteractionUtil';
import type { JsonRepresentation } from './InteractionUtil';
import Dict = NodeJS.Dict;
export interface JsonInteractionHandlerInput {

View File

@ -1,5 +1,5 @@
import type { Json } from '../../util/Json';
import { ControlHandler } from './ControlHandler';
import type { Json } from './InteractionUtil';
import type { JsonInteractionHandlerInput } from './JsonInteractionHandler';
/**

View File

@ -1,4 +1,5 @@
import type { Json, JsonRepresentation } from './InteractionUtil';
import type { Json } from '../../util/Json';
import type { JsonRepresentation } from './InteractionUtil';
import { JsonInteractionHandler } from './JsonInteractionHandler';
/**

View File

@ -1,11 +1,13 @@
import { string } from 'yup';
import type { ObjectSchema, Schema, ValidateOptions } from 'yup';
import type { AnyObject, Maybe, ObjectSchema, Schema, ValidateOptions } from 'yup';
import { BadRequestHttpError } from '../../util/errors/BadRequestHttpError';
import { createErrorMessage } from '../../util/errors/ErrorUtil';
import type { Json } from '../../util/Json';
import { isUrl } from '../../util/StringUtil';
import type { Json } from './InteractionUtil';
import Dict = NodeJS.Dict;
type BaseObjectSchema = ObjectSchema<Maybe<AnyObject>>;
// The builtin `url` validator of `yup` does not support localhost URLs, so we create a custom one here.
// The reason for having a URL validator on the WebID is to prevent us from generating invalid ACL,
// which would break the pod creation causing us to have an incomplete pod.
@ -20,16 +22,16 @@ export const URL_SCHEMA = string().trim().optional().test({
},
});
function isObjectSchema(schema: Schema): schema is ObjectSchema<any> {
function isObjectSchema(schema: Schema): schema is BaseObjectSchema {
return schema.type === 'object';
}
// `T` can't extend Schema since it could also be a Reference, which is a type `yup` doesn't export
type SchemaType<T> = T extends ObjectSchema<any> ? ObjectType<T> : { required: boolean; type: string };
type SchemaType<T> = T extends BaseObjectSchema ? ObjectType<T> : { required: boolean; type: string };
// The type of the fields in an object schema
type FieldType<T extends ObjectSchema<any>> = T extends { fields: Record<infer R, any> } ? R : never;
type FieldType<T extends BaseObjectSchema> = T extends { fields: Record<infer R, unknown> } ? R : never;
// Simplified type we use to represent yup objects
type ObjectType<T extends ObjectSchema<any>> =
type ObjectType<T extends BaseObjectSchema> =
{ required: boolean; type: 'object'; fields: {[ K in FieldType<T> ]: SchemaType<T['fields'][K]> }};
/**
@ -50,7 +52,7 @@ function parseSchemaDescription<T extends Schema>(schema: T): SchemaType<T> {
/**
* Generates a simplified representation of a yup schema.
*/
export function parseSchema<T extends ObjectSchema<any>>(schema: T): Pick<SchemaType<T>, 'fields'> {
export function parseSchema<T extends BaseObjectSchema>(schema: T): Pick<SchemaType<T>, 'fields'> {
const result = parseSchemaDescription(schema);
return { fields: result.fields };
}
@ -58,13 +60,12 @@ export function parseSchema<T extends ObjectSchema<any>>(schema: T): Pick<Schema
/**
* Same functionality as the yup validate function, but throws a {@link BadRequestHttpError} if there is an error.
*/
export async function validateWithError<T extends ObjectSchema<any>>(
export async function validateWithError<T extends BaseObjectSchema>(
schema: T,
data: unknown,
options?: ValidateOptions<any>,
options?: ValidateOptions<AnyObject>,
): Promise<T['__outputType']> {
try {
// eslint-disable-next-line ts/no-unsafe-return
return await schema.validate(data, options);
} catch (error: unknown) {
throw new BadRequestHttpError(createErrorMessage(error));

View File

@ -22,9 +22,10 @@ export class BaseAccountStore extends Initializer implements AccountStore {
private readonly storage: AccountLoginStorage<{ [ACCOUNT_TYPE]: typeof ACCOUNT_STORAGE_DESCRIPTION }>;
private initialized = false;
public constructor(storage: AccountLoginStorage<any>) {
// Wrong typings to prevent Components.js typing issues
public constructor(storage: AccountLoginStorage<Record<string, never>>) {
super();
this.storage = storage as typeof this.storage;
this.storage = storage as unknown as typeof this.storage;
}
// Initialize the type definitions

View File

@ -27,9 +27,10 @@ export class BaseClientCredentialsStore extends Initializer implements ClientCre
private initialized = false;
public constructor(storage: AccountLoginStorage<any>) {
// Wrong typings to prevent Components.js typing issues
public constructor(storage: AccountLoginStorage<Record<string, never>>) {
super();
this.storage = storage as typeof this.storage;
this.storage = storage as unknown as typeof this.storage;
}
// Initialize the type definitions

View File

@ -1,10 +1,11 @@
import { RepresentationMetadata } from '../../../http/representation/RepresentationMetadata';
import { getLoggerFor } from '../../../logging/LogUtil';
import type { Json } from '../../../util/Json';
import { SOLID_HTTP } from '../../../util/Vocabularies';
import { ACCOUNT_SETTINGS_REMEMBER_LOGIN } from '../account/util/AccountStore';
import type { AccountStore } from '../account/util/AccountStore';
import type { CookieStore } from '../account/util/CookieStore';
import type { Json, JsonRepresentation } from '../InteractionUtil';
import type { JsonRepresentation } from '../InteractionUtil';
import { finishInteraction } from '../InteractionUtil';
import type { JsonInteractionHandlerInput } from '../JsonInteractionHandler';
import { JsonInteractionHandler } from '../JsonInteractionHandler';

View File

@ -29,9 +29,10 @@ export class BasePasswordStore extends Initializer implements PasswordStore {
private readonly saltRounds: number;
private initialized = false;
public constructor(storage: AccountLoginStorage<any>, saltRounds = 10) {
// Wrong typings to prevent Components.js typing issues
public constructor(storage: AccountLoginStorage<Record<string, never>>, saltRounds = 10) {
super();
this.storage = storage as typeof this.storage;
this.storage = storage as unknown as typeof this.storage;
this.saltRounds = saltRounds;
}

View File

@ -44,9 +44,10 @@ export class BasePodStore extends Initializer implements PodStore {
private initialized = false;
public constructor(storage: AccountLoginStorage<any>, manager: PodManager, visible = false) {
// Wrong typings to prevent Components.js typing issues
public constructor(storage: AccountLoginStorage<Record<string, never>>, manager: PodManager, visible = false) {
super();
this.storage = storage as typeof this.storage;
this.storage = storage as unknown as typeof this.storage;
this.visible = visible;
this.manager = manager;
}

View File

@ -10,7 +10,7 @@ import type { InteractionRoute } from './InteractionRoute';
* Rejects operations that target a different route,
* otherwise the input parameters are passed to the source handler.
*/
export class InteractionRouteHandler<T extends InteractionRoute<any>> extends JsonInteractionHandler {
export class InteractionRouteHandler<T extends InteractionRoute<string>> extends JsonInteractionHandler {
protected readonly route: T;
protected readonly source: JsonInteractionHandler;

View File

@ -23,9 +23,10 @@ export class BaseWebIdStore extends Initializer implements WebIdStore {
private readonly storage: AccountLoginStorage<{ [WEBID_STORAGE_TYPE]: typeof WEBID_STORAGE_DESCRIPTION }>;
private initialized = false;
public constructor(storage: AccountLoginStorage<any>) {
// Wrong typings to prevent Components.js typing issues
public constructor(storage: AccountLoginStorage<Record<string, never>>) {
super();
this.storage = storage as typeof this.storage;
this.storage = storage as unknown as typeof this.storage;
}
// Initialize the type definitions

View File

@ -615,6 +615,7 @@ export * from './util/GenericEventEmitter';
export * from './util/GuardedStream';
export * from './util/HeaderUtil';
export * from './util/IterableUtil';
export * from './util/Json';
export * from './util/PathUtil';
export * from './util/PromiseUtil';
export * from './util/QuadUtil';

View File

@ -105,9 +105,9 @@ export class AppRunner {
let configs = input.config ?? [ '@css:config/default.json' ];
configs = (Array.isArray(configs) ? configs : [ configs ]).map(resolveAssetPath);
let componentsManager: ComponentsManager<any>;
let componentsManager: ComponentsManager<App | CliResolver>;
try {
componentsManager = await this.createComponentsManager<any>(loaderProperties, configs);
componentsManager = await this.createComponentsManager<App>(loaderProperties, configs);
} catch (error: unknown) {
this.resolveError(`Could not build the config files from ${configs.join(',')}`, error);
}
@ -227,7 +227,7 @@ export class AppRunner {
// Finally try and read from the config.community-solid-server
// field in the root package.json
const pkg = await readJSON(packageJsonPath) as { config?: Record<string, any> };
const pkg = await readJSON(packageJsonPath) as { config?: Record<string, unknown> };
if (typeof pkg.config?.['community-solid-server'] === 'object') {
return pkg.config['community-solid-server'] as Record<string, unknown>;
}

View File

@ -19,7 +19,7 @@ export class YargsParameter {
* @param name - Name of the parameter. Corresponds to the first parameter passed to the `yargs.options` function.
* @param options - Options for a single parameter that should be parsed. @range {json}
*/
public constructor(name: string, options: Record<string, any>) {
public constructor(name: string, options: Record<string, unknown>) {
this.name = name;
this.options = options;
}

View File

@ -68,11 +68,12 @@ export interface V6MigrationInitializerArgs {
/**
* Storages for which all entries need to be removed.
*/
cleanupStorages: KeyValueStorage<string, any>[];
cleanupStorages: KeyValueStorage<string, unknown>[];
/**
* The storage that will contain the account data in the new format.
* Wrong typings to prevent Components.js typing issues.
*/
newAccountStorage: AccountLoginStorage<any>;
newAccountStorage: AccountLoginStorage<Record<string, never>>;
/**
* The storage that will contain the setup entries in the new format.
*/
@ -100,7 +101,7 @@ export class V6MigrationInitializer extends Initializer {
private readonly accountStorage: KeyValueStorage<string, Account | Settings>;
private readonly clientCredentialsStorage: KeyValueStorage<string, ClientCredentials>;
private readonly cleanupStorages: KeyValueStorage<string, any>[];
private readonly cleanupStorages: KeyValueStorage<string, unknown>[];
private readonly newAccountStorage: AccountLoginStorage<typeof STORAGE_DESCRIPTION>;
private readonly newSetupStorage: KeyValueStorage<string, string>;
@ -113,7 +114,7 @@ export class V6MigrationInitializer extends Initializer {
this.accountStorage = args.accountStorage;
this.clientCredentialsStorage = args.clientCredentialsStorage;
this.cleanupStorages = args.cleanupStorages;
this.newAccountStorage = args.newAccountStorage as AccountLoginStorage<typeof STORAGE_DESCRIPTION>;
this.newAccountStorage = args.newAccountStorage as unknown as AccountLoginStorage<typeof STORAGE_DESCRIPTION>;
this.newSetupStorage = args.newSetupStorage;
}

View File

@ -14,7 +14,7 @@ export class CombinedShorthandResolver extends ShorthandResolver {
}
public async handle(input: Record<string, unknown>): Promise<Record<string, unknown>> {
const vars: Record<string, any> = {};
const vars: Record<string, unknown> = {};
for (const [ name, computer ] of Object.entries(this.resolvers)) {
try {
vars[name] = await computer.handleSafe(input);

View File

@ -13,7 +13,7 @@ export class WinstonLogger extends BaseLogger {
this.logger = logger;
}
public log(level: LogLevel, message: string, meta?: any): this {
public log(level: LogLevel, message: string, meta?: unknown): this {
this.logger.log(level, message, meta);
return this;
}

View File

@ -1,3 +1,4 @@
import type { TransformableInfo } from 'logform';
import { createLogger, format, transports } from 'winston';
import type * as Transport from 'winston-transport';
import type { Logger, LogMetadata } from './Logger';
@ -33,7 +34,7 @@ export class WinstonLoggerFactory implements LoggerFactory {
format.timestamp(),
format.metadata({ fillExcept: [ 'level', 'timestamp', 'label', 'message' ]}),
format.printf(
({ level: levelInner, message, label: labelInner, timestamp, metadata: meta }: Record<string, any>): string =>
({ level: levelInner, message, label: labelInner, timestamp, metadata: meta }: TransformableInfo): string =>
`${timestamp} [${labelInner}] {${this.clusterInfo(meta as LogMetadata)}} ${levelInner}: ${message}`,
),
),

View File

@ -10,7 +10,7 @@ import type { ComponentsJsFactory } from './ComponentsJsFactory';
* but moduleState will be stored in between calls.
*/
export class BaseComponentsJsFactory implements ComponentsJsFactory {
private readonly options: IComponentsManagerBuilderOptions<any>;
private readonly options: IComponentsManagerBuilderOptions<unknown>;
public constructor(relativeModulePath = '../../../', logLevel = 'error') {
this.options = {
@ -21,7 +21,7 @@ export class BaseComponentsJsFactory implements ComponentsJsFactory {
};
}
private async buildManager(): Promise<ComponentsManager<any>> {
private async buildManager(): Promise<ComponentsManager<unknown>> {
const manager = await ComponentsManager.build(this.options);
this.options.moduleState = manager.moduleState;
return manager;
@ -35,7 +35,7 @@ export class BaseComponentsJsFactory implements ComponentsJsFactory {
*
* @returns The resulting object, corresponding to the given component IRI.
*/
public async generate<T>(configPath: string, componentIri: string, variables: Record<string, any>):
public async generate<T>(configPath: string, componentIri: string, variables: Record<string, unknown>):
Promise<T> {
const manager = await this.buildManager();
await manager.configRegistry.register(configPath);

View File

@ -10,5 +10,5 @@ export interface ComponentsJsFactory {
*
* @returns The resulting object, corresponding to the given component IRI.
*/
generate: <T>(configPath: string, componentIri: string, variables: Record<string, any>) => Promise<T>;
generate: <T>(configPath: string, componentIri: string, variables: Record<string, unknown>) => Promise<T>;
}

View File

@ -35,10 +35,10 @@ export class CorsHandler extends HttpHandler {
req: CorsRequest,
res: {
statusCode?: number;
setHeader: (key: string, value: string) => any;
end: () => any;
setHeader: (key: string, value: string) => unknown;
end: () => unknown;
},
next: (err?: any) => any,
next: (err?: unknown) => unknown,
) => void;
public constructor(options: SimpleCorsOptions = {}) {

View File

@ -5,7 +5,7 @@ import type { AsyncHandlerInput, AsyncHandlerOutput } from '../../util/handlers/
import { AsyncHandler } from '../../util/handlers/AsyncHandler';
import { trimTrailingSlashes } from '../../util/PathUtil';
export interface BaseRouterHandlerArgs<T extends AsyncHandler<any, any>> {
export interface BaseRouterHandlerArgs<T extends AsyncHandler<unknown, unknown>> {
/**
* The base URL of the server.
* Not required if no value is provided for `allowedPathNames`.
@ -36,7 +36,7 @@ export interface BaseRouterHandlerArgs<T extends AsyncHandler<any, any>> {
*
* `canHandleInput` expects a ResourceIdentifier to indicate it expects the target to have been validated already.
*/
export abstract class BaseRouterHandler<T extends AsyncHandler<any, any>>
export abstract class BaseRouterHandler<T extends AsyncHandler<unknown, unknown>>
extends AsyncHandler<AsyncHandlerInput<T>, AsyncHandlerOutput<T>> {
protected readonly baseUrlLength: number;
protected readonly handler: T;

View File

@ -154,7 +154,7 @@ export class LockingResourceStore implements AtomicResourceStore {
// Spy on the source to maintain the lock upon reading.
const data = Object.create(source, {
read: {
value(size: number): any {
value(size: number): unknown {
maintainLock();
return source.read(size);
},

View File

@ -355,7 +355,7 @@ export class FileDataAccessor implements DataAccessor {
* @param data - The data to be put in the file.
*/
protected async writeDataFile(path: string, data: Readable): Promise<void> {
return new Promise((resolve, reject): any => {
return new Promise((resolve, reject): void => {
const writeStream = createWriteStream(path);
data.pipe(writeStream);
data.on('error', (error): void => {

View File

@ -13,7 +13,7 @@ import { isInternalContentType } from '../conversion/ConversionUtil';
import type { DataAccessor } from './DataAccessor';
interface DataEntry {
data: any[];
data: unknown[];
metadata: RepresentationMetadata;
}
interface ContainerEntry {

View File

@ -58,7 +58,7 @@ export class DynamicJsonToTemplateConverter extends RepresentationConverter {
return representation;
}
const contents = JSON.parse(await readableToString(representation.data)) as NodeJS.Dict<any>;
const contents = JSON.parse(await readableToString(representation.data)) as NodeJS.Dict<unknown>;
const rendered = await this.templateEngine.handleSafe({ contents, template: { templateFile: typeMap[type] }});
const metadata = new RepresentationMetadata(representation.metadata, { [CONTENT_TYPE]: type });

View File

@ -8,7 +8,7 @@ import { QuotaStrategy } from './QuotaStrategy';
export class GlobalQuotaStrategy extends QuotaStrategy {
private readonly base: string;
public constructor(limit: Size, reporter: SizeReporter<any>, base: string) {
public constructor(limit: Size, reporter: SizeReporter<unknown>, base: string) {
super(reporter, limit);
this.base = base;
}

View File

@ -17,7 +17,7 @@ export class PodQuotaStrategy extends QuotaStrategy {
public constructor(
limit: Size,
reporter: SizeReporter<any>,
reporter: SizeReporter<unknown>,
identifierStrategy: IdentifierStrategy,
accessor: DataAccessor,
) {

View File

@ -18,10 +18,10 @@ import type { SizeReporter } from '../size-reporter/SizeReporter';
* This can be bytes, quads, file count, ...
*/
export abstract class QuotaStrategy {
public readonly reporter: SizeReporter<any>;
public readonly reporter: SizeReporter<unknown>;
public readonly limit: Size;
public constructor(reporter: SizeReporter<any>, limit: Size) {
protected constructor(reporter: SizeReporter<unknown>, limit: Size) {
this.reporter = reporter;
this.limit = limit;
}
@ -87,7 +87,7 @@ export abstract class QuotaStrategy {
const { reporter } = this;
return guardStream(new PassThrough({
async transform(this, chunk: any, enc: string, done: () => void): Promise<void> {
async transform(this, chunk: unknown, enc: string, done: () => void): Promise<void> {
total += await reporter.calculateChunkSize(chunk);
const availableSpace = await that.getAvailableSpace(identifier);
if (availableSpace.amount < total) {

View File

@ -9,6 +9,7 @@ import { EventEmitter } from 'node:events';
* Use the {@link createGenericEventEmitterClass} function to generate an event emitter class with the correct typings
* in case {@link EventEmitter} needs to be extended.
*/
// eslint-disable-next-line ts/no-explicit-any
export interface GenericEventEmitter<TEvent extends string | symbol, TFunc extends (...args: any[]) => void>
extends EventEmitter {
addListener: (event: TEvent, listener: TFunc) => this;

View File

@ -12,7 +12,7 @@
export function* map<TIn, TOut>(
iterable: Iterable<TIn>,
callbackFn: (element: TIn, index: number) => TOut,
thisArg?: any,
thisArg?: unknown,
): Iterable<TOut> {
const boundMapFn = callbackFn.bind(thisArg);
let count = 0;
@ -31,8 +31,11 @@ export function* map<TIn, TOut>(
* @param callbackFn - Function that is called to test every element.
* @param thisArg - Value to use as `this` when executing `callbackFn`.
*/
export function* filter<T>(iterable: Iterable<T>, callbackFn: (element: T, index: number) => boolean, thisArg?: any):
Iterable<T> {
export function* filter<T>(
iterable: Iterable<T>,
callbackFn: (element: T, index: number) => boolean,
thisArg?: unknown,
): Iterable<T> {
const boundFilterFn = callbackFn.bind(thisArg);
let count = 0;
for (const value of iterable) {
@ -63,7 +66,7 @@ export function* concat<T>(iterables: Iterable<Iterable<T>>): Iterable<T> {
* @param callbackFn - Function that is called to test every element.
* @param thisArg - Value to use as `this` when executing `callbackFn`.
*/
export function find<T>(iterable: Iterable<T>, callbackFn: (element: T, index: number) => boolean, thisArg?: any):
export function find<T>(iterable: Iterable<T>, callbackFn: (element: T, index: number) => boolean, thisArg?: unknown):
T | undefined {
const boundMapFn = callbackFn.bind(thisArg);
const count = 0;

4
src/util/Json.ts Normal file
View File

@ -0,0 +1,4 @@
/**
* A JSON object.
*/
export type Json = string | number | boolean | NodeJS.Dict<Json> | Json[];

View File

@ -12,7 +12,7 @@ const logger = getLoggerFor('LockUtil');
export async function setJitterTimeout(delay: number, jitter = 0): Promise<void> {
jitter = Math.max(0, Math.floor(Math.random() * jitter));
delay = Math.max(0, delay + jitter);
return new Promise<void>((resolve): any => setTimeout(resolve, delay));
return new Promise<void>((resolve): unknown => setTimeout(resolve, delay));
}
export interface AttemptSettings {

View File

@ -6,6 +6,7 @@ import type { ResourceIdentifier } from '../http/representation/ResourceIdentifi
import type { HttpRequest } from '../server/HttpRequest';
import { BadRequestHttpError } from './errors/BadRequestHttpError';
import { errorTermsToMetadata } from './errors/HttpErrorUtil';
import type { Json } from './Json';
/**
* Changes a potential Windows path into a POSIX path.
@ -305,8 +306,8 @@ export function resolveAssetPath(path = modulePathPlaceholder): string {
/**
* Reads the project package.json and returns it.
*/
export async function readPackageJson(): Promise<Record<string, any>> {
return readJson(resolveModulePath('package.json')) as Promise<Record<string, any>>;
export async function readPackageJson(): Promise<Record<string, Json>> {
return readJson(resolveModulePath('package.json')) as Promise<Record<string, Json>>;
}
/**

View File

@ -2,10 +2,11 @@
* Helper class for instantiating multiple objects with Components.js.
* See https://github.com/LinkedSoftwareDependencies/Components.js/issues/26
*/
// eslint-disable-next-line ts/no-extraneous-class
export class RecordObject implements Record<string, any> {
public constructor(record: Record<string, string> = {}) {
export class RecordObject implements Record<string, unknown> {
public constructor(record: Record<string, unknown> = {}) {
// eslint-disable-next-line no-constructor-return
return record;
}
[key: string]: unknown;
}

View File

@ -57,7 +57,7 @@ export class SliceStream extends Transform {
}
// eslint-disable-next-line ts/naming-convention
public _transform(chunk: any, encoding: BufferEncoding, callback: TransformCallback): void {
public _transform(chunk: unknown, encoding: BufferEncoding, callback: TransformCallback): void {
this.source.pause();
if (this.writableObjectMode) {
this.objectSlice(chunk);
@ -72,12 +72,12 @@ export class SliceStream extends Transform {
protected binarySlice(chunk: Buffer): void {
let length = chunk.length;
if (this.remainingSkip > 0) {
chunk = chunk.slice(this.remainingSkip);
chunk = chunk.subarray(this.remainingSkip);
this.remainingSkip -= length - chunk.length;
length = chunk.length;
}
if (length > 0 && this.remainingSkip <= 0) {
chunk = chunk.slice(0, this.remainingRead);
chunk = chunk.subarray(0, this.remainingRead);
this.push(chunk);
this.remainingRead -= length;
this.checkEnd();

View File

@ -10,6 +10,7 @@ import { isHttpRequest } from '../server/HttpRequest';
import { InternalServerError } from './errors/InternalServerError';
import type { Guarded } from './GuardedStream';
import { guardStream } from './GuardedStream';
import type { Json } from './Json';
import type { PromiseOrValue } from './PromiseUtil';
export const endOfStream = promisify(eos);
@ -45,9 +46,9 @@ export async function readableToQuads(stream: Readable): Promise<Store> {
*
* @returns The parsed object.
*/
export async function readJsonStream(stream: Readable): Promise<NodeJS.Dict<any>> {
export async function readJsonStream(stream: Readable): Promise<Json> {
const body = await readableToString(stream);
return JSON.parse(body) as NodeJS.Dict<any>;
return JSON.parse(body) as Json;
}
/**
@ -119,16 +120,16 @@ export function pipeSafely<T extends Writable>(
return guardStream(destination);
}
export interface AsyncTransformOptions<T = any> extends DuplexOptions {
export interface AsyncTransformOptions<T = unknown> extends DuplexOptions {
/**
* Transforms data from the source by calling the `push` method
*/
transform?: (this: Transform, data: T, encoding: string) => PromiseOrValue<any>;
transform?: (this: Transform, data: T, encoding: string) => PromiseOrValue<unknown>;
/**
* Performs any final actions after the source has ended
*/
flush?: (this: Transform) => PromiseOrValue<any>;
flush?: (this: Transform) => PromiseOrValue<unknown>;
}
/**
@ -140,7 +141,7 @@ export interface AsyncTransformOptions<T = any> extends DuplexOptions {
*
* @returns The transformed stream
*/
export function transformSafely<T = any>(
export function transformSafely<T = unknown>(
source: NodeJS.ReadableStream,
{
transform = function(data): void {
@ -179,6 +180,6 @@ export function transformSafely<T = any>(
* @param contents - Data to stream.
* @param options - Options to pass to the Readable constructor. See {@link Readable.from}.
*/
export function guardedStreamFrom(contents: string | Iterable<any>, options?: ReadableOptions): Guarded<Readable> {
export function guardedStreamFrom(contents: string | Iterable<unknown>, options?: ReadableOptions): Guarded<Readable> {
return guardStream(Readable.from(typeof contents === 'string' ? [ contents ] : contents, options));
}

View File

@ -14,7 +14,7 @@ type ValueVocabulary<TBase extends string, TLocal extends string> =
/**
* A {@link ValueVocabulary} where the URI values are {@link NamedNode}s.
*/
type TermVocabulary<T> = T extends ValueVocabulary<any, any> ? {[K in keyof T]: NamedNode<T[K]> } : never;
type TermVocabulary<T> = T extends ValueVocabulary<string, string> ? {[K in keyof T]: NamedNode<T[K]> } : never;
/**
* Contains a namespace and keys linking to the entries in this namespace.
@ -35,15 +35,15 @@ export type PartialVocabulary<TBase extends string> =
/**
* A local name of a {@link Vocabulary}.
*/
export type VocabularyLocal<T> = T extends Vocabulary<any, infer TKey> ? TKey : never;
export type VocabularyLocal<T> = T extends Vocabulary<string, infer TKey> ? TKey : never;
/**
* A URI string entry of a {@link Vocabulary}.
*/
export type VocabularyValue<T> = T extends Vocabulary<any, infer TKey> ? T[TKey] : never;
export type VocabularyValue<T> = T extends Vocabulary<string, infer TKey> ? T[TKey] : never;
/**
* A {@link NamedNode} entry of a {@link Vocabulary}.
*/
export type VocabularyTerm<T> = T extends Vocabulary<any, infer TKey> ? T['terms'][TKey] : never;
export type VocabularyTerm<T> = T extends Vocabulary<string, infer TKey> ? T['terms'][TKey] : never;
/**
* Creates a {@link ValueVocabulary} with the given `baseUri` as namespace and all `localNames` as entries.

View File

@ -44,7 +44,7 @@ export class HttpError<T extends number = number> extends Error implements HttpE
this.generateMetadata();
}
public static isInstance(error: any): error is HttpError {
public static isInstance(error: unknown): error is HttpError {
return isError(error) &&
typeof (error as HttpError).statusCode === 'number' &&
Boolean((error as HttpError).metadata);
@ -77,7 +77,7 @@ export interface HttpErrorClass<TCode extends number = number> {
/**
* Checks if the given error is an instance of this class.
*/
readonly isInstance: (error: any) => error is HttpError<TCode>;
readonly isInstance: (error: unknown) => error is HttpError<TCode>;
}
/**
@ -99,7 +99,7 @@ export function generateHttpErrorClass<TCode extends number>(statusCode: TCode,
super(statusCode, name, message, options);
}
public static isInstance(error: any): error is SpecificHttpError {
public static isInstance(error: unknown): error is SpecificHttpError {
return HttpError.isInstance(error) && error.statusCode === statusCode;
}
};

View File

@ -16,7 +16,7 @@ export class RedirectHttpError<TCode extends number = number> extends HttpError<
this.metadata.add(SOLID_HTTP.terms.location, DataFactory.namedNode(location));
}
public static isInstance(error: any): error is RedirectHttpError {
public static isInstance(error: unknown): error is RedirectHttpError {
return HttpError.isInstance(error) && typeof (error as RedirectHttpError).location === 'string';
}
}
@ -46,7 +46,7 @@ export function generateRedirectHttpErrorClass<TCode extends number>(
super(code, name, location, message, options);
}
public static isInstance(error: any): error is SpecificRedirectHttpError {
public static isInstance(error: unknown): error is SpecificRedirectHttpError {
return RedirectHttpError.isInstance(error) && error.statusCode === code;
}
};

View File

@ -26,7 +26,7 @@ export interface SystemError extends Error {
/**
* If present, extra details about the error condition.
*/
info?: any;
info?: unknown;
/**
* If present, the file path when reporting a file system error.
*/

View File

@ -4,7 +4,7 @@ import { UnionHandler } from './UnionHandler';
/**
* A utility handler that concatenates the results of all its handlers into a single result.
*/
export class ArrayUnionHandler<T extends AsyncHandler<any, any[]>> extends UnionHandler<T> {
export class ArrayUnionHandler<T extends AsyncHandler<unknown, unknown[]>> extends UnionHandler<T> {
public constructor(handlers: T[], requireAll?: boolean, ignoreErrors?: boolean) {
super(handlers, requireAll, ignoreErrors);
}

View File

@ -1,6 +1,6 @@
type Awaited<T> = T extends PromiseLike<infer U> ? U : T;
export type AsyncHandlerInput<T extends AsyncHandler<any, any>> = Parameters<T['handle']>[0];
export type AsyncHandlerOutput<T extends AsyncHandler<any, any>> = Awaited<ReturnType<T['handle']>>;
export type AsyncHandlerInput<T extends AsyncHandler<unknown, unknown>> = Parameters<T['handle']>[0];
export type AsyncHandlerOutput<T extends AsyncHandler<unknown, unknown>> = Awaited<ReturnType<T['handle']>>;
/**
* Simple interface for classes that can potentially handle a specific kind of data asynchronously.

View File

@ -12,7 +12,7 @@ type NestedMap<TOut> = TOut | WeakMap<object, NestedMap<TOut>>;
* This also means that the cache key needs to be an object.
* Errors will be thrown in case a primitive is used.
*/
export class CachedHandler<TIn extends Record<string, any>, TOut = void> extends AsyncHandler<TIn, TOut> {
export class CachedHandler<TIn extends Record<string, unknown>, TOut = void> extends AsyncHandler<TIn, TOut> {
private readonly source: AsyncHandler<TIn, TOut>;
private readonly fields?: [keyof TIn, ...(keyof TIn)[]];

View File

@ -7,7 +7,7 @@ import { AsyncHandler } from './AsyncHandler';
* The generic type extends `any` due to Components.js requirements.
*/
// eslint-disable-next-line ts/no-unnecessary-type-constraint
export class StaticHandler<T extends any = void> extends AsyncHandler<any, T> {
export class StaticHandler<T extends unknown = void> extends AsyncHandler<unknown, T> {
private readonly value?: T;
public constructor(value?: T) {

View File

@ -4,7 +4,7 @@ import { AsyncHandler } from './AsyncHandler';
/**
* Utility handler that can handle all input and always throws the given error.
*/
export class StaticThrowHandler extends AsyncHandler<any, never> {
export class StaticThrowHandler extends AsyncHandler<unknown, never> {
private readonly error: HttpError;
public constructor(error: HttpError) {

View File

@ -8,7 +8,7 @@ import { filterHandlers, findHandler } from './HandlerUtil';
* Will run the handlers and then call the abstract `combine` function with the results,
* which then generates the handler's output.
*/
export abstract class UnionHandler<T extends AsyncHandler<any, any>> extends
export abstract class UnionHandler<T extends AsyncHandler<unknown, unknown>> extends
AsyncHandler<AsyncHandlerInput<T>, AsyncHandlerOutput<T>> {
protected readonly handlers: T[];
private readonly requireAll: boolean;

View File

@ -4,7 +4,7 @@ import { AsyncHandler } from './AsyncHandler';
/**
* Handler that does not support any input and will always throw an error.
*/
export class UnsupportedAsyncHandler extends AsyncHandler<any, never> {
export class UnsupportedAsyncHandler extends AsyncHandler<unknown, never> {
private readonly errorMessage?: string;
public constructor(errorMessage?: string) {

View File

@ -6,7 +6,7 @@ type Entry<TKey, TVal> = { key: TKey; value: TVal };
* A {@link Map} implementation that maps the Key object to a string using the provided hash function.
* This ensures that equal objects that are not the same instance are mapped to the same value.
*/
export class HashMap<TKey = any, TVal = any> implements Map<TKey, TVal> {
export class HashMap<TKey = unknown, TVal = unknown> implements Map<TKey, TVal> {
private readonly hashMap: Map<string, Entry<TKey, TVal>>;
private readonly hashFn: (key: TKey) => string;
@ -64,7 +64,7 @@ export class HashMap<TKey = any, TVal = any> implements Map<TKey, TVal> {
}
}
public forEach(callbackfn: (value: TVal, key: TKey, map: Map<TKey, TVal>) => void, thisArg?: any): void {
public forEach(callbackfn: (value: TVal, key: TKey, map: Map<TKey, TVal>) => void, thisArg?: unknown): void {
for (const [ key, value ] of this) {
callbackfn.bind(thisArg)(value, key, this);
}

View File

@ -2,22 +2,22 @@ import { resolvePromiseOrValue } from '../PromiseUtil';
import type { PromiseOrValue } from '../PromiseUtil';
import type { SetMultiMap } from './SetMultiMap';
export type ArrayElement<TArray extends readonly any[]> = TArray[number];
export type ArrayElement<TArray extends readonly unknown[]> = TArray[number];
export type EmptyObject = Record<string, never>;
export type MapKey<T> = T extends Map<infer TKey, any> ? TKey : never;
export type MapValue<T> = T extends Map<any, infer TValue> ? TValue : never;
export type MapEntry<T> = T extends Map<any, any> ? [MapKey<T>, MapValue<T>] : never;
export type MapKey<T> = T extends Map<infer TKey, unknown> ? TKey : never;
export type MapValue<T> = T extends Map<unknown, infer TValue> ? TValue : never;
export type MapEntry<T> = T extends Map<unknown, unknown> ? [MapKey<T>, MapValue<T>] : never;
/**
* A simplified version of {@link MapConstructor} that only allows creating an empty {@link Map}.
*/
export type EmptyMapConstructor = new() => Map<any, any>;
export type EmptyMapConstructor = new() => Map<unknown, unknown>;
/**
* Options describing the necessary changes when calling {@link modify}.
*/
export type ModifyOptions<T extends SetMultiMap<any, any>> = {
export type ModifyOptions<T extends SetMultiMap<unknown, unknown>> = {
/**
* Entries that need to be added to the Map.
*/
@ -35,6 +35,7 @@ export type ModifyOptions<T extends SetMultiMap<any, any>> = {
* @param map - Map to start from.
* @param options - {@link ModifyOptions} describing the necessary changes.
*/
// eslint-disable-next-line ts/no-explicit-any
export function modify<T extends SetMultiMap<any, any>>(map: T, options: ModifyOptions<T>): T {
for (const key of options.remove ?? []) {
map.delete(key);

View File

@ -55,5 +55,5 @@ export interface SetMultiMap<TKey, TVal> extends Map<TKey, TVal | ReadonlySet<TV
/**
* Loops over all key/value bindings.
*/
forEach: (callbackfn: (value: TVal, key: TKey, map: SetMultiMap<TKey, TVal>) => void, thisArg?: any) => void;
forEach: (callbackfn: (value: TVal, key: TKey, map: SetMultiMap<TKey, TVal>) => void, thisArg?: unknown) => void;
}

View File

@ -138,7 +138,7 @@ export class WrappedSetMultiMap<TKey, TVal> implements SetMultiMap<TKey, TVal> {
return this.map.values();
}
public forEach(callbackfn: (value: TVal, key: TKey, map: SetMultiMap<TKey, TVal>) => void, thisArg?: any): void {
public forEach(callbackfn: (value: TVal, key: TKey, map: SetMultiMap<TKey, TVal>) => void, thisArg?: unknown): void {
for (const [ key, value ] of this) {
callbackfn.bind(thisArg)(value, key, this);
}

View File

@ -10,7 +10,7 @@ import Dict = NodeJS.Dict;
* All subsequent engines will be called with no template parameter.
* Contents will still be passed along and another entry will be added for the body of the previous output.
*/
export class ChainedTemplateEngine<T extends Dict<any> = Dict<any>> extends TemplateEngine<T> {
export class ChainedTemplateEngine<T extends Dict<unknown> = Dict<unknown>> extends TemplateEngine<T> {
private readonly firstEngine: TemplateEngine<T>;
private readonly chainedEngines: TemplateEngine[];
private readonly renderedName: string;

View File

@ -7,7 +7,7 @@ import Dict = NodeJS.Dict;
/**
* Fills in EJS templates.
*/
export class EjsTemplateEngine<T extends Dict<any> = Dict<any>> extends ExtensionBasedTemplateEngine<T> {
export class EjsTemplateEngine<T extends Dict<unknown> = Dict<unknown>> extends ExtensionBasedTemplateEngine<T> {
private readonly baseUrl: string;
/**

View File

@ -8,7 +8,7 @@ import Dict = NodeJS.Dict;
/**
* Parent class for template engines that accept handling based on whether the template extension is supported.
*/
export abstract class ExtensionBasedTemplateEngine<T extends Dict<any> = Dict<any>> extends TemplateEngine<T> {
export abstract class ExtensionBasedTemplateEngine<T extends Dict<unknown> = Dict<unknown>> extends TemplateEngine<T> {
protected readonly supportedExtensions: string[];
/**

View File

@ -7,7 +7,7 @@ import Dict = NodeJS.Dict;
/**
* Fills in Handlebars templates.
*/
export class HandlebarsTemplateEngine<T extends Dict<any> = Dict<any>> extends ExtensionBasedTemplateEngine<T> {
export class HandlebarsTemplateEngine<T extends Dict<unknown> = Dict<unknown>> extends ExtensionBasedTemplateEngine<T> {
private readonly baseUrl: string;
/**

View File

@ -6,7 +6,7 @@ import Dict = NodeJS.Dict;
/**
* Template engine that renders output based on a static template file.
*/
export class StaticTemplateEngine<T extends Dict<any> = Dict<any>> extends TemplateEngine<T> {
export class StaticTemplateEngine<T extends Dict<unknown> = Dict<unknown>> extends TemplateEngine<T> {
private readonly template: Template;
private readonly templateEngine: AsyncHandler<TemplateEngineInput<T>, string>;

View File

@ -31,5 +31,5 @@ export interface TemplateEngineInput<T> {
* Generic interface for classes that implement a template engine.
* A template engine renders content into a template.
*/
export abstract class TemplateEngine<T extends Dict<any> = Dict<any>>
export abstract class TemplateEngine<T extends Dict<unknown> = Dict<unknown>>
extends AsyncHandler<TemplateEngineInput<T>, string> {}