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>
99 lines
3.1 KiB
TypeScript
99 lines
3.1 KiB
TypeScript
/**
|
|
* Copyright (c) 2026 The xterm.js authors. All rights reserved.
|
|
* @license MIT
|
|
*/
|
|
|
|
import { assert } from 'chai';
|
|
import { TextBlinkStateManager } from './TextBlinkStateManager';
|
|
import { MockOptionsService } from '../../../common/TestUtils.test';
|
|
import type { ICoreBrowserService } from '../../services/Services';
|
|
import { Emitter } from '../../../common/Event';
|
|
|
|
class FakeWindow {
|
|
public nextId = 1;
|
|
public intervals = new Map<number, () => void>();
|
|
|
|
public setInterval(callback: () => void, _duration: number): number {
|
|
const id = this.nextId++;
|
|
this.intervals.set(id, callback);
|
|
return id;
|
|
}
|
|
|
|
public clearInterval(id: number): void {
|
|
this.intervals.delete(id);
|
|
}
|
|
}
|
|
|
|
function createManager(duration: number): {
|
|
manager: TextBlinkStateManager;
|
|
window: FakeWindow;
|
|
getRenderCount: () => number;
|
|
} {
|
|
const fakeWindow = new FakeWindow();
|
|
let renderCount = 0;
|
|
const coreBrowserService: ICoreBrowserService = {
|
|
serviceBrand: undefined,
|
|
isFocused: true,
|
|
dpr: 1,
|
|
onDprChange: new Emitter<number>().event,
|
|
onWindowChange: new Emitter<Window & typeof globalThis>().event,
|
|
window: fakeWindow as any,
|
|
mainDocument: {} as any
|
|
};
|
|
const optionsService = new MockOptionsService({ blinkIntervalDuration: duration });
|
|
const manager = new TextBlinkStateManager(() => {
|
|
renderCount++;
|
|
}, coreBrowserService, optionsService);
|
|
return {
|
|
manager,
|
|
window: fakeWindow,
|
|
getRenderCount: () => renderCount
|
|
};
|
|
}
|
|
|
|
function getOnlyIntervalCallback(window: FakeWindow): () => void {
|
|
const iterator = window.intervals.values();
|
|
const first = iterator.next();
|
|
assert.ok(!first.done);
|
|
assert.ok(iterator.next().done);
|
|
return first.value;
|
|
}
|
|
|
|
describe('TextBlinkStateManager', () => {
|
|
it('starts interval only when needed', () => {
|
|
const { manager, window } = createManager(100);
|
|
assert.equal(window.intervals.size, 0);
|
|
manager.setNeedsBlinkInViewport(true);
|
|
assert.equal(window.intervals.size, 1);
|
|
});
|
|
|
|
it('stops interval and restores blink visibility when no longer needed', () => {
|
|
const { manager, window, getRenderCount } = createManager(100);
|
|
manager.setNeedsBlinkInViewport(true);
|
|
const tick = getOnlyIntervalCallback(window);
|
|
tick();
|
|
const rendersAfterTick = getRenderCount();
|
|
assert.equal(manager.isBlinkOn, false);
|
|
manager.setNeedsBlinkInViewport(false);
|
|
assert.equal(window.intervals.size, 0);
|
|
assert.equal(manager.isBlinkOn, true);
|
|
assert.equal(getRenderCount(), rendersAfterTick + 1);
|
|
});
|
|
|
|
it('pauses while viewport is hidden and resumes when visible', () => {
|
|
const { manager, window } = createManager(100);
|
|
manager.setNeedsBlinkInViewport(true);
|
|
assert.equal(window.intervals.size, 1);
|
|
manager.setViewportVisible(false);
|
|
assert.equal(window.intervals.size, 0);
|
|
manager.setViewportVisible(true);
|
|
assert.equal(window.intervals.size, 1);
|
|
});
|
|
|
|
it('does not start interval when duration is zero', () => {
|
|
const { manager, window } = createManager(0);
|
|
manager.setNeedsBlinkInViewport(true);
|
|
assert.equal(window.intervals.size, 0);
|
|
});
|
|
});
|