@lvce-editor/shared-process 0.10.1 → 0.10.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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lvce-editor/shared-process",
3
- "version": "0.10.1",
4
- "description": "",
3
+ "version": "0.10.2",
4
+ "description": "Utility package for @lvce-editor/server",
5
5
  "main": "index.js",
6
6
  "type": "module",
7
7
  "scripts": {
@@ -20,8 +20,8 @@
20
20
  "node": ">=16"
21
21
  },
22
22
  "dependencies": {
23
- "@lvce-editor/extension-host": "0.10.1",
24
- "@lvce-editor/pty-host": "0.10.1",
23
+ "@lvce-editor/extension-host": "0.10.2",
24
+ "@lvce-editor/pty-host": "0.10.2",
25
25
  "debug": "^4.3.4",
26
26
  "execa": "^6.1.0",
27
27
  "exit-hook": "^3.1.0",
@@ -1,73 +1,102 @@
1
- import fs, { cpSync, readdirSync, readFileSync, writeFileSync } from 'fs'
2
- import path, { join } from 'path'
1
+ import * as FileSystem from '../FileSystem/FileSystem.js'
2
+ import * as JsonFile from '../JsonFile/JsonFile.js'
3
+ import * as Path from '../Path/Path.js'
3
4
 
4
5
  // TODO
5
6
  // - implement this for syntax highlighting projects
6
7
  // - implement this for language features web extensions
7
8
 
8
- const readExtensionManifest = (path) => {
9
- const content = readFileSync(path, 'utf8')
10
- return { ...JSON.parse(content), path }
9
+ const readExtensionManifest = async (path) => {
10
+ const json = await JsonFile.readJson(path)
11
+ return { ...json, path }
11
12
  }
12
13
 
13
14
  const getThemeName = (dirent) => {
14
15
  return dirent.slice('builtin.theme-'.length)
15
16
  }
16
17
 
18
+ const replace = async (path, occurrence, replacement) => {
19
+ const oldContent = await FileSystem.readFile(path)
20
+ if (!oldContent.includes(occurrence)) {
21
+ throw new Error(`failed to replace occurrence ${occurrence}: Not found`)
22
+ }
23
+ // @ts-ignore
24
+ const newContent = oldContent.replaceAll(occurrence, replacement)
25
+ await FileSystem.writeFile(path, newContent)
26
+ }
27
+
17
28
  /**
18
- *
19
- * @param {{root:string, pathPrefix:string }} param0
29
+ * @param {string} dirent
20
30
  */
21
- export const exportStatic = async ({ root, pathPrefix }) => {
22
- const dirents = readdirSync(
23
- join(root, 'node_modules', '@lvce-editor', 'server', 'static')
24
- )
25
- const RE_COMMIT_HASH = /^[a-z\d]+$/
26
- const isCommitHash = (dirent) => {
27
- return dirent.length === 7 && dirent.match(RE_COMMIT_HASH)
28
- }
29
- const commitHash = dirents.find(isCommitHash) || ''
31
+ const isLanguageBasics = (dirent) => {
32
+ return dirent.startsWith('builtin.language-basics')
33
+ }
30
34
 
31
- const extensionJson = readExtensionManifest(join(root, 'extension.json'))
32
- const colorThemeName = extensionJson.id.slice('builtin.theme-'.length)
33
- const name = extensionJson.name || extensionJson.id || ''
34
- const description = extensionJson.description || ''
35
- fs.rmSync(join(root, 'dist'), { recursive: true, force: true })
35
+ /**
36
+ * @param {string} dirent
37
+ */
38
+ const isTheme = (dirent) => {
39
+ return dirent.startsWith('builtin.theme-')
40
+ }
36
41
 
37
- fs.mkdirSync(path.join(root, 'dist'))
42
+ /**
43
+ * @param {string} dirent
44
+ */
45
+ const isIconTheme = (dirent) => {
46
+ return dirent === 'builtin.vscode-icons'
47
+ }
38
48
 
39
- fs.mkdirSync(
40
- join(
41
- root,
42
- 'dist',
43
- commitHash,
44
- 'extensions',
45
- `builtin.theme-${colorThemeName}`
46
- ),
47
- {
48
- recursive: true,
49
- }
50
- )
51
- fs.cpSync(
52
- join(root, 'node_modules', '@lvce-editor', 'server', 'static'),
53
- join(root, 'dist'),
54
- {
55
- recursive: true,
56
- }
57
- )
49
+ const compare = (a, b) => {
50
+ return a.localeCompare(b)
51
+ }
58
52
 
59
- const replaceSync = (path, occurrence, replacement) => {
60
- const oldContent = readFileSync(path, 'utf8')
61
- if (!oldContent.includes(occurrence)) {
62
- throw new Error(`failed to replace occurrence ${occurrence}: Not found`)
53
+ const toSorted = (objects, compare) => {
54
+ return [...objects].sort(compare)
55
+ }
56
+
57
+ const mergeThemes = (builtinThemes, extensionThemes) => {
58
+ const seen = []
59
+ const merged = []
60
+ for (const extensionTheme of extensionThemes) {
61
+ seen.push(extensionTheme)
62
+ merged.push(extensionTheme)
63
+ }
64
+ for (const builtinTheme of builtinThemes) {
65
+ if (seen.includes(builtinTheme)) {
66
+ continue
63
67
  }
64
- // @ts-ignore
65
- const newContent = oldContent.replaceAll(occurrence, replacement)
66
- writeFileSync(path, newContent)
68
+ merged.push(builtinTheme)
67
69
  }
70
+ const sorted = toSorted(merged, compare)
71
+ return sorted
72
+ }
73
+
74
+ const RE_COMMIT_HASH = /^[a-z\d]+$/
75
+ const isCommitHash = (dirent) => {
76
+ return dirent.length === 7 && dirent.match(RE_COMMIT_HASH)
77
+ }
78
+
79
+ /**
80
+ * @param {string} root
81
+ */
82
+ const clean = async (root) => {
83
+ await FileSystem.remove(Path.join(root, 'dist'))
84
+ await FileSystem.mkdir(Path.join(root, 'dist'))
85
+ }
86
+
87
+ /**
88
+ * @param {string} root
89
+ */
90
+ const copyStaticFiles = async (root, commitHash) => {
91
+ await FileSystem.copy(
92
+ Path.join(root, 'node_modules', '@lvce-editor', 'server', 'static'),
93
+ Path.join(root, 'dist')
94
+ )
95
+ }
68
96
 
69
- replaceSync(
70
- join(
97
+ const applyOverrides = async ({ root, commitHash, pathPrefix }) => {
98
+ await replace(
99
+ Path.join(
71
100
  root,
72
101
  'dist',
73
102
  commitHash,
@@ -79,8 +108,8 @@ export const exportStatic = async ({ root, pathPrefix }) => {
79
108
  'platform = getPlatform();',
80
109
  'platform = "web"'
81
110
  )
82
- replaceSync(
83
- join(
111
+ await replace(
112
+ Path.join(
84
113
  root,
85
114
  'dist',
86
115
  commitHash,
@@ -92,8 +121,8 @@ export const exportStatic = async ({ root, pathPrefix }) => {
92
121
  `return "/${commitHash}";`,
93
122
  `return "${pathPrefix}/${commitHash}";`
94
123
  )
95
- replaceSync(
96
- join(
124
+ await replace(
125
+ Path.join(
97
126
  root,
98
127
  'dist',
99
128
  commitHash,
@@ -105,8 +134,8 @@ export const exportStatic = async ({ root, pathPrefix }) => {
105
134
  'platform = getPlatform();',
106
135
  'platform = "web"'
107
136
  )
108
- replaceSync(
109
- join(
137
+ await replace(
138
+ Path.join(
110
139
  root,
111
140
  'dist',
112
141
  commitHash,
@@ -118,8 +147,8 @@ export const exportStatic = async ({ root, pathPrefix }) => {
118
147
  `platform2 = "remote";`,
119
148
  'platform2 = "web";'
120
149
  )
121
- replaceSync(
122
- join(
150
+ await replace(
151
+ Path.join(
123
152
  root,
124
153
  'dist',
125
154
  commitHash,
@@ -131,8 +160,8 @@ export const exportStatic = async ({ root, pathPrefix }) => {
131
160
  `return "/${commitHash}";`,
132
161
  `return "${pathPrefix}/${commitHash}";`
133
162
  )
134
- replaceSync(
135
- join(
163
+ await replace(
164
+ Path.join(
136
165
  root,
137
166
  'dist',
138
167
  commitHash,
@@ -149,8 +178,8 @@ export const exportStatic = async ({ root, pathPrefix }) => {
149
178
  return \`\${assetDir}/themes/\${colorThemeId}.json\`
150
179
  }`
151
180
  )
152
- replaceSync(
153
- join(
181
+ await replace(
182
+ Path.join(
154
183
  root,
155
184
  'dist',
156
185
  commitHash,
@@ -167,8 +196,8 @@ export const exportStatic = async ({ root, pathPrefix }) => {
167
196
  return \`\${assetDir}/icon-themes/\${iconThemeId}.json\`
168
197
  }`
169
198
  )
170
- replaceSync(
171
- join(
199
+ await replace(
200
+ Path.join(
172
201
  root,
173
202
  'dist',
174
203
  commitHash,
@@ -182,8 +211,8 @@ export const exportStatic = async ({ root, pathPrefix }) => {
182
211
  )
183
212
 
184
213
  // workaround for firefox bug
185
- replaceSync(
186
- join(
214
+ await replace(
215
+ Path.join(
187
216
  root,
188
217
  'dist',
189
218
  commitHash,
@@ -196,44 +225,43 @@ export const exportStatic = async ({ root, pathPrefix }) => {
196
225
  `export {}
197
226
  //# sourceMappingURL`
198
227
  )
199
- replaceSync(
200
- join(root, 'dist', commitHash, 'config', 'defaultSettings.json'),
201
- `"workbench.colorTheme": "slime"`,
202
- `"workbench.colorTheme": "${colorThemeName}"`
203
- )
204
- replaceSync(
205
- join(root, 'dist', commitHash, 'config', 'defaultSettings.json'),
228
+
229
+ await replace(
230
+ Path.join(root, 'dist', commitHash, 'config', 'defaultSettings.json'),
206
231
  `"workbench.saveStateOnVisibilityChange": false`,
207
232
  `"workbench.saveStateOnVisibilityChange": true`
208
233
  )
209
234
 
210
- const extensionDirents = readdirSync(
211
- join(root, 'node_modules', '@lvce-editor', 'shared-process', 'extensions')
235
+ const extensionDirents = await FileSystem.readDir(
236
+ Path.join(
237
+ root,
238
+ 'node_modules',
239
+ '@lvce-editor',
240
+ 'shared-process',
241
+ 'extensions'
242
+ )
212
243
  )
213
244
 
214
- const isLanguageBasics = (dirent) => {
215
- return dirent.startsWith('builtin.language-basics')
216
- }
217
-
218
- const isTheme = (dirent) => {
219
- return dirent.startsWith('builtin.theme-')
220
- }
221
-
222
- const isIconTheme = (dirent) => {
223
- return dirent === 'builtin.vscode-icons'
224
- }
225
-
226
245
  const languageBasicsDirents = extensionDirents.filter(isLanguageBasics)
227
246
  const themeDirents = extensionDirents.filter(isTheme)
228
247
  const iconThemeDirents = extensionDirents.filter(isIconTheme)
229
248
 
230
- const writeJson = (path, json) => {
231
- const content = JSON.stringify(json, null, 2) + '\n'
232
- writeFileSync(path, content)
249
+ const getLanguages = (extension) => {
250
+ const languages = []
251
+ for (const language of extension.languages || []) {
252
+ languages.push({
253
+ ...language,
254
+ tokenize: `${pathPrefix}/${commitHash}/extensions/${extension.id}/${language.tokenize}`,
255
+ })
256
+ }
257
+ return languages
233
258
  }
234
259
 
260
+ /**
261
+ * @param {string} dirent
262
+ */
235
263
  const getManifestPath = (dirent) => {
236
- return join(
264
+ return Path.join(
237
265
  root,
238
266
  'node_modules',
239
267
  '@lvce-editor',
@@ -243,28 +271,18 @@ export const exportStatic = async ({ root, pathPrefix }) => {
243
271
  'extension.json'
244
272
  )
245
273
  }
246
- const getLanguages = (extension) => {
247
- const languages = []
248
- for (const language of extension.languages || []) {
249
- languages.push({
250
- ...language,
251
- tokenize: `${pathPrefix}/${commitHash}/extensions/${extension.id}/${language.tokenize}`,
252
- })
253
- }
254
- return languages
255
- }
256
- const languages = languageBasicsDirents
257
- .map(getManifestPath)
258
- .map(readExtensionManifest)
259
- .flatMap(getLanguages)
260
- writeJson(
261
- join(root, 'dist', commitHash, 'config', 'languages.json'),
274
+
275
+ const manifestPaths = languageBasicsDirents.map(getManifestPath)
276
+ const manifests = await Promise.all(manifestPaths.map(readExtensionManifest))
277
+ const languages = manifests.flatMap(getLanguages)
278
+ await JsonFile.writeJson(
279
+ Path.join(root, 'dist', commitHash, 'config', 'languages.json'),
262
280
  languages
263
281
  )
264
282
 
265
283
  for (const languageBasicsDirent of languageBasicsDirents) {
266
- cpSync(
267
- join(
284
+ await FileSystem.copy(
285
+ Path.join(
268
286
  root,
269
287
  'node_modules',
270
288
  '@lvce-editor',
@@ -272,17 +290,14 @@ export const exportStatic = async ({ root, pathPrefix }) => {
272
290
  'extensions',
273
291
  languageBasicsDirent
274
292
  ),
275
- join(root, 'dist', commitHash, 'extensions', languageBasicsDirent),
276
- {
277
- recursive: true,
278
- }
293
+ Path.join(root, 'dist', commitHash, 'extensions', languageBasicsDirent)
279
294
  )
280
295
  }
281
296
 
282
297
  for (const themeDirent of themeDirents) {
283
298
  const themeId = getThemeName(themeDirent)
284
- cpSync(
285
- join(
299
+ await FileSystem.copy(
300
+ Path.join(
286
301
  root,
287
302
  'node_modules',
288
303
  '@lvce-editor',
@@ -291,42 +306,20 @@ export const exportStatic = async ({ root, pathPrefix }) => {
291
306
  themeDirent,
292
307
  'color-theme.json'
293
308
  ),
294
- join(root, 'dist', commitHash, 'themes', `${themeId}.json`)
309
+ Path.join(root, 'dist', commitHash, 'themes', `${themeId}.json`)
295
310
  )
296
311
  }
297
312
 
298
- const compare = (a, b) => {
299
- return a.localeCompare(b)
300
- }
301
-
302
- const toSorted = (objects, compare) => {
303
- return [...objects].sort(compare)
304
- }
305
-
306
- const mergeThemes = (builtinThemes, extensionThemes) => {
307
- const seen = []
308
- const merged = []
309
- for (const extensionTheme of extensionThemes) {
310
- seen.push(extensionTheme)
311
- merged.push(extensionTheme)
312
- }
313
- for (const builtinTheme of builtinThemes) {
314
- if (seen.includes(builtinTheme)) {
315
- continue
316
- }
317
- merged.push(builtinTheme)
318
- }
319
- const sorted = toSorted(merged, compare)
320
- return sorted
321
- }
322
-
323
- const themeIds = mergeThemes(themeDirents.map(getThemeName), [colorThemeName])
324
- writeJson(join(root, 'dist', commitHash, 'config', 'themes.json'), themeIds)
313
+ const themeIds = mergeThemes(themeDirents.map(getThemeName), [])
314
+ await JsonFile.writeJson(
315
+ Path.join(root, 'dist', commitHash, 'config', 'themes.json'),
316
+ themeIds
317
+ )
325
318
 
326
319
  for (const iconThemeDirent of iconThemeDirents) {
327
320
  const iconThemeId = iconThemeDirent.slice('builtin.'.length)
328
- cpSync(
329
- join(
321
+ await FileSystem.copy(
322
+ Path.join(
330
323
  root,
331
324
  'node_modules',
332
325
  '@lvce-editor',
@@ -335,10 +328,10 @@ export const exportStatic = async ({ root, pathPrefix }) => {
335
328
  iconThemeDirent,
336
329
  'icon-theme.json'
337
330
  ),
338
- join(root, 'dist', commitHash, 'icon-themes', `${iconThemeId}.json`)
331
+ Path.join(root, 'dist', commitHash, 'icon-themes', `${iconThemeId}.json`)
339
332
  )
340
- cpSync(
341
- join(
333
+ await FileSystem.copy(
334
+ Path.join(
342
335
  root,
343
336
  'node_modules',
344
337
  '@lvce-editor',
@@ -347,101 +340,280 @@ export const exportStatic = async ({ root, pathPrefix }) => {
347
340
  iconThemeDirent,
348
341
  'icons'
349
342
  ),
350
- join(root, 'dist', commitHash, 'file-icons'),
351
- {
352
- recursive: true,
353
- }
343
+ Path.join(root, 'dist', commitHash, 'file-icons')
354
344
  )
355
345
  }
356
-
357
- cpSync(
358
- join(root, 'color-theme.json'),
359
- join(root, 'dist', commitHash, 'themes', `${colorThemeName}.json`)
360
- )
361
- replaceSync(
362
- join(root, 'dist', 'index.html'),
346
+ await replace(
347
+ Path.join(root, 'dist', 'index.html'),
363
348
  `/${commitHash}`,
364
349
  `${pathPrefix}/${commitHash}`
365
350
  )
366
- replaceSync(
367
- join(root, 'dist', 'index.html'),
351
+ await replace(
352
+ Path.join(root, 'dist', 'index.html'),
368
353
  `/manifest.json`,
369
354
  `${pathPrefix}/manifest.json`
370
355
  )
371
- replaceSync(
372
- join(root, 'dist', 'index.html'),
356
+
357
+ await replace(
358
+ Path.join(root, 'dist', 'index.html'),
359
+ '</title>',
360
+ `</title>
361
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">`
362
+ )
363
+ await replace(
364
+ Path.join(root, 'dist', 'manifest.json'),
365
+ `/${commitHash}`,
366
+ `${pathPrefix}/${commitHash}`
367
+ )
368
+
369
+ await replace(
370
+ Path.join(root, 'dist', commitHash, 'css', 'App.css'),
371
+ `/${commitHash}`,
372
+ `${pathPrefix}/${commitHash}`
373
+ )
374
+ }
375
+
376
+ const addExtensionSeo = async ({ root, name, description }) => {
377
+ await replace(
378
+ Path.join(root, 'dist', 'index.html'),
373
379
  '<title>Code Editor</title>',
374
380
  `<title>${name}</title>`
375
381
  )
376
- replaceSync(
377
- join(root, 'dist', 'manifest.json'),
382
+ await replace(
383
+ Path.join(root, 'dist', 'manifest.json'),
378
384
  `"name": "Code Editor Web - OSS"`,
379
385
  `"name": "${name}"`
380
386
  )
381
- replaceSync(
382
- join(root, 'dist', 'manifest.json'),
387
+ await replace(
388
+ Path.join(root, 'dist', 'manifest.json'),
383
389
  `"short_name": "Web - OSS"`,
384
390
  `"short_name": "${name}"`
385
391
  )
386
- replaceSync(
387
- join(root, 'dist', 'manifest.json'),
392
+ await replace(
393
+ Path.join(root, 'dist', 'manifest.json'),
388
394
  `"description": "Web Code Editor."`,
389
395
  `"description": "${description}"`
390
396
  )
391
- replaceSync(
392
- join(root, 'dist', 'index.html'),
397
+ await replace(
398
+ Path.join(root, 'dist', 'index.html'),
393
399
  '<meta name="description" content="Online Code Editor" />',
394
400
  `<meta name="description" content="${description}" />`
395
401
  )
396
- replaceSync(
397
- join(root, 'dist', 'index.html'),
398
- '</title>',
399
- `</title>
400
- <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">`
402
+ }
403
+
404
+ const getId = (object) => {
405
+ return object.id
406
+ }
407
+
408
+ const addExtensionThemes = async ({ root, extensionJson, commitHash }) => {
409
+ const colorThemes = extensionJson.colorThemes || []
410
+ if (colorThemes.length === 0) {
411
+ return
412
+ }
413
+ for (const colorTheme of colorThemes) {
414
+ const { id, path } = colorTheme
415
+ await FileSystem.mkdir(
416
+ Path.join(root, 'dist', commitHash, 'extensions', `builtin.theme-${id}`)
417
+ )
418
+ await FileSystem.copy(
419
+ Path.join(root, path),
420
+ Path.join(root, 'dist', commitHash, 'themes', `${id}.json`)
421
+ )
422
+ await replace(
423
+ Path.join(root, 'dist', commitHash, 'config', 'defaultSettings.json'),
424
+ `"workbench.colorTheme": "slime"`,
425
+ `"workbench.colorTheme": "${id}"`
426
+ )
427
+ await FileSystem.copyFile(
428
+ Path.join(root, 'README.md'),
429
+ Path.join(
430
+ root,
431
+ 'dist',
432
+ commitHash,
433
+ 'extensions',
434
+ `builtin.theme-${id}`,
435
+ 'README.md'
436
+ )
437
+ )
438
+ await FileSystem.copyFile(
439
+ Path.join(root, 'extension.json'),
440
+ Path.join(
441
+ root,
442
+ 'dist',
443
+ commitHash,
444
+ 'extensions',
445
+ `builtin.theme-${id}`,
446
+ 'extension.json'
447
+ )
448
+ )
449
+ await FileSystem.copyFile(
450
+ Path.join(root, 'color-theme.json'),
451
+ Path.join(
452
+ root,
453
+ 'dist',
454
+ commitHash,
455
+ 'extensions',
456
+ `builtin.theme-${id}`,
457
+ 'color-theme.json'
458
+ )
459
+ )
460
+ }
461
+ const themesJson = await JsonFile.readJson(
462
+ Path.join(root, 'dist', commitHash, 'config', 'themes.json')
401
463
  )
402
- replaceSync(
403
- join(root, 'dist', 'manifest.json'),
404
- `/${commitHash}`,
405
- `${pathPrefix}/${commitHash}`
464
+ const ids = colorThemes.map(getId)
465
+ const mergedThemes = mergeThemes(themesJson, ids)
466
+ await JsonFile.writeJson(
467
+ Path.join(root, 'dist', commitHash, 'config', 'themes.json'),
468
+ mergedThemes
406
469
  )
470
+ }
407
471
 
408
- fs.copyFileSync(
409
- join(root, 'README.md'),
410
- join(
411
- root,
412
- 'dist',
413
- commitHash,
414
- 'extensions',
415
- `builtin.theme-${colorThemeName}`,
416
- 'README.md'
417
- )
472
+ const compareId = (a, b) => {
473
+ return a.id.localeCompare(b.id)
474
+ }
475
+
476
+ const mergeLanguages = (languages, extensionLanguages) => {
477
+ const seen = []
478
+ const merged = []
479
+ for (const language of extensionLanguages) {
480
+ seen.push(language.id)
481
+ merged.push(language)
482
+ }
483
+ for (const language of languages) {
484
+ if (seen.includes(language.id)) {
485
+ continue
486
+ }
487
+ merged.push(language)
488
+ }
489
+ merged.sort(compareId)
490
+ return merged
491
+ }
492
+
493
+ const toPlaygroundFile = (file) => {
494
+ return `/playground/${file}`
495
+ }
496
+
497
+ const addExtensionLanguages = async ({
498
+ root,
499
+ extensionJson,
500
+ commitHash,
501
+ pathPrefix,
502
+ }) => {
503
+ const languages = extensionJson.languages || []
504
+ if (languages.length === 0) {
505
+ return
506
+ }
507
+ const extensionId = extensionJson.id
508
+ await FileSystem.remove(
509
+ Path.join(root, 'dist', commitHash, 'extensions', extensionId)
510
+ )
511
+ await FileSystem.mkdir(
512
+ Path.join(root, 'dist', commitHash, 'extensions', extensionId)
513
+ )
514
+ await FileSystem.copyFile(
515
+ Path.join(root, 'README.md'),
516
+ Path.join(root, 'dist', commitHash, 'extensions', extensionId, 'README.md')
418
517
  )
419
- fs.copyFileSync(
420
- join(root, 'extension.json'),
421
- join(
518
+ await FileSystem.copy(
519
+ Path.join(root, 'src'),
520
+ Path.join(root, 'dist', commitHash, 'extensions', extensionId, 'src')
521
+ )
522
+ await FileSystem.copyFile(
523
+ Path.join(root, 'extension.json'),
524
+ Path.join(
422
525
  root,
423
526
  'dist',
424
527
  commitHash,
425
528
  'extensions',
426
- `builtin.theme-${colorThemeName}`,
529
+ extensionId,
427
530
  'extension.json'
428
531
  )
429
532
  )
430
- fs.copyFileSync(
431
- join(root, 'color-theme.json'),
432
- join(
433
- root,
434
- 'dist',
435
- commitHash,
436
- 'extensions',
437
- `builtin.theme-${colorThemeName}`,
438
- 'color-theme.json'
439
- )
533
+ const extensionLanguages = []
534
+ for (const language of languages) {
535
+ extensionLanguages.push({
536
+ ...language,
537
+ tokenize: `${pathPrefix}/${commitHash}/extensions/${extensionId}/${language.tokenize}`,
538
+ })
539
+ }
540
+ const builtinLanguages = await JsonFile.readJson(
541
+ Path.join(root, 'dist', commitHash, 'config', 'languages.json')
542
+ )
543
+ const mergedLanguages = mergeLanguages(builtinLanguages, extensionLanguages)
544
+ await JsonFile.writeJson(
545
+ Path.join(root, 'dist', commitHash, 'config', 'languages.json'),
546
+ mergedLanguages
547
+ )
548
+ await FileSystem.remove(Path.join(root, 'dist', commitHash, 'playground'))
549
+ await FileSystem.copy(
550
+ Path.join(root, 'test', 'cases'),
551
+ Path.join(root, 'dist', commitHash, 'playground')
440
552
  )
441
553
 
442
- replaceSync(
443
- join(root, 'dist', commitHash, 'css', 'App.css'),
444
- `/${commitHash}`,
445
- `${pathPrefix}/${commitHash}`
554
+ const testFiles = await FileSystem.readDir(Path.join(root, 'test', 'cases'))
555
+ const fileMap = testFiles.map(toPlaygroundFile)
556
+ await JsonFile.writeJson(
557
+ Path.join(root, 'dist', commitHash, 'config', 'fileMap.json'),
558
+ fileMap
559
+ )
560
+ }
561
+
562
+ const addExtension = async ({ root, commitHash, pathPrefix }) => {
563
+ const extensionJson = await readExtensionManifest(
564
+ Path.join(root, 'extension.json')
446
565
  )
566
+ const name = extensionJson.name || extensionJson.id || ''
567
+ const description = extensionJson.description || ''
568
+ await addExtensionSeo({
569
+ root,
570
+ name,
571
+ description,
572
+ })
573
+ await addExtensionThemes({
574
+ root,
575
+ commitHash,
576
+ extensionJson,
577
+ })
578
+ await addExtensionLanguages({
579
+ root,
580
+ commitHash,
581
+ extensionJson,
582
+ pathPrefix,
583
+ })
584
+ }
585
+
586
+ /**
587
+ *
588
+ * @param {{root:string, pathPrefix:string }} param0
589
+ */
590
+ export const exportStatic = async ({ root, pathPrefix }) => {
591
+ const dirents = await FileSystem.readDir(
592
+ Path.join(root, 'node_modules', '@lvce-editor', 'server', 'static')
593
+ )
594
+ const commitHash = dirents.find(isCommitHash) || ''
595
+
596
+ console.time('clean')
597
+ await clean(root)
598
+ console.timeEnd('clean')
599
+
600
+ console.time('copyStaticFiles')
601
+ await copyStaticFiles(root, commitHash)
602
+ console.timeEnd('copyStaticFiles')
603
+
604
+ console.time('applyOverrides')
605
+ await applyOverrides({
606
+ root,
607
+ commitHash,
608
+ pathPrefix,
609
+ })
610
+ console.timeEnd('applyOverrides')
611
+
612
+ console.time('addExtension')
613
+ await addExtension({
614
+ root,
615
+ commitHash,
616
+ pathPrefix,
617
+ })
618
+ console.timeEnd('addExtension')
447
619
  }
@@ -270,6 +270,21 @@ export const stat = async (path) => {
270
270
  export const chmod = async (path, permissions) => {
271
271
  await fs.chmod(path, permissions)
272
272
  }
273
+ export const copyFile = async (from, to) => {
274
+ try {
275
+ await fs.copyFile(from, to)
276
+ } catch (error) {
277
+ throw new VError(error, `Failed to copy file from ${from} to ${to}`)
278
+ }
279
+ }
280
+
281
+ export const cp = async (from, to) => {
282
+ try {
283
+ await fs.cp(from, to, { recursive: true })
284
+ } catch (error) {
285
+ throw new VError(error, `Failed to copy folder from ${from} to ${to}`)
286
+ }
287
+ }
273
288
 
274
289
  // export const unwatch = (id) => {
275
290
  // state.watchers[id].close()