@tui-sandbox/library 6.0.2 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/dist/browser/assets/{index-DJEG76in.js → index-Bup5cvb2.js} +3 -3
- package/dist/browser/index.html +1 -1
- package/dist/src/browser/neovim-client.d.ts +3 -1
- package/dist/src/browser/neovim-client.js +5 -2
- package/dist/src/client/index.d.ts +1 -1
- package/dist/src/client/index.js +1 -1
- package/dist/src/client/terminal-client.d.ts +15 -0
- package/dist/src/client/{neovim-client.js → terminal-client.js} +10 -1
- package/dist/src/server/cypress-support/contents.js +19 -1
- package/dist/src/server/cypress-support/contents.test.js +19 -1
- package/dist/src/server/cypress-support/createCypressSupportFile.js +2 -1
- package/dist/src/server/neovim/NeovimApplication.d.ts +10 -1
- package/dist/src/server/neovim/NeovimApplication.js +15 -12
- package/dist/src/server/neovim/environment/createTempDir.test.js +2 -4
- package/dist/src/server/neovim/index.d.ts +4 -1
- package/dist/src/server/neovim/index.js +34 -0
- package/dist/src/server/server.d.ts +54 -4
- package/dist/src/server/server.js +13 -72
- package/dist/src/server/types.d.ts +7 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/browser/neovim-client.ts +11 -3
- package/src/client/index.ts +1 -1
- package/src/client/{neovim-client.ts → terminal-client.ts} +13 -3
- package/src/server/cypress-support/contents.test.ts +19 -1
- package/src/server/cypress-support/contents.ts +19 -1
- package/src/server/cypress-support/createCypressSupportFile.ts +2 -1
- package/src/server/neovim/NeovimApplication.ts +22 -15
- package/src/server/neovim/environment/createTempDir.test.ts +1 -1
- package/src/server/neovim/index.ts +46 -1
- package/src/server/server.ts +18 -6
- package/src/server/types.ts +12 -0
- package/dist/src/client/neovim-client.d.ts +0 -11
package/dist/browser/index.html
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<title>tui-sandbox integration tests</title>
|
|
6
|
-
<script type="module" crossorigin src="/assets/index-
|
|
6
|
+
<script type="module" crossorigin src="/assets/index-Bup5cvb2.js"></script>
|
|
7
7
|
<link rel="stylesheet" crossorigin href="/assets/index-Bf37MeF1.css">
|
|
8
8
|
</head>
|
|
9
9
|
<body>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BlockingCommandClientInput } from "../server/server.js";
|
|
2
|
+
import type { BlockingShellCommandOutput, StartNeovimGenericArguments, TestDirectory } from "../server/types.js";
|
|
2
3
|
declare global {
|
|
3
4
|
interface Window {
|
|
4
5
|
startNeovim(startArguments?: StartNeovimGenericArguments): Promise<TestDirectory>;
|
|
6
|
+
runBlockingShellCommand(input: BlockingCommandClientInput): Promise<BlockingShellCommandOutput>;
|
|
5
7
|
}
|
|
6
8
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TerminalClient } from "../client/index.js";
|
|
2
2
|
const app = document.querySelector("#app");
|
|
3
3
|
if (!app) {
|
|
4
4
|
throw new Error("No app element found");
|
|
5
5
|
}
|
|
6
|
-
const client = new
|
|
6
|
+
const client = new TerminalClient(app);
|
|
7
7
|
/** Entrypoint for the test runner (cypress) */
|
|
8
8
|
window.startNeovim = async function (startArgs) {
|
|
9
9
|
const testDirectory = await client.startNeovim({
|
|
@@ -13,3 +13,6 @@ window.startNeovim = async function (startArgs) {
|
|
|
13
13
|
});
|
|
14
14
|
return testDirectory;
|
|
15
15
|
};
|
|
16
|
+
window.runBlockingShellCommand = async function (input) {
|
|
17
|
+
return client.runBlockingShellCommand(input);
|
|
18
|
+
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { rgbify } from "./color-utilities.js";
|
|
2
|
-
export {
|
|
2
|
+
export { TerminalClient } from "./terminal-client.js";
|
package/dist/src/client/index.js
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import "@xterm/xterm/css/xterm.css";
|
|
2
|
+
import type { BlockingCommandClientInput } from "../server/server.js";
|
|
3
|
+
import type { BlockingShellCommandOutput, StartNeovimGenericArguments, TestDirectory } from "../server/types.js";
|
|
4
|
+
import "./style.css";
|
|
5
|
+
/** Manages the terminal state in the browser as well as the (browser's)
|
|
6
|
+
* connection to the server side terminal application api. */
|
|
7
|
+
export declare class TerminalClient {
|
|
8
|
+
private readonly ready;
|
|
9
|
+
private readonly tabId;
|
|
10
|
+
private readonly terminal;
|
|
11
|
+
private readonly trpc;
|
|
12
|
+
constructor(app: HTMLElement);
|
|
13
|
+
startNeovim(args: StartNeovimGenericArguments): Promise<TestDirectory>;
|
|
14
|
+
runBlockingShellCommand(input: BlockingCommandClientInput): Promise<BlockingShellCommandOutput>;
|
|
15
|
+
}
|
|
@@ -2,7 +2,9 @@ import { createTRPCClient, httpBatchLink, splitLink, unstable_httpSubscriptionLi
|
|
|
2
2
|
import "@xterm/xterm/css/xterm.css";
|
|
3
3
|
import "./style.css";
|
|
4
4
|
import { getTabId, startTerminal } from "./websocket-client.js";
|
|
5
|
-
|
|
5
|
+
/** Manages the terminal state in the browser as well as the (browser's)
|
|
6
|
+
* connection to the server side terminal application api. */
|
|
7
|
+
export class TerminalClient {
|
|
6
8
|
ready;
|
|
7
9
|
tabId;
|
|
8
10
|
terminal;
|
|
@@ -68,4 +70,11 @@ export class NeovimClient {
|
|
|
68
70
|
});
|
|
69
71
|
return testDirectory;
|
|
70
72
|
}
|
|
73
|
+
async runBlockingShellCommand(input) {
|
|
74
|
+
await this.ready;
|
|
75
|
+
return this.trpc.neovim.runBlockingShellCommand.mutate({
|
|
76
|
+
...input,
|
|
77
|
+
tabId: this.tabId,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
71
80
|
}
|
|
@@ -9,8 +9,12 @@ export async function createCypressSupportFileContents() {
|
|
|
9
9
|
//
|
|
10
10
|
// This file is autogenerated by tui-sandbox. Do not edit it directly.
|
|
11
11
|
//
|
|
12
|
+
import type { BlockingCommandClientInput } from "@tui-sandbox/library/dist/src/server/server"
|
|
13
|
+
import type {
|
|
14
|
+
BlockingShellCommandOutput,
|
|
15
|
+
StartNeovimGenericArguments,
|
|
16
|
+
} from "@tui-sandbox/library/dist/src/server/types"
|
|
12
17
|
import type { OverrideProperties } from "type-fest"
|
|
13
|
-
import type { StartNeovimGenericArguments } from "@tui-sandbox/library/dist/src/server/types"
|
|
14
18
|
import type { MyTestDirectory, MyTestDirectoryFile } from "../../MyTestDirectory"
|
|
15
19
|
|
|
16
20
|
export type NeovimContext = {
|
|
@@ -21,6 +25,7 @@ export type NeovimContext = {
|
|
|
21
25
|
declare global {
|
|
22
26
|
interface Window {
|
|
23
27
|
startNeovim(startArguments?: MyStartNeovimServerArguments): Promise<NeovimContext>
|
|
28
|
+
runBlockingShellCommand(input: BlockingCommandClientInput): Promise<BlockingShellCommandOutput>
|
|
24
29
|
}
|
|
25
30
|
}
|
|
26
31
|
|
|
@@ -39,6 +44,12 @@ Cypress.Commands.add("startNeovim", (startArguments?: MyStartNeovimServerArgumen
|
|
|
39
44
|
})
|
|
40
45
|
})
|
|
41
46
|
|
|
47
|
+
Cypress.Commands.add("runBlockingShellCommand", (input: BlockingCommandClientInput) => {
|
|
48
|
+
cy.window().then(async win => {
|
|
49
|
+
return await win.runBlockingShellCommand(input)
|
|
50
|
+
})
|
|
51
|
+
})
|
|
52
|
+
|
|
42
53
|
Cypress.Commands.add("typeIntoTerminal", (text: string, options?: Partial<Cypress.TypeOptions>) => {
|
|
43
54
|
// the syntax for keys is described here:
|
|
44
55
|
// https://docs.cypress.io/api/commands/type
|
|
@@ -56,7 +67,14 @@ declare global {
|
|
|
56
67
|
namespace Cypress {
|
|
57
68
|
interface Chainable {
|
|
58
69
|
startNeovim(args?: MyStartNeovimServerArguments): Chainable<NeovimContext>
|
|
70
|
+
|
|
71
|
+
/** Types text into the terminal, making the terminal application receive
|
|
72
|
+
* the keystrokes as input. Requires neovim to be running. */
|
|
59
73
|
typeIntoTerminal(text: string, options?: Partial<Cypress.TypeOptions>): Chainable<void>
|
|
74
|
+
|
|
75
|
+
/** Runs a shell command in a blocking manner, waiting for the command to
|
|
76
|
+
* finish before returning. Requires neovim to be running. */
|
|
77
|
+
runBlockingShellCommand(input: BlockingCommandClientInput): Chainable<BlockingShellCommandOutput>
|
|
60
78
|
}
|
|
61
79
|
}
|
|
62
80
|
}
|
|
@@ -6,7 +6,11 @@ it("should return the expected contents", async () => {
|
|
|
6
6
|
//
|
|
7
7
|
// This file is autogenerated by tui-sandbox. Do not edit it directly.
|
|
8
8
|
//
|
|
9
|
-
import type {
|
|
9
|
+
import type { BlockingCommandClientInput } from "@tui-sandbox/library/dist/src/server/server"
|
|
10
|
+
import type {
|
|
11
|
+
BlockingShellCommandOutput,
|
|
12
|
+
StartNeovimGenericArguments,
|
|
13
|
+
} from "@tui-sandbox/library/dist/src/server/types"
|
|
10
14
|
import type { OverrideProperties } from "type-fest"
|
|
11
15
|
import type { MyTestDirectory, MyTestDirectoryFile } from "../../MyTestDirectory"
|
|
12
16
|
|
|
@@ -18,6 +22,7 @@ it("should return the expected contents", async () => {
|
|
|
18
22
|
declare global {
|
|
19
23
|
interface Window {
|
|
20
24
|
startNeovim(startArguments?: MyStartNeovimServerArguments): Promise<NeovimContext>
|
|
25
|
+
runBlockingShellCommand(input: BlockingCommandClientInput): Promise<BlockingShellCommandOutput>
|
|
21
26
|
}
|
|
22
27
|
}
|
|
23
28
|
|
|
@@ -36,6 +41,12 @@ it("should return the expected contents", async () => {
|
|
|
36
41
|
})
|
|
37
42
|
})
|
|
38
43
|
|
|
44
|
+
Cypress.Commands.add("runBlockingShellCommand", (input: BlockingCommandClientInput) => {
|
|
45
|
+
cy.window().then(async win => {
|
|
46
|
+
return await win.runBlockingShellCommand(input)
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
|
|
39
50
|
Cypress.Commands.add("typeIntoTerminal", (text: string, options?: Partial<Cypress.TypeOptions>) => {
|
|
40
51
|
// the syntax for keys is described here:
|
|
41
52
|
// https://docs.cypress.io/api/commands/type
|
|
@@ -53,7 +64,14 @@ it("should return the expected contents", async () => {
|
|
|
53
64
|
namespace Cypress {
|
|
54
65
|
interface Chainable {
|
|
55
66
|
startNeovim(args?: MyStartNeovimServerArguments): Chainable<NeovimContext>
|
|
67
|
+
|
|
68
|
+
/** Types text into the terminal, making the terminal application receive
|
|
69
|
+
* the keystrokes as input. Requires neovim to be running. */
|
|
56
70
|
typeIntoTerminal(text: string, options?: Partial<Cypress.TypeOptions>): Chainable<void>
|
|
71
|
+
|
|
72
|
+
/** Runs a shell command in a blocking manner, waiting for the command to
|
|
73
|
+
* finish before returning. Requires neovim to be running. */
|
|
74
|
+
runBlockingShellCommand(input: BlockingCommandClientInput): Chainable<BlockingShellCommandOutput>
|
|
57
75
|
}
|
|
58
76
|
}
|
|
59
77
|
}
|
|
@@ -14,12 +14,13 @@ export async function createCypressSupportFile({ cypressSupportDirectoryPath, su
|
|
|
14
14
|
oldSchema = readFileSync(outputFilePath, "utf-8");
|
|
15
15
|
}
|
|
16
16
|
catch (error) {
|
|
17
|
-
console.log(`No existing cypress support file found at ${outputFilePath}
|
|
17
|
+
console.log(`No existing cypress support file found at ${outputFilePath}`);
|
|
18
18
|
}
|
|
19
19
|
if (oldSchema !== text) {
|
|
20
20
|
// it's important to not write the file if the schema hasn't changed
|
|
21
21
|
// because file watchers will trigger on file changes and we don't want to
|
|
22
22
|
// trigger a build if the schema hasn't changed
|
|
23
|
+
console.log(`🪛 Writing cypress support file to ${outputFilePath}`);
|
|
23
24
|
writeFileSync(outputFilePath, text);
|
|
24
25
|
return "updated";
|
|
25
26
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import EventEmitter from "events";
|
|
2
|
+
import type { NeovimClient as NeovimApiClient } from "neovim";
|
|
2
3
|
import type { TestDirectory } from "../types.js";
|
|
3
4
|
import { DisposableSingleApplication } from "../utilities/DisposableSingleApplication.js";
|
|
5
|
+
import type { Lazy } from "../utilities/Lazy.js";
|
|
4
6
|
export type StdoutMessage = "stdout";
|
|
5
7
|
export type StartNeovimGenericArguments = {
|
|
6
8
|
filename: string | {
|
|
@@ -15,15 +17,22 @@ export type TerminalDimensions = {
|
|
|
15
17
|
cols: number;
|
|
16
18
|
rows: number;
|
|
17
19
|
};
|
|
20
|
+
type ResettableState = {
|
|
21
|
+
testDirectory: TestDirectory;
|
|
22
|
+
socketPath: string;
|
|
23
|
+
client: Lazy<Promise<NeovimApiClient>>;
|
|
24
|
+
};
|
|
18
25
|
export declare class NeovimApplication {
|
|
19
26
|
private readonly testEnvironmentPath;
|
|
20
27
|
readonly application: DisposableSingleApplication;
|
|
21
|
-
|
|
28
|
+
state: ResettableState | undefined;
|
|
22
29
|
readonly events: EventEmitter;
|
|
23
30
|
constructor(testEnvironmentPath: string, application?: DisposableSingleApplication);
|
|
24
31
|
/**
|
|
25
32
|
* Kill the current application and start a new one with the given arguments.
|
|
26
33
|
*/
|
|
27
34
|
startNextAndKillCurrent(testDirectory: TestDirectory, startArgs: StartNeovimGenericArguments, terminalDimensions: TerminalDimensions): Promise<void>;
|
|
35
|
+
getEnvironmentVariables(testDirectory: TestDirectory, additionalEnvironmentVariables?: Record<string, string>): NodeJS.ProcessEnv;
|
|
28
36
|
[Symbol.asyncDispose](): Promise<void>;
|
|
29
37
|
}
|
|
38
|
+
export {};
|
|
@@ -53,18 +53,7 @@ export class NeovimApplication {
|
|
|
53
53
|
neovimArguments.push("--listen", socketPath);
|
|
54
54
|
const stdout = this.events;
|
|
55
55
|
await this.application.startNextAndKillCurrent(async () => {
|
|
56
|
-
const env =
|
|
57
|
-
...process.env,
|
|
58
|
-
HOME: testDirectory.rootPathAbsolute,
|
|
59
|
-
// this is needed so that neovim can load its configuration, emulating
|
|
60
|
-
// a common setup real neovim users have
|
|
61
|
-
XDG_CONFIG_HOME: join(testDirectory.rootPathAbsolute, ".config"),
|
|
62
|
-
// the data directory is where lazy.nvim stores its plugins. To prevent
|
|
63
|
-
// downloading a new set of plugins for each test, share the data
|
|
64
|
-
// directory.
|
|
65
|
-
XDG_DATA_HOME: join(testDirectory.testEnvironmentPath, ".repro", "data"),
|
|
66
|
-
...startArgs.additionalEnvironmentVariables,
|
|
67
|
-
};
|
|
56
|
+
const env = this.getEnvironmentVariables(testDirectory, startArgs.additionalEnvironmentVariables);
|
|
68
57
|
return TerminalApplication.start({
|
|
69
58
|
command: "nvim",
|
|
70
59
|
args: neovimArguments,
|
|
@@ -86,6 +75,20 @@ export class NeovimApplication {
|
|
|
86
75
|
};
|
|
87
76
|
console.log(`🚀 Started Neovim instance ${processId}`);
|
|
88
77
|
}
|
|
78
|
+
getEnvironmentVariables(testDirectory, additionalEnvironmentVariables) {
|
|
79
|
+
return {
|
|
80
|
+
...process.env,
|
|
81
|
+
HOME: testDirectory.rootPathAbsolute,
|
|
82
|
+
// this is needed so that neovim can load its configuration, emulating
|
|
83
|
+
// a common setup real neovim users have
|
|
84
|
+
XDG_CONFIG_HOME: join(testDirectory.rootPathAbsolute, ".config"),
|
|
85
|
+
// the data directory is where lazy.nvim stores its plugins. To prevent
|
|
86
|
+
// downloading a new set of plugins for each test, share the data
|
|
87
|
+
// directory.
|
|
88
|
+
XDG_DATA_HOME: join(testDirectory.testEnvironmentPath, ".repro", "data"),
|
|
89
|
+
...additionalEnvironmentVariables,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
89
92
|
async [Symbol.asyncDispose]() {
|
|
90
93
|
await this.application[Symbol.asyncDispose]();
|
|
91
94
|
if (!this.state)
|
|
@@ -72,7 +72,7 @@ it("should create a temp dir with no contents", async () => {
|
|
|
72
72
|
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
73
73
|
try {
|
|
74
74
|
// typically the user will want to have contents, but this should not be an error
|
|
75
|
-
const dir = __addDisposableResource(env_1, TempDirectory.create(),
|
|
75
|
+
const dir = __addDisposableResource(env_1, TempDirectory.create(), false);
|
|
76
76
|
const result = await createTempDir({
|
|
77
77
|
testEnvironmentPath: dir.path,
|
|
78
78
|
outputFilePath: nodePath.join(dir.path, "MyTestDirectory.ts"),
|
|
@@ -87,8 +87,6 @@ it("should create a temp dir with no contents", async () => {
|
|
|
87
87
|
env_1.hasError = true;
|
|
88
88
|
}
|
|
89
89
|
finally {
|
|
90
|
-
|
|
91
|
-
if (result_1)
|
|
92
|
-
await result_1;
|
|
90
|
+
__disposeResources(env_1);
|
|
93
91
|
}
|
|
94
92
|
});
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "core-js/proposals/async-explicit-resource-management.js";
|
|
2
|
+
import type { BlockingCommandInput } from "../server.js";
|
|
3
|
+
import type { BlockingShellCommandOutput, StartNeovimGenericArguments, TestDirectory } from "../types.js";
|
|
2
4
|
import type { TestServerConfig } from "../updateTestdirectorySchemaFile.js";
|
|
3
5
|
import type { TabId } from "../utilities/tabId.js";
|
|
4
6
|
import type { TerminalDimensions } from "./NeovimApplication.js";
|
|
@@ -10,3 +12,4 @@ export declare function sendStdin(options: {
|
|
|
10
12
|
tabId: TabId;
|
|
11
13
|
data: string;
|
|
12
14
|
}): Promise<void>;
|
|
15
|
+
export declare function runBlockingShellCommand(signal: AbortSignal | undefined, input: BlockingCommandInput): Promise<BlockingShellCommandOutput>;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import assert from "assert";
|
|
2
|
+
import { exec } from "child_process";
|
|
3
|
+
import "core-js/proposals/async-explicit-resource-management.js";
|
|
4
|
+
import util from "util";
|
|
2
5
|
import { convertEventEmitterToAsyncGenerator } from "../utilities/generator.js";
|
|
3
6
|
import { createTempDir, removeTestDirectories } from "./environment/createTempDir.js";
|
|
4
7
|
import { NeovimApplication } from "./NeovimApplication.js";
|
|
@@ -33,3 +36,34 @@ export async function sendStdin(options) {
|
|
|
33
36
|
assert(neovim.application, `Neovim application not found for client id ${options.tabId.tabId}. Maybe it's not started yet?`);
|
|
34
37
|
await neovim.application.write(options.data);
|
|
35
38
|
}
|
|
39
|
+
export async function runBlockingShellCommand(signal, input) {
|
|
40
|
+
const neovim = neovims.get(input.tabId.tabId);
|
|
41
|
+
assert(neovim !== undefined, `Neovim instance for clientId not found - cannot run blocking shell command. Maybe neovim's not started yet?`);
|
|
42
|
+
const testDirectory = neovim.state?.testDirectory;
|
|
43
|
+
assert(testDirectory, `Test directory not found for client id ${input.tabId.tabId}. Maybe neovim's not started yet?`);
|
|
44
|
+
const execPromise = util.promisify(exec);
|
|
45
|
+
const env = neovim.getEnvironmentVariables(testDirectory, input.envOverrides);
|
|
46
|
+
const processPromise = execPromise(input.command, {
|
|
47
|
+
signal: signal,
|
|
48
|
+
shell: input.shell,
|
|
49
|
+
uid: input.uid,
|
|
50
|
+
gid: input.gid,
|
|
51
|
+
cwd: input.cwd ?? env["HOME"],
|
|
52
|
+
env,
|
|
53
|
+
});
|
|
54
|
+
try {
|
|
55
|
+
const result = await processPromise;
|
|
56
|
+
console.log(`Successfully ran shell blockingCommand (${input.command}) with stdout: ${result.stdout}, stderr: ${result.stderr}`);
|
|
57
|
+
return {
|
|
58
|
+
type: "success",
|
|
59
|
+
stdout: result.stdout,
|
|
60
|
+
stderr: result.stderr,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
console.warn(`Error running shell blockingCommand (${input.command})`, e);
|
|
65
|
+
return {
|
|
66
|
+
type: "failed",
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -1,11 +1,46 @@
|
|
|
1
1
|
import type { inferRouterInputs } from "@trpc/server";
|
|
2
2
|
import "core-js/proposals/async-explicit-resource-management.js";
|
|
3
|
+
import type { Except } from "type-fest";
|
|
4
|
+
import { z } from "zod";
|
|
3
5
|
import { TestServer } from "./TestServer.js";
|
|
4
6
|
import type { TestServerConfig } from "./updateTestdirectorySchemaFile.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
declare const blockingCommandInputSchema: z.ZodObject<{
|
|
8
|
+
command: z.ZodString;
|
|
9
|
+
shell: z.ZodOptional<z.ZodString>;
|
|
10
|
+
tabId: z.ZodObject<{
|
|
11
|
+
tabId: z.ZodString;
|
|
12
|
+
}, "strip", z.ZodTypeAny, {
|
|
13
|
+
tabId: string;
|
|
14
|
+
}, {
|
|
15
|
+
tabId: string;
|
|
16
|
+
}>;
|
|
17
|
+
uid: z.ZodOptional<z.ZodNumber>;
|
|
18
|
+
gid: z.ZodOptional<z.ZodNumber>;
|
|
19
|
+
cwd: z.ZodOptional<z.ZodString>;
|
|
20
|
+
envOverrides: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
21
|
+
}, "strip", z.ZodTypeAny, {
|
|
22
|
+
command: string;
|
|
23
|
+
tabId: {
|
|
24
|
+
tabId: string;
|
|
25
|
+
};
|
|
26
|
+
cwd?: string | undefined;
|
|
27
|
+
uid?: number | undefined;
|
|
28
|
+
gid?: number | undefined;
|
|
29
|
+
shell?: string | undefined;
|
|
30
|
+
envOverrides?: Record<string, string> | undefined;
|
|
31
|
+
}, {
|
|
32
|
+
command: string;
|
|
33
|
+
tabId: {
|
|
34
|
+
tabId: string;
|
|
35
|
+
};
|
|
36
|
+
cwd?: string | undefined;
|
|
37
|
+
uid?: number | undefined;
|
|
38
|
+
gid?: number | undefined;
|
|
39
|
+
shell?: string | undefined;
|
|
40
|
+
envOverrides?: Record<string, string> | undefined;
|
|
41
|
+
}>;
|
|
42
|
+
export type BlockingCommandClientInput = Except<BlockingCommandInput, "tabId">;
|
|
43
|
+
export type BlockingCommandInput = z.infer<typeof blockingCommandInputSchema>;
|
|
9
44
|
/** @private */
|
|
10
45
|
export declare function createAppRouter(config: TestServerConfig): Promise<import("@trpc/server/unstable-core-do-not-import").BuiltRouter<{
|
|
11
46
|
ctx: object;
|
|
@@ -55,8 +90,23 @@ export declare function createAppRouter(config: TestServerConfig): Promise<impor
|
|
|
55
90
|
};
|
|
56
91
|
output: void;
|
|
57
92
|
}>;
|
|
93
|
+
runBlockingShellCommand: import("@trpc/server").TRPCMutationProcedure<{
|
|
94
|
+
input: {
|
|
95
|
+
command: string;
|
|
96
|
+
tabId: {
|
|
97
|
+
tabId: string;
|
|
98
|
+
};
|
|
99
|
+
cwd?: string | undefined;
|
|
100
|
+
uid?: number | undefined;
|
|
101
|
+
gid?: number | undefined;
|
|
102
|
+
shell?: string | undefined;
|
|
103
|
+
envOverrides?: Record<string, string> | undefined;
|
|
104
|
+
};
|
|
105
|
+
output: import("./types.js").BlockingShellCommandOutput;
|
|
106
|
+
}>;
|
|
58
107
|
}>;
|
|
59
108
|
}>>>;
|
|
60
109
|
export type AppRouter = Awaited<ReturnType<typeof createAppRouter>>;
|
|
61
110
|
export type RouterInput = inferRouterInputs<AppRouter>;
|
|
62
111
|
export declare function startTestServer(config: TestServerConfig): Promise<TestServer>;
|
|
112
|
+
export {};
|
|
@@ -1,55 +1,3 @@
|
|
|
1
|
-
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
2
|
-
if (value !== null && value !== void 0) {
|
|
3
|
-
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
4
|
-
var dispose, inner;
|
|
5
|
-
if (async) {
|
|
6
|
-
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
7
|
-
dispose = value[Symbol.asyncDispose];
|
|
8
|
-
}
|
|
9
|
-
if (dispose === void 0) {
|
|
10
|
-
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
11
|
-
dispose = value[Symbol.dispose];
|
|
12
|
-
if (async) inner = dispose;
|
|
13
|
-
}
|
|
14
|
-
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
15
|
-
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
16
|
-
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
17
|
-
}
|
|
18
|
-
else if (async) {
|
|
19
|
-
env.stack.push({ async: true });
|
|
20
|
-
}
|
|
21
|
-
return value;
|
|
22
|
-
};
|
|
23
|
-
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
24
|
-
return function (env) {
|
|
25
|
-
function fail(e) {
|
|
26
|
-
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
27
|
-
env.hasError = true;
|
|
28
|
-
}
|
|
29
|
-
var r, s = 0;
|
|
30
|
-
function next() {
|
|
31
|
-
while (r = env.stack.pop()) {
|
|
32
|
-
try {
|
|
33
|
-
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
34
|
-
if (r.dispose) {
|
|
35
|
-
var result = r.dispose.call(r.value);
|
|
36
|
-
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
37
|
-
}
|
|
38
|
-
else s |= 1;
|
|
39
|
-
}
|
|
40
|
-
catch (e) {
|
|
41
|
-
fail(e);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
45
|
-
if (env.hasError) throw env.error;
|
|
46
|
-
}
|
|
47
|
-
return next();
|
|
48
|
-
};
|
|
49
|
-
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
50
|
-
var e = new Error(message);
|
|
51
|
-
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
|
-
});
|
|
53
1
|
import "core-js/proposals/async-explicit-resource-management.js";
|
|
54
2
|
import { z } from "zod";
|
|
55
3
|
import { trpc } from "./connection/trpc.js";
|
|
@@ -57,7 +5,16 @@ import * as neovim from "./neovim/index.js";
|
|
|
57
5
|
import { TestServer } from "./TestServer.js";
|
|
58
6
|
import { applicationAvailable } from "./utilities/applicationAvailable.js";
|
|
59
7
|
import { tabIdSchema } from "./utilities/tabId.js";
|
|
60
|
-
|
|
8
|
+
const blockingCommandInputSchema = z.object({
|
|
9
|
+
command: z.string(),
|
|
10
|
+
shell: z.string().optional(),
|
|
11
|
+
tabId: tabIdSchema,
|
|
12
|
+
// child_process.ProcessEnvOptions
|
|
13
|
+
uid: z.number().optional(),
|
|
14
|
+
gid: z.number().optional(),
|
|
15
|
+
cwd: z.string().optional(),
|
|
16
|
+
envOverrides: z.record(z.string()).optional(),
|
|
17
|
+
});
|
|
61
18
|
/** @private */
|
|
62
19
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
63
20
|
export async function createAppRouter(config) {
|
|
@@ -93,6 +50,9 @@ export async function createAppRouter(config) {
|
|
|
93
50
|
sendStdin: trpc.procedure.input(z.object({ tabId: tabIdSchema, data: z.string() })).mutation(options => {
|
|
94
51
|
return neovim.sendStdin(options.input);
|
|
95
52
|
}),
|
|
53
|
+
runBlockingShellCommand: trpc.procedure.input(blockingCommandInputSchema).mutation(async (options) => {
|
|
54
|
+
return neovim.runBlockingShellCommand(options.signal, options.input);
|
|
55
|
+
}),
|
|
96
56
|
}),
|
|
97
57
|
});
|
|
98
58
|
return appRouter;
|
|
@@ -105,22 +65,3 @@ export async function startTestServer(config) {
|
|
|
105
65
|
await testServer.startAndRun(appRouter);
|
|
106
66
|
return testServer;
|
|
107
67
|
}
|
|
108
|
-
var autocleanup;
|
|
109
|
-
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
110
|
-
try {
|
|
111
|
-
/** Stack for managing resources that need to be disposed of when the server
|
|
112
|
-
* shuts down */
|
|
113
|
-
autocleanup = __addDisposableResource(env_1, new AsyncDisposableStack(), true);
|
|
114
|
-
autocleanup.defer(() => {
|
|
115
|
-
console.log("Closing any open test applications");
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
catch (e_1) {
|
|
119
|
-
env_1.error = e_1;
|
|
120
|
-
env_1.hasError = true;
|
|
121
|
-
}
|
|
122
|
-
finally {
|
|
123
|
-
const result_1 = __disposeResources(env_1);
|
|
124
|
-
if (result_1)
|
|
125
|
-
await result_1;
|
|
126
|
-
}
|
|
@@ -26,3 +26,10 @@ export type TestDirectory = {
|
|
|
26
26
|
contents: object;
|
|
27
27
|
};
|
|
28
28
|
export type { StartNeovimGenericArguments } from "../server/neovim/NeovimApplication.js";
|
|
29
|
+
export type BlockingShellCommandOutput = {
|
|
30
|
+
type: "success";
|
|
31
|
+
stdout: string;
|
|
32
|
+
stderr: string;
|
|
33
|
+
} | {
|
|
34
|
+
type: "failed";
|
|
35
|
+
};
|