use branded types for external types

This commit is contained in:
Peter Fajdiga
2024-09-29 20:16:16 +02:00
parent 93fe2a3cfd
commit 2081b9997c
12 changed files with 54 additions and 13 deletions

View File

@@ -1,8 +1,12 @@
type KWin = {
__brand: "KWin";
readConfig(key: string, defaultValue: any): any;
};
type Workspace = {
__brand: "Workspace";
readonly activities: string[];
readonly desktops: KwinDesktop[];
readonly currentDesktop: KwinDesktop;
@@ -44,10 +48,12 @@ const enum MaximizedMode {
Maximized,
}
type Tile = unknown;
type Output = unknown;
type Tile = { __brand: "Tile" };
type Output = { __brand: "Output" };
type KwinClient = {
__brand: "KwinClient";
readonly shadeable: boolean;
readonly caption: string;
readonly minSize: Readonly<QmlSize>;
@@ -77,7 +83,7 @@ type KwinClient = {
minimized: boolean;
frameGeometry: QmlRect;
desktops: KwinDesktop[]; // empty array means all desktops
tile: Tile;
tile: Tile|null;
opacity: number;
readonly fullScreenChanged: QSignal<[]>;
@@ -95,10 +101,12 @@ type KwinClient = {
};
type KwinDesktop = {
__brand: "KwinDesktop";
readonly id: string;
};
type ShortcutHandler = {
type ShortcutHandler = QmlObject & {
readonly activated: QSignal<[]>;
destroy(): void;
};

View File

@@ -1,3 +1,3 @@
type Notification = {
type Notification = QmlObject & {
sendEvent(): void;
};

16
src/lib/extern/qt.ts vendored
View File

@@ -1,21 +1,29 @@
type Console = {
__brand: "Console";
log(...args: any[]): void;
assert(assertion: boolean, message?: string): void;
};
type Qt = {
__brand: "Qt";
rect(x: number, y: number, width: number, height: number): QmlRect;
createQmlObject(qml: string, parent: QmlObject): QmlObject;
};
type QmlObject = unknown;
type QmlObject = { __brand: "QmlObject" };
type QmlPoint = {
__brand: "QmlPoint";
x: number;
y: number;
};
type QmlRect = {
__brand: "QmlRect";
x: number;
y: number;
width: number;
@@ -27,16 +35,20 @@ type QmlRect = {
};
type QmlSize = {
__brand: "QmlSize";
width: number;
height: number;
};
type QSignal<T extends unknown[]> = {
__brand: "QSignal";
connect(handler: (...args: [...T]) => void): void;
disconnect(handler: (...args: [...T]) => void): void;
};
type QmlTimer = {
type QmlTimer = QmlObject & {
interval: number;
readonly triggered: QSignal<[]>;
restart(): void;

View File

@@ -1,4 +1,6 @@
class MockKwinClient {
public readonly __brand = "KwinClient";
private static readonly borderThickness = 10;
public readonly shadeable: boolean = false;
@@ -10,7 +12,7 @@ class MockKwinClient {
public readonly resizeable: boolean = true;
public readonly fullScreenable: boolean = true;
public readonly maximizable: boolean = true;
public readonly output: Output = false;
public readonly output: Output = { __brand: "Output" };
public readonly dock: boolean = false;
public readonly normalWindow: boolean = true;
public readonly managed: boolean = true;
@@ -24,7 +26,7 @@ class MockKwinClient {
public shade: boolean = false;
public minimized: boolean = false;
public desktops: KwinDesktop[] = [];
public tile: Tile = false;
public tile: Tile|null = null;
public opacity: number = 1.0;
public readonly fullScreenChanged = new MockQSignal();

View File

@@ -1,4 +1,6 @@
class MockQSignal<T extends unknown[]> {
public readonly __brand = "QSignal";
private readonly handlers: Set<(...args: [...T]) => void> = new Set();
public connect(handler: (...args: [...T]) => void) {

View File

@@ -1,4 +1,6 @@
class MockQmlPoint {
public readonly __brand = "QmlPoint";
constructor(
public x: number,
public y: number,

View File

@@ -1,4 +1,6 @@
class MockQmlRect {
public readonly __brand = "QmlRect";
constructor(
private _x: number,
private _y: number,

View File

@@ -1,4 +1,6 @@
class MockQmlSize {
public readonly __brand = "QmlSize";
constructor(
public width: number,
public height: number,

View File

@@ -1,4 +1,6 @@
class MockQmlTimer {
public readonly __brand = "QmlObject";
public interval = 0;
public readonly triggered = new MockQSignal();

View File

@@ -1,4 +1,6 @@
class MockQt {
public readonly __brand = "Qt";
private shortcuts = new Map<string, MockShortcutHandler>();
public point(x: number, y: number) {
@@ -9,7 +11,7 @@ class MockQt {
return new MockQmlRect(x, y, width, height);
}
public createQmlObject(qml: string, parent: QmlObject) {
public createQmlObject(qml: string, parent: QmlObject): QmlObject {
if (qml.includes("Timer")) {
return new MockQmlTimer();
} else if (qml.includes("ShortcutHandler")) {
@@ -18,7 +20,7 @@ class MockQt {
this.shortcuts.set(shortcutName, shortcutHandler);
return shortcutHandler;
} else {
assert(false, "Unexpected qml string: " + qml);
throw new Error("Unexpected qml string: " + qml);
}
}

View File

@@ -1,4 +1,6 @@
class MockShortcutHandler {
public readonly __brand = "QmlObject";
public readonly activated: MockQSignal<[]> = new MockQSignal();
public destroy() {}

View File

@@ -1,9 +1,14 @@
class MockWorkspace {
public readonly __brand = "Workspace";
public activities = ["test-activity"];
public desktops = [{id: "desktop1"}, {id: "desktop2"}];
public desktops: KwinDesktop[] = [
{ __brand: "KwinDesktop", id: "desktop1" },
{ __brand: "KwinDesktop", id: "desktop2" }
];
public currentDesktop = this.desktops[0];
public currentActivity = this.activities[0];
public activeScreen = {};
public activeScreen: Output = { __brand: "Output" };
public windows = [];
public cursorPos = new MockQmlPoint(0, 0);