@lvce-editor/shared-process 0.0.2

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 (143) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +41 -0
  3. package/bin/sharedProcess.js +3 -0
  4. package/index.js +6 -0
  5. package/package.json +96 -0
  6. package/src/parts/Assert/Assert.js +57 -0
  7. package/src/parts/Callback/Callback.js +48 -0
  8. package/src/parts/ChildProcess/ChildProcess.js +98 -0
  9. package/src/parts/ClipBoard/ClipBoard.ipc.js +7 -0
  10. package/src/parts/ClipBoard/ClipBoard.js +23 -0
  11. package/src/parts/ClipBoard/ClipBoardGnome.js +78 -0
  12. package/src/parts/ClipBoard/ClipBoardNoop.js +14 -0
  13. package/src/parts/ClipBoard/ClipBoardWindows.js +22 -0
  14. package/src/parts/Command/Command.js +264 -0
  15. package/src/parts/Configuration/Configuration.ipc.js +7 -0
  16. package/src/parts/Configuration/Configuration.js +39 -0
  17. package/src/parts/Credentials/Credentials.ipc.js +10 -0
  18. package/src/parts/Credentials/Credentials.js +69 -0
  19. package/src/parts/Debug/Debug.js +3 -0
  20. package/src/parts/Developer/Developer.ipc.js +20 -0
  21. package/src/parts/Developer/Developer.js +132 -0
  22. package/src/parts/Download/Download.js +33 -0
  23. package/src/parts/Electron/Electron.ipc.js +19 -0
  24. package/src/parts/Electron/Electron.js +99 -0
  25. package/src/parts/Env/Env.js +3 -0
  26. package/src/parts/Error/Error.js +30 -0
  27. package/src/parts/ErrorHandling/ErrorHandling.js +40 -0
  28. package/src/parts/Exec/Exec.js +16 -0
  29. package/src/parts/Extension/Extension.js +7 -0
  30. package/src/parts/ExtensionHost/ExtensionHost.ipc.js +80 -0
  31. package/src/parts/ExtensionHost/ExtensionHost.js +163 -0
  32. package/src/parts/ExtensionHost/ExtensionHostBraceCompletion.js +14 -0
  33. package/src/parts/ExtensionHost/ExtensionHostClosingTag.js +14 -0
  34. package/src/parts/ExtensionHost/ExtensionHostColorTheme.js +60 -0
  35. package/src/parts/ExtensionHost/ExtensionHostCommand.js +19 -0
  36. package/src/parts/ExtensionHost/ExtensionHostCompletion.js +12 -0
  37. package/src/parts/ExtensionHost/ExtensionHostDefinition.js +12 -0
  38. package/src/parts/ExtensionHost/ExtensionHostDiagnostic.js +7 -0
  39. package/src/parts/ExtensionHost/ExtensionHostFileSystem.js +23 -0
  40. package/src/parts/ExtensionHost/ExtensionHostFormatting.js +4 -0
  41. package/src/parts/ExtensionHost/ExtensionHostHover.js +12 -0
  42. package/src/parts/ExtensionHost/ExtensionHostIconTheme.js +35 -0
  43. package/src/parts/ExtensionHost/ExtensionHostImplementation.js +12 -0
  44. package/src/parts/ExtensionHost/ExtensionHostKeyBindings.js +23 -0
  45. package/src/parts/ExtensionHost/ExtensionHostLanguages.js +84 -0
  46. package/src/parts/ExtensionHost/ExtensionHostManagement.js +26 -0
  47. package/src/parts/ExtensionHost/ExtensionHostOutput.js +3 -0
  48. package/src/parts/ExtensionHost/ExtensionHostQuickPick.js +6 -0
  49. package/src/parts/ExtensionHost/ExtensionHostReference.js +12 -0
  50. package/src/parts/ExtensionHost/ExtensionHostRename.js +27 -0
  51. package/src/parts/ExtensionHost/ExtensionHostSemanticTokens.js +10 -0
  52. package/src/parts/ExtensionHost/ExtensionHostSourceControl.js +15 -0
  53. package/src/parts/ExtensionHost/ExtensionHostStats.js +3 -0
  54. package/src/parts/ExtensionHost/ExtensionHostStatusBar.js +7 -0
  55. package/src/parts/ExtensionHost/ExtensionHostTabCompletion.js +12 -0
  56. package/src/parts/ExtensionHost/ExtensionHostTextDocument.js +35 -0
  57. package/src/parts/ExtensionHost/ExtensionHostTypeDefinition.js +12 -0
  58. package/src/parts/ExtensionHost/ExtensionHostWorkspace.js +3 -0
  59. package/src/parts/ExtensionManagement/ExtensionManagement.ipc.js +11 -0
  60. package/src/parts/ExtensionManagement/ExtensionManagement.js +319 -0
  61. package/src/parts/FileSystem/FileSystem.ipc.js +32 -0
  62. package/src/parts/FileSystem/FileSystem.js +228 -0
  63. package/src/parts/Git/Git.js +58 -0
  64. package/src/parts/Json/Json.js +67 -0
  65. package/src/parts/JsonFile/JsonFile.js +14 -0
  66. package/src/parts/JsonRpc/JsonRpc.js +22 -0
  67. package/src/parts/Native/Native.ipc.js +6 -0
  68. package/src/parts/Native/Native.js +14 -0
  69. package/src/parts/OutputChannel/OutputChannel.ipc.js +51 -0
  70. package/src/parts/OutputChannel/OutputChannel.js +37 -0
  71. package/src/parts/ParentIpc/ParentIpc.js +203 -0
  72. package/src/parts/Path/Path.js +17 -0
  73. package/src/parts/Platform/Platform.ipc.js +18 -0
  74. package/src/parts/Platform/Platform.js +165 -0
  75. package/src/parts/Preferences/Preferences.ipc.js +6 -0
  76. package/src/parts/Preferences/Preferences.js +75 -0
  77. package/src/parts/PrettyError/PrettyError.js +86 -0
  78. package/src/parts/Process/Process.ipc.js +7 -0
  79. package/src/parts/Process/Process.js +7 -0
  80. package/src/parts/Queue/Queue.js +35 -0
  81. package/src/parts/RequiresSocket/RequiresSocket.js +11 -0
  82. package/src/parts/RgPath/RgPath.js +1 -0
  83. package/src/parts/Root/Root.js +6 -0
  84. package/src/parts/Search/Search.ipc.js +6 -0
  85. package/src/parts/Search/Search.js +101 -0
  86. package/src/parts/SearchFile/SearchFile.ipc.js +6 -0
  87. package/src/parts/SearchFile/SearchFile.js +51 -0
  88. package/src/parts/Socket/Socket.js +132 -0
  89. package/src/parts/Stats/Stats.js +45 -0
  90. package/src/parts/Terminal/Terminal.ipc.js +45 -0
  91. package/src/parts/Terminal/Terminal.js +161 -0
  92. package/src/parts/TextDocument/TextDocument.ipc.js +6 -0
  93. package/src/parts/TextDocument/TextDocument.js +37 -0
  94. package/src/parts/Trace/Trace.js +15 -0
  95. package/src/parts/Trash/Trash.js +11 -0
  96. package/src/parts/WebSocketServer/WebSocketServer.ipc.js +6 -0
  97. package/src/parts/WebSocketServer/WebSocketServer.js +43 -0
  98. package/src/parts/Workspace/Workspace.ipc.js +7 -0
  99. package/src/parts/Workspace/Workspace.js +107 -0
  100. package/src/sharedProcessMain.js +61 -0
  101. package/test/Callback.test.js +42 -0
  102. package/test/ClipBoard.test.js +105 -0
  103. package/test/Credentials.test.js +147 -0
  104. package/test/Developer.test.js +34 -0
  105. package/test/Electron.test.js +93 -0
  106. package/test/Error.test.js +16 -0
  107. package/test/Exec.test.js +25 -0
  108. package/test/ExtensionHost.test.js +127 -0
  109. package/test/ExtensionHostColorTheme.test.js +141 -0
  110. package/test/ExtensionHostCommand.test.js +27 -0
  111. package/test/ExtensionHostCompletion.test.js +45 -0
  112. package/test/ExtensionHostDefinition.test.js +35 -0
  113. package/test/ExtensionHostDiagnostic.test.js +23 -0
  114. package/test/ExtensionHostFileSystem.test.js +91 -0
  115. package/test/ExtensionHostFormatting.test.js +27 -0
  116. package/test/ExtensionHostIconTheme.test.js +73 -0
  117. package/test/ExtensionHostLanguages.test.js +212 -0
  118. package/test/ExtensionHostOutput.test.js +23 -0
  119. package/test/ExtensionHostRename.test.js +59 -0
  120. package/test/ExtensionHostSemanticTokens.test.js +26 -0
  121. package/test/ExtensionHostTabCompletion.test.js +35 -0
  122. package/test/ExtensionHostTextDocument.test.js +61 -0
  123. package/test/ExtensionHostTypeDefinition.test.js +35 -0
  124. package/test/ExtensionHostWorkspace.test.js +21 -0
  125. package/test/ExtensionManagement.test.js +408 -0
  126. package/test/FileSystem.test.js +294 -0
  127. package/test/Json.test.js +25 -0
  128. package/test/Native.test.js +31 -0
  129. package/test/OutputChannel.test.js +68 -0
  130. package/test/Path.test.js +17 -0
  131. package/test/Platform.test.js +61 -0
  132. package/test/Preferences.test.js +140 -0
  133. package/test/Process.test.js +9 -0
  134. package/test/RgPath.test.js +5 -0
  135. package/test/Search.test.js +45 -0
  136. package/test/SearchFile.test.js +80 -0
  137. package/test/Terminal.test.js +53 -0
  138. package/test/Trash.test.js +34 -0
  139. package/test/WebSocketServer.test.js +98 -0
  140. package/test/fixture-search-1/index.html +10 -0
  141. package/test/fixture-search-file-1/fileA +0 -0
  142. package/test/fixture-search-file-1/fileB +0 -0
  143. package/test/fixture-search-file-1/nested/fileC +0 -0
