mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
chore: Improve linting within @k8slens/core
- Turning on @typescript-eslint/recommended-requiring-type-checking - Turning off @typescript-eslint/no-unnecessary-type-assertion (due too many false positives) - Making @typescript-eslint/no-explicit-any an error (except in tests) Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
1 parent
6184c2f03b
commit
fa44b795d4
734 files changed
+32216
-4566
No files matched your search
@@ -3,9 +3,9 @@ export interface EventEmitterOptions {
|
||||
prepend?: boolean; // put listener to the beginning
|
||||
}
|
||||
|
||||
export type EventEmitterCallback<D extends any[]> = (...data: D) => void | boolean;
|
||||
export type EventEmitterCallback<D extends unknown[]> = (...data: D) => void | boolean;
|
||||
|
||||
export class EventEmitter<D extends any[]> {
|
||||
export class EventEmitter<D extends unknown[]> {
|
||||
protected listeners: [EventEmitterCallback<D>, EventEmitterOptions][] = [];
|
||||
|
||||
addListener(callback: EventEmitterCallback<D>, options: EventEmitterOptions = {}) {
|
||||
|
||||
@@ -14,9 +14,9 @@ import type { Logger } from "@k8slens/logger";
|
||||
import type Fetch from "@k8slens/node-fetch";
|
||||
import type { RequestInit, Response } from "@k8slens/node-fetch";
|
||||
import type { Defaulted } from "@k8slens/utilities";
|
||||
import { isObject, isString, json } from "@k8slens/utilities";
|
||||
import { isArray, isObject, isString, json } from "@k8slens/utilities";
|
||||
|
||||
export interface JsonApiData {}
|
||||
export type JsonApiData = Record<string, never>;
|
||||
|
||||
export interface JsonApiError {
|
||||
code?: number;
|
||||
@@ -56,11 +56,11 @@ export interface JsonApiLog {
|
||||
method: string;
|
||||
reqUrl: string;
|
||||
reqInit: RequestInit;
|
||||
data?: any;
|
||||
error?: any;
|
||||
data?: unknown;
|
||||
error?: unknown;
|
||||
}
|
||||
|
||||
export type GetRequestOptions = () => Promise<RequestInit>;
|
||||
export type GetRequestOptions = () => RequestInit | Promise<RequestInit>;
|
||||
|
||||
export interface JsonApiConfig {
|
||||
apiBase: string;
|
||||
@@ -236,7 +236,7 @@ export class JsonApi<Data = JsonApiData, Params extends JsonApiParams<Data> = Js
|
||||
|
||||
const text = await res.text();
|
||||
const parseResponse = json.parse(text || "{}");
|
||||
const data = parseResponse.callWasSuccessful ? (parseResponse.response as Data) : (text as Data);
|
||||
const data = parseResponse.isOk ? (parseResponse.value as Data) : (text as Data);
|
||||
|
||||
if (status >= 200 && status < 300) {
|
||||
this.onData.emit(data, res);
|
||||
@@ -271,7 +271,7 @@ export class JsonApi<Data = JsonApiData, Params extends JsonApiParams<Data> = Js
|
||||
|
||||
const { errors, message } = error as { errors?: { title: string }[]; message?: string };
|
||||
|
||||
if (Array.isArray(errors)) {
|
||||
if (isArray(errors)) {
|
||||
return errors.map((error) => error.title);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,24 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { DiContainerForInjection } from "@ogre-tools/injectable";
|
||||
import { getInjectable, getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { KubeApi } from "@k8slens/kube-api";
|
||||
|
||||
export const kubeApiInjectionToken = getInjectionToken<KubeApi<any, any>>({
|
||||
export const kubeApiInjectionToken = getInjectionToken<KubeApi>({
|
||||
id: "kube-api-injection-token",
|
||||
});
|
||||
|
||||
export interface KubeApiInjectableParts<Api> {
|
||||
id: string;
|
||||
instantiate: (
|
||||
di: DiContainerForInjection,
|
||||
) => Api extends KubeApi<infer Kube, infer Data> ? KubeApi<Kube, Data> & Api : never;
|
||||
}
|
||||
|
||||
export const getKubeApiInjectable = <Api>(parts: KubeApiInjectableParts<Api>) =>
|
||||
getInjectable({
|
||||
id: parts.id,
|
||||
instantiate: (di) => parts.instantiate(di),
|
||||
injectionToken: kubeApiInjectionToken,
|
||||
});
|
||||
@@ -184,7 +184,7 @@ export type KubeApiWatchCallback<T extends KubeJsonApiData = KubeJsonApiData> =
|
||||
error: KubeStatus | Response | null | Record<string, unknown>,
|
||||
) => void;
|
||||
|
||||
export interface KubeApiWatchOptions<Object extends KubeObject, Data extends KubeJsonApiDataFor<Object>> {
|
||||
export interface KubeApiWatchOptions<Kube extends KubeObject, Data extends KubeJsonApiDataFor<Kube>> {
|
||||
/**
|
||||
* If the resource is namespaced then the default is `"default"`
|
||||
*/
|
||||
@@ -248,7 +248,7 @@ export type SpecificResourceDescriptor<Scope extends KubeObjectScope> = {
|
||||
*/
|
||||
name: string;
|
||||
} & (Scope extends KubeObjectScope.Cluster
|
||||
? {}
|
||||
? { namespace?: undefined }
|
||||
: Scope extends KubeObjectScope.Namespace
|
||||
? {
|
||||
/**
|
||||
@@ -278,8 +278,8 @@ export interface KubeApiDependencies {
|
||||
}
|
||||
|
||||
export class KubeApi<
|
||||
Object extends KubeObject = KubeObject,
|
||||
Data extends KubeJsonApiDataFor<Object> = KubeJsonApiDataFor<Object>,
|
||||
Kube extends KubeObject = KubeObject,
|
||||
Data extends KubeJsonApiDataFor<Kube> = KubeJsonApiDataFor<Kube>,
|
||||
> {
|
||||
readonly kind: string;
|
||||
|
||||
@@ -297,7 +297,7 @@ export class KubeApi<
|
||||
|
||||
readonly isNamespaced: boolean;
|
||||
|
||||
public readonly objectConstructor: KubeObjectConstructor<Object, Data>;
|
||||
public readonly objectConstructor: KubeObjectConstructor<Kube, Data>;
|
||||
|
||||
protected readonly request: KubeJsonApi;
|
||||
|
||||
@@ -315,7 +315,7 @@ export class KubeApi<
|
||||
|
||||
protected readonly allowedUsableVersions: Partial<Record<string, string[]>> | undefined;
|
||||
|
||||
constructor(protected readonly dependencies: KubeApiDependencies, opts: KubeApiOptions<Object, Data>) {
|
||||
constructor(protected readonly dependencies: KubeApiDependencies, opts: KubeApiOptions<Kube, Data>) {
|
||||
const {
|
||||
objectConstructor,
|
||||
request = this.dependencies.maybeKubeApi,
|
||||
@@ -382,13 +382,15 @@ export class KubeApi<
|
||||
|
||||
try {
|
||||
const { apiPrefix, apiGroup, resource } = parsedApi;
|
||||
const list = (await this.request.get(`${apiPrefix}/${apiGroup}`)) as KubeApiResourceVersionList;
|
||||
const resourceVersions = getOrderedVersions(list, this.allowedUsableVersions?.[apiGroup]);
|
||||
const list = await this.request.get(`${apiPrefix}/${apiGroup}`);
|
||||
const resourceVersions = getOrderedVersions(
|
||||
list as unknown as KubeApiResourceVersionList,
|
||||
this.allowedUsableVersions?.[apiGroup],
|
||||
);
|
||||
|
||||
for (const resourceVersion of resourceVersions) {
|
||||
const { resources } = (await this.request.get(
|
||||
`${apiPrefix}/${resourceVersion.groupVersion}`,
|
||||
)) as KubeApiResourceList;
|
||||
const res = await this.request.get(`${apiPrefix}/${resourceVersion.groupVersion}`);
|
||||
const resources = res.resources as { name: string }[];
|
||||
|
||||
if (resources.some(({ name }) => name === resource)) {
|
||||
return {
|
||||
@@ -496,7 +498,7 @@ export class KubeApi<
|
||||
return query;
|
||||
}
|
||||
|
||||
protected parseResponse(data: unknown, namespace?: string): Object | Object[] | null {
|
||||
protected parseResponse(data: unknown, namespace?: string): Kube | Kube[] | null {
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
@@ -559,10 +561,7 @@ export class KubeApi<
|
||||
});
|
||||
}
|
||||
|
||||
async list(
|
||||
{ namespace = "", reqInit }: KubeApiListOptions = {},
|
||||
query?: KubeApiQueryParams,
|
||||
): Promise<Object[] | null> {
|
||||
async list({ namespace = "", reqInit }: KubeApiListOptions = {}, query?: KubeApiQueryParams): Promise<Kube[] | null> {
|
||||
await this.checkPreferredVersion();
|
||||
|
||||
const url = this.formatUrlForListing(namespace);
|
||||
@@ -580,7 +579,7 @@ export class KubeApi<
|
||||
throw new Error(`GET multiple request to ${url} returned not an array: ${JSON.stringify(parsed)}`);
|
||||
}
|
||||
|
||||
async get(desc: ResourceDescriptor, query?: KubeApiQueryParams): Promise<Object | null> {
|
||||
async get(desc: ResourceDescriptor, query?: KubeApiQueryParams): Promise<Kube | null> {
|
||||
await this.checkPreferredVersion();
|
||||
|
||||
const url = this.formatUrlForNotListing(desc);
|
||||
@@ -596,8 +595,8 @@ export class KubeApi<
|
||||
|
||||
async create(
|
||||
{ name, namespace }: Partial<ResourceDescriptor>,
|
||||
partialData?: PartialDeep<Object>,
|
||||
): Promise<Object | null> {
|
||||
partialData?: PartialDeep<Kube>,
|
||||
): Promise<Kube | null> {
|
||||
await this.checkPreferredVersion();
|
||||
|
||||
const apiUrl = this.formatUrlForNotListing({ namespace });
|
||||
@@ -619,7 +618,7 @@ export class KubeApi<
|
||||
return parsed;
|
||||
}
|
||||
|
||||
async update({ name, namespace }: ResourceDescriptor, data: PartialDeep<Object>): Promise<Object | null> {
|
||||
async update({ name, namespace }: ResourceDescriptor, data: PartialDeep<Kube>): Promise<Kube | null> {
|
||||
await this.checkPreferredVersion();
|
||||
const apiUrl = this.formatUrlForNotListing({ namespace, name });
|
||||
|
||||
@@ -674,23 +673,19 @@ export class KubeApi<
|
||||
return res as Scale;
|
||||
}
|
||||
|
||||
async patch(desc: ResourceDescriptor, data: PartialDeep<Object>): Promise<Object | null>;
|
||||
async patch(desc: ResourceDescriptor, data: PartialDeep<Kube>): Promise<Kube | null>;
|
||||
async patch(desc: ResourceDescriptor, data: PartialDeep<Kube>, strategy: "strategic" | "merge"): Promise<Kube | null>;
|
||||
async patch(desc: ResourceDescriptor, data: Patch, strategy: "json"): Promise<Kube | null>;
|
||||
async patch(
|
||||
desc: ResourceDescriptor,
|
||||
data: PartialDeep<Object>,
|
||||
strategy: "strategic" | "merge",
|
||||
): Promise<Object | null>;
|
||||
async patch(desc: ResourceDescriptor, data: Patch, strategy: "json"): Promise<Object | null>;
|
||||
async patch(
|
||||
desc: ResourceDescriptor,
|
||||
data: PartialDeep<Object> | Patch,
|
||||
data: PartialDeep<Kube> | Patch,
|
||||
strategy: KubeApiPatchType,
|
||||
): Promise<Object | null>;
|
||||
): Promise<Kube | null>;
|
||||
async patch(
|
||||
desc: ResourceDescriptor,
|
||||
data: PartialDeep<Object> | Patch,
|
||||
data: PartialDeep<Kube> | Patch,
|
||||
strategy: KubeApiPatchType = "strategic",
|
||||
): Promise<Object | null> {
|
||||
): Promise<Kube | null> {
|
||||
await this.checkPreferredVersion();
|
||||
const apiUrl = this.formatUrlForNotListing(desc);
|
||||
|
||||
@@ -740,7 +735,7 @@ export class KubeApi<
|
||||
});
|
||||
}
|
||||
|
||||
watch(opts?: KubeApiWatchOptions<Object, Data>): Disposer {
|
||||
watch(opts?: KubeApiWatchOptions<Kube, Data>): Disposer {
|
||||
let errorReceived = false;
|
||||
let timedRetry: NodeJS.Timeout;
|
||||
const {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from "./src/abort-controller";
|
||||
export * from "./src/add-event-listener";
|
||||
export * from "./src/array";
|
||||
export * from "./src/backoff-caller";
|
||||
export * from "./src/base64";
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
export function addEventListener<K extends keyof HTMLElementEventMap>(target: HTMLElement, type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions) {
|
||||
target.addEventListener(type, listener, options);
|
||||
|
||||
return () => target.removeEventListener(type, listener, options);
|
||||
}
|
||||
|
||||
export function addWindowEventListener<K extends keyof WindowEventMap>(type: K, listener: (this: Window, ev: WindowEventMap[K]) => any, options?: boolean | AddEventListenerOptions) {
|
||||
window.addEventListener(type, listener, options);
|
||||
|
||||
return () => window.removeEventListener(type, listener, options);
|
||||
}
|
||||
@@ -12,6 +12,15 @@ function filled<T>(length: number, value: T): T[] {
|
||||
return Array(length).fill(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* A inference typed version of `Array(length).fill(value)`
|
||||
* @param length The number of entries
|
||||
* @param value The value of each of the indices
|
||||
*/
|
||||
function filledWith<T>(length: number, fn: (index: number) => T): T[] {
|
||||
return Array(length).fill(undefined).map((value, index) => fn(index));
|
||||
}
|
||||
|
||||
/**
|
||||
* This function splits an array into two sub arrays on the first instance of
|
||||
* element (from the left). If the array does not contain the element. The
|
||||
@@ -52,4 +61,5 @@ export const array = {
|
||||
bifurcate,
|
||||
filled,
|
||||
split,
|
||||
filledWith,
|
||||
};
|
||||
@@ -56,7 +56,7 @@ export const backoffCaller = async <T, E>(fn: () => AsyncResult<T, E>, options?:
|
||||
do {
|
||||
result = await fn();
|
||||
|
||||
if (result.callWasSuccessful) {
|
||||
if (result.isOk) {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,20 +3,16 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { Result } from "./result";
|
||||
import type { JsonValue } from "type-fest";
|
||||
import { result, Result } from "./result";
|
||||
|
||||
export const json = {
|
||||
parse: (input: string): Result<unknown, Error> => {
|
||||
try {
|
||||
return {
|
||||
callWasSuccessful: true,
|
||||
response: JSON.parse(input) as unknown,
|
||||
}
|
||||
return result.ok(JSON.parse(input) as unknown);
|
||||
} catch (error) {
|
||||
return {
|
||||
callWasSuccessful: false,
|
||||
error: error as Error,
|
||||
}
|
||||
return result.error(error as Error);
|
||||
}
|
||||
},
|
||||
clone: <T>(input: JsonValue & T): T => JSON.parse(JSON.stringify(input)),
|
||||
};
|
||||
@@ -17,12 +17,12 @@ import type React from "react";
|
||||
// <Icon onClick={prevDefault(() => console.log('stay on the page and open dialog'))}/>
|
||||
// </a>
|
||||
|
||||
export function prevDefault<E extends React.SyntheticEvent | Event, R>(callback: (evt: E) => R): (event: E) => R {
|
||||
export function prevDefault<E extends React.SyntheticEvent | Event>(callback: (evt: E) => unknown): (event: E) => void {
|
||||
return function (evt: E) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
|
||||
return callback(evt);
|
||||
return void callback(evt);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -6,16 +6,34 @@
|
||||
/**
|
||||
* A helper type for async functions that return a `Result`
|
||||
*/
|
||||
export type AsyncResult<Response, Error = string> = Promise<Result<Response, Error>>;
|
||||
export type AsyncResult<Value, Err> = Promise<Result<Value, Err>>;
|
||||
|
||||
/**
|
||||
* Result describes the "error is just more data" pattern instead of using exceptions for
|
||||
* normal execution
|
||||
*/
|
||||
export type Result<Response, Error = string> =
|
||||
| (
|
||||
Response extends void
|
||||
? { callWasSuccessful: true; response?: undefined }
|
||||
: { callWasSuccessful: true; response: Response }
|
||||
)
|
||||
| { callWasSuccessful: false; error: Error };
|
||||
export type Result<Value, Err> =
|
||||
| OkResult<Value>
|
||||
| ErrorResult<Err>;
|
||||
|
||||
export type ErrorResult<Err> = { readonly isOk: false; readonly error: Err };
|
||||
export type OkResult<Value> = (
|
||||
Value extends void
|
||||
? { readonly isOk: true; readonly value?: undefined }
|
||||
: { readonly isOk: true; readonly value: Value }
|
||||
);
|
||||
|
||||
export const result = {
|
||||
ok: <Value>(value: Value) => ({
|
||||
isOk: true,
|
||||
value: value,
|
||||
}) as OkResult<Value>,
|
||||
error: <Err>(error: Err) => ({
|
||||
isOk: false,
|
||||
error,
|
||||
}) as ErrorResult<Err>,
|
||||
wrapError: <Err>(error: string, cause: ErrorResult<Err>) => ({
|
||||
isOk: false,
|
||||
error: new Error(error, { cause: cause.error }),
|
||||
}) as ErrorResult<Error>,
|
||||
}
|
||||
@@ -123,10 +123,17 @@ export function isDefined<T>(val: T | undefined | null): val is T {
|
||||
return val != null;
|
||||
}
|
||||
|
||||
export function isFunction(val: unknown): val is (...args: unknown[]) => unknown {
|
||||
export type ExtractOr<T, U, Fallback = never> = Extract<T, U> extends never ? Fallback : Extract<T, U>;
|
||||
|
||||
// @ts-expect-error
|
||||
export declare function isFunction<T>(val: T): val is ExtractOr<T, Function, (...args: unknown[]) => unknown> {
|
||||
return typeof val === "function";
|
||||
}
|
||||
|
||||
export function isArray(val: unknown): val is unknown[] {
|
||||
return Array.isArray(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value in the second position is non-nullable
|
||||
*/
|
||||
@@ -196,14 +203,14 @@ export type ComputeOutputFormat<Format> = Format extends "string"
|
||||
? Buffer
|
||||
: string | Buffer;
|
||||
|
||||
export interface ChildProcessExecpetion<Format> extends ExecFileException {
|
||||
export interface ChildProcessException<Format> extends ExecFileException {
|
||||
stderr: ComputeOutputFormat<Format>;
|
||||
stdout: ComputeOutputFormat<Format>;
|
||||
}
|
||||
|
||||
const isStringOrBuffer = (val: unknown): val is string | Buffer => isString(val) || isBuffer(val);
|
||||
|
||||
export function isChildProcessError(error: unknown, format?: OutputFormat): error is ChildProcessExecpetion<typeof format> {
|
||||
export function isChildProcessError(error: unknown, format?: OutputFormat): error is ChildProcessException<typeof format> {
|
||||
if (!isExecFileException(error)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user