Core context management module for Milkdown editor providing dependency injection and state management
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Promise-based timer system with event-driven resolution for scheduling and synchronization in plugin architectures. Provides Clock and Timer classes for managing asynchronous operations, timeouts, and coordination between different parts of the system.
Container that manages timer instances and provides access to timing operations. Acts as a central registry for all timers in the system.
/**
* Clock manages timer instances and provides timing coordination
*/
class Clock {
/** Internal timer storage (readonly) */
readonly store: TimerMap;
/** Get a timer from the clock by timer type, throws if not found */
get(timer: TimerType): Timer;
/** Remove a timer from the clock by timer type */
remove(timer: TimerType): void;
/** Check if the clock has a timer by timer type */
has(timer: TimerType): boolean;
}Usage Examples:
import { Clock, createTimer } from "@milkdown/ctx";
const clock = new Clock();
const loadTimer = createTimer("data-load", 5000);
// Create timer in clock
loadTimer.create(clock.store);
// Check if timer exists
if (clock.has(loadTimer)) {
const timer = clock.get(loadTimer);
console.log("Timer status:", timer.status); // "pending"
}
// Remove timer
clock.remove(loadTimer);Promise-based timer that can be resolved externally through event dispatching. Supports timeout mechanisms and status tracking.
/**
* Timer provides promise-based timing with event-driven resolution
*/
class Timer {
/** The timer type definition (readonly) */
readonly type: TimerType;
/** Current timer status: pending, resolved, or rejected (readonly) */
readonly status: TimerStatus;
/** Start the timer and return a promise that resolves when done() is called */
start(): Promise<void>;
/** Resolve the timer by dispatching a custom event */
done(): void;
}
type TimerStatus = 'pending' | 'resolved' | 'rejected';Usage Examples:
import { Clock, createTimer } from "@milkdown/ctx";
const clock = new Clock();
const processTimer = createTimer("process-data", 10000);
const timer = processTimer.create(clock.store);
// Start timer
const timerPromise = timer.start();
console.log("Timer status:", timer.status); // "pending"
// Resolve timer after some operation
setTimeout(() => {
timer.done();
console.log("Timer status:", timer.status); // "resolved"
}, 2000);
// Wait for completion
timerPromise.then(() => {
console.log("Timer completed successfully!");
}).catch((error) => {
console.error("Timer timed out:", error.message);
});Type definition for creating timer instances with specified names and timeout durations.
/**
* TimerType defines the structure for creating timer instances
*/
class TimerType {
/** Unique identifier for the timer type (readonly) */
readonly id: symbol;
/** Human-readable timer name (readonly) */
readonly name: string;
/** Timeout duration in milliseconds (readonly) */
readonly timeout: number;
/** Create a timer type with name and optional timeout (default 3000ms) */
constructor(name: string, timeout?: number);
/** Create a timer instance in the specified clock */
create(clock: TimerMap): Timer;
}Usage Examples:
import { TimerType, Clock } from "@milkdown/ctx";
// Create timer types with different timeouts
const quickTimer = new TimerType("quick-task", 1000);
const normalTimer = new TimerType("normal-task", 5000);
const longTimer = new TimerType("long-task", 30000);
const clock = new Clock();
// Create timer instances
const quick = quickTimer.create(clock.store);
const normal = normalTimer.create(clock.store);
const long = longTimer.create(clock.store);
console.log("Quick timer timeout:", quick.type.timeout); // 1000
console.log("Normal timer timeout:", normal.type.timeout); // 5000
console.log("Long timer timeout:", long.type.timeout); // 30000Factory function for creating TimerType instances with cleaner syntax.
/**
* Factory function for creating TimerType instances
* @param name - Unique name for the timer
* @param timeout - Timeout duration in milliseconds (default 3000)
* @returns New TimerType instance
*/
function createTimer(name: string, timeout?: number): TimerType;Usage Examples:
import { createTimer, Clock } from "@milkdown/ctx";
// Create various timer types
const authTimer = createTimer("authentication", 5000);
const apiTimer = createTimer("api-request", 10000);
const renderTimer = createTimer("render-complete", 2000);
const defaultTimer = createTimer("default-task"); // Uses 3000ms default
const clock = new Clock();
// Use in coordination scenarios
const timers = [authTimer, apiTimer, renderTimer].map(type =>
type.create(clock.store)
);
// Start all timers
const promises = timers.map(timer => timer.start());
// Simulate completion in sequence
setTimeout(() => timers[0].done(), 1000); // auth completes
setTimeout(() => timers[1].done(), 2000); // api completes
setTimeout(() => timers[2].done(), 3000); // render completes
Promise.all(promises).then(() => {
console.log("All operations completed!");
});import { Clock, createTimer } from "@milkdown/ctx";
async function sequentialTasks() {
const clock = new Clock();
const tasks = [
createTimer("load-config", 2000),
createTimer("init-database", 3000),
createTimer("start-server", 1000)
];
// Create all timers
const timers = tasks.map(task => task.create(clock.store));
// Execute sequentially
for (let i = 0; i < timers.length; i++) {
const timer = timers[i];
const promise = timer.start();
// Simulate task completion
setTimeout(() => timer.done(), 500 * (i + 1));
await promise;
console.log(`Task ${timer.type.name} completed`);
}
console.log("All tasks completed sequentially");
}import { Clock, createTimer } from "@milkdown/ctx";
async function parallelTasksWithTimeouts() {
const clock = new Clock();
const tasks = [
createTimer("fast-task", 1000),
createTimer("medium-task", 3000),
createTimer("slow-task", 5000)
];
const timers = tasks.map(task => task.create(clock.store));
const promises = timers.map(timer => timer.start());
// Simulate different completion times
setTimeout(() => timers[0].done(), 500); // fast completes
setTimeout(() => timers[1].done(), 2500); // medium completes
// slow task will timeout (no done() call)
// Handle mixed success/timeout results
const results = await Promise.allSettled(promises);
results.forEach((result, index) => {
const timerName = timers[index].type.name;
if (result.status === 'fulfilled') {
console.log(`${timerName} completed successfully`);
} else {
console.log(`${timerName} timed out:`, result.reason.message);
}
});
}import { Clock, createTimer, Container, createSlice } from "@milkdown/ctx";
type AppState = 'initializing' | 'loading' | 'ready' | 'error';
class AppStateMachine {
private clock = new Clock();
private container = new Container();
private stateSlice = createSlice<AppState>('initializing', 'app-state');
constructor() {
this.stateSlice.create(this.container.sliceMap);
}
async initialize() {
const initTimer = createTimer("initialize", 2000);
const timer = initTimer.create(this.clock.store);
const stateSlice = this.container.get(this.stateSlice);
stateSlice.set('initializing');
// Start initialization
const promise = timer.start();
try {
// Simulate initialization work
setTimeout(() => {
stateSlice.set('loading');
timer.done();
}, 1000);
await promise;
stateSlice.set('ready');
console.log("App initialized successfully");
} catch (error) {
stateSlice.set('error');
console.error("Initialization failed:", error);
}
}
getState(): AppState {
return this.container.get(this.stateSlice);
}
}/** Internal type for the clock's timer storage */
type TimerMap = Map<symbol, Timer>;
/** Timer status enumeration */
type TimerStatus = 'pending' | 'resolved' | 'rejected';The timer system throws specific errors from @milkdown/exception:
import { Clock, createTimer } from "@milkdown/ctx";
const clock = new Clock();
const timer = createTimer("test-timer", 1000);
try {
// This will throw timerNotFound
clock.get(timer);
} catch (error) {
console.error("Timer not found:", error.message);
}
// Timer timeout handling
const timeoutTimer = createTimer("timeout-test", 1000);
const timerInstance = timeoutTimer.create(clock.store);
timerInstance.start().catch((error) => {
console.error("Timer timed out:", error.message);
// Error: "Timing timeout-test timeout."
});
// Don't call timerInstance.done() - let it timeoutTimers use the browser's event system for coordination:
import { createTimer, Clock } from "@milkdown/ctx";
const clock = new Clock();
const eventTimer = createTimer("custom-event", 5000);
const timer = eventTimer.create(clock.store);
// Listen for timer events directly (advanced usage)
addEventListener("custom-event", (event) => {
if (event instanceof CustomEvent) {
console.log("Timer event received:", event.detail);
}
});
// Start timer
timer.start().then(() => {
console.log("Timer completed via event system");
});
// Resolve timer (triggers custom event)
setTimeout(() => timer.done(), 2000);