@tui-sandbox/library 11.11.2 → 12.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.
Files changed (92) hide show
  1. package/dist/browser/assets/index-CYUPHpRk.css +1 -0
  2. package/dist/browser/assets/index-DPQpUaDL.js +9 -0
  3. package/dist/browser/index.html +2 -2
  4. package/dist/src/browser/neovim-client.d.ts +2 -0
  5. package/dist/src/browser/neovim-client.js +2 -0
  6. package/dist/src/browser/neovim-client.js.map +1 -1
  7. package/dist/src/client/index.d.ts +1 -0
  8. package/dist/src/client/neovim-terminal-client.d.ts +0 -2
  9. package/dist/src/client/neovim-terminal-client.js +0 -2
  10. package/dist/src/client/neovim-terminal-client.js.map +1 -1
  11. package/dist/src/client/startTerminal.d.ts +0 -2
  12. package/dist/src/client/startTerminal.js +0 -2
  13. package/dist/src/client/startTerminal.js.map +1 -1
  14. package/dist/src/client/terminal-terminal-client.d.ts +0 -1
  15. package/dist/src/client/terminal-terminal-client.js +0 -1
  16. package/dist/src/client/terminal-terminal-client.js.map +1 -1
  17. package/dist/src/server/cypress-support/contents.js +9 -11
  18. package/dist/src/server/cypress-support/contents.js.map +1 -1
  19. package/dist/src/server/index.d.ts +4 -0
  20. package/dist/src/server/index.js.map +1 -1
  21. package/dist/tsconfig.tsbuildinfo +1 -1
  22. package/package.json +34 -8
  23. package/CHANGELOG.md +0 -941
  24. package/dist/browser/assets/index-BQzArJW3.js +0 -9
  25. package/dist/browser/assets/index-hkmOP7rU.css +0 -1
  26. package/index.html +0 -11
  27. package/src/browser/neovim-client.ts +0 -126
  28. package/src/client/MyNeovimConfigModification.test.ts +0 -25
  29. package/src/client/MyNeovimConfigModification.ts +0 -8
  30. package/src/client/color-utilities.test.ts +0 -10
  31. package/src/client/color-utilities.ts +0 -9
  32. package/src/client/cypress-assertions.ts +0 -35
  33. package/src/client/index.ts +0 -4
  34. package/src/client/neovim-terminal-client.ts +0 -130
  35. package/src/client/public/DejaVuSansMNerdFontMono-Regular.ttf +0 -0
  36. package/src/client/startTerminal.ts +0 -97
  37. package/src/client/style.css +0 -32
  38. package/src/client/terminal-config.ts +0 -25
  39. package/src/client/terminal-terminal-client.ts +0 -106
  40. package/src/client/validateMouseEvent.ts +0 -22
  41. package/src/scripts/commands/commandRun.ts +0 -68
  42. package/src/scripts/commands/commandTuiNeovimExec.ts +0 -36
  43. package/src/scripts/commands/commandTuiNeovimPrepare.ts +0 -12
  44. package/src/scripts/commands/commandTuiStart.ts +0 -36
  45. package/src/scripts/parseArguments.test.ts +0 -28
  46. package/src/scripts/parseArguments.ts +0 -66
  47. package/src/scripts/resolveConfig.test.ts +0 -78
  48. package/src/scripts/resolveTuiConfig.ts +0 -65
  49. package/src/scripts/tui.ts +0 -77
  50. package/src/server/TestServer.ts +0 -73
  51. package/src/server/applications/neovim/NeovimApplication.ts +0 -236
  52. package/src/server/applications/neovim/NeovimJavascriptApiClient.test.ts +0 -48
  53. package/src/server/applications/neovim/NeovimJavascriptApiClient.ts +0 -68
  54. package/src/server/applications/neovim/api.ts +0 -257
  55. package/src/server/applications/neovim/environment/TempDirectory.ts +0 -18
  56. package/src/server/applications/neovim/environment/createTempDir.test.ts +0 -29
  57. package/src/server/applications/neovim/environment/createTempDir.ts +0 -91
  58. package/src/server/applications/neovim/neovimRouter.ts +0 -100
  59. package/src/server/applications/neovim/prepareNewTestDirectory.test.ts +0 -32
  60. package/src/server/applications/neovim/prepareNewTestDirectory.ts +0 -21
  61. package/src/server/applications/terminal/TerminalTestApplication.ts +0 -101
  62. package/src/server/applications/terminal/api.ts +0 -89
  63. package/src/server/applications/terminal/runBlockingShellCommand.test.ts +0 -41
  64. package/src/server/applications/terminal/runBlockingShellCommand.ts +0 -64
  65. package/src/server/applications/terminal/terminalRouter.ts +0 -47
  66. package/src/server/blockingCommandInputSchema.test.ts +0 -24
  67. package/src/server/blockingCommandInputSchema.ts +0 -27
  68. package/src/server/config.test.ts +0 -7
  69. package/src/server/config.ts +0 -18
  70. package/src/server/connection/trpc.ts +0 -3
  71. package/src/server/cypress-support/contents.ts +0 -245
  72. package/src/server/cypress-support/createCypressSupportFile.test.ts +0 -69
  73. package/src/server/cypress-support/createCypressSupportFile.ts +0 -56
  74. package/src/server/dirtree/index.test.ts +0 -352
  75. package/src/server/dirtree/index.ts +0 -144
  76. package/src/server/dirtree/json-to-zod.ts +0 -60
  77. package/src/server/index.ts +0 -6
  78. package/src/server/server.ts +0 -34
  79. package/src/server/types.ts +0 -98
  80. package/src/server/updateTestdirectorySchemaFile.test.ts +0 -49
  81. package/src/server/updateTestdirectorySchemaFile.ts +0 -71
  82. package/src/server/utilities/DisposableSingleApplication.test.ts +0 -92
  83. package/src/server/utilities/DisposableSingleApplication.ts +0 -49
  84. package/src/server/utilities/Lazy.ts +0 -16
  85. package/src/server/utilities/TerminalApplication.ts +0 -100
  86. package/src/server/utilities/generator.test.ts +0 -50
  87. package/src/server/utilities/generator.ts +0 -12
  88. package/src/server/utilities/tabId.ts +0 -4
  89. package/src/server/utilities/timeout.ts +0 -3
  90. package/src/server/utilities/timeoutable.ts +0 -19
  91. package/tsconfig.json +0 -31
  92. package/vite.config.js +0 -27
