mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Turn on strict mode in tsconfig.json, some helpful lints, and required cleanup where strictness necessitates it (#5195)
* Turn on strict mode in tsconfig.json - Add route, clusterRoute, and payloadValidatedClusterRoute helper functions to improve types with backend routes - Turn on the following new lints: - react/jsx-first-prop-new-line - react/jsx-wrap-multilines - react/jsx-one-expression-per-line - react/jsx-max-props-per-line - react/jsx-indent - react/jsx-indent-props Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix build Signed-off-by: Sebastian Malton <sebastian@malton.name> * Replace KubeObject scope strings with enum Signed-off-by: Sebastian Malton <sebastian@malton.name> * Revert package.json version changes Signed-off-by: Sebastian Malton <sebastian@malton.name> * revert move hostedCluster(Id) Signed-off-by: Sebastian Malton <sebastian@malton.name> * change some type param names to be not single letters Signed-off-by: Sebastian Malton <sebastian@malton.name> * remove copy-extension-themes Signed-off-by: Sebastian Malton <sebastian@malton.name> * add new make clean action Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix build to not use webpack for generating types Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix kube-object-menu.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix select.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix catalog.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * revert move fileNameMigration to index Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix ref logic error Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix log-resource-selector.test.tsx tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix dock-store.test.ts test by overriding createStorage to not touch file system Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix cluster.test.ts tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix kube=api.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fixed hotbar-store.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix kubeconfig-manager.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix cluster-role-bindings/__tests__/dialog.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix role-bindings/__tests__/dialog.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix pods.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix delete-cluster-dialog.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix daemonset.store.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix replicaset.store.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix statefulsets/dialog/dialog.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix replicasets/scale-dialog/dialog.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix deployments.store.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix deployments/scale/dialog.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix cronjob.store.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix stateful-set.api.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix deployment.api.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix api-manager.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix statefulset.store.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix job.store.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix pods.store.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix scroll-spy.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix hotbar-remove-command.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix catalog-entity-registry.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix welcome.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix verify-that-all-routes-have-route-component.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix pod-tolerations.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * better fix for previous 3 fixes, plus also select.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix kube-object-menu.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix app-paths.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix dock-tabs.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix isReactNode typing Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix sub-title.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix drawer.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix list-layout.tsx and header.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix error-boundary.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix upgrade-chart/store.ts and dock-tab.store.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix install-chart/store.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix edit-resource/store.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix create-resource/store.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix namespace-select.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix namespace-select-filter.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix crd-list.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix wrong types for extensions Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix circular dependency Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix circular dependency on catalogCategoryRegistry Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix api-kube Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix type errors, most <Select /> errors Signed-off-by: Sebastian Malton <sebastian@malton.name> * fixing more type errors Signed-off-by: Sebastian Malton <sebastian@malton.name> * some more fixing type errors Signed-off-by: Sebastian Malton <sebastian@malton.name> * convert all KubeApis to injectable with legacy global backups Signed-off-by: Sebastian Malton <sebastian@malton.name> * factor out into a common file all the exports Signed-off-by: Sebastian Malton <sebastian@malton.name> * convert all KubeObjectStores to injectable with legacy global backups Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix lint Signed-off-by: Sebastian Malton <sebastian@malton.name> * remove unused legacy KubeApi globals Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix bad previous commit Signed-off-by: Sebastian Malton <sebastian@malton.name> * more crash fixing Signed-off-by: Sebastian Malton <sebastian@malton.name> * try and fix behavioural tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix sidebar-and-tab-navigation-for-core.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix sidebar-and-tab-navigation-for-extensions.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix navigation-using-application-menu.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix catalog.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * Make ThemeStore non-singleton and fix navigation-to-terminal-preferences.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * extensions.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix catalog-entity-registry.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix navigation-using-application-menu.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix log-resource-selector.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix dock-tabs.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix delete-cluster-dialog.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix navigation-to-kubernetes-preferences.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix navigation-to-editor-preferences.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix navigation-to-proxy-preferences.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix navigation-using-application-menu.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix navigation-to-application-preferences.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix dock-store.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix select.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix role-bindings/__tests__/dialog.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix hotbar-remove-command.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix cluster-role-bindings/__tests__/dialog.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix navigation-to-extension-specific-preferences.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix navigation-to-telemetry-preferences.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix closing-preferences.test.tsx Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix navigation-to-editor-preferences.test.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix navigation-to-proxy-preferences.test.ts - Fix other type errors too Signed-off-by: Sebastian Malton <sebastian@malton.name> * final tweaks Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add more tsconfig files, fix bug in <Catalog> - Make all of history, navigation injectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix type errors Signed-off-by: Sebastian Malton <sebastian@malton.name> * Convert all of kube-details-params/ and navigate/ to injectable - This fixes a runtime error that was encountered during testing Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix runtime errors on renderer - remove all static uses of `createPageParam` (and then removed the legacy global) - Made LensRendererExtension and LensMainExtension just used dependencies and not the getLegacyDi - Fixed circular dep in extension-loader Signed-off-by: Sebastian Malton <sebastian@malton.name> * Move registerStore calls to after injectMany Signed-off-by: Sebastian Malton <sebastian@malton.name> * replace all the rest of the legacy uses of apiManager Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix stack overflow and cycles in DI Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix NamespaceSelectFilter not opening Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix WizardStep and AddNamespaceDialog Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix KubeApi's not being registered Signed-off-by: Sebastian Malton <sebastian@malton.name> * cleanup WindowManager Signed-off-by: Sebastian Malton <sebastian@malton.name> * Proper fix for Wizard, fix NamespaceStore.subscribe Signed-off-by: Sebastian Malton <sebastian@malton.name> * Rewrite withTooltip to be more type correct - Fixes mobx related "too many recursive actions" error - Change all the uses of withTooltips to be functional components Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add e2e test to cover kube api registration Signed-off-by: Sebastian Malton <sebastian@malton.name> * cleanup internal-commands Signed-off-by: Sebastian Malton <sebastian@malton.name> * remove cast in <Animate> Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix command-palette e2e test Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix type error after rebase Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix test name Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix lint Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix code to help CodeQL scanner Signed-off-by: Sebastian Malton <sebastian@malton.name> * update intree extension lock files Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix build-extensions picking wrong @types/react Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix tests from rebase Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix type error Signed-off-by: Sebastian Malton <sebastian@malton.name> * Make KubeconfigSyncManager more injectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix crash in test mode for Dialog Signed-off-by: Sebastian Malton <sebastian@malton.name> * make Select snapshots deterministic Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix new type error Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix kube-object.store.test.ts typing Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix merge build issues Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix snapshots after merge Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix lint after merge Signed-off-by: Sebastian Malton <sebastian@malton.name> * reexport BaseKubeJsonApiObjectMetadata Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix typo in terminalSpawningPool Signed-off-by: Sebastian Malton <sebastian@malton.name> * remove duplicate license header Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix typo to waitUntilDefined Signed-off-by: Sebastian Malton <sebastian@malton.name> * remove iter use from getLegacyGlobalDiForExtensionApi Signed-off-by: Sebastian Malton <sebastian@malton.name> * remove complex createStorage override Signed-off-by: Sebastian Malton <sebastian@malton.name> * override logger with mocks only when needed for tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * remove specialized overrideStore flags for getDiForUnitTesting Signed-off-by: Sebastian Malton <sebastian@malton.name> * remove unnecessary | undefined types from the exactOptionalFieldTypes experiment Signed-off-by: Sebastian Malton <sebastian@malton.name> * use more descriptive name for local test mocks Signed-off-by: Sebastian Malton <sebastian@malton.name> * remove unnecessary addition to 'make clean' target Signed-off-by: Sebastian Malton <sebastian@malton.name> * remove oddity of KubeObjectStore.getById(undefined) being allowed Signed-off-by: Sebastian Malton <sebastian@malton.name> * rename KubeObject.getDescriptor in favour of name without fundemental JS meaning Signed-off-by: Sebastian Malton <sebastian@malton.name> * Simplify legacyRegisterApi when working in behaviour unit tests - Don't emit within main environment as there should be no auto registering there Signed-off-by: Sebastian Malton <sebastian@malton.name> * change confusing variable name in ReactiveDuration Signed-off-by: Sebastian Malton <sebastian@malton.name> * make visitor pattern more explicit for Entity contextMenuOpen Signed-off-by: Sebastian Malton <sebastian@malton.name> * toggleDetails -> toggleKubeDetailsPane is more specific Signed-off-by: Sebastian Malton <sebastian@malton.name> * remove outdated comment Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix bug where LensExtension dependencies are not set Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix tests from the revert of react 18 Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix more tests from merge Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix typings with new is-compatible-extension tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * more type fixing Signed-off-by: Sebastian Malton <sebastian@malton.name> * Revert in-tree extension versions Signed-off-by: Sebastian Malton <sebastian@malton.name> * Improve name of guarding injectable for stores and apis - New name better implies that it is just a guard state and does not do anything Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add helper for <Select>.isMulti for storing in a Set<Value> Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix is-compatible-extension.test.ts types Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
1 parent
381d77c633
commit
dfcb7c3330
1062 files changed
+26512
-28689
No files matched your search
@@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { reduce } from "../iter";
|
||||
import { join, nth, reduce } from "../iter";
|
||||
|
||||
describe("iter", () => {
|
||||
describe("reduce", () => {
|
||||
@@ -15,4 +15,28 @@ describe("iter", () => {
|
||||
expect(reduce([], (acc: number[], current: number) => [acc[0] + current], [])).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("join", () => {
|
||||
it("should not prefix the output by the seperator", () => {
|
||||
expect(join(["a", "b", "c"].values(), " ")).toBe("a b c");
|
||||
});
|
||||
|
||||
it("should return empty string if iterator is empty", () => {
|
||||
expect(join([].values(), " ")).toBe("");
|
||||
});
|
||||
|
||||
it("should return just first entry if iterator is of size 1", () => {
|
||||
expect(join(["d"].values(), " ")).toBe("d");
|
||||
});
|
||||
});
|
||||
|
||||
describe("nth", () => {
|
||||
it("should return undefined past the end of the iterator", () => {
|
||||
expect(nth(["a"], 123)).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should by 0-indexing the index", () => {
|
||||
expect(nth(["a", "b"], 0)).toBe("a");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -6,11 +6,12 @@
|
||||
import type { Options } from "auto-bind";
|
||||
import autoBindClass from "auto-bind";
|
||||
import autoBindReactClass from "auto-bind/react";
|
||||
import React from "react";
|
||||
|
||||
// Automatically bind methods to their class instance
|
||||
export function autoBind<T extends object>(obj: T, opts?: Options): T {
|
||||
if ("componentWillUnmount" in obj) {
|
||||
return autoBindReactClass(obj as any, opts);
|
||||
if (obj instanceof React.Component) {
|
||||
return autoBindReactClass(obj, opts);
|
||||
}
|
||||
|
||||
return autoBindClass(obj, opts);
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
*/
|
||||
|
||||
import { compile } from "path-to-regexp";
|
||||
import type { RouteProps } from "react-router";
|
||||
import { isDefined } from "./type-narrowing";
|
||||
|
||||
export interface UrlRouteProps extends RouteProps {
|
||||
path: string;
|
||||
}
|
||||
|
||||
export interface URLParams<P extends object = {}, Q extends object = {}> {
|
||||
params?: P;
|
||||
@@ -21,7 +27,7 @@ export function buildURL<P extends object = {}, Q extends object = {}>(path: str
|
||||
fragment && `#${fragment}`,
|
||||
];
|
||||
|
||||
return parts.filter(Boolean).join("");
|
||||
return parts.filter(isDefined).join("");
|
||||
}
|
||||
|
||||
export function buildURLPositional<P extends object = {}, Q extends object = {}>(path: string) {
|
||||
|
||||
@@ -4,22 +4,26 @@
|
||||
*/
|
||||
|
||||
// Convert object's keys to camelCase format
|
||||
import { camelCase, isPlainObject } from "lodash";
|
||||
import { camelCase } from "lodash";
|
||||
import type { SingleOrMany } from "./types";
|
||||
import { isObject } from "./type-narrowing";
|
||||
|
||||
export function toCamelCase(obj: Record<string, any>): any {
|
||||
export function toCamelCase<T extends Record<string, unknown>[]>(obj: T): T;
|
||||
export function toCamelCase<T extends Record<string, unknown>>(obj: T): T;
|
||||
|
||||
export function toCamelCase(obj: SingleOrMany<Record<string, unknown> | unknown>): SingleOrMany<Record<string, unknown> | unknown> {
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map(toCamelCase);
|
||||
}
|
||||
else if (isPlainObject(obj)) {
|
||||
return Object.keys(obj).reduce((result, key) => {
|
||||
const value = obj[key];
|
||||
|
||||
result[camelCase(key)] = typeof value === "object" ? toCamelCase(value) : value;
|
||||
if (isObject(obj)) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(obj)
|
||||
.map(([key, value]) => {
|
||||
return [camelCase(key), toCamelCase(value)];
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}, {} as any);
|
||||
}
|
||||
else {
|
||||
return obj;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
@@ -25,24 +25,3 @@ export function getClusterIdFromHost(host: string): ClusterId | undefined {
|
||||
export function getClusterFrameUrl(clusterId: ClusterId) {
|
||||
return `//${clusterId}.${location.host}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the result of `getClusterIdFromHost` from the current `location.host`
|
||||
*/
|
||||
export function getHostedClusterId(): ClusterId | undefined {
|
||||
// catch being called in main
|
||||
if (typeof location === "undefined") {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return getClusterIdFromHost(location.host);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true only if code is running within a cluster iframe context
|
||||
*/
|
||||
export function isClusterPageContext(): boolean {
|
||||
if (typeof window === "undefined") return false;
|
||||
|
||||
return !!getClusterIdFromHost(window.location.host);
|
||||
}
|
||||
@@ -4,6 +4,8 @@
|
||||
*/
|
||||
|
||||
import { runInAction } from "mobx";
|
||||
import { inspect } from "util";
|
||||
import { isDefined } from "./type-narrowing";
|
||||
|
||||
/**
|
||||
* Get the value behind `key`. If it was not present, first insert `value`
|
||||
@@ -17,7 +19,17 @@ export function getOrInsert<K, V>(map: Map<K, V>, key: K, value: V): V {
|
||||
map.set(key, value);
|
||||
}
|
||||
|
||||
return map.get(key);
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
return map.get(key)!;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates map and returns the value that was just inserted
|
||||
*/
|
||||
export function put<K, V>(map: Map<K, V>, key: K, value: V): V {
|
||||
map.set(key, value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -45,7 +57,8 @@ export function getOrInsertWith<K, V>(map: Map<K, V>, key: K, builder: () => V):
|
||||
map.set(key, builder());
|
||||
}
|
||||
|
||||
return map.get(key);
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
return map.get(key)!;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,7 +69,8 @@ export async function getOrInsertWithAsync<K, V>(map: Map<K, V>, key: K, asyncBu
|
||||
map.set(key, await asyncBuilder());
|
||||
}
|
||||
|
||||
return map.get(key);
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
return map.get(key)!;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,7 +81,7 @@ export async function getOrInsertWithAsync<K, V>(map: Map<K, V>, key: K, asyncBu
|
||||
*/
|
||||
export function strictSet<K, V>(map: Map<K, V>, key: K, val: V): typeof map {
|
||||
if (map.has(key)) {
|
||||
throw new TypeError("Duplicate key in map");
|
||||
throw new TypeError(`Map already contains key: ${inspect(key)}`);
|
||||
}
|
||||
|
||||
return map.set(key, val);
|
||||
@@ -80,10 +94,11 @@ export function strictSet<K, V>(map: Map<K, V>, key: K, val: V): typeof map {
|
||||
*/
|
||||
export function strictGet<K, V>(map: Map<K, V>, key: K): V {
|
||||
if (!map.has(key)) {
|
||||
throw new TypeError("key not in map");
|
||||
throw new TypeError(`Map does not contains key: ${inspect(key)}`);
|
||||
}
|
||||
|
||||
return map.get(key);
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
return map.get(key)!;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,3 +114,10 @@ export function toggle<K>(set: Set<K>, key: K): void {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function to also check for defined-ness
|
||||
*/
|
||||
export function includes<T>(src: T[], value: T | null | undefined): boolean {
|
||||
return isDefined(value) && src.includes(value);
|
||||
}
|
||||
@@ -11,7 +11,7 @@ interface Extendable<T> {
|
||||
|
||||
export type ExtendableDisposer = Disposer & Extendable<Disposer>;
|
||||
|
||||
export function disposer(...args: Disposer[]): ExtendableDisposer {
|
||||
export function disposer(...args: (Disposer | undefined | null)[]): ExtendableDisposer {
|
||||
const res = () => {
|
||||
args.forEach(dispose => dispose?.());
|
||||
args.length = 0;
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
*/
|
||||
|
||||
import request from "request";
|
||||
import type { JsonValue } from "type-fest";
|
||||
import { parse } from "./json";
|
||||
|
||||
export interface DownloadFileOptions {
|
||||
url: string;
|
||||
@@ -41,11 +43,11 @@ export function downloadFile({ url, timeout, gzip = true }: DownloadFileOptions)
|
||||
};
|
||||
}
|
||||
|
||||
export function downloadJson(args: DownloadFileOptions): DownloadFileTicket<any> {
|
||||
export function downloadJson(args: DownloadFileOptions): DownloadFileTicket<JsonValue> {
|
||||
const { promise, ...rest } = downloadFile(args);
|
||||
|
||||
return {
|
||||
promise: promise.then(res => JSON.parse(res.toString())),
|
||||
promise: promise.then(res => parse(res.toString())),
|
||||
...rest,
|
||||
};
|
||||
}
|
||||
@@ -14,7 +14,6 @@ export * from "./abort-controller";
|
||||
export * from "./app-version";
|
||||
export * from "./autobind";
|
||||
export * from "./camelCase";
|
||||
export * from "./cloneJson";
|
||||
export * from "./cluster-id-url-parsing";
|
||||
export * from "./collection-functions";
|
||||
export * from "./convertCpu";
|
||||
@@ -28,7 +27,6 @@ export * from "./formatDuration";
|
||||
export * from "./getRandId";
|
||||
export * from "./hash-set";
|
||||
export * from "./n-fircate";
|
||||
export * from "./objects";
|
||||
export * from "./openBrowser";
|
||||
export * from "./paths";
|
||||
export * from "./promise-exec";
|
||||
@@ -40,7 +38,9 @@ export * from "./splitArray";
|
||||
export * from "./tar";
|
||||
export * from "./toJS";
|
||||
export * from "./type-narrowing";
|
||||
export * from "./types";
|
||||
export * from "./wait-for-path";
|
||||
export * from "./wait";
|
||||
|
||||
export type { Tuple } from "./tuple";
|
||||
|
||||
@@ -48,10 +48,14 @@ import * as iter from "./iter";
|
||||
import * as array from "./array";
|
||||
import * as tuple from "./tuple";
|
||||
import * as base64 from "./base64";
|
||||
import * as object from "./objects";
|
||||
import * as json from "./json";
|
||||
|
||||
export {
|
||||
iter,
|
||||
array,
|
||||
tuple,
|
||||
base64,
|
||||
object,
|
||||
json,
|
||||
};
|
||||
@@ -12,14 +12,14 @@ export type IsAllowedResource = (resource: KubeResource) => boolean;
|
||||
const isAllowedResourceInjectable = getInjectable({
|
||||
id: "is-allowed-resource",
|
||||
|
||||
instantiate: (di, resourceName: KubeResource) => {
|
||||
instantiate: (di, resourceName: string) => {
|
||||
const allowedResources = di.inject(allowedResourcesInjectable);
|
||||
|
||||
return computed(() => allowedResources.get().has(resourceName));
|
||||
},
|
||||
|
||||
lifecycle: lifecycleEnum.keyedSingleton({
|
||||
getInstanceKey: (di, resource: KubeResource) => resource,
|
||||
getInstanceKey: (di, resource: string) => resource,
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
+46
-16
@@ -5,14 +5,31 @@
|
||||
|
||||
export type Falsey = false | 0 | "" | null | undefined;
|
||||
|
||||
interface Iterator<T> {
|
||||
filter(fn: (val: T) => unknown): Iterator<T>;
|
||||
filterMap<U>(fn: (val: T) => Falsey | U): Iterator<U>;
|
||||
find(fn: (val: T) => unknown): T | undefined;
|
||||
collect<U>(fn: (values: Iterable<T>) => U): U;
|
||||
map<U>(fn: (val: T) => U): Iterator<U>;
|
||||
join(sep?: string): string;
|
||||
}
|
||||
|
||||
export function pipeline<T>(src: IterableIterator<T>): Iterator<T> {
|
||||
return {
|
||||
filter: (fn) => pipeline(filter(src, fn)),
|
||||
filterMap: (fn) => pipeline(filterMap(src, fn)),
|
||||
map: (fn) => pipeline(map(src, fn)),
|
||||
find: (fn) => find(src, fn),
|
||||
join: (sep) => join(src, sep),
|
||||
collect: (fn) => fn(src),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new type safe empty Iterable
|
||||
* @returns An `Iterable` that yields 0 items
|
||||
*/
|
||||
// eslint-disable-next-line require-yield
|
||||
export function* newEmpty<T>(): IterableIterator<T> {
|
||||
return;
|
||||
}
|
||||
export function* newEmpty<T>(): IterableIterator<T> {}
|
||||
|
||||
/**
|
||||
* Creates a new `Iterable` that yields at most n items from src.
|
||||
@@ -167,25 +184,38 @@ export function reduce<T, R = T>(src: Iterable<T>, reducer: (acc: R, cur: T) =>
|
||||
* @param connector The string value to intersperse between the yielded values
|
||||
* @returns The concatenated entries of `src` interspersed with copies of `connector`
|
||||
*/
|
||||
export function join(src: Iterable<string>, connector = ","): string {
|
||||
return reduce(src, (acc, cur) => `${acc}${connector}${cur}`, "");
|
||||
export function join(src: IterableIterator<unknown>, connector = ","): string {
|
||||
const iterSrc = src[Symbol.iterator]();
|
||||
const first = iterSrc.next();
|
||||
|
||||
if (first.done === true) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return reduce(iterSrc, (acc, cur) => `${acc}${connector}${cur}`, `${first.value}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next value after iterating over the iterable `index` times.
|
||||
*
|
||||
* For example: `nth(["a", "b"], 0)` will return `"a"`
|
||||
* For example: `nth(["a", "b"], 1)` will return `"b"`
|
||||
* For example: `nth(["a", "b"], 2)` will return `undefined`
|
||||
* Iterate `n` times and then return the next value.
|
||||
* @param src The value to iterate over
|
||||
* @param n The zero-index value for the item to return to.
|
||||
*/
|
||||
export function nth<T>(src: Iterable<T>, index: number): T | undefined {
|
||||
const iteree = src[Symbol.iterator]();
|
||||
export function nth<T>(src: Iterable<T>, n: number): T | undefined {
|
||||
const iterator = src[Symbol.iterator]();
|
||||
|
||||
while (index-- > 0) {
|
||||
iteree.next();
|
||||
while (n --> 0) {
|
||||
iterator.next();
|
||||
}
|
||||
|
||||
return iteree.next().value;
|
||||
return iterator.next().value;
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience function to get the first item of an iterator
|
||||
* @param src The value to iterate over
|
||||
*/
|
||||
export function first<T>(src: Iterable<T>): T | undefined {
|
||||
return nth(src, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
// Clone json-serializable object
|
||||
import type { JsonValue } from "type-fest";
|
||||
|
||||
export function cloneJsonObject<T = object>(obj: T): T {
|
||||
return JSON.parse(JSON.stringify(obj));
|
||||
export function parse(input: string): JsonValue {
|
||||
return JSON.parse(input);
|
||||
}
|
||||
@@ -23,7 +23,8 @@ export function lazyInitialized<T>(builder: () => T): LazyInitialized<T> {
|
||||
return {
|
||||
get() {
|
||||
if (called) {
|
||||
return value;
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
return value!;
|
||||
}
|
||||
|
||||
value = builder();
|
||||
|
||||
@@ -8,9 +8,22 @@
|
||||
* be a specific subset
|
||||
*/
|
||||
export function fromEntries<T, Key extends string>(entries: Iterable<readonly [Key, T]>): Record<Key, T> {
|
||||
return Object.fromEntries(entries) as { [k in Key]: T };
|
||||
return Object.fromEntries(entries) as Record<Key, T>;
|
||||
}
|
||||
|
||||
export function entries<T extends Record<string, any>>(obj: T): [keyof T, T[keyof T]][] {
|
||||
return Object.entries(obj);
|
||||
export function keys<K extends keyof any>(obj: Partial<Record<K, any>>): K[];
|
||||
|
||||
export function keys<K extends keyof any>(obj: Record<K, any>): K[] {
|
||||
return Object.keys(obj) as K[];
|
||||
}
|
||||
|
||||
export function entries<K extends string | number | symbol, V>(obj: Partial<Record<K, V>> | null | undefined): [K, V][];
|
||||
export function entries<K extends string | number | symbol, V>(obj: Record<K, V> | null | undefined): [K, V][];
|
||||
|
||||
export function entries<K extends string | number | symbol, V>(obj: Record<K, V> | null | undefined): [K, V][] {
|
||||
if (obj && typeof obj == "object") {
|
||||
return Object.entries(obj) as never;
|
||||
}
|
||||
|
||||
return [] as never;
|
||||
}
|
||||
@@ -24,7 +24,7 @@ export class ReadableWebToNodeStream<T extends TypedArray> extends Readable {
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader
|
||||
*/
|
||||
private reader: ReadableStreamReader<T>;
|
||||
private pendingRead: Promise<ReadableStreamDefaultReadResult<T>>;
|
||||
private pendingRead?: Promise<ReadableStreamDefaultReadResult<T>>;
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
@@ -51,6 +51,8 @@ export class Singleton {
|
||||
* Default: `true`
|
||||
* @returns An instance of the child class
|
||||
*/
|
||||
static getInstance<T, R extends any[]>(this: StaticThis<T, R>, strict?: true): T;
|
||||
static getInstance<T, R extends any[]>(this: StaticThis<T, R>, strict: false): T | undefined;
|
||||
static getInstance<T, R extends any[]>(this: StaticThis<T, R>, strict = true): T | undefined {
|
||||
if (!Singleton.instances.has(this) && strict) {
|
||||
throw new TypeError(`instance of ${this.name} is not created`);
|
||||
|
||||
@@ -51,7 +51,7 @@ export function sortCompare<T>(left: T, right: T): Ordering {
|
||||
|
||||
interface ChartVersion {
|
||||
version: string;
|
||||
__version?: SemVer;
|
||||
__version?: SemVer | null;
|
||||
}
|
||||
|
||||
export function sortCompareChartVersions(left: ChartVersion, right: ChartVersion): Ordering {
|
||||
@@ -74,13 +74,13 @@ export function sortCompareChartVersions(left: ChartVersion, right: ChartVersion
|
||||
|
||||
export function sortCharts(charts: RawHelmChart[]) {
|
||||
interface ExtendedHelmChart extends RawHelmChart {
|
||||
__version: SemVer;
|
||||
__version?: SemVer | null;
|
||||
}
|
||||
|
||||
const chartsWithVersion = Array.from(
|
||||
iter.map(
|
||||
charts,
|
||||
(chart => {
|
||||
chart => {
|
||||
const __version = coerce(chart.version, { includePrerelease: true, loose: true });
|
||||
|
||||
if (!__version) {
|
||||
@@ -90,7 +90,7 @@ export function sortCharts(charts: RawHelmChart[]) {
|
||||
(chart as ExtendedHelmChart).__version = __version;
|
||||
|
||||
return chart as ExtendedHelmChart;
|
||||
}),
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
+18
-6
@@ -8,14 +8,26 @@
|
||||
import type { ExtractOptions, FileStat } from "tar";
|
||||
import tar from "tar";
|
||||
import path from "path";
|
||||
import { parse } from "./json";
|
||||
import type { JsonValue } from "type-fest";
|
||||
|
||||
export interface ReadFileFromTarOpts {
|
||||
export type ReadFileFromTarOpts<ParseJson extends boolean> = {
|
||||
tarPath: string;
|
||||
filePath: string;
|
||||
parseJson?: boolean;
|
||||
}
|
||||
} & (
|
||||
ParseJson extends true
|
||||
? {
|
||||
parseJson: true;
|
||||
}
|
||||
: {
|
||||
parseJson?: false;
|
||||
}
|
||||
);
|
||||
|
||||
export function readFileFromTar<R = Buffer>({ tarPath, filePath, parseJson }: ReadFileFromTarOpts): Promise<R> {
|
||||
export function readFileFromTar(opts: ReadFileFromTarOpts<false>): Promise<Buffer>;
|
||||
export function readFileFromTar(opts: ReadFileFromTarOpts<true>): Promise<JsonValue>;
|
||||
|
||||
export function readFileFromTar<ParseJson extends boolean>({ tarPath, filePath, parseJson = false }: ReadFileFromTarOpts<ParseJson>): Promise<JsonValue | Buffer> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const fileChunks: Buffer[] = [];
|
||||
|
||||
@@ -32,7 +44,7 @@ export function readFileFromTar<R = Buffer>({ tarPath, filePath, parseJson }: Re
|
||||
});
|
||||
entry.once("end", () => {
|
||||
const data = Buffer.concat(fileChunks);
|
||||
const result = parseJson ? JSON.parse(data.toString("utf8")) : data;
|
||||
const result = parseJson ? parse(data.toString("utf8")) : data;
|
||||
|
||||
resolve(result);
|
||||
});
|
||||
@@ -51,7 +63,7 @@ export async function listTarEntries(filePath: string): Promise<string[]> {
|
||||
await tar.list({
|
||||
file: filePath,
|
||||
onentry: (entry: FileStat) => {
|
||||
entries.push(path.normalize(entry.path as any as string));
|
||||
entries.push(path.normalize(entry.path as unknown as string));
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -24,6 +24,9 @@ type TupleOfImpl<T, N extends number, R extends unknown[]> = R["length"] extends
|
||||
* @yields A tuple of the next element from each of the sources
|
||||
* @returns The tuple of all the sources as soon as at least one of the sources is exausted
|
||||
*/
|
||||
export function zip<T>(src1: T[]): Iterator<[T], Tuple<T[], 1>>;
|
||||
export function zip<T>(src1: T[], src2: T[]): Iterator<[T, T], Tuple<T[], 2>>;
|
||||
|
||||
export function* zip<T, N extends number>(...sources: Tuple<T[], N>): Iterator<Tuple<T, N>, Tuple<T[], N>> {
|
||||
const maxSafeLength = Math.min(...sources.map(source => source.length));
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { ExecException, ExecFileException } from "child_process";
|
||||
import type { IncomingMessage } from "http";
|
||||
|
||||
/**
|
||||
* Narrows `val` to include the property `key` (if true is returned)
|
||||
* @param val The object to be tested
|
||||
@@ -38,7 +41,7 @@ export function hasTypedProperty<S extends object, K extends PropertyKey, V>(val
|
||||
* @param key The key to test if it is present on the object (must be a literal for tsc to do any meaningful typing)
|
||||
* @param isValid a function to check if the field (when present) is valid
|
||||
*/
|
||||
export function hasOptionalProperty<S extends object, K extends PropertyKey, V>(val: S, key: K, isValid: (value: unknown) => value is V): val is (S & { [key in K]?: V }) {
|
||||
export function hasOptionalTypedProperty<S extends object, K extends PropertyKey, V>(val: S, key: K, isValid: (value: unknown) => value is V): val is (S & { [key in K]?: V }) {
|
||||
if (hasOwnProperty(val, key)) {
|
||||
return typeof val[key] === "undefined" || isValid(val[key]);
|
||||
}
|
||||
@@ -73,6 +76,21 @@ export function isString(val: unknown): val is string {
|
||||
return typeof val === "string";
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if val is of type Buffer
|
||||
* @param val the value to be checked
|
||||
*/export function isBuffer(val: unknown): val is Buffer {
|
||||
return val instanceof Buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if val is of type number
|
||||
* @param val the value to be checked
|
||||
*/
|
||||
export function isNumber(val: unknown): val is number {
|
||||
return typeof val === "number";
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if val is of type boolean
|
||||
* @param val the value to be checked
|
||||
@@ -89,6 +107,20 @@ export function isObject(val: unknown): val is object {
|
||||
return typeof val === "object" && val !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if `val` is defined, useful for filtering out undefined values in a strict manner
|
||||
*/
|
||||
export function isDefined<T>(val: T | undefined | null): val is T {
|
||||
return val != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value in the second position is non-nullable
|
||||
*/
|
||||
export function hasDefinedTupleValue<K, V>(pair: [K, V | undefined | null]): pair is [K, V] {
|
||||
return pair[1] != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new predicate function (with the same predicate) from `fn`. Such
|
||||
* that it can be called with just the value to be tested.
|
||||
@@ -100,3 +132,81 @@ export function isObject(val: unknown): val is object {
|
||||
export function bindPredicate<FnArgs extends any[], T>(fn: (arg1: unknown, ...args: FnArgs) => arg1 is T, ...boundArgs: FnArgs): (arg1: unknown) => arg1 is T {
|
||||
return (arg1: unknown): arg1 is T => fn(arg1, ...boundArgs);
|
||||
}
|
||||
|
||||
export function hasDefiniteField<Field extends keyof T, T>(field: Field): (val: T) => val is T & { [f in Field]-?: NonNullable<T[Field]> } {
|
||||
return (val): val is T & { [f in Field]-?: NonNullable<T[Field]> } => val[field] != null;
|
||||
}
|
||||
|
||||
export function isErrnoException(error: unknown): error is NodeJS.ErrnoException {
|
||||
return isObject(error)
|
||||
&& hasOptionalTypedProperty(error, "code", isString)
|
||||
&& hasOptionalTypedProperty(error, "path", isString)
|
||||
&& hasOptionalTypedProperty(error, "syscall", isString)
|
||||
&& hasOptionalTypedProperty(error, "errno", isNumber)
|
||||
&& error instanceof Error;
|
||||
}
|
||||
|
||||
export function isExecException(error: unknown): error is ExecException {
|
||||
return isObject(error)
|
||||
&& hasOptionalTypedProperty(error, "cmd", isString)
|
||||
&& hasOptionalTypedProperty(error, "killed", isBoolean)
|
||||
&& hasOptionalTypedProperty(error, "signal", isString)
|
||||
&& hasOptionalTypedProperty(error, "code", isNumber)
|
||||
&& error instanceof Error;
|
||||
}
|
||||
|
||||
export function isExecFileException(error: unknown): error is ExecFileException {
|
||||
return isExecException(error) && isErrnoException(error);
|
||||
}
|
||||
|
||||
export type OutputFormat = "string" | "buffer";
|
||||
export type ComputeOutputFormat<Format> = Format extends "string"
|
||||
? string
|
||||
: Format extends "buffer"
|
||||
? Buffer
|
||||
: string | Buffer;
|
||||
|
||||
export interface ChildProcessExecpetion<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> {
|
||||
if (!isExecFileException(error)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (format === "string") {
|
||||
return hasTypedProperty(error, "stderr", isString)
|
||||
&& hasTypedProperty(error, "stdout", isString);
|
||||
} else if (format === "buffer") {
|
||||
return hasTypedProperty(error, "stderr", isBuffer)
|
||||
&& hasTypedProperty(error, "stdout", isBuffer);
|
||||
} else {
|
||||
return hasTypedProperty(error, "stderr", isStringOrBuffer)
|
||||
&& hasTypedProperty(error, "stdout", isStringOrBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
export interface RequestLikeError extends Error {
|
||||
statusCode?: number;
|
||||
failed?: boolean;
|
||||
timedOut?: boolean;
|
||||
error?: string;
|
||||
response?: IncomingMessage & { body?: any };
|
||||
}
|
||||
|
||||
/**
|
||||
* A type guard for checking if the error is similar in shape to a request package error
|
||||
*/
|
||||
export function isRequestError(error: unknown): error is RequestLikeError {
|
||||
return isObject(error)
|
||||
&& hasOptionalTypedProperty(error, "statusCode", isNumber)
|
||||
&& hasOptionalTypedProperty(error, "failed", isBoolean)
|
||||
&& hasOptionalTypedProperty(error, "timedOut", isBoolean)
|
||||
&& hasOptionalTypedProperty(error, "error", isString)
|
||||
&& hasOptionalTypedProperty(error, "response", isObject)
|
||||
&& error instanceof Error;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { SetRequired } from "type-fest";
|
||||
|
||||
export type RemoveUndefinedFromValues<K> = {
|
||||
[P in keyof K]: NonNullable<K[P]>;
|
||||
};
|
||||
|
||||
/**
|
||||
* This type helps define which fields of some type will always be defined
|
||||
*/
|
||||
export type Defaulted<Params, DefaultParams extends keyof Params> = RemoveUndefinedFromValues<Required<Pick<Params, DefaultParams>>> & Omit<Params, DefaultParams>;
|
||||
|
||||
export type OptionVarient<Key, Base, RequiredKey extends keyof Base> = {
|
||||
type: Key;
|
||||
} & Pick<Base, RequiredKey> & {
|
||||
[OtherKey in Exclude<keyof Base, RequiredKey>]?: undefined;
|
||||
};
|
||||
|
||||
export type SingleOrMany<T> = T | T[];
|
||||
|
||||
export type IfEquals<T, U, Y=unknown, N=never> =
|
||||
(<G>() => G extends T ? 1 : 2) extends
|
||||
(<G>() => G extends U ? 1 : 2) ? Y : N;
|
||||
|
||||
export type MaybeSetRequired<BaseType, Keys extends keyof BaseType, Query> = Query extends true
|
||||
? SetRequired<BaseType, Keys>
|
||||
: BaseType;
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { IComputedValue } from "mobx";
|
||||
import { runInAction, when } from "mobx";
|
||||
import type { Disposer } from "./disposer";
|
||||
|
||||
export async function waitUntilDefined<T>(getter: (() => T | null | undefined) | IComputedValue<T | null | undefined>, opts?: { timeout?: number }): Promise<T> {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
let res: T | null | undefined;
|
||||
|
||||
when(
|
||||
() => {
|
||||
res = typeof getter === "function"
|
||||
? getter()
|
||||
: getter.get();
|
||||
|
||||
if (res != null) {
|
||||
resolve(res);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
() => {},
|
||||
{
|
||||
onError: reject,
|
||||
...opts,
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function onceDefined<T>(getter: () => T | null | undefined, action: (val: T) => void): Disposer {
|
||||
let res: T | null | undefined;
|
||||
|
||||
return when(
|
||||
() => {
|
||||
res = getter();
|
||||
|
||||
if (res != null) {
|
||||
const r = res;
|
||||
|
||||
runInAction(() => {
|
||||
action(r);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
() => {},
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user