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
Core dependency injection and state management system through Container and Slice patterns. Provides type-safe reactive state management with watcher support, ideal for building plugin-based architectures where components need to share and react to state changes.
Central registry that manages typed slices for dependency injection. Acts as a type-safe container where slices can be stored, retrieved, and managed by type or name.
/**
* Container manages a collection of typed slices for dependency injection
*/
class Container {
/** Get a slice from the container by slice type or slice name */
get<T, N extends string = string>(slice: SliceType<T, N> | N): Slice<T, N>;
/** Remove a slice from the container by slice type or slice name */
remove<T, N extends string = string>(slice: SliceType<T, N> | N): void;
/** Check if the container has a slice by slice type or slice name */
has<T, N extends string = string>(slice: SliceType<T, N> | N): boolean;
}Usage Examples:
import { Container, createSlice } from "@milkdown/ctx";
const container = new Container();
const userSlice = createSlice({ name: "Anonymous" }, "user");
// Create and add slice to container
userSlice.create(container.sliceMap, { name: "Alice" });
// Check if slice exists
if (container.has(userSlice)) {
const slice = container.get(userSlice);
console.log(slice.get()); // { name: "Alice" }
}
// Remove slice
container.remove(userSlice);Container for typed values with reactive update capabilities. Supports watchers for reactive programming patterns and provides methods for value management.
/**
* Slice holds a typed value and supports reactive updates through watchers
*/
class Slice<T = any, N extends string = string> {
/** The type of the slice */
readonly type: SliceType<T, N>;
/** Add a watcher for changes in the slice, returns unsubscribe function */
on(watcher: (value: T) => unknown): () => void;
/** Add a one-time watcher that removes itself after first call */
once(watcher: (value: T) => unknown): () => void;
/** Remove a specific watcher */
off(watcher: (value: T) => unknown): void;
/** Remove all watchers */
offAll(): void;
/** Set the value of the slice and notify all watchers */
set(value: T): void;
/** Get the current value of the slice */
get(): T;
/** Update the value using a callback function and notify watchers */
update(updater: (prev: T) => T): void;
}Usage Examples:
import { Container, createSlice } from "@milkdown/ctx";
const container = new Container();
const counterSlice = createSlice(0, "counter");
const slice = counterSlice.create(container.sliceMap);
// Watch for changes
const unsubscribe = slice.on((value) => {
console.log("Counter updated:", value);
});
// Update values
slice.set(5); // Logs: "Counter updated: 5"
slice.update((prev) => prev + 1); // Logs: "Counter updated: 6"
// One-time watcher
slice.once((value) => {
console.log("This will only log once:", value);
});
slice.set(10); // Logs both watchers
slice.set(20); // Only logs the persistent watcher
// Cleanup
unsubscribe();
slice.offAll();Type definition for creating slices across different containers. Defines the structure and default value for slices while maintaining type safety.
/**
* SliceType defines the structure for creating typed slices
*/
class SliceType<T = any, N extends string = string> {
/** Unique identifier for the slice type */
readonly id: symbol;
/** Human-readable name for the slice type */
readonly name: N;
/** Create a slice type with a default value and unique name */
constructor(value: T, name: N);
/** Create a slice instance in the specified container */
create(container: SliceMap, value?: T): Slice<T, N>;
}Usage Examples:
import { Container, SliceType } from "@milkdown/ctx";
// Create slice type
const configSliceType = new SliceType(
{ theme: "light", language: "en" },
"config"
);
const container = new Container();
// Create slice with default value
const configSlice = configSliceType.create(container.sliceMap);
console.log(configSlice.get()); // { theme: "light", language: "en" }
// Create slice with custom value
const customConfigSlice = configSliceType.create(
container.sliceMap,
{ theme: "dark", language: "es" }
);
console.log(customConfigSlice.get()); // { theme: "dark", language: "es" }Factory function for creating SliceType instances with cleaner syntax.
/**
* Factory function for creating SliceType instances
* @param value - Default value for the slice
* @param name - Unique name for the slice type
* @returns New SliceType instance
*/
function createSlice<T = any, N extends string = string>(
value: T,
name: N
): SliceType<T, N>;Usage Examples:
import { createSlice, Container } from "@milkdown/ctx";
// Create different types of slices
const stringSlice = createSlice("hello", "greeting");
const numberSlice = createSlice(42, "answer");
const arraySlice = createSlice<string[]>([], "items");
const objectSlice = createSlice({ x: 0, y: 0 }, "position");
const container = new Container();
// Use them in containers
const greeting = stringSlice.create(container.sliceMap);
const position = objectSlice.create(container.sliceMap, { x: 10, y: 20 });
console.log(greeting.get()); // "hello"
console.log(position.get()); // { x: 10, y: 20 }/** Internal type for the container's slice storage */
type SliceMap = Map<symbol, Slice>;The context management system throws specific errors from @milkdown/exception:
import { Container, createSlice } from "@milkdown/ctx";
const container = new Container();
const missingSlice = createSlice("test", "missing");
try {
container.get(missingSlice); // Throws contextNotFound error
} catch (error) {
console.error("Slice not found:", error.message);
}