@lvce-editor/shared-process 0.0.2 → 0.0.6
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/config/builtinCommands.json +367 -0
- package/config/colorTheme.json +98 -0
- package/config/defaultKeyBindings.json +649 -0
- package/config/defaultSettings.json +17 -0
- package/extensions/builtin.theme-slime/README.md +5 -0
- package/extensions/builtin.theme-slime/color-theme.json +205 -0
- package/extensions/builtin.theme-slime/extension.json +13 -0
- package/extensions/builtin.theme-slime/icon.png +0 -0
- package/package.json +3 -3
- package/src/parts/Env/Env.js +1 -1
- package/src/parts/Platform/Platform.js +7 -0
- package/src/parts/Preferences/Preferences.js +3 -6
- package/src/parts/Root/Root.js +1 -1
- package/test/Callback.test.js +0 -42
- package/test/ClipBoard.test.js +0 -105
- package/test/Credentials.test.js +0 -147
- package/test/Developer.test.js +0 -34
- package/test/Electron.test.js +0 -93
- package/test/Error.test.js +0 -16
- package/test/Exec.test.js +0 -25
- package/test/ExtensionHost.test.js +0 -127
- package/test/ExtensionHostColorTheme.test.js +0 -141
- package/test/ExtensionHostCommand.test.js +0 -27
- package/test/ExtensionHostCompletion.test.js +0 -45
- package/test/ExtensionHostDefinition.test.js +0 -35
- package/test/ExtensionHostDiagnostic.test.js +0 -23
- package/test/ExtensionHostFileSystem.test.js +0 -91
- package/test/ExtensionHostFormatting.test.js +0 -27
- package/test/ExtensionHostIconTheme.test.js +0 -73
- package/test/ExtensionHostLanguages.test.js +0 -212
- package/test/ExtensionHostOutput.test.js +0 -23
- package/test/ExtensionHostRename.test.js +0 -59
- package/test/ExtensionHostSemanticTokens.test.js +0 -26
- package/test/ExtensionHostTabCompletion.test.js +0 -35
- package/test/ExtensionHostTextDocument.test.js +0 -61
- package/test/ExtensionHostTypeDefinition.test.js +0 -35
- package/test/ExtensionHostWorkspace.test.js +0 -21
- package/test/ExtensionManagement.test.js +0 -408
- package/test/FileSystem.test.js +0 -294
- package/test/Json.test.js +0 -25
- package/test/Native.test.js +0 -31
- package/test/OutputChannel.test.js +0 -68
- package/test/Path.test.js +0 -17
- package/test/Platform.test.js +0 -61
- package/test/Preferences.test.js +0 -140
- package/test/Process.test.js +0 -9
- package/test/RgPath.test.js +0 -5
- package/test/Search.test.js +0 -45
- package/test/SearchFile.test.js +0 -80
- package/test/Terminal.test.js +0 -53
- package/test/Trash.test.js +0 -34
- package/test/WebSocketServer.test.js +0 -98
- package/test/fixture-search-1/index.html +0 -10
- package/test/fixture-search-file-1/fileA +0 -0
- package/test/fixture-search-file-1/fileB +0 -0
- package/test/fixture-search-file-1/nested/fileC +0 -0
|
@@ -1,408 +0,0 @@
|
|
|
1
|
-
import { createReadStream, createWriteStream } from 'node:fs'
|
|
2
|
-
import {
|
|
3
|
-
access,
|
|
4
|
-
mkdir,
|
|
5
|
-
mkdtemp,
|
|
6
|
-
readdir,
|
|
7
|
-
readFile,
|
|
8
|
-
rm,
|
|
9
|
-
writeFile,
|
|
10
|
-
} from 'node:fs/promises'
|
|
11
|
-
import http from 'node:http'
|
|
12
|
-
import { tmpdir } from 'node:os'
|
|
13
|
-
import { dirname, join } from 'node:path'
|
|
14
|
-
import { pipeline } from 'node:stream/promises'
|
|
15
|
-
import { constants, createBrotliCompress } from 'node:zlib'
|
|
16
|
-
import getPort from 'get-port'
|
|
17
|
-
import { jest } from '@jest/globals'
|
|
18
|
-
import tar from 'tar-fs'
|
|
19
|
-
import VError from 'verror'
|
|
20
|
-
import * as ExtensionManagement from '../src/parts/ExtensionManagement/ExtensionManagement.js'
|
|
21
|
-
import * as Platform from '../src/parts/Platform/Platform.js'
|
|
22
|
-
|
|
23
|
-
const getTmpDir = () => {
|
|
24
|
-
return mkdtemp(join(tmpdir(), 'foo-'))
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const exists = async (path) => {
|
|
28
|
-
try {
|
|
29
|
-
await access(path)
|
|
30
|
-
return true
|
|
31
|
-
} catch {
|
|
32
|
-
return false
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* @param {string} inDir
|
|
38
|
-
* @param {string} outFile
|
|
39
|
-
*/
|
|
40
|
-
export const compress = async (inDir, outFile) => {
|
|
41
|
-
await mkdir(dirname(outFile), { recursive: true })
|
|
42
|
-
await pipeline(
|
|
43
|
-
tar.pack(inDir),
|
|
44
|
-
createBrotliCompress({
|
|
45
|
-
params: {
|
|
46
|
-
[constants.BROTLI_PARAM_QUALITY]: constants.BROTLI_MIN_QUALITY,
|
|
47
|
-
},
|
|
48
|
-
}),
|
|
49
|
-
createWriteStream(outFile)
|
|
50
|
-
)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const createExtensionTarBr = async (files) => {
|
|
54
|
-
const folder = '/tmp/extension-test/test-author.test-extension'
|
|
55
|
-
await rm(folder, { force: true, recursive: true })
|
|
56
|
-
await mkdir(folder, { recursive: true })
|
|
57
|
-
for (const [filePath, content] of Object.entries(files)) {
|
|
58
|
-
await writeFile(`${folder}/${filePath}`, content)
|
|
59
|
-
}
|
|
60
|
-
await compress(folder, `${folder}.tar.br`)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
let server
|
|
64
|
-
let handler
|
|
65
|
-
|
|
66
|
-
beforeAll(async () => {
|
|
67
|
-
const port = await getPort()
|
|
68
|
-
server = http.createServer((request, response) => {
|
|
69
|
-
handler(request, response)
|
|
70
|
-
})
|
|
71
|
-
await new Promise((resolve) => {
|
|
72
|
-
server.listen(port, () => {
|
|
73
|
-
resolve(undefined)
|
|
74
|
-
})
|
|
75
|
-
})
|
|
76
|
-
process.env.LVCE_MARKETPLACE_URL = `http://localhost:${port}`
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
afterAll(() => {
|
|
80
|
-
server.close()
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
afterEach(() => {
|
|
84
|
-
jest.restoreAllMocks()
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
// TODO this test is flaky sometimes: Jest has detected the following 1 open handle potentially keeping Jest from exiting: ● JSSTREAM
|
|
88
|
-
test.skip('install', async () => {
|
|
89
|
-
await createExtensionTarBr({
|
|
90
|
-
'extension.json': `{
|
|
91
|
-
"id": "test-author.test-extension",
|
|
92
|
-
"name": "test-extension",
|
|
93
|
-
"publisher": "test-author",
|
|
94
|
-
"version": "0.0.1",
|
|
95
|
-
"main": "main.js"
|
|
96
|
-
}
|
|
97
|
-
`,
|
|
98
|
-
'main.js': 'export const activate = () => { console.info("hello world") }',
|
|
99
|
-
'package.json': '{ "type" : "module" }',
|
|
100
|
-
})
|
|
101
|
-
handler = async (request, response) => {
|
|
102
|
-
switch (request.url) {
|
|
103
|
-
case '/download/test-author.test-extension':
|
|
104
|
-
response.statusCode = 200
|
|
105
|
-
await pipeline(
|
|
106
|
-
createReadStream(
|
|
107
|
-
'/tmp/extension-test/test-author.test-extension.tar.br'
|
|
108
|
-
),
|
|
109
|
-
response
|
|
110
|
-
)
|
|
111
|
-
break
|
|
112
|
-
default:
|
|
113
|
-
response.statusCode = 404
|
|
114
|
-
response.end()
|
|
115
|
-
break
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
const tmpDir = await getTmpDir()
|
|
119
|
-
Platform.state.getExtensionsPath = () => tmpDir
|
|
120
|
-
await ExtensionManagement.install('test-author.test-extension')
|
|
121
|
-
expect(
|
|
122
|
-
await readFile(
|
|
123
|
-
join(tmpDir, 'test-author.test-extension/extension.json'),
|
|
124
|
-
'utf-8'
|
|
125
|
-
)
|
|
126
|
-
).toBe(`{
|
|
127
|
-
"id": "test-author.test-extension",
|
|
128
|
-
"name": "test-extension",
|
|
129
|
-
"publisher": "test-author",
|
|
130
|
-
"version": "0.0.1",
|
|
131
|
-
"main": "main.js"
|
|
132
|
-
}
|
|
133
|
-
`)
|
|
134
|
-
expect(
|
|
135
|
-
await readFile(join(tmpDir, 'test-author.test-extension/main.js'), 'utf-8')
|
|
136
|
-
).toBe('export const activate = () => { console.info("hello world") }')
|
|
137
|
-
expect(
|
|
138
|
-
await readFile(
|
|
139
|
-
join(tmpDir, 'test-author.test-extension/package.json'),
|
|
140
|
-
'utf-8'
|
|
141
|
-
)
|
|
142
|
-
).toBe('{ "type" : "module" }')
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
test('install should fail when the server sends a bad status code', async () => {
|
|
146
|
-
handler = (request, response) => {
|
|
147
|
-
switch (request.url) {
|
|
148
|
-
default:
|
|
149
|
-
response.statusCode = 404
|
|
150
|
-
return response.end()
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
const tmpDir = await getTmpDir()
|
|
154
|
-
Platform.state.getExtensionsPath = () => tmpDir
|
|
155
|
-
await expect(
|
|
156
|
-
ExtensionManagement.install('test-author.test-extension')
|
|
157
|
-
).rejects.toThrowError(
|
|
158
|
-
/Failed to install extension "test-author.test-extension": Failed to download "http:\/\/localhost:\d+\/download\/test-author.test-extension": Response code 404 \(Not Found\)/
|
|
159
|
-
)
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
test('install should fail when the server sends an invalid compressed object', async () => {
|
|
163
|
-
// TODO avoid side effect in tests, use createServer
|
|
164
|
-
handler = (request, res) => {
|
|
165
|
-
switch (request.url) {
|
|
166
|
-
case '/download/test-author.test-extension':
|
|
167
|
-
res.statusCode = 200
|
|
168
|
-
return res.end('abc')
|
|
169
|
-
default:
|
|
170
|
-
res.statusCode = 404
|
|
171
|
-
return res.end()
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
const tmpDir = await getTmpDir()
|
|
175
|
-
Platform.state.getExtensionsPath = () => tmpDir
|
|
176
|
-
await expect(
|
|
177
|
-
ExtensionManagement.install('test-author.test-extension')
|
|
178
|
-
).rejects.toThrowError(
|
|
179
|
-
/^Failed to install extension "test-author.test-extension": unexpected end of file/
|
|
180
|
-
)
|
|
181
|
-
})
|
|
182
|
-
|
|
183
|
-
test('uninstall', async () => {
|
|
184
|
-
const tmpDir = await getTmpDir()
|
|
185
|
-
Platform.state.getExtensionsPath = () => tmpDir
|
|
186
|
-
await mkdir(join(tmpDir, 'test-author.test-extension'))
|
|
187
|
-
expect(await exists(join(tmpDir, 'test-author.test-extension'))).toBe(true)
|
|
188
|
-
await ExtensionManagement.uninstall('test-author.test-extension')
|
|
189
|
-
expect(await exists(join(tmpDir, 'test-author.test-extension'))).toBe(false)
|
|
190
|
-
})
|
|
191
|
-
|
|
192
|
-
test("uninstall should fail when extension doesn't exist", async () => {
|
|
193
|
-
const tmpDir = await getTmpDir()
|
|
194
|
-
Platform.state.getExtensionsPath = () => tmpDir
|
|
195
|
-
await expect(
|
|
196
|
-
ExtensionManagement.uninstall('test-author.test-extension')
|
|
197
|
-
).rejects.toThrowError(
|
|
198
|
-
/^Failed to uninstall extension "test-author.test-extension": ENOENT: no such file or directory/
|
|
199
|
-
)
|
|
200
|
-
})
|
|
201
|
-
|
|
202
|
-
// TODO test for extension main not found (extension host)
|
|
203
|
-
|
|
204
|
-
// TODO test for extension json not found (extension host)
|
|
205
|
-
|
|
206
|
-
// TODO test for extension code import fails (extension host)
|
|
207
|
-
// TODO test for extension activation fails (in extension host)
|
|
208
|
-
// TODO test for extension deactivation fails (in extension host)
|
|
209
|
-
// TODO test for global unhandlederror/unhandledrejection (in extension host)
|
|
210
|
-
|
|
211
|
-
test('getAllExtensions', async () => {
|
|
212
|
-
const tmpDir1 = await getTmpDir()
|
|
213
|
-
const manifestPath1 = join(tmpDir1, 'test-extension', 'extension.json')
|
|
214
|
-
await mkdir(dirname(manifestPath1))
|
|
215
|
-
await writeFile(manifestPath1, JSON.stringify({ id: 'test-extension' }))
|
|
216
|
-
const tmpDir2 = await getTmpDir()
|
|
217
|
-
const manifestPath2 = join(tmpDir2, 'builtin-extension', 'extension.json')
|
|
218
|
-
await mkdir(dirname(manifestPath2))
|
|
219
|
-
await writeFile(manifestPath2, JSON.stringify({ id: 'builtin-extension' }))
|
|
220
|
-
const tmpDir3 = await getTmpDir()
|
|
221
|
-
Platform.state.getExtensionsPath = () => tmpDir1
|
|
222
|
-
Platform.state.getBuiltinExtensionsPath = () => tmpDir2
|
|
223
|
-
Platform.state.getDisabledExtensionsPath = () => tmpDir3
|
|
224
|
-
expect(await ExtensionManagement.getAllExtensions()).toEqual([
|
|
225
|
-
{
|
|
226
|
-
status: 'fulfilled',
|
|
227
|
-
id: 'builtin-extension',
|
|
228
|
-
path: join(tmpDir2, 'builtin-extension'),
|
|
229
|
-
},
|
|
230
|
-
{
|
|
231
|
-
status: 'fulfilled',
|
|
232
|
-
id: 'test-extension',
|
|
233
|
-
path: join(tmpDir1, 'test-extension'),
|
|
234
|
-
},
|
|
235
|
-
])
|
|
236
|
-
})
|
|
237
|
-
|
|
238
|
-
test('getAllExtensions - invalid extension.json', async () => {
|
|
239
|
-
const spy = jest.spyOn(console, 'warn').mockImplementation(() => {})
|
|
240
|
-
const tmpDir1 = await getTmpDir()
|
|
241
|
-
const manifestPath = join(tmpDir1, 'test-extension', 'extension.json')
|
|
242
|
-
await mkdir(dirname(manifestPath))
|
|
243
|
-
await writeFile(manifestPath, '{invalid json}')
|
|
244
|
-
const tmpDir2 = await getTmpDir()
|
|
245
|
-
const tmpDir3 = await getTmpDir()
|
|
246
|
-
Platform.state.getExtensionsPath = () => tmpDir1
|
|
247
|
-
Platform.state.getBuiltinExtensionsPath = () => tmpDir2
|
|
248
|
-
Platform.state.getDisabledExtensionsPath = () => tmpDir3
|
|
249
|
-
expect(await ExtensionManagement.getAllExtensions()).toEqual([
|
|
250
|
-
{
|
|
251
|
-
path: join(tmpDir1, 'test-extension'),
|
|
252
|
-
reason: new VError(
|
|
253
|
-
'Failed to load extension "test-extension": Failed to load extension manifest: JSON parsing error:'
|
|
254
|
-
),
|
|
255
|
-
status: 'rejected',
|
|
256
|
-
},
|
|
257
|
-
])
|
|
258
|
-
})
|
|
259
|
-
|
|
260
|
-
test('disable', async () => {
|
|
261
|
-
const tmpDir1 = await getTmpDir()
|
|
262
|
-
const tmpDir2 = await getTmpDir()
|
|
263
|
-
await mkdir(join(tmpDir1, 'test-extension'))
|
|
264
|
-
await writeFile(join(tmpDir1, 'test-extension', 'extension.json'), '{}')
|
|
265
|
-
Platform.state.getExtensionsPath = () => tmpDir1
|
|
266
|
-
Platform.state.getDisabledExtensionsPath = () => tmpDir2
|
|
267
|
-
await ExtensionManagement.disable('test-extension')
|
|
268
|
-
expect(await readdir(tmpDir1)).toEqual([])
|
|
269
|
-
expect(await readdir(tmpDir2)).toEqual(['test-extension'])
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
test('disable should fail if enabled extension path does not exist', async () => {
|
|
273
|
-
const tmpDir1 = await getTmpDir()
|
|
274
|
-
const tmpDir2 = await getTmpDir()
|
|
275
|
-
await mkdir(join(tmpDir1, 'test-extension'))
|
|
276
|
-
await writeFile(join(tmpDir1, 'test-extension', 'extension.json'), '{}')
|
|
277
|
-
Platform.state.getExtensionsPath = () => tmpDir1
|
|
278
|
-
Platform.state.getDisabledExtensionsPath = () => tmpDir2
|
|
279
|
-
const nonExistentPath1 = join(tmpDir1, 'non-existent-extension')
|
|
280
|
-
const nonExistentPath2 = join(tmpDir2, 'non-existent-extension')
|
|
281
|
-
await expect(
|
|
282
|
-
ExtensionManagement.disable('non-existent-extension')
|
|
283
|
-
).rejects.toThrowError(
|
|
284
|
-
`Failed to disable extension non-existent-extension: ENOENT: no such file or directory, rename '${nonExistentPath1}' -> '${nonExistentPath2}'`
|
|
285
|
-
)
|
|
286
|
-
})
|
|
287
|
-
|
|
288
|
-
test('getExtensions - empty object', async () => {
|
|
289
|
-
const tmpDir1 = await getTmpDir()
|
|
290
|
-
const tmpDir2 = await getTmpDir()
|
|
291
|
-
await mkdir(join(tmpDir1, 'test-extension-1'))
|
|
292
|
-
await writeFile(join(tmpDir1, 'test-extension-1', 'extension.json'), '{}')
|
|
293
|
-
Platform.state.getBuiltinExtensionsPath = () => tmpDir1
|
|
294
|
-
Platform.state.getExtensionsPath = () => tmpDir2
|
|
295
|
-
expect(await ExtensionManagement.getExtensions()).toEqual([
|
|
296
|
-
{
|
|
297
|
-
status: 'fulfilled',
|
|
298
|
-
path: join(tmpDir1, '/test-extension-1'),
|
|
299
|
-
},
|
|
300
|
-
])
|
|
301
|
-
})
|
|
302
|
-
|
|
303
|
-
test.skip('getExtensions - error - invalid value - empty array', async () => {
|
|
304
|
-
const tmpDir1 = await getTmpDir()
|
|
305
|
-
const tmpDir2 = await getTmpDir()
|
|
306
|
-
await mkdir(join(tmpDir1, 'test-extension-1'))
|
|
307
|
-
await writeFile(join(tmpDir1, 'test-extension-1', 'extension.json'), '[]')
|
|
308
|
-
Platform.state.getBuiltinExtensionsPath = () => tmpDir1
|
|
309
|
-
Platform.state.getExtensionsPath = () => tmpDir2
|
|
310
|
-
expect(await ExtensionManagement.getExtensions()).toEqual([
|
|
311
|
-
{
|
|
312
|
-
status: 'fulfilled',
|
|
313
|
-
|
|
314
|
-
path: join(tmpDir1, 'test-extension-1'),
|
|
315
|
-
},
|
|
316
|
-
])
|
|
317
|
-
})
|
|
318
|
-
|
|
319
|
-
test('getExtensions - error - invalid value - null', async () => {
|
|
320
|
-
const tmpDir1 = await getTmpDir()
|
|
321
|
-
const tmpDir2 = await getTmpDir()
|
|
322
|
-
await mkdir(join(tmpDir1, 'test-extension-1'))
|
|
323
|
-
await writeFile(join(tmpDir1, 'test-extension-1', 'extension.json'), 'null')
|
|
324
|
-
Platform.state.getBuiltinExtensionsPath = () => tmpDir1
|
|
325
|
-
Platform.state.getExtensionsPath = () => tmpDir2
|
|
326
|
-
expect(await ExtensionManagement.getExtensions()).toEqual([
|
|
327
|
-
{
|
|
328
|
-
status: 'rejected',
|
|
329
|
-
reason: new VError(
|
|
330
|
-
'Failed to load extension "test-extension-1": Failed to load extension manifest: Invalid manifest file: Not an JSON object.'
|
|
331
|
-
),
|
|
332
|
-
path: join(tmpDir1, 'test-extension-1'),
|
|
333
|
-
},
|
|
334
|
-
])
|
|
335
|
-
})
|
|
336
|
-
|
|
337
|
-
test('getExtensions - error - invalid value - string', async () => {
|
|
338
|
-
const tmpDir1 = await getTmpDir()
|
|
339
|
-
const tmpDir2 = await getTmpDir()
|
|
340
|
-
await mkdir(join(tmpDir1, 'test-extension-1'))
|
|
341
|
-
await writeFile(join(tmpDir1, 'test-extension-1', 'extension.json'), '""')
|
|
342
|
-
Platform.state.getBuiltinExtensionsPath = () => tmpDir1
|
|
343
|
-
Platform.state.getExtensionsPath = () => tmpDir2
|
|
344
|
-
expect(await ExtensionManagement.getExtensions()).toEqual([
|
|
345
|
-
{
|
|
346
|
-
status: 'rejected',
|
|
347
|
-
reason: new VError(
|
|
348
|
-
'Failed to load extension "test-extension-1": Failed to load extension manifest: Invalid manifest file: Not an JSON object.'
|
|
349
|
-
),
|
|
350
|
-
path: join(tmpDir1, 'test-extension-1'),
|
|
351
|
-
},
|
|
352
|
-
])
|
|
353
|
-
})
|
|
354
|
-
|
|
355
|
-
test('getExtensions - error - invalid value - number', async () => {
|
|
356
|
-
const tmpDir1 = await getTmpDir()
|
|
357
|
-
const tmpDir2 = await getTmpDir()
|
|
358
|
-
await mkdir(join(tmpDir1, 'test-extension-1'))
|
|
359
|
-
await writeFile(join(tmpDir1, 'test-extension-1', 'extension.json'), '42')
|
|
360
|
-
Platform.state.getBuiltinExtensionsPath = () => tmpDir1
|
|
361
|
-
Platform.state.getExtensionsPath = () => tmpDir2
|
|
362
|
-
expect(await ExtensionManagement.getExtensions()).toEqual([
|
|
363
|
-
{
|
|
364
|
-
status: 'rejected',
|
|
365
|
-
reason: new VError(
|
|
366
|
-
'Failed to load extension "test-extension-1": Failed to load extension manifest: Invalid manifest file: Not an JSON object.'
|
|
367
|
-
),
|
|
368
|
-
path: join(tmpDir1, 'test-extension-1'),
|
|
369
|
-
},
|
|
370
|
-
])
|
|
371
|
-
})
|
|
372
|
-
|
|
373
|
-
test('getExtensions - error - invalid value - boolean', async () => {
|
|
374
|
-
const tmpDir1 = await getTmpDir()
|
|
375
|
-
const tmpDir2 = await getTmpDir()
|
|
376
|
-
await mkdir(join(tmpDir1, 'test-extension-1'))
|
|
377
|
-
await writeFile(join(tmpDir1, 'test-extension-1', 'extension.json'), 'true')
|
|
378
|
-
Platform.state.getBuiltinExtensionsPath = () => tmpDir1
|
|
379
|
-
Platform.state.getExtensionsPath = () => tmpDir2
|
|
380
|
-
expect(await ExtensionManagement.getExtensions()).toEqual([
|
|
381
|
-
{
|
|
382
|
-
status: 'rejected',
|
|
383
|
-
reason: new VError(
|
|
384
|
-
'Failed to load extension "test-extension-1": Failed to load extension manifest: Invalid manifest file: Not an JSON object.'
|
|
385
|
-
),
|
|
386
|
-
path: join(tmpDir1, 'test-extension-1'),
|
|
387
|
-
},
|
|
388
|
-
])
|
|
389
|
-
})
|
|
390
|
-
|
|
391
|
-
// TODO should have better error message here and also stack
|
|
392
|
-
test('getExtensions - error - invalid json', async () => {
|
|
393
|
-
const tmpDir1 = await getTmpDir()
|
|
394
|
-
const tmpDir2 = await getTmpDir()
|
|
395
|
-
await mkdir(join(tmpDir1, 'test-extension-1'))
|
|
396
|
-
await writeFile(join(tmpDir1, 'test-extension-1', 'extension.json'), '{')
|
|
397
|
-
Platform.state.getBuiltinExtensionsPath = () => tmpDir1
|
|
398
|
-
Platform.state.getExtensionsPath = () => tmpDir2
|
|
399
|
-
expect(await ExtensionManagement.getExtensions()).toEqual([
|
|
400
|
-
{
|
|
401
|
-
reason: new VError(
|
|
402
|
-
'Failed to load extension "test-extension-1": Failed to load extension manifest: Unexpected end of JSON input while parsing "{"'
|
|
403
|
-
),
|
|
404
|
-
status: 'rejected',
|
|
405
|
-
path: join(tmpDir1, 'test-extension-1'),
|
|
406
|
-
},
|
|
407
|
-
])
|
|
408
|
-
})
|
package/test/FileSystem.test.js
DELETED
|
@@ -1,294 +0,0 @@
|
|
|
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
|
-
})
|