@@ -1,98 +0,0 @@
1
- import type { VimValue } from "neovim/lib/types/VimValue.js"
2
- import * as z from "zod"
3
-
4
- /** Describes the contents of the test directory, which is a blueprint for
5
- * files and directories. Tests can create a unique, safe environment for
6
- * interacting with the contents of such a directory.
7
- *
8
- * Having strong typing for the test directory contents ensures that tests can
9
- * be written with confidence that the files and directories they expect are
10
- * actually found. Otherwise the tests are brittle and can break easily.
11
- */
12
- export type TestDirectory<TContents extends Record<string, unknown> = Record<string, unknown>> = {
13
- /** The path to the unique test directory (the root).
14
- *
15
- * @example /Users/mikavilpas/git/tui-sandbox/packages/integration-tests/test-environment/testdirs/dir-0199UZ
16
- */
17
- rootPathAbsolute: string
18
-
19
- /** The path to the test environment directory, which is the blueprint for
20
- *
21
- * the test directory.
22
- * @example /Users/mikavilpas/git/tui-sandbox/packages/integration-tests/test-environment
23
- * */
24
- testEnvironmentPath: string
25
-
26
- /** The relative path from the {@link testEnvironmentPath} to {@link rootPathAbsolute}.
27
- *
28
- * @example testdirs/dir-0199UZ/
29
- */
30
- testEnvironmentPathRelative: string
31
-
32
- latestEnvironmentSymlink: string
33
-
34
- contents: TContents
35
- }
36
-
37
- export const serverTestDirectorySchema = z.object({
38
- rootPathAbsolute: z.string(),
39
- testEnvironmentPath: z.string(),
40
- testEnvironmentPathRelative: z.string(),
41
- latestEnvironmentSymlink: z.string(),
42
- contents: z.record(z.string(), z.unknown()),
43
- })
44
- export type ServerTestDirectory = z.infer<typeof serverTestDirectorySchema>
45
-
46
- export type TestEnvironmentCommonEnvironmentVariables = {
47
- HOME: string
48
-
49
- /** This is needed so that the application being tested can load its
50
- * configuration, emulating a common setup real users have
51
- */
52
- XDG_CONFIG_HOME: string
53
-
54
- /** The data directory is where the application stores its data. To prevent
55
- * downloading a new set of plugins/whatever for each test, share the data
56
- * directory.
57
- */
58
- XDG_DATA_HOME: string
59
-
60
- /** The path to the test environment directory, which is the blueprint for
61
- * the test directory.
62
- * @example /Users/mikavilpas/git/tui-sandbox/packages/integration-tests/test-environment
63
- * */
64
- TUI_SANDBOX_TEST_ENVIRONMENT_PATH: string
65
- }
66
-
67
- export type { StartNeovimGenericArguments } from "./applications/neovim/NeovimApplication.js"
68
-
69
- export type BlockingShellCommandOutput =
70
- | {
71
- type: "success"
72
- stdout: string
73
- stderr: string
74
- }
75
- | {
76
- type: "failed"
77
- // for now we log the error to the server's console output. It will be
78
- // visible when running the tests.
79
- }
80
-
81
- export type RunLuaCodeOutput = {
82
- value?: VimValue
83
- // to catch errors, use pcall() in the Lua code
84
- }
85
-
86
- export type RunExCommandOutput = { value?: string }
87
-
88
- /**
89
- * Require all of an object's keys to be set explicitly. This is useful for
90
- * readability: writing all the keys makes their presence explicit. They could
91
- * also be added via a spread operator (...obj), but in that case the following
92
- * cases are unclear:
93
- *
94
- * - extra keys might be included because TypeScript does not check for them
95
- * - if the target object type has optional keys, they might be missing. In
96
- * this case, they will never get set
97
- **/
98
- export type AllKeys<T extends Record<never, never>> = Record<keyof T, unknown>
@@ -1,49 +0,0 @@
1
- import { readFileSync, writeFileSync } from "fs"
2
- import type { PartialDeep } from "type-fest"
3
- import { describe, expect, it, vi } from "vitest"
4
- import { buildTestDirectorySchema } from "./dirtree/index.js"
5
- import type { TestServerConfig, UpdateTestdirectorySchemaFileResult } from "./updateTestdirectorySchemaFile.js"
6
- import { updateTestdirectorySchemaFile } from "./updateTestdirectorySchemaFile.js"
7
-
8
- vi.mock("fs")
9
- vi.mock("./dirtree")
10
- vi.spyOn(console, "log").mockImplementation(vi.fn())
11
-
12
- const mock = {
13
- readFileSync: vi.mocked(readFileSync),
14
- writeFileSync: vi.mocked(writeFileSync),
15
- buildTestDirectorySchema: vi.mocked(buildTestDirectorySchema),
16
- }
17
-
18
- describe("when the schema has not changed", () => {
19
- it("does not write the file", async () => {
20
- mock.buildTestDirectorySchema.mockResolvedValue("schema")
21
- mock.readFileSync.mockImplementation(() => "schema")
22
-
23
- const result = await updateTestdirectorySchemaFile({
24
- directories: {
25
- testEnvironmentPath: "path",
26
- outputFilePath: "path",
27
- },
28
- } satisfies PartialDeep<TestServerConfig> as TestServerConfig)
29
-
30
- expect(result).toBe("did-nothing" satisfies UpdateTestdirectorySchemaFileResult)
31
- })
32
- })
33
-
34
- describe("when the schema has changed", () => {
35
- it("writes the file", async () => {
36
- mock.buildTestDirectorySchema.mockResolvedValue("new schema")
37
- mock.readFileSync.mockImplementation(() => "old schema")
38
-
39
- const result = await updateTestdirectorySchemaFile({
40
- directories: {
41
- testEnvironmentPath: "path",
42
- outputFilePath: "path",
43
- },
44
- } satisfies PartialDeep<TestServerConfig> as TestServerConfig)
45
-
46
- expect(result).toBe("updated" satisfies UpdateTestdirectorySchemaFileResult)
47
- expect(mock.writeFileSync).toHaveBeenCalledWith("path", "new schema")
48
- })
49
- })
@@ -1,71 +0,0 @@
1
- import { readFileSync, writeFileSync } from "fs"
2
- import { debuglog } from "util"
3
- import * as z from "zod"
4
- import { buildTestDirectorySchema } from "./dirtree/index.js"
5
-
6
- const log = debuglog(`tui-sandbox.${updateTestdirectorySchemaFile.name}`)
7
-
8
- export type DirectoriesConfig = TestServerConfig["directories"]
9
-
10
- export type TestServerConfig = z.output<typeof testServerConfigSchema>
11
-
12
- export type TestServerConfigMetadata = {
13
- configFilePath: string
14
- config: TestServerConfig
15
- }
16
-
17
- export type Dictionary = Record<string, string>
18
-
19
- export type CustomizeEnv = (env: Dictionary) => Promise<Dictionary>
20
-
21
- export type CustomizeMiseEnvironmentVariables = (
22
- env: Dictionary,
23
- defaultImplementation: CustomizeEnv
24
- ) => Promise<Record<string, string>>
25
-
26
- export type NeovimIntegrationDefaultAppName = "nvim"
27
- const neovimIntegration = z.strictObject({
28
- NVIM_APPNAMEs: z
29
- .array(z.string())
30
- .min(1)
31
- .default(["nvim" satisfies NeovimIntegrationDefaultAppName]),
32
- })
33
-
34
- export type NeovimIntegrationConfig = z.output<typeof neovimIntegration>
35
-
36
- export const testServerConfigSchema = z.strictObject({
37
- directories: z.object({
38
- testEnvironmentPath: z.string(),
39
- outputFilePath: z.string(),
40
- latestSymlinkName: z.string().optional().default("latest"),
41
- }),
42
- port: z.number().int().min(1).max(65535),
43
- integrations: z.strictObject({
44
- neovim: neovimIntegration,
45
- }),
46
- })
47
-
48
- export type UpdateTestdirectorySchemaFileResult = "updated" | "did-nothing"
49
-
50
- export async function updateTestdirectorySchemaFile(
51
- config: TestServerConfig
52
- ): Promise<UpdateTestdirectorySchemaFileResult> {
53
- const newSchema: string = await buildTestDirectorySchema(config)
54
- let oldSchema = ""
55
-
56
- try {
57
- oldSchema = readFileSync(config.directories.outputFilePath, "utf-8")
58
- } catch {
59
- log("No existing schema file found, creating a new one")
60
- }
61
-
62
- if (oldSchema !== newSchema) {
63
- // it's important to not write the file if the schema hasn't changed
64
- // because file watchers will trigger on file changes and we don't want to
65
- // trigger a build if the schema hasn't changed
66
- writeFileSync(config.directories.outputFilePath, newSchema)
67
- return "updated"
68
- } else {
69
- return "did-nothing"
70
- }
71
- }
@@ -1,92 +0,0 @@
1
- import { describe, expect, it, vi } from "vitest"
2
- import type { StartableApplication } from "./DisposableSingleApplication.js"
3
- import { DisposableSingleApplication } from "./DisposableSingleApplication.js"
4
- import type { ExitInfo } from "./TerminalApplication.js"
5
-
6
- vi.spyOn(console, "log").mockImplementation(vi.fn())
7
-
8
- class TestDisposableSingleApplication extends DisposableSingleApplication {
9
- public getApplication() {
10
- return this.application
11
- }
12
- }
13
-
14
- const fakeApp = {
15
- processId: 123,
16
- write: vi.fn(),
17
- killAndWait: vi.fn(),
18
- untilExit: Promise.resolve<ExitInfo>({ exitCode: 0, signal: undefined }),
19
- } satisfies StartableApplication
20
-
21
- describe("DisposableSingleApplication", () => {
22
- it("has no application when created", () => {
23
- const app = new TestDisposableSingleApplication()
24
- expect(app.processId()).toBeUndefined()
25
- expect(app.getApplication()).toBeUndefined()
26
- })
27
-
28
- it("can start an application", async () => {
29
- const app = new TestDisposableSingleApplication()
30
- await app.startNextAndKillCurrent(async () => fakeApp)
31
- expect(app.processId()).toBe(123)
32
- expect(app.getApplication()).toBe(fakeApp)
33
- })
34
-
35
- it("can write to the application", async () => {
36
- const app = new TestDisposableSingleApplication()
37
- await app.startNextAndKillCurrent(async () => fakeApp)
38
- await app.write("hello")
39
- expect(fakeApp.write).toHaveBeenCalledWith("hello")
40
- })
41
-
42
- it("fails to write if the application is not started", async () => {
43
- // there is no need to support soft failing in the ui, so we do hard
44
- // failing to make this error obvious
45
- const app = new TestDisposableSingleApplication()
46
- await expect(app.write("hello")).rejects.toThrowErrorMatchingInlineSnapshot(
47
- `[AssertionError: The application not started yet. It makes no sense to write to it, so this looks like a bug.]`
48
- )
49
- })
50
-
51
- describe("untilExit allows waiting for the application to exit", () => {
52
- it("successful exit works", async () => {
53
- const app = new TestDisposableSingleApplication()
54
- await app.startNextAndKillCurrent(async () => fakeApp)
55
- fakeApp.untilExit = Promise.resolve({ exitCode: 1, signal: 9 })
56
- await expect(app.untilExit()).resolves.toStrictEqual({
57
- exitCode: 1,
58
- signal: 9,
59
- } satisfies ExitInfo)
60
- })
61
-
62
- it("when the application throws an error, the error is propagated", async () => {
63
- const app = new TestDisposableSingleApplication()
64
- await app.startNextAndKillCurrent(async () => fakeApp)
65
- fakeApp.untilExit = Promise.reject(new Error("fake error"))
66
- await expect(app.untilExit()).rejects.toThrowError(new Error("fake error"))
67
- })
68
- })
69
-
70
- describe("disposing", () => {
71
- it("disposes the application when disposed", async () => {
72
- // it's important to make sure there are no dangling applications when
73
- // starting new tests or ending the user session entirely and closing the
74
- // application
75
- const app = new TestDisposableSingleApplication()
76
-
77
- await app.startNextAndKillCurrent(async () => fakeApp)
78
- expect(app.getApplication()).toBe(fakeApp)
79
-
80
- await app[Symbol.asyncDispose]()
81
- expect(fakeApp.killAndWait).toHaveBeenCalledOnce()
82
- })
83
-
84
- it("does nothing if there is no application to dispose", async () => {
85
- const app = new TestDisposableSingleApplication()
86
- expect(app.getApplication()).toBeUndefined()
87
- expect(app.processId()).toBeUndefined()
88
-
89
- expect(() => app[Symbol.asyncDispose]()).not.toThrow()
90
- })
91
- })
92
- })
@@ -1,49 +0,0 @@
1
- import assert from "assert"
2
- import { debuglog } from "util"
3
- import type { ExitInfo, TerminalApplication } from "./TerminalApplication.js"
4
-
5
- export type StartableApplication = Pick<TerminalApplication, "write" | "processId" | "killAndWait" | "untilExit">
6
-
7
- const log = debuglog("tui-sandbox.DisposableSingleApplication")
8
-
9
- /** A testable application that can be started, killed, and given input. For a
10
- * single instance of this interface, only a single instance can be running at
11
- * a time.
12
- */
13
- export class DisposableSingleApplication implements AsyncDisposable {
14
- protected application: StartableApplication | undefined
15
-
16
- public async startNextAndKillCurrent(startNext: () => Promise<StartableApplication>): Promise<void> {
17
- await this[Symbol.asyncDispose]()
18
- this.application = await startNext()
19
- }
20
-
21
- public async untilExit(): Promise<ExitInfo> {
22
- assert(
23
- this.application,
24
- "The application not started yet. It makes no sense to wait for it to exit, so this looks like a bug."
25
- )
26
- return this.application.untilExit
27
- }
28
-
29
- public async write(input: string): Promise<void> {
30
- assert(
31
- this.application,
32
- "The application not started yet. It makes no sense to write to it, so this looks like a bug."
33
- )
34
- this.application.write(input)
35
- }
36
-
37
- public processId(): number | undefined {
38
- return this.application?.processId
39
- }
40
-
41
- /** Kill the current application if it exists. */
42
- public async [Symbol.asyncDispose](): Promise<void> {
43
- if (this.processId() === undefined) {
44
- return
45
- }
46
- log(`Killing current application ${this.processId()}...`)
47
- await this.application?.killAndWait()
48
- }
49
- }
@@ -1,16 +0,0 @@
1
- export class Lazy<T> {
2
- private value?: T
3
-
4
- constructor(private readonly factory: () => T) {}
5
-
6
- get(): T {
7
- if (this.value === undefined) {
8
- this.value = this.factory()
9
- }
10
- return this.value
11
- }
12
-
13
- set(value: T): void {
14
- this.value = value
15
- }
16
- }
@@ -1,100 +0,0 @@
1
- import type winston from "winston"
2
- import { createLogger, format, transports } from "winston"
3
-
4
- import type { ITerminalDimensions } from "@xterm/addon-fit"
5
- import type { IPty } from "node-pty"
6
- import pty from "node-pty"
7
- import { debuglog } from "util"
8
- import type { StartableApplication } from "./DisposableSingleApplication.js"
9
-
10
- const log = debuglog("tui-sandbox.TerminalApplication")
11
-
12
- export type ExitInfo = { exitCode: number; signal: number | undefined }
13
-
14
- // NOTE separating stdout and stderr is not supported by node-pty
15
- // https://github.com/microsoft/node-pty/issues/71
16
- export class TerminalApplication implements StartableApplication {
17
- public readonly processId: number
18
-
19
- public readonly logger: winston.Logger
20
-
21
- private constructor(
22
- private readonly subProcess: IPty,
23
- public readonly onStdoutOrStderr: (data: string) => void,
24
- public readonly untilExit: Promise<ExitInfo>,
25
- public readonly name: string
26
- ) {
27
- this.processId = subProcess.pid
28
-
29
- this.logger = createLogger({
30
- transports: [new transports.Console()],
31
- defaultMeta: { pid: this.processId },
32
- format: format.combine(format.colorize(), format.cli()),
33
- })
34
-
35
- this.logger.debug(`started`)
36
-
37
- subProcess.onExit(({ exitCode, signal }) => {
38
- signal satisfies number | undefined
39
- const msg = `Child process ${this.processId} (${this.name}) exited with code ${String(exitCode)} and signal ${String(signal)}`
40
- this.onStdoutOrStderr(msg)
41
- this.logger.debug(msg)
42
- })
43
- }
44
-
45
- /** @constructor Start a new terminal application. */
46
- public static start({
47
- onStdoutOrStderr,
48
- command,
49
- args,
50
- cwd,
51
- env,
52
- dimensions,
53
- }: {
54
- onStdoutOrStderr: (data: string) => void
55
- command: string
56
- args: string[]
57
- cwd: string
58
- env?: NodeJS.ProcessEnv
59
- dimensions: ITerminalDimensions
60
- }): TerminalApplication {
61
- log(`Starting '${command}' with args '${args.join(" ")}' in cwd '${cwd}'`)
62
-
63
- const ptyProcess = pty.spawn(command, args, {
64
- name: "xterm-color",
65
- cwd,
66
- env,
67
- cols: dimensions.cols,
68
- rows: dimensions.rows,
69
- })
70
- ptyProcess.onData(onStdoutOrStderr)
71
- ptyProcess.onExit(({ exitCode, signal }) => {
72
- log(`Child process exited with code ${exitCode} and signal ${signal}`)
73
- })
74
-
75
- const processId = ptyProcess.pid
76
-
77
- if (!processId) {
78
- throw new Error("Failed to spawn child process")
79
- }
80
- const untilExit = new Promise<ExitInfo>(resolve => {
81
- ptyProcess.onExit(({ exitCode, signal }) => {
82
- // console.log(`Child process ${processId} exited with code ${exitCode} and signal ${signal}`)
83
- resolve({ exitCode, signal })
84
- })
85
- })
86
-
87
- return new TerminalApplication(ptyProcess, onStdoutOrStderr, untilExit, ptyProcess.process satisfies string)
88
- }
89
-
90
- /** Write to the terminal's stdin. */
91
- public write(data: string): void {
92
- this.subProcess.write(data)
93
- }
94
-
95
- public async killAndWait(): Promise<void> {
96
- log(`💣 Killing process ${this.processId}`)
97
- this.subProcess.kill()
98
- log(`💥 Killed process ${this.processId}`)
99
- }
100
- }
@@ -1,50 +0,0 @@
1
- import { EventEmitter } from "stream"
2
- import { describe, expect, it } from "vitest"
3
- import { convertEventEmitterToAsyncGenerator } from "./generator.js"
4
-
5
- describe("when a listener is attached", () => {
6
- it("forwards events from an EventEmitter to an async generator", async () => {
7
- const eventEmitter = new EventEmitter()
8
- const generator = convertEventEmitterToAsyncGenerator(eventEmitter, "test")
9
-
10
- {
11
- const promise = generator.next()
12
- eventEmitter.emit("test", "message")
13
-
14
- expect(await promise).toMatchInlineSnapshot(`
15
- {
16
- "done": false,
17
- "value": "message",
18
- }
19
- `)
20
-
21
- const promise2 = generator.next()
22
- eventEmitter.emit("test", "message2")
23
-
24
- expect(await promise2).toMatchInlineSnapshot(`
25
- {
26
- "done": false,
27
- "value": "message2",
28
- }
29
- `)
30
- }
31
- })
32
- })
33
-
34
- describe("when no listener is attached, messages are lost permanently", () => {
35
- it("does not resend lost events after a subscriber attaches", async () => {
36
- const eventEmitter = new EventEmitter()
37
- eventEmitter.emit("test", "this message should be lost")
38
-
39
- const generator = convertEventEmitterToAsyncGenerator(eventEmitter, "test")
40
- const promise = generator.next()
41
- eventEmitter.emit("test", "new message that will be received")
42
-
43
- expect(await promise).toMatchInlineSnapshot(`
44
- {
45
- "done": false,
46
- "value": "new message that will be received",
47
- }
48
- `)
49
- })
50
- })
@@ -1,12 +0,0 @@
1
- import type EventEmitter from "events"
2
-
3
- export async function* convertEventEmitterToAsyncGenerator(
4
- emitter: EventEmitter,
5
- eventName: string
6
- ): AsyncGenerator<string, void, unknown> {
7
- while (true) {
8
- yield await new Promise(resolve => {
9
- emitter.once(eventName, resolve)
10
- })
11
- }
12
- }
@@ -1,4 +0,0 @@
1
- import * as z from "zod"
2
-
3
- export type TabId = z.infer<typeof tabIdSchema>
4
- export const tabIdSchema = z.object({ tabId: z.string() })
@@ -1,3 +0,0 @@
1
- export function timeout(ms: number): Promise<unknown> {
2
- return new Promise(resolve => setTimeout(resolve, ms))
3
- }
@@ -1,19 +0,0 @@
1
- import assert from "node:assert"
2
-
3
- export async function timeoutable<T>(timeoutMs: number, promise: Promise<T>): Promise<T> {
4
- let timeoutHandle: NodeJS.Timeout
5
-
6
- const timeoutPromise = new Promise<T>((_, reject) => {
7
- timeoutHandle = setTimeout(() => {
8
- reject(new Error(`Operation timed out after ${timeoutMs}ms`))
9
- }, timeoutMs)
10
- })
11
-
12
- try {
13
- return await Promise.race([promise, timeoutPromise])
14
- } finally {
15
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
16
- assert(timeoutHandle!)
17
- clearTimeout(timeoutHandle)
18
- }
19
- }
package/tsconfig.json DELETED
@@ -1,31 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "skipLibCheck": true,
4
- "module": "NodeNext",
5
- "sourceMap": true,
6
- "noImplicitOverride": true,
7
- "noPropertyAccessFromIndexSignature": true,
8
- "noUncheckedIndexedAccess": true,
9
- "moduleResolution": "NodeNext",
10
- "target": "ES2022",
11
- "isolatedModules": true,
12
- "esModuleInterop": true,
13
- "allowJs": true,
14
- "outDir": "dist",
15
- "lib": ["ES2023", "ESNext.Disposable"],
16
- "types": ["node", "cypress"],
17
- "composite": true,
18
-
19
- /* Linting */
20
- "strict": true,
21
- "noUnusedLocals": false,
22
- "noUnusedParameters": true,
23
- "noFallthroughCasesInSwitch": true
24
- },
25
-
26
- "include": [
27
- //
28
- "./src/",
29
- "src/scripts/tui.ts"
30
- ]
31
- }
package/vite.config.js DELETED
@@ -1,27 +0,0 @@
1
- import { defineConfig } from "vite"
2
-
3
- // https://vitejs.dev/config/
4
- export default defineConfig({
5
- server: {
6
- host: "127.0.0.1",
7
- https: false,
8
- strictPort: true,
9
- proxy: {
10
- // inside @tui-sandbox/library, a vite development server can be used. It
11
- // will proxy requests to the backend.
12
- //
13
- // When running in production, the backend starts its own static file
14
- // server that is used (in development, it's just ignored).
15
- "/trpc": "http://localhost:3000",
16
- },
17
- },
18
- build: {
19
- outDir: "./dist/browser/",
20
- },
21
- test: {
22
- exclude: ["node_modules", "dist"],
23
- globals: true, // This will make describe, it, etc. available globally
24
- environment: "node",
25
- mockReset: true,
26
- },
27
- })