@@ -0,0 +1,294 @@
1
+ import * as fs from 'node:fs'
2
+ import { mkdtemp, writeFile } from 'node:fs/promises'
3
+ import { tmpdir } from 'node:os'
4
+ import { join } from 'node:path'
5
+ import { setTimeout } from 'node:timers/promises'
6
+ import * as FileSystem from '../src/parts/FileSystem/FileSystem.js'
7
+
8
+ const getTmpDir = () => {
9
+ return mkdtemp(join(tmpdir(), 'foo-'))
10
+ }
11
+
12
+ test('copy - file', async () => {
13
+ const tmpDir1 = await getTmpDir()
14
+ const source = join(tmpDir1, 'a.txt')
15
+ await writeFile(source, 'a')
16
+ const tmpDir2 = await getTmpDir()
17
+ const target = join(tmpDir2, 'a.txt')
18
+ await FileSystem.copy(source, target)
19
+ expect(await fs.promises.readFile(target, 'utf-8')).toBe('a')
20
+ })
21
+
22
+ test('copy - error - source does not exist', async () => {
23
+ const tmpDir1 = await getTmpDir()
24
+ const source = join(tmpDir1, 'a.txt')
25
+ const tmpDir2 = await getTmpDir()
26
+ const target = join(tmpDir2, 'a.txt')
27
+ await expect(FileSystem.copy(source, target)).rejects.toThrowError(
28
+ new Error(
29
+ `Failed to copy "${source}" to "${target}": ENOENT: no such file or directory, lstat '${source}'`
30
+ )
31
+ )
32
+ })
33
+
34
+ test('copy - to self', async () => {
35
+ const tmpDir1 = await getTmpDir()
36
+ const source = join(tmpDir1, 'a.txt')
37
+ await writeFile(source, 'a')
38
+ const target = source
39
+ await expect(FileSystem.copy(source, target)).rejects.toThrowError(
40
+ new Error(
41
+ `Failed to copy "${source}" to "${target}": Source and destination must not be the same.`
42
+ )
43
+ )
44
+ })
45
+
46
+ test('createFile', async () => {
47
+ const tmpDir = await getTmpDir()
48
+ const testFile = join(tmpDir, 'a.txt')
49
+ await FileSystem.createFile(testFile)
50
+ expect(await fs.promises.readFile(testFile, 'utf-8')).toBe('')
51
+ })
52
+
53
+ test('createFile - should throw error if file already exists', async () => {
54
+ const tmpDir = await getTmpDir()
55
+ const testFile = join(tmpDir, 'a.txt')
56
+ await fs.promises.writeFile(testFile, 'abc')
57
+ expect(FileSystem.createFile(testFile)).rejects.toThrowError(
58
+ `Failed to create file "${testFile}": EEXIST: file already exists, open '${testFile}'`
59
+ )
60
+ })
61
+
62
+ test('create folder', async () => {
63
+ const tmpDir = await getTmpDir()
64
+ const testFolder = join(tmpDir, 'a')
65
+ await FileSystem.createFolder(testFolder)
66
+ expect(await fs.promises.readdir(tmpDir)).toEqual(['a'])
67
+ })
68
+
69
+ test('create folder - should fail if folder already exists', async () => {
70
+ const tmpDir = await getTmpDir()
71
+ const testFolder = join(tmpDir, 'a')
72
+ await fs.promises.mkdir(testFolder)
73
+ expect(FileSystem.createFolder(testFolder)).rejects.toThrowError(
74
+ `Failed to create folder "${testFolder}": EEXIST: file already exists, mkdir '${testFolder}'`
75
+ )
76
+ })
77
+
78
+ // TODO test recursive create folder
79
+
80
+ test('writeFile', async () => {
81
+ const tmpDir = await getTmpDir()
82
+ const testFile = join(tmpDir, 'writefile.txt')
83
+ expect(await FileSystem.exists(testFile)).toBe(false)
84
+ await FileSystem.writeFile(testFile, 'Hello World')
85
+ expect(await fs.promises.readFile(testFile, 'utf-8')).toBe('Hello World')
86
+ })
87
+
88
+ test('writeFile - nonexistent file', async () => {
89
+ const tmpDir = await getTmpDir()
90
+ const tmpFile = join(tmpDir, 'folder', 'non-existing-file.txt')
91
+ await expect(FileSystem.writeFile(tmpFile, 'Hello World')).rejects.toThrow(
92
+ `Failed to write to file "${tmpFile}": ENOENT`
93
+ )
94
+ })
95
+
96
+ test.skip('writeFile - parallel write on different files works', async () => {
97
+ // queue would be correct but slower
98
+
99
+ const tmpDir = await getTmpDir()
100
+ const testFile1 = join(tmpDir, 'writefile1.txt')
101
+ const testFile2 = join(tmpDir, 'writefile2.txt')
102
+ const testFile3 = join(tmpDir, 'writefile3.txt')
103
+ const testFile4 = join(tmpDir, 'writefile4.txt')
104
+ const testFile5 = join(tmpDir, 'writefile5.txt')
105
+
106
+ await Promise.all([
107
+ FileSystem.writeFile(testFile1, 'Hello World 1'),
108
+ FileSystem.writeFile(testFile2, 'Hello World 2'),
109
+ FileSystem.writeFile(testFile3, 'Hello World 3'),
110
+ FileSystem.writeFile(testFile4, 'Hello World 4'),
111
+ FileSystem.writeFile(testFile5, 'Hello World 5'),
112
+ ])
113
+ expect(fs.readFileSync(testFile1, 'utf-8')).toBe('Hello World 1')
114
+ expect(fs.readFileSync(testFile2, 'utf-8')).toBe('Hello World 2')
115
+ expect(fs.readFileSync(testFile3, 'utf-8')).toBe('Hello World 3')
116
+ expect(fs.readFileSync(testFile4, 'utf-8')).toBe('Hello World 4')
117
+ expect(fs.readFileSync(testFile5, 'utf-8')).toBe('Hello World 5')
118
+ })
119
+
120
+ test.skip('writeFile - parallel write on same files works and is sequentialized', async () => {
121
+ // queue would be correct but slower
122
+
123
+ const tmpDir = await getTmpDir()
124
+ const testFile = join(tmpDir, 'writefile.txt')
125
+ await Promise.all([
126
+ FileSystem.writeFile(testFile, 'Hello World 1'),
127
+ FileSystem.writeFile(testFile, 'Hello World 2'),
128
+ setTimeout(10).then(() => FileSystem.writeFile(testFile, 'Hello World 3')),
129
+ FileSystem.writeFile(testFile, 'Hello World 4'),
130
+ setTimeout(10).then(() => FileSystem.writeFile(testFile, 'Hello World 5')),
131
+ ])
132
+ expect(fs.readFileSync(testFile, 'utf-8')).toBe('Hello World 5')
133
+ })
134
+
135
+ test('writeFile (string, error handling)', async () => {
136
+ const tmpDir = await getTmpDir()
137
+ const testFile = join(tmpDir, 'flushed.txt')
138
+ fs.mkdirSync(testFile) // this will trigger an error later because testFile is now a directory!
139
+ let expectedError
140
+ try {
141
+ await FileSystem.writeFile(testFile, 'Hello World')
142
+ } catch (error) {
143
+ expectedError = error
144
+ }
145
+ expect(expectedError).toBeDefined()
146
+ })
147
+
148
+ test('ensureFile - created parent folders recursively', async () => {
149
+ const tmpDir = await getTmpDir()
150
+ const testFile = join(tmpDir, 'a', 'b', 'c', 'd', 'writefile.txt')
151
+ expect(await FileSystem.exists(testFile)).toBe(false)
152
+ await FileSystem.ensureFile(testFile, 'Hello World')
153
+ expect(await fs.promises.readFile(testFile, 'utf-8')).toBe('Hello World')
154
+ })
155
+
156
+ test('remove', async () => {
157
+ const tmpDir = await getTmpDir()
158
+ const testFile = join(tmpDir, 'file-to-be-removed.txt')
159
+ await fs.promises.writeFile(testFile, '')
160
+ await FileSystem.remove(testFile)
161
+ expect(fs.existsSync(testFile)).toBe(false)
162
+ })
163
+
164
+ test('remove - non-existing file', async () => {
165
+ const tmpDir = await getTmpDir()
166
+ const testFile = join(tmpDir, 'non-existing.txt')
167
+ await FileSystem.remove(testFile)
168
+ })
169
+
170
+ test('rename', async () => {
171
+ const tmpDir = await getTmpDir()
172
+ const oldPath = join(tmpDir, 'file-to-be-moved.txt')
173
+ const newPath = join(tmpDir, 'file-has-been-moved.txt')
174
+ await fs.promises.writeFile(oldPath, '')
175
+ await FileSystem.rename(oldPath, newPath)
176
+ expect(fs.existsSync(oldPath)).toBe(false)
177
+ expect(fs.existsSync(newPath)).toBe(true)
178
+ })
179
+
180
+ test('rename - non existing old path', async () => {
181
+ const tmpDir = await getTmpDir()
182
+ const oldPath = join(tmpDir, 'non-existing.txt')
183
+ const newPath = join(tmpDir, 'file-has-been-moved.txt')
184
+ await expect(FileSystem.rename(oldPath, newPath)).rejects.toThrow(
185
+ `Failed to rename "${oldPath}" to "${newPath}": ENOENT`
186
+ )
187
+ })
188
+
189
+ test('rename - new path in non-existing nested directory', async () => {
190
+ const tmpDir = await getTmpDir()
191
+ const oldPath = join(tmpDir, 'file-to-be-moved.txt')
192
+ const newPath = join(tmpDir, 'nested/nested/nested/file-has-been-moved.txt')
193
+ await fs.promises.writeFile(oldPath, '')
194
+ await expect(FileSystem.rename(oldPath, newPath)).rejects.toThrow(
195
+ `Failed to rename "${oldPath}" to "${newPath}": ENOENT:`
196
+ )
197
+ })
198
+
199
+ const waitForWatcherReady = async (watcher) => {
200
+ await new Promise((resolve) => {
201
+ watcher.once('ready', async () => {
202
+ // try to fix tests on macos through timeout :/
203
+ await setTimeout(100)
204
+ resolve(undefined)
205
+ })
206
+ })
207
+ }
208
+
209
+ // TODO all file watcher tests are very flaky on macos/windows ci
210
+
211
+ test.skip('watch - add', async () => {
212
+ const tmpDir = await getTmpDir()
213
+ const watcher = FileSystem.watch(tmpDir)
214
+ const events = []
215
+ let _resolve
216
+ let i = 0
217
+ await waitForWatcherReady(watcher)
218
+ watcher.on('all', (...args) => {
219
+ events.push([args[0], args[1]])
220
+ i++
221
+ if (i === 2) {
222
+ _resolve()
223
+ }
224
+ })
225
+ const resolvePromise = new Promise((resolve) => {
226
+ _resolve = resolve
227
+ })
228
+ await fs.promises.writeFile(join(tmpDir, 'abc.txt'), 'sample text')
229
+ await fs.promises.writeFile(join(tmpDir, 'def.txt'), 'sample text')
230
+ await resolvePromise
231
+ await setTimeout(1000)
232
+ expect(events).toEqual([
233
+ ['add', join(tmpDir, 'abc.txt')],
234
+ ['add', join(tmpDir, 'def.txt')],
235
+ ])
236
+ watcher.close()
237
+ })
238
+
239
+ test.skip('watch - remove', async () => {
240
+ const tmpDir = await getTmpDir()
241
+ await fs.promises.writeFile(join(tmpDir, 'abc.txt'), 'sample text')
242
+ const watcher = FileSystem.watch(tmpDir)
243
+ const events = []
244
+ let _resolve
245
+ let i = 0
246
+ await waitForWatcherReady(watcher)
247
+ watcher.on('all', (...args) => {
248
+ events.push([args[0], args[1]])
249
+ i++
250
+ if (i === 1) {
251
+ _resolve()
252
+ }
253
+ })
254
+ const resolvePromise = new Promise((resolve) => {
255
+ _resolve = resolve
256
+ })
257
+ await fs.promises.rm(join(tmpDir, 'abc.txt'))
258
+ await resolvePromise
259
+ await setTimeout(1000)
260
+ expect(events).toEqual([['unlink', join(tmpDir, 'abc.txt')]])
261
+ watcher.close()
262
+ })
263
+
264
+ test.skip('watch - rename', async () => {
265
+ const tmpDir = await getTmpDir()
266
+ await fs.promises.writeFile(join(tmpDir, 'abc.txt'), 'sample text')
267
+ const watcher = FileSystem.watch(tmpDir)
268
+ const events = []
269
+ let _resolve
270
+ let i = 0
271
+ await waitForWatcherReady(watcher)
272
+ watcher.on('all', (...args) => {
273
+ events.push([args[0], args[1]])
274
+ i++
275
+ if (i === 2) {
276
+ _resolve()
277
+ }
278
+ })
279
+ const resolvePromise = new Promise((resolve) => {
280
+ _resolve = resolve
281
+ })
282
+ await fs.promises.rename(join(tmpDir, 'abc.txt'), join(tmpDir, 'def.txt'))
283
+ await resolvePromise
284
+ await setTimeout(1000)
285
+ expect(events).toEqual([
286
+ ['add', join(tmpDir, 'def.txt')],
287
+ ['unlink', join(tmpDir, 'abc.txt')],
288
+ ])
289
+ watcher.close()
290
+ })
291
+
292
+ test('getPathSeparator', () => {
293
+ expect(FileSystem.getPathSeparator()).toEqual(expect.any(String))
294
+ })
@@ -0,0 +1,25 @@
1
+ import * as Json from '../src/parts/Json/Json.js'
2
+
3
+ test('parse', async () => {
4
+ expect(await Json.parse('{ "x": 42 }')).toEqual({ x: 42 })
5
+ })
6
+
7
+ test('parse - syntax error', async () => {
8
+ await expect(
9
+ Json.parse('{ "x" 42 }', '/test/some-file.txt')
10
+ ).rejects.toThrowError(
11
+ /^Unexpected number in JSON at position 6 while parsing/
12
+ )
13
+ })
14
+
15
+ test('stringify', () => {
16
+ expect(Json.stringify({ x: 42 })).toBe(`{
17
+ "x": 42
18
+ }
19
+ `)
20
+ })
21
+
22
+ test('stringify - invalid parameter', () => {
23
+ expect(Json.stringify(Symbol('a'))).toBe(`undefined
24
+ `)
25
+ })
@@ -0,0 +1,31 @@
1
+ import { jest } from '@jest/globals'
2
+
3
+ jest.unstable_mockModule('open', () => {
4
+ return {
5
+ default: jest.fn(() => {
6
+ throw new Error('not implemented')
7
+ }),
8
+ }
9
+ })
10
+
11
+ const open = await import('open')
12
+ const Native = await import('../src/parts/Native/Native.js')
13
+
14
+ test('openFolder', async () => {
15
+ // @ts-ignore
16
+ open.default.mockImplementation(() => {})
17
+ await Native.openFolder('/test')
18
+ expect(open.default).toHaveBeenCalledTimes(1)
19
+ expect(open.default).toHaveBeenCalledWith('/test')
20
+ })
21
+
22
+ test('openFolder - error', async () => {
23
+ // @ts-ignore
24
+ open.default.mockImplementation(() => {
25
+ throw new TypeError('x is not a function')
26
+ })
27
+ // TODO should say that is is a TypeError
28
+ await expect(Native.openFolder('/test')).rejects.toThrowError(
29
+ new Error('Failed to open /test: x is not a function')
30
+ )
31
+ })
@@ -0,0 +1,68 @@
1
+ import { createWriteStream } from 'node:fs'
2
+ import * as fs from 'node:fs/promises'
3
+ import { mkdtemp } from 'node:fs/promises'
4
+ import { tmpdir } from 'node:os'
5
+ import { join } from 'node:path'
6
+ import { jest } from '@jest/globals'
7
+ import waitForExpect from 'wait-for-expect'
8
+ import * as OutputChannel from '../src/parts/OutputChannel/OutputChannel.js'
9
+ import * as Platform from '../src/parts/Platform/Platform.js'
10
+
11
+ const getTmpDir = () => {
12
+ return mkdtemp(join(tmpdir(), 'foo-'))
13
+ }
14
+
15
+ if (Platform.isWindows()) {
16
+ test.todo('output channel test')
17
+ } else {
18
+ test('writing to channel via stream', async () => {
19
+ const tmpDir = await getTmpDir()
20
+ await fs.writeFile(join(tmpDir, 'log.txt'), '')
21
+ const onData = jest.fn()
22
+ const state = OutputChannel.open(join(tmpDir, 'log.txt'), onData)
23
+ const writeStream = createWriteStream(join(tmpDir, 'log.txt'))
24
+ writeStream.write('a')
25
+ await waitForExpect(() => {
26
+ expect(onData).toHaveBeenNthCalledWith(1, 'a')
27
+ })
28
+ writeStream.write('b')
29
+ await waitForExpect(() => {
30
+ expect(onData).toHaveBeenNthCalledWith(2, 'b')
31
+ })
32
+ writeStream.write('c')
33
+ writeStream.close()
34
+ await waitForExpect(() => {
35
+ expect(onData).toHaveBeenNthCalledWith(3, 'c')
36
+ })
37
+ OutputChannel.dispose(state)
38
+ })
39
+
40
+ test('writing to channel', async () => {
41
+ const tmpDir = await getTmpDir()
42
+ await fs.writeFile(join(tmpDir, 'log.txt'), '')
43
+ const onData = jest.fn()
44
+ const state = OutputChannel.open(join(tmpDir, 'log.txt'), onData)
45
+ await fs.writeFile(join(tmpDir, 'log.txt'), 'abc\n')
46
+ await waitForExpect(() => {
47
+ expect(onData).toHaveBeenCalledWith('abc\n')
48
+ })
49
+ OutputChannel.dispose(state)
50
+ })
51
+
52
+ test('non-existing file', async () => {
53
+ const tmpDir = await getTmpDir()
54
+ const onData = jest.fn()
55
+ const onError = jest.fn()
56
+ const state = OutputChannel.open(
57
+ join(tmpDir, 'non-existing-file.txt'),
58
+ onData,
59
+ onError
60
+ )
61
+ expect(onError).toHaveBeenCalledWith(
62
+ expect.stringMatching(
63
+ /^Error: ENOENT: no such file or directory, access /
64
+ )
65
+ )
66
+ OutputChannel.dispose(state)
67
+ })
68
+ }
@@ -0,0 +1,17 @@
1
+ import * as Path from '../src/parts/Path/Path.js'
2
+
3
+ test('join', () => {
4
+ if (process.platform === 'win32') {
5
+ expect(Path.join('test', 'my-file.txt')).toBe('test\\my-file.txt')
6
+ } else {
7
+ expect(Path.join('test', 'my-file.txt')).toBe('test/my-file.txt')
8
+ }
9
+ })
10
+
11
+ test('dirname', () => {
12
+ if (process.platform === 'win32') {
13
+ expect(Path.dirname('test\\my-file.txt')).toBe('test')
14
+ } else {
15
+ expect(Path.dirname('test/my-file.txt')).toBe('test')
16
+ }
17
+ })
@@ -0,0 +1,61 @@
1
+ import * as Platform from '../src/parts/Platform/Platform.js'
2
+
3
+ test('isWindows', () => {
4
+ expect(Platform.isWindows()).toEqual(expect.any(Boolean))
5
+ })
6
+
7
+ test('isMacOs', () => {
8
+ expect(Platform.isMacOs()).toEqual(expect.any(Boolean))
9
+ })
10
+
11
+ test('getDataDir', () => {
12
+ expect(Platform.getDataDir()).toEqual(expect.any(String))
13
+ })
14
+
15
+ test('getConfigDir', () => {
16
+ expect(Platform.getConfigDir()).toEqual(expect.any(String))
17
+ })
18
+
19
+ test('getCacheDir', () => {
20
+ expect(Platform.getCacheDir()).toEqual(expect.any(String))
21
+ })
22
+
23
+ test('getHomeDir', () => {
24
+ expect(Platform.getHomeDir()).toEqual(expect.any(String))
25
+ })
26
+
27
+ test('getCachedExtensionsPath', () => {
28
+ expect(Platform.getCachedExtensionsPath()).toEqual(expect.any(String))
29
+ })
30
+
31
+ test('getBuiltinExtensionsPath', () => {
32
+ expect(Platform.getBuiltinExtensionsPath()).toEqual(expect.any(String))
33
+ })
34
+
35
+ test('getDisabledExtensionsPath', () => {
36
+ expect(Platform.getDisabledExtensionsPath()).toEqual(expect.any(String))
37
+ })
38
+
39
+ test('getMarketplaceUrl', () => {
40
+ expect(Platform.getMarketplaceUrl()).toEqual(expect.any(String))
41
+ })
42
+
43
+ test('getDesktop', () => {
44
+ expect(Platform.getDesktop()).toEqual(expect.any(String))
45
+ })
46
+
47
+ test('getPathSeparator', () => {
48
+ expect(Platform.getPathSeparator()).toEqual(expect.any(String))
49
+ })
50
+
51
+ test('getLogsDir', () => {
52
+ expect(Platform.getLogsDir()).toEqual(expect.any(String))
53
+ })
54
+
55
+ test('getUserSettingsPath', () => {
56
+ expect(Platform.getUserSettingsPath()).toEqual(expect.any(String))
57
+ })
58
+
59
+ test('getRecentlyOpenedPath', () => {
60
+ expect(Platform.getRecentlyOpenedPath()).toEqual(expect.any(String))
61
+ })
@@ -0,0 +1,140 @@
1
+ import { mkdtemp, readFile, writeFile, mkdir } from 'node:fs/promises'
2
+ import { tmpdir } from 'node:os'
3
+ import { join } from 'node:path'
4
+ import * as Platform from '../src/parts/Platform/Platform.js'
5
+ import * as Preferences from '../src/parts/Preferences/Preferences.js'
6
+
7
+ const getTmpDir = () => {
8
+ return mkdtemp(join(tmpdir(), 'foo-'))
9
+ }
10
+
11
+ // test.skip('getAll - no preferences exist', async () => {
12
+ // const tmpDir = await getTmpDir()
13
+ // Platform.state.getConfigDir = () => {
14
+ // return tmpDir
15
+ // }
16
+ // expect(await Preferences.getAll()).toEqual({
17
+ // 'editor.fontFamily': "'Fira Code'",
18
+ // 'editor.fontSize': 14,
19
+ // 'extensions.autoUpdate': true,
20
+ // 'workbench.activityBar.visible': true,
21
+ // 'workbench.colorTheme': 'slime',
22
+ // 'workbench.iconTheme': 'vscode-icons',
23
+ // 'workbench.sideBar.visible': true,
24
+ // })
25
+ // })
26
+
27
+ // test('set - no preferences exist', async () => {
28
+ // const tmpDir = await getTmpDir()
29
+ // Platform.state.getConfigDir = () => {
30
+ // return tmpDir
31
+ // }
32
+ // await Preferences.set('sample-key', 'sample-value')
33
+ // expect(await readFile(join(tmpDir, 'settings.json'), 'utf-8')).toBe(`{
34
+ // \"sample-key\": \"sample-value\"
35
+ // }
36
+ // `)
37
+ // })
38
+
39
+ // test('set - no preferences exist in nested folder', async () => {
40
+ // const tmpDir = await getTmpDir()
41
+ // Platform.state.getConfigDir = () => {
42
+ // return join(tmpDir, 'my-app', 'nested')
43
+ // }
44
+ // await Preferences.set('sample-key', 'sample-value')
45
+ // expect(
46
+ // await readFile(join(tmpDir, 'my-app', 'nested', 'settings.json'), 'utf-8')
47
+ // ).toBe(`{
48
+ // \"sample-key\": \"sample-value\"
49
+ // }
50
+ // `)
51
+ // })
52
+
53
+ // test('set - preferences exist', async () => {
54
+ // const tmpDir = await getTmpDir()
55
+ // Platform.state.getConfigDir = () => {
56
+ // return tmpDir
57
+ // }
58
+ // await writeFile(
59
+ // join(tmpDir, 'settings.json'),
60
+ // JSON.stringify({
61
+ // 'key-0': '0',
62
+ // }) + '\n'
63
+ // )
64
+ // await Preferences.set('sample-key', 'sample-value')
65
+ // expect(await readFile(join(tmpDir, 'settings.json'), 'utf-8')).toBe(`{
66
+ // \"key-0\": \"0\",
67
+ // \"sample-key\": \"sample-value\"
68
+ // }
69
+ // `)
70
+ // })
71
+
72
+ // test.skip('set - preferences exist but are invalid json', async () => {
73
+ // const tmpDir = await getTmpDir()
74
+ // Platform.state.getConfigDir = () => {
75
+ // return tmpDir
76
+ // }
77
+ // const settingsPath = join(tmpDir, 'settings.json')
78
+ // await writeFile(settingsPath, `"`)
79
+ // // TODO should handle error gracefully
80
+ // await expect(
81
+ // Preferences.set('sample-key', 'sample-value')
82
+ // ).rejects.toThrowError(
83
+ // new Error(
84
+ // `Unexpected end of JSON input while parsing "\\"" in ${settingsPath}`
85
+ // )
86
+ // )
87
+ // })
88
+
89
+ test('getAll - error', async () => {
90
+ const tmpDir = await getTmpDir()
91
+ Platform.state.getAppDir = () => {
92
+ return tmpDir
93
+ }
94
+ await expect(Preferences.getAll()).rejects.toThrowError(
95
+ /^Failed to get all preferences: Failed to load default preferences: ENOENT/
96
+ )
97
+ })
98
+
99
+ // test('getDefaultPreferences - error', async () => {
100
+ // const tmpDir = await getTmpDir()
101
+ // Platform.state.getAppDir = () => {
102
+ // return tmpDir
103
+ // }
104
+ // await expect(Preferences.getDefaultPreferences()).rejects.toThrowError(
105
+ // /^Failed to load default preferences: ENOENT/
106
+ // )
107
+ // })
108
+
109
+ // test('set - error', async () => {
110
+ // const tmpDir = await getTmpDir()
111
+ // await mkdir(join(tmpDir, 'settings.json'))
112
+ // Platform.state.getConfigDir = () => {
113
+ // return tmpDir
114
+ // }
115
+ // await expect(Preferences.set('x', 42)).rejects.toThrowError(
116
+ // /^Failed to set key in user settings: failed to get user preferences: EISDIR/
117
+ // )
118
+ // })
119
+
120
+ // test('getUserSettingsContent - error', async () => {
121
+ // const tmpDir = await getTmpDir()
122
+ // await mkdir(join(tmpDir, 'settings.json'))
123
+ // Platform.state.getConfigDir = () => {
124
+ // return tmpDir
125
+ // }
126
+ // await expect(Preferences.getUserSettingsContent()).rejects.toThrowError(
127
+ // /^Failed to load user settings: EISDIR/
128
+ // )
129
+ // })
130
+
131
+ // test('setUserSettingsContent - error', async () => {
132
+ // const tmpDir = await getTmpDir()
133
+ // await mkdir(join(tmpDir, 'settings.json'))
134
+ // Platform.state.getConfigDir = () => {
135
+ // return tmpDir
136
+ // }
137
+ // await expect(Preferences.setUserSettingsContent('')).rejects.toThrowError(
138
+ // /^Failed to write to user settings file: EISDIR/
139
+ // )
140
+ // })
@@ -0,0 +1,9 @@
1
+ import * as Process from '../src/parts/Process/Process.js'
2
+
3
+ test('crash', () => {
4
+ expect(Process.crash).toThrow()
5
+ })
6
+
7
+ test('crashAsync', () => {
8
+ expect(Process.crashAsync).rejects.toThrow()
9
+ })
@@ -0,0 +1,5 @@
1
+ import * as RgPath from '../src/parts/RgPath/RgPath.js'
2
+
3
+ test('rgPath', () => {
4
+ expect(RgPath.rgPath).toEqual(expect.any(String))
5
+ })