Fixes https://github.com/xtermjs/xterm.js/issues/5896 TypeScript path mappings for common/*, browser/*, and headless/* were not rewritten in emitted JavaScript, which forced webpack resolve aliases and NODE_PATH workarounds so runtime could resolve modules. That added build complexity and broke tooling such as ESLint import/no-cycle. Changes: - Convert ~750 imports across src/, addons/, and test/ to relative paths - Remove common/browser/headless paths and src catch-all mappings from tsconfigs (keep @xterm/addon-* demo and addon typings paths) - Remove webpack resolve.alias for common, browser, headless, and vs - Drop NODE_PATH from unit tests, benchmarks, and VS Code launch config - Fix addon-image IIPImageStorage to import ./Types after removing catch-all * Verified: npm run build, esbuild, package, package-headless Co-authored-by: Cursor <cursoragent@cursor.com>
119 lines
3.4 KiB
TypeScript
119 lines
3.4 KiB
TypeScript
/**
|
|
* Copyright (c) 2024-2026 The xterm.js authors. All rights reserved.
|
|
* @license MIT
|
|
*
|
|
* Minimal event utilities for xterm.js core.
|
|
* Simplified from VS Code's event.ts - no leak detection/profiling.
|
|
*/
|
|
|
|
import { IDisposable, DisposableStore, toDisposable } from './Lifecycle';
|
|
|
|
export interface IEvent<T> {
|
|
(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore): IDisposable;
|
|
}
|
|
|
|
export class Emitter<T> {
|
|
private _listeners: { fn: (e: T) => any, thisArgs: any }[] = [];
|
|
private _disposed = false;
|
|
private _event: IEvent<T> | undefined;
|
|
|
|
public get event(): IEvent<T> {
|
|
if (this._event) {
|
|
return this._event;
|
|
}
|
|
this._event = (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore) => {
|
|
if (this._disposed) {
|
|
return toDisposable(() => {});
|
|
}
|
|
|
|
const entry = { fn: listener, thisArgs };
|
|
this._listeners.push(entry);
|
|
|
|
const result = toDisposable(() => {
|
|
const idx = this._listeners.indexOf(entry);
|
|
if (idx !== -1) {
|
|
this._listeners.splice(idx, 1);
|
|
}
|
|
});
|
|
|
|
if (disposables) {
|
|
if (Array.isArray(disposables)) {
|
|
disposables.push(result);
|
|
} else {
|
|
disposables.add(result);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
};
|
|
return this._event;
|
|
}
|
|
|
|
public fire(event: T): void {
|
|
if (this._disposed) {
|
|
return;
|
|
}
|
|
switch (this._listeners.length) {
|
|
case 0: return;
|
|
case 1: {
|
|
const { fn, thisArgs } = this._listeners[0];
|
|
fn.call(thisArgs, event);
|
|
return;
|
|
}
|
|
default: {
|
|
// Snapshot listeners to allow modifications during iteration (2+ listeners)
|
|
const listeners = this._listeners.slice();
|
|
for (const { fn, thisArgs } of listeners) {
|
|
fn.call(thisArgs, event);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public dispose(): void {
|
|
if (this._disposed) {
|
|
return;
|
|
}
|
|
this._disposed = true;
|
|
this._listeners.length = 0;
|
|
}
|
|
}
|
|
|
|
export namespace EventUtils {
|
|
export function forward<T>(from: IEvent<T>, to: Emitter<T>): IDisposable {
|
|
return from(e => to.fire(e));
|
|
}
|
|
|
|
export function map<I, O>(event: IEvent<I>, map: (i: I) => O): IEvent<O> {
|
|
return (listener: (e: O) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore) => {
|
|
return event(i => listener.call(thisArgs, map(i)), undefined, disposables);
|
|
};
|
|
}
|
|
|
|
export function any<T>(...events: IEvent<T>[]): IEvent<T>;
|
|
export function any(...events: IEvent<any>[]): IEvent<void>;
|
|
export function any<T>(...events: IEvent<T>[]): IEvent<T> {
|
|
return (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore) => {
|
|
const store = new DisposableStore();
|
|
for (const event of events) {
|
|
store.add(event(e => listener.call(thisArgs, e)));
|
|
}
|
|
if (disposables) {
|
|
if (Array.isArray(disposables)) {
|
|
disposables.push(store);
|
|
} else {
|
|
disposables.add(store);
|
|
}
|
|
}
|
|
return store;
|
|
};
|
|
}
|
|
|
|
export function runAndSubscribe<T>(event: IEvent<T>, handler: (e: T) => void, initial: T): IDisposable;
|
|
export function runAndSubscribe<T>(event: IEvent<T>, handler: (e: T | undefined) => void): IDisposable;
|
|
export function runAndSubscribe<T>(event: IEvent<T>, handler: (e: T | undefined) => void, initial?: T): IDisposable {
|
|
handler(initial);
|
|
return event(e => handler(e));
|
|
}
|
|
}
|