Essential utility functions and classes for TypeScript/JavaScript applications including JSON handling, MIME data management, promise delegation, secure tokens, and cross-platform random number generation.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Promise wrapper that separates promise creation from resolution logic, enabling flexible asynchronous workflows where the resolution logic cannot be defined at the point of promise creation.
A class which wraps a promise into a delegate object, allowing external resolution or rejection of the promise.
/**
* A class which wraps a promise into a delegate object.
*
* Notes:
* This class is useful when the logic to resolve or reject a promise
* cannot be defined at the point where the promise is created.
*/
class PromiseDelegate<T> {
/**
* Construct a new promise delegate
*/
constructor();
/**
* The promise wrapped by the delegate
*/
readonly promise: Promise<T>;
/**
* Resolve the wrapped promise with the given value
* @param value - The value to use for resolving the promise
*/
resolve(value: T | PromiseLike<T>): void;
/**
* Reject the wrapped promise with the given value
* @param reason - The reason for rejecting the promise
*/
reject(reason: any): void;
}Usage Examples:
import { PromiseDelegate } from "@lumino/coreutils";
// Basic usage - create a delegate and resolve it later
const delegate = new PromiseDelegate<string>();
// The promise can be awaited or chained
delegate.promise.then(value => {
console.log("Resolved with:", value);
}).catch(error => {
console.log("Rejected with:", error);
});
// Later, resolve the promise from elsewhere
setTimeout(() => {
delegate.resolve("Hello, World!");
}, 1000);
// Or reject it
// delegate.reject(new Error("Something went wrong"));Async Event Handling:
import { PromiseDelegate } from "@lumino/coreutils";
class EventEmitter {
private listeners = new Map<string, PromiseDelegate<any>[]>();
// Wait for a specific event to occur
waitForEvent<T>(eventName: string): Promise<T> {
const delegate = new PromiseDelegate<T>();
if (!this.listeners.has(eventName)) {
this.listeners.set(eventName, []);
}
this.listeners.get(eventName)!.push(delegate);
return delegate.promise;
}
// Emit an event, resolving all waiting promises
emit<T>(eventName: string, data: T): void {
const delegates = this.listeners.get(eventName) || [];
delegates.forEach(delegate => delegate.resolve(data));
this.listeners.set(eventName, []);
}
}
// Usage
const emitter = new EventEmitter();
const dataPromise = emitter.waitForEvent<{id: number, name: string}>("user-loaded");
dataPromise.then(userData => {
console.log("User loaded:", userData.name);
});
// Later, in another part of the application
emitter.emit("user-loaded", { id: 123, name: "Alice" });Resource Loading:
import { PromiseDelegate } from "@lumino/coreutils";
class ResourceLoader {
private loadingPromises = new Map<string, PromiseDelegate<any>>();
loadResource<T>(url: string): Promise<T> {
// Return existing promise if already loading
if (this.loadingPromises.has(url)) {
return this.loadingPromises.get(url)!.promise;
}
// Create new delegate for this resource
const delegate = new PromiseDelegate<T>();
this.loadingPromises.set(url, delegate);
// Start loading (could be HTTP request, file read, etc.)
this.startLoading(url, delegate);
return delegate.promise;
}
private startLoading<T>(url: string, delegate: PromiseDelegate<T>): void {
// Simulate async loading
fetch(url)
.then(response => response.json())
.then(data => {
delegate.resolve(data);
this.loadingPromises.delete(url);
})
.catch(error => {
delegate.reject(error);
this.loadingPromises.delete(url);
});
}
}
// Usage
const loader = new ResourceLoader();
const userPromise = loader.loadResource<{name: string, email: string}>("/api/user/123");
const configPromise = loader.loadResource<{theme: string, locale: string}>("/api/config");
Promise.all([userPromise, configPromise]).then(([user, config]) => {
console.log(`Hello ${user.name}, your theme is ${config.theme}`);
});Conditional Resolution:
import { PromiseDelegate } from "@lumino/coreutils";
class ConditionalTask<T> {
private delegate = new PromiseDelegate<T>();
private conditions: (() => boolean)[] = [];
constructor() {}
get promise(): Promise<T> {
return this.delegate.promise;
}
addCondition(condition: () => boolean): this {
this.conditions.push(condition);
this.checkConditions();
return this;
}
setResult(result: T): void {
this.result = result;
this.checkConditions();
}
setError(error: any): void {
this.delegate.reject(error);
}
private result?: T;
private checkConditions(): void {
if (this.result !== undefined && this.conditions.every(cond => cond())) {
this.delegate.resolve(this.result);
}
}
}
// Usage
const task = new ConditionalTask<string>();
let userLoggedIn = false;
let dataLoaded = false;
task
.addCondition(() => userLoggedIn)
.addCondition(() => dataLoaded);
task.promise.then(result => {
console.log("All conditions met:", result);
});
// Simulate conditions being met
setTimeout(() => {
userLoggedIn = true;
task.setResult("Task completed!");
}, 1000);
setTimeout(() => {
dataLoaded = true;
}, 1500);Timeout with Cleanup:
import { PromiseDelegate } from "@lumino/coreutils";
function withTimeout<T>(promise: Promise<T>, timeoutMs: number): Promise<T> {
const delegate = new PromiseDelegate<T>();
let timeoutId: number;
// Race between the original promise and timeout
promise.then(
value => {
clearTimeout(timeoutId);
delegate.resolve(value);
},
error => {
clearTimeout(timeoutId);
delegate.reject(error);
}
);
timeoutId = setTimeout(() => {
delegate.reject(new Error(`Operation timed out after ${timeoutMs}ms`));
}, timeoutMs);
return delegate.promise;
}
// Usage
const slowOperation = new Promise(resolve => {
setTimeout(() => resolve("Done!"), 5000);
});
const fastTimeout = withTimeout(slowOperation, 2000);
fastTimeout.catch(error => {
console.log(error.message); // "Operation timed out after 2000ms"
});