Skip to content

Commit 19a9ad3

Browse files
authored
Add workspace state to app container (#1902)
1 parent 7004e94 commit 19a9ad3

5 files changed

Lines changed: 84 additions & 0 deletions

File tree

extensions/ql-vscode/src/common/app.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Disposable } from "../pure/disposable-object";
22
import { AppEventEmitter } from "./events";
33
import { Logger } from "./logging";
4+
import { Memento } from "./memento";
45

56
export interface App {
67
createEventEmitter<T>(): AppEventEmitter<T>;
@@ -11,6 +12,7 @@ export interface App {
1112
extensionPath: string;
1213
globalStoragePath: string;
1314
workspaceStoragePath?: string;
15+
workspaceState: Memento;
1416
}
1517

1618
export enum AppMode {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* A memento represents a storage utility. It can store and retrieve
3+
* values.
4+
*
5+
* It is an interface used by the VS Code API. We replicate it here
6+
* to avoid the dependency to the VS Code API.
7+
*/
8+
export interface Memento {
9+
/**
10+
* Returns the stored keys.
11+
*
12+
* @return The stored keys.
13+
*/
14+
keys(): readonly string[];
15+
16+
/**
17+
* Return a value.
18+
*
19+
* @param key A string.
20+
* @return The stored value or `undefined`.
21+
*/
22+
get<T>(key: string): T | undefined;
23+
24+
/**
25+
* Return a value.
26+
*
27+
* @param key A string.
28+
* @param defaultValue A value that should be returned when there is no
29+
* value (`undefined`) with the given key.
30+
* @return The stored value or the defaultValue.
31+
*/
32+
get<T>(key: string, defaultValue: T): T;
33+
34+
/**
35+
* Store a value. The value must be JSON-stringifyable.
36+
*
37+
* *Note* that using `undefined` as value removes the key from the underlying
38+
* storage.
39+
*
40+
* @param key A string.
41+
* @param value A value. MUST not contain cyclic references.
42+
*/
43+
update(key: string, value: any): Thenable<void>;
44+
}

extensions/ql-vscode/src/common/vscode/vscode-app.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Disposable } from "../../pure/disposable-object";
33
import { App, AppMode } from "../app";
44
import { AppEventEmitter } from "../events";
55
import { extLogger, Logger } from "../logging";
6+
import { Memento } from "../memento";
67
import { VSCodeAppEventEmitter } from "./events";
78

89
export class ExtensionApp implements App {
@@ -22,6 +23,10 @@ export class ExtensionApp implements App {
2223
return this.extensionContext.storageUri?.fsPath;
2324
}
2425

26+
public get workspaceState(): Memento {
27+
return this.extensionContext.workspaceState;
28+
}
29+
2530
public get subscriptions(): Disposable[] {
2631
return this.extensionContext.subscriptions;
2732
}

extensions/ql-vscode/test/__mocks__/appMock.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
import { App, AppMode } from "../../src/common/app";
22
import { AppEvent, AppEventEmitter } from "../../src/common/events";
3+
import { Memento } from "../../src/common/memento";
34
import { Disposable } from "../../src/pure/disposable-object";
45
import { createMockLogger } from "./loggerMock";
6+
import { createMockMemento } from "./mementoMock";
57

68
export function createMockApp({
79
extensionPath = "/mock/extension/path",
810
workspaceStoragePath = "/mock/workspace/storage/path",
911
globalStoragePath = "/mock/global/storage/path",
1012
createEventEmitter = <T>() => new MockAppEventEmitter<T>(),
1113
executeCommand = jest.fn(() => Promise.resolve()),
14+
workspaceState = createMockMemento(),
1215
}: {
1316
extensionPath?: string;
1417
workspaceStoragePath?: string;
1518
globalStoragePath?: string;
1619
createEventEmitter?: <T>() => AppEventEmitter<T>;
1720
executeCommand?: () => Promise<void>;
21+
workspaceState?: Memento;
1822
}): App {
1923
return {
2024
mode: AppMode.Test,
@@ -23,6 +27,7 @@ export function createMockApp({
2327
extensionPath,
2428
workspaceStoragePath,
2529
globalStoragePath,
30+
workspaceState,
2631
createEventEmitter,
2732
executeCommand,
2833
};
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Memento } from "../../src/common/memento";
2+
3+
export function createMockMemento(): Memento {
4+
return new MockMemento();
5+
}
6+
7+
export class MockMemento<T> implements Memento {
8+
private readonly map: Map<string, T>;
9+
10+
constructor() {
11+
this.map = new Map<string, T>();
12+
}
13+
14+
public keys(): readonly string[] {
15+
return Array.from(this.map.keys());
16+
}
17+
18+
public get<T>(key: string): T | undefined;
19+
public get<T>(key: string, defaultValue: T): T;
20+
public get(key: any, defaultValue?: any): T | T | undefined {
21+
return this.map.get(key) || defaultValue;
22+
}
23+
24+
public update(key: string, value: any): Thenable<void> {
25+
this.map.set(key, value);
26+
return Promise.resolve();
27+
}
28+
}

0 commit comments

Comments
 (0)