@lvce-editor/shared-process 0.13.0 → 0.14.1

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 (112) hide show
  1. package/config/defaultKeyBindings.json +1 -784
  2. package/config/defaultSettings.json +8 -1
  3. package/extensions/builtin.language-basics-css/extension.json +2 -1
  4. package/extensions/builtin.language-basics-css/languageConfiguration.json +21 -0
  5. package/extensions/builtin.language-basics-css/src/tokenizeCss.js +10 -1
  6. package/extensions/builtin.language-basics-dotenv/extension.json +5 -1
  7. package/extensions/builtin.language-basics-go/src/tokenizeGo.js +79 -10
  8. package/extensions/builtin.language-basics-html/languageConfiguration.json +66 -0
  9. package/extensions/builtin.language-basics-html/src/tokenizeHtml.js +89 -27
  10. package/extensions/builtin.language-basics-java/src/tokenizeJava.js +6 -5
  11. package/extensions/builtin.language-basics-javascript/src/tokenizeJavaScript.js +29 -1
  12. package/extensions/builtin.language-basics-json/extension.json +4 -2
  13. package/extensions/builtin.language-basics-json/src/tokenizeJson.js +3 -0
  14. package/extensions/builtin.language-basics-jsx/src/tokenizeJsx.js +18 -5
  15. package/extensions/builtin.language-basics-typescript/src/tokenizeTypeScript.js +26 -0
  16. package/extensions/builtin.language-basics-vue/src/tokenizeVue.js +1 -1
  17. package/extensions/builtin.language-basics-xml/extension.json +3 -1
  18. package/extensions/builtin.theme-atom-one-dark/color-theme.json +2 -2
  19. package/extensions/builtin.theme-ayu/color-theme.json +6 -2
  20. package/extensions/builtin.theme-cobalt2/color-theme.json +5 -2
  21. package/extensions/builtin.theme-slime/color-theme.json +2 -2
  22. package/package.json +10 -11
  23. package/src/parts/Assert/Assert.js +1 -6
  24. package/src/parts/AssertionError/AssertionError.js +6 -0
  25. package/src/parts/BulkReplacement/BulkReplacement.ipc.js +7 -0
  26. package/src/parts/BulkReplacement/BulkReplacement.js +20 -0
  27. package/src/parts/BulkReplacementContent/BulkReplacementContent.js +30 -0
  28. package/src/parts/ChildProcessError/ChildProcessError.js +45 -0
  29. package/src/parts/ChromeExtension/ChromeExtension.js +2 -5
  30. package/src/parts/CleanStack/CleanStack.js +90 -2
  31. package/src/parts/CliList/CliList.js +3 -0
  32. package/src/parts/ClipBoard/ClipBoard.js +2 -2
  33. package/src/parts/ClipBoard/ClipBoardGnome.js +1 -2
  34. package/src/parts/ClipBoard/ClipBoardNoop.js +2 -2
  35. package/src/parts/ClipBoard/ClipBoardWindows.js +1 -3
  36. package/src/parts/Command/Command.js +5 -10
  37. package/src/parts/Credentials/Credentials.ipc.js +5 -5
  38. package/src/parts/Credentials/Credentials.js +2 -10
  39. package/src/parts/Desktop/Desktop.js +22 -0
  40. package/src/parts/Download/Download.js +2 -2
  41. package/src/parts/Error/Error.js +1 -1
  42. package/src/parts/ErrorCodes/ErrorCodes.js +2 -1
  43. package/src/parts/ErrorHandling/ErrorHandling.js +8 -14
  44. package/src/parts/ExportStatic/ExportStatic.js +8 -3
  45. package/src/parts/ExtensionHost/ExtensionHost.js +1 -2
  46. package/src/parts/ExtensionHost/ExtensionHostKeyBindings.js +0 -12
  47. package/src/parts/ExtensionHostRpc/ExtensionHostRpc.js +1 -1
  48. package/src/parts/ExtensionInstallFromFile/ExtensionInstallFromFile.js +1 -1
  49. package/src/parts/ExtensionInstallFromGitHub/ExtensionInstallFromGitHub.js +1 -1
  50. package/src/parts/ExtensionInstallFromUrl/ExtensionInstallFromUrl.js +1 -1
  51. package/src/parts/ExtensionLink/ExtensionLink.js +0 -19
  52. package/src/parts/ExtensionList/ExtensionList.js +11 -2
  53. package/src/parts/ExtensionManagement/ExtensionManagement.js +6 -58
  54. package/src/parts/ExtensionManagement/ExtensionManagementColorTheme.js +3 -1
  55. package/src/parts/ExtensionManagement/ExtensionManagementIconTheme.js +1 -1
  56. package/src/parts/ExtensionManagement/ExtensionManagementLanguages.js +7 -3
  57. package/src/parts/ExtensionManifestInputType/ExtensionManifestInputType.js +2 -0
  58. package/src/parts/ExtensionManifests/ExtensionManifests.js +3 -0
  59. package/src/parts/ExtensionManifests/ExtensionManifestsFromFolder.js +5 -15
  60. package/src/parts/ExtensionManifests/ExtensionManifestsFromLinkedExtensionsFolder.js +56 -0
  61. package/src/parts/ExtensionUninstall/ExtensionUninstall.js +18 -0
  62. package/src/parts/ExtensionUnlink/ExtensionUnlink.js +1 -1
  63. package/src/parts/Extract/Extract.js +2 -6
  64. package/src/parts/ExtractZip/ExtractZip.js +1 -1
  65. package/src/parts/{Error → FileNotFoundError}/FileNotFoundError.js +9 -2
  66. package/src/parts/FileSystem/FileSystem.js +6 -32
  67. package/src/parts/FirstNodeWorkerEventType/FirstNodeWorkerEventType.js +5 -0
  68. package/src/parts/GetDirentType/GetDirentType.js +27 -0
  69. package/src/parts/GetFirstNodeChildProcessEvent/GetFirstNodeChildProcessEvent.js +39 -0
  70. package/src/parts/GetFirstNodeWorkerEvent/GetFirstNodeWorkerEvent.js +21 -0
  71. package/src/parts/GetNewLineIndex/GetNewLineIndex.js +9 -0
  72. package/src/parts/GetResponse/GetResponse.js +16 -6
  73. package/src/parts/GetTextSearchRipGrepArgs/GetTextSearchRipGrepArgs.js +14 -0
  74. package/src/parts/InstallExtension/InstallExtension.ipc.js +6 -0
  75. package/src/parts/InstallExtension/InstallExtension.js +33 -0
  76. package/src/parts/IpcParent/IpcParent.js +9 -0
  77. package/src/parts/IpcParentModule/IpcParentModule.js +12 -0
  78. package/src/parts/IpcParentType/IpcParentType.js +2 -0
  79. package/src/parts/IpcParentWithNodeForkedProcess/IpcParentWithNodeForkedProcess.js +49 -0
  80. package/src/parts/IpcParentWithNodeWorker/IpcParentWithNodeWorker.js +36 -0
  81. package/src/parts/IsEnoentErrorWindows/IsEnoentErrorWindows.js +3 -0
  82. package/src/parts/IsIgnoredError/IsIgnoredError.js +14 -0
  83. package/src/parts/Json/Json.js +3 -5
  84. package/src/parts/JsonError/JsonError.js +8 -14
  85. package/src/parts/JsonParsingError/JsonParsingError.js +17 -0
  86. package/src/parts/Jsonc/Jsonc.js +304 -0
  87. package/src/parts/JsoncCharCode/JsoncCharCode.js +23 -0
  88. package/src/parts/JsoncFile/JsoncFile.js +8 -0
  89. package/src/parts/JsoncTokenType/JsoncTokenType.js +11 -0
  90. package/src/parts/LimitString/LimitString.js +3 -1
  91. package/src/parts/MergeStacks/MergeStacks.js +3 -2
  92. package/src/parts/Module/Module.js +4 -0
  93. package/src/parts/ModuleId/ModuleId.js +2 -0
  94. package/src/parts/ModuleMap/ModuleMap.js +4 -0
  95. package/src/parts/Native/Native.js +1 -1
  96. package/src/parts/ParentIpc/ParentIpc.js +2 -1
  97. package/src/parts/Platform/Platform.js +0 -21
  98. package/src/parts/Preferences/Preferences.js +6 -8
  99. package/src/parts/PrettyError/PrettyError.js +16 -7
  100. package/src/parts/PrintPrettyError/PrintPrettyError.js +3 -1
  101. package/src/parts/RecentlyOpened/RecentlyOpened.js +3 -7
  102. package/src/parts/RequiresSocket/RequiresSocket.js +1 -0
  103. package/src/parts/RipGrep/RipGrep.js +1 -1
  104. package/src/parts/SearchFile/SearchFile.js +4 -9
  105. package/src/parts/Socket/Socket.js +2 -7
  106. package/src/parts/Terminal/Terminal.ipc.js +4 -41
  107. package/src/parts/Terminal/Terminal.js +29 -25
  108. package/src/parts/TextSearch/TextSearch.js +102 -108
  109. package/src/parts/ToAbsolutePaths/ToAbsolutePaths.js +9 -0
  110. package/src/parts/ToTextSearchResult/ToTextSearchResult.js +42 -0
  111. package/src/parts/Trash/Trash.js +1 -2
  112. /package/src/parts/{RgPath/RgPath.js → RipGrepPath/RipGrepPath.js} +0 -0
@@ -1,5 +1,5 @@
1
1
  import keytar from 'keytar'
2
- import VError from 'verror'
2
+ import { VError } from '../VError/VError.js'
3
3
 
4
4
  /**
5
5
  * @param {string} service
@@ -9,7 +9,6 @@ export const deletePassword = async (service, account) => {
9
9
  try {
10
10
  return await keytar.deletePassword(service, account)
11
11
  } catch (error) {
12
- // @ts-ignore
13
12
  throw new VError(error, `Failed to delete password from service ${service}`)
14
13
  }
15
14
  }
@@ -21,11 +20,7 @@ export const findCredentials = async (service) => {
21
20
  try {
22
21
  return keytar.findCredentials(service)
23
22
  } catch (error) {
24
- throw new VError(
25
- // @ts-ignore
26
- error,
27
- `Failed to find credentials from service ${service}`
28
- )
23
+ throw new VError(error, `Failed to find credentials from service ${service}`)
29
24
  }
30
25
  }
31
26
 
@@ -36,7 +31,6 @@ export const findPassword = async (service) => {
36
31
  try {
37
32
  return await keytar.findPassword(service)
38
33
  } catch (error) {
39
- // @ts-ignore
40
34
  throw new VError(error, `Failed to find password from service ${service}`)
41
35
  }
42
36
  }
@@ -49,7 +43,6 @@ export const getPassword = async (service, account) => {
49
43
  try {
50
44
  return await keytar.getPassword(service, account)
51
45
  } catch (error) {
52
- // @ts-ignore
53
46
  throw new VError(error, `Failed to get password from service ${service}`)
54
47
  }
55
48
  }
@@ -63,7 +56,6 @@ export const setPassword = async (service, account, password) => {
63
56
  try {
64
57
  return await keytar.setPassword(service, account, password)
65
58
  } catch (error) {
66
- // @ts-ignore
67
59
  throw new VError(error, `Failed to set password for service ${service}`)
68
60
  }
69
61
  }
@@ -0,0 +1,22 @@
1
+ import * as DesktopType from '../DesktopType/DesktopType.js'
2
+ import * as Platform from '../Platform/Platform.js'
3
+
4
+ export const getDesktop = () => {
5
+ const { ORIGINAL_XDG_CURRENT_DESKTOP, XDG_CURRENT_DESKTOP } = process.env
6
+ if (ORIGINAL_XDG_CURRENT_DESKTOP && ORIGINAL_XDG_CURRENT_DESKTOP !== 'undefined') {
7
+ if (ORIGINAL_XDG_CURRENT_DESKTOP === 'ubuntu:GNOME') {
8
+ return DesktopType.Gnome
9
+ }
10
+ return ORIGINAL_XDG_CURRENT_DESKTOP
11
+ }
12
+ if (XDG_CURRENT_DESKTOP) {
13
+ if (XDG_CURRENT_DESKTOP === 'ubuntu:GNOME') {
14
+ return DesktopType.Gnome
15
+ }
16
+ return XDG_CURRENT_DESKTOP
17
+ }
18
+ if (Platform.isWindows) {
19
+ return DesktopType.Windows
20
+ }
21
+ return DesktopType.Unknown
22
+ }
@@ -1,9 +1,9 @@
1
+ import got, { RequestError } from 'got'
1
2
  import { createWriteStream } from 'node:fs'
2
3
  import { mkdir, rm } from 'node:fs/promises'
3
4
  import { pipeline } from 'node:stream/promises'
4
- import got, { RequestError } from 'got'
5
- import VError from 'verror'
6
5
  import * as Path from '../Path/Path.js'
6
+ import { VError } from '../VError/VError.js'
7
7
 
8
8
  export const download = async (url, outFile) => {
9
9
  try {
@@ -1,4 +1,4 @@
1
- import VError from 'verror'
1
+ import { VError } from '../VError/VError.js'
2
2
 
3
3
  /**
4
4
  *
@@ -1,6 +1,8 @@
1
1
  export const E_COLOR_THEME_NOT_FOUND = 'E_COLOR_THEME_NOT_FOUND'
2
+ export const E_COMMAND_NOT_FOUND = 'E_COMMAND_NOT_FOUND'
2
3
  export const E_ICON_THEME_NOT_FOUND = 'E_ICON_THEME_NOT_FOUND'
3
4
  export const E_MANIFEST_NOT_FOUND = 'E_MANIFEST_NOT_FOUND'
5
+ export const EACCES = 'EACCES'
4
6
  export const ECONNRESET = 'ECONNRESET'
5
7
  export const EEXIST = 'EEXIST'
6
8
  export const EISDIR = 'EISDIR'
@@ -12,4 +14,3 @@ export const EPIPE = 'EPIPE'
12
14
  export const ERR_IPC_CHANNEL_CLOSED = 'ERR_IPC_CHANNEL_CLOSED'
13
15
  export const ERR_MODULE_NOT_FOUND = 'ERR_MODULE_NOT_FOUND'
14
16
  export const EXDEV = 'EXDEV'
15
- export const E_COMMAND_NOT_FOUND = 'E_COMMAND_NOT_FOUND'
@@ -1,9 +1,11 @@
1
- import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
2
1
  import * as ExitCode from '../ExitCode/ExitCode.js'
2
+ import * as IsIgnoredError from '../IsIgnoredError/IsIgnoredError.js'
3
3
  import * as JsonRpcVersion from '../JsonRpcVersion/JsonRpcVersion.js'
4
+ import * as Logger from '../Logger/Logger.js'
4
5
  import * as PrettyError from '../PrettyError/PrettyError.js'
5
6
  import * as Process from '../Process/Process.js'
6
7
  import * as Socket from '../Socket/Socket.js'
8
+ import * as GetNewLineIndex from '../GetNewLineIndex/GetNewLineIndex.js'
7
9
 
8
10
  export const state = {
9
11
  seenErrors: [],
@@ -48,7 +50,7 @@ export const handleError = (error) => {
48
50
 
49
51
  const firstErrorLine = (error) => {
50
52
  if (error.stack) {
51
- return error.stack.slice(0, error.stack.indexOf('\n'))
53
+ return error.stack.slice(0, GetNewLineIndex.getNewLineIndex(error.stack))
52
54
  }
53
55
  if (error.message) {
54
56
  return error.message
@@ -57,19 +59,11 @@ const firstErrorLine = (error) => {
57
59
  }
58
60
 
59
61
  export const handleUncaughtExceptionMonitor = (error, origin) => {
60
- console.info(`[shared process] uncaught exception: ${firstErrorLine(error)}`)
61
- if (error && error.code === ErrorCodes.EPIPE && !process.connected) {
62
- // parent process is disposed, ignore
62
+ Logger.info(`[shared process] uncaught exception: ${firstErrorLine(error)}`)
63
+ if (IsIgnoredError.isIgnoredError(error)) {
63
64
  return
64
65
  }
65
- if (error && error.code === ErrorCodes.ERR_IPC_CHANNEL_CLOSED && !Process.isConnected()) {
66
- // parent process is disposed, ignore
67
- return
68
- }
69
- // console.log(error)
70
66
  const prettyError = PrettyError.prepare(error)
71
- // console.error(prettyError.message)
72
- console.error(prettyError.codeFrame)
73
- console.error(prettyError.stack)
74
- Process.exit(ExitCode.Error)
67
+ Logger.error(prettyError.codeFrame + '\n' + prettyError.stack + '\n')
68
+ Process.setExitCode(ExitCode.Error)
75
69
  }
@@ -226,9 +226,14 @@ const applyOverrides = async ({ root, commitHash, pathPrefix }) => {
226
226
  <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">`
227
227
  )
228
228
  }
229
- await replace(Path.join(root, 'dist', 'manifest.json'), `/${commitHash}`, `${pathPrefix}/${commitHash}`)
230
- await replace(Path.join(root, 'dist', commitHash, 'css', 'parts', 'ViewletTitleBarButtons.css'), `/${commitHash}`, `${pathPrefix}/${commitHash}`)
231
- await replace(Path.join(root, 'dist', commitHash, 'css', 'App.css'), `/${commitHash}`, `${pathPrefix}/${commitHash}`)
229
+ if (pathPrefix) {
230
+ await replace(Path.join(root, 'dist', 'manifest.json'), `/${commitHash}`, `${pathPrefix}/${commitHash}`)
231
+ await replace(Path.join(root, 'dist', 'manifest.json'), `"start_url": "/"`, `"start_url": "${pathPrefix}"`)
232
+ await replace(Path.join(root, 'dist', commitHash, 'css', 'App.css'), `/${commitHash}`, `${pathPrefix}/${commitHash}`)
233
+ await replace(Path.join(root, 'dist', commitHash, 'css', 'parts', 'EditorTabs.css'), `/${commitHash}`, `${pathPrefix}/${commitHash}`)
234
+ await replace(Path.join(root, 'dist', commitHash, 'css', 'parts', 'ViewletTitleBarButtons.css'), `/${commitHash}`, `${pathPrefix}/${commitHash}`)
235
+ await replace(Path.join(root, 'dist', commitHash, 'css', 'parts', 'ViewletTitleBarIcon.css'), `/${commitHash}`, `${pathPrefix}/${commitHash}`)
236
+ }
232
237
  }
233
238
 
234
239
  const addExtensionSeo = async ({ root, name, description }) => {
@@ -1,10 +1,10 @@
1
- import VError from 'verror'
2
1
  import * as Assert from '../Assert/Assert.js'
3
2
  import * as Callback from '../Callback/Callback.js'
4
3
  import * as ExtensionHostIpc from '../ExtensionHostIpc/ExtensionHostIpc.js'
5
4
  import * as ExtensionHostRpc from '../ExtensionHostRpc/ExtensionHostRpc.js'
6
5
  import * as JsonRpc from '../JsonRpc/JsonRpc.js'
7
6
  import * as JsonRpcVersion from '../JsonRpcVersion/JsonRpcVersion.js'
7
+ import { VError } from '../VError/VError.js'
8
8
 
9
9
  // TODO maybe rename to extension host management for clarity
10
10
 
@@ -41,7 +41,6 @@ export const start = async (socket) => {
41
41
  state.extensionHosts[id] = extensionHost
42
42
  return id
43
43
  } catch (error) {
44
- // @ts-ignore
45
44
  throw new VError(error, 'Failed to start extension host')
46
45
  }
47
46
  }
@@ -1,16 +1,4 @@
1
- import VError from 'verror'
2
- import * as Callback from '../Callback/Callback.js'
3
- import * as ChildProcess from '../ChildProcess/ChildProcess.js'
4
- import * as Debug from '../Debug/Debug.js'
5
- import * as Error from '../Error/Error.js'
6
1
  import * as ExtensionManagement from '../ExtensionManagement/ExtensionManagement.js'
7
- import * as ReadJson from '../JsonFile/JsonFile.js'
8
- import * as JsonRpc from '../JsonRpc/JsonRpc.js'
9
- import * as Path from '../Path/Path.js'
10
- import * as Root from '../Root/Root.js'
11
- import * as Socket from '../Socket/Socket.js'
12
- import * as TextDocument from '../TextDocument/TextDocument.js'
13
- import * as Platform from '../Platform/Platform.js'
14
2
 
15
3
  const getExtensionKeyBindings = (extension) => {
16
4
  return extension.keyBindings || []
@@ -1,6 +1,6 @@
1
- import VError from 'verror'
2
1
  import * as Assert from '../Assert/Assert.js'
3
2
  import * as Timeout from '../Timeout/Timeout.js'
3
+ import { VError } from '../VError/VError.js'
4
4
 
5
5
  // TODO maybe rename to extension host management for clarity
6
6
 
@@ -1,9 +1,9 @@
1
- import VError from 'verror'
2
1
  import * as Extract from '../Extract/Extract.js'
3
2
  import * as FileSystem from '../FileSystem/FileSystem.js'
4
3
  import * as JsonFile from '../JsonFile/JsonFile.js'
5
4
  import * as Path from '../Path/Path.js'
6
5
  import * as Platform from '../Platform/Platform.js'
6
+ import { VError } from '../VError/VError.js'
7
7
 
8
8
  const getCachedExtensionFolderName = (path) => {
9
9
  const baseName = Path.basename(path)
@@ -1,9 +1,9 @@
1
- import VError from 'verror'
2
1
  import * as DownloadAndExtract from '../DownloadAndExtract/DownloadAndExtract.js'
3
2
  import * as FileSystem from '../FileSystem/FileSystem.js'
4
3
  import * as JsonFile from '../JsonFile/JsonFile.js'
5
4
  import * as Path from '../Path/Path.js'
6
5
  import * as Platform from '../Platform/Platform.js'
6
+ import { VError } from '../VError/VError.js'
7
7
 
8
8
  export const install = async ({ user, repo, branch }) => {
9
9
  try {
@@ -1,11 +1,11 @@
1
1
  import { rename, rm } from 'node:fs/promises'
2
2
  import { join } from 'node:path'
3
- import VError from 'verror'
4
3
  import * as Download from '../Download/Download.js'
5
4
  import * as Extract from '../Extract/Extract.js'
6
5
  import * as JsonFile from '../JsonFile/JsonFile.js'
7
6
  import * as Platform from '../Platform/Platform.js'
8
7
  import * as TmpFile from '../TmpFile/TmpFile.js'
8
+ import { VError } from '../VError/VError.js'
9
9
 
10
10
  export const install = async ({ url }) => {
11
11
  try {
@@ -23,22 +23,6 @@ const linkFallBack = async (path) => {
23
23
  }
24
24
  }
25
25
 
26
- const linkMonoRepo = async (path, error) => {
27
- try {
28
- const monoRepoPath = Path.join(path, 'packages', 'extension')
29
- const manifest = await ExtensionManifest.get(monoRepoPath)
30
- if (manifest.status === ExtensionManifestStatus.Rejected) {
31
- throw manifest.reason
32
- }
33
- const linkedExtensionsPath = Platform.getLinkedExtensionsPath()
34
- // @ts-ignore
35
- const to = Path.join(linkedExtensionsPath, manifest.id)
36
- await SymLink.createSymLink(monoRepoPath, to)
37
- } catch {
38
- throw error
39
- }
40
- }
41
-
42
26
  export const link = async (path) => {
43
27
  try {
44
28
  const manifest = await ExtensionManifest.get(path)
@@ -53,9 +37,6 @@ export const link = async (path) => {
53
37
  if (error && error.code === ErrorCodes.EEXIST) {
54
38
  return linkFallBack(path)
55
39
  }
56
- if (error && error.code === ErrorCodes.E_MANIFEST_NOT_FOUND) {
57
- await linkMonoRepo(path, new VError(error, `Failed to link extension`))
58
- }
59
40
  throw new VError(error, `Failed to link extension`)
60
41
  }
61
42
  }
@@ -1,9 +1,9 @@
1
1
  import { basename } from 'node:path'
2
- import VError from 'verror'
3
2
  import * as ExtensionManifestInputType from '../ExtensionManifestInputType/ExtensionManifestInputType.js'
4
3
  import * as ExtensionManifests from '../ExtensionManifests/ExtensionManifests.js'
5
4
  import * as Platform from '../Platform/Platform.js'
6
5
  import * as ExtensionManifestStatus from '../ExtensionManifestStatus/ExtensionManifestStatus.js'
6
+ import { VError } from '../VError/VError.js'
7
7
 
8
8
  const getManifestVersion = (json) => {
9
9
  if (json && json.version && typeof json.version === 'string') {
@@ -19,12 +19,21 @@ const getManifestId = (json) => {
19
19
  return basename(json.path)
20
20
  }
21
21
 
22
+ const getSymlink = (json) => {
23
+ if (json && json.symlink && typeof json.symlink === 'string') {
24
+ return json.symlink
25
+ }
26
+ return ''
27
+ }
28
+
22
29
  const getManifestInfo = (json) => {
23
30
  const id = getManifestId(json)
24
31
  const version = getManifestVersion(json)
32
+ const symlink = getSymlink(json)
25
33
  return {
26
34
  id,
27
35
  version,
36
+ symlink,
28
37
  }
29
38
  }
30
39
 
@@ -41,7 +50,7 @@ export const list = async () => {
41
50
  try {
42
51
  const manifests = await ExtensionManifests.getAll([
43
52
  {
44
- type: ExtensionManifestInputType.Folder,
53
+ type: ExtensionManifestInputType.LinkedExtensionsFolder,
45
54
  path: Platform.getLinkedExtensionsPath(),
46
55
  },
47
56
  {
@@ -1,58 +1,10 @@
1
- import { mkdir, rename, rm } from 'node:fs/promises'
2
- import { VError } from '../VError/VError.js'
1
+ import { mkdir, rename } from 'node:fs/promises'
3
2
  import * as Debug from '../Debug/Debug.js'
4
3
  import * as ExtensionManifestInputType from '../ExtensionManifestInputType/ExtensionManifestInputType.js'
5
4
  import * as ExtensionManifests from '../ExtensionManifests/ExtensionManifests.js'
6
5
  import * as Path from '../Path/Path.js'
7
6
  import * as Platform from '../Platform/Platform.js'
8
- import * as Queue from '../Queue/Queue.js'
9
-
10
- export const install = async (id) => {
11
- // TODO this should be a stateless function, renderer-worker should have info on marketplace url
12
- // TODO use command.execute
13
- try {
14
- const { download } = await import('../Download/Download.js')
15
- const { extractTarBr } = await import('../Extract/Extract.js')
16
- const marketplaceUrl = Platform.getMarketplaceUrl()
17
- Debug.debug(`ExtensionManagement#install ${id}`)
18
- const cachedExtensionsPath = Platform.getCachedExtensionsPath()
19
- const extensionsPath = Platform.getExtensionsPath()
20
- // TODO maybe a queue is over engineering here
21
- await Queue.add('download', async () => {
22
- Debug.debug(`ExtensionManagement#download ${id}`)
23
- // TODO use command.execute
24
- await download(
25
- `${marketplaceUrl}/download/${id}`,
26
- Path.join(cachedExtensionsPath, `${id}.tar.br`)
27
- )
28
- Debug.debug(`ExtensionManagement#extract ${id}`)
29
- await extractTarBr(
30
- Path.join(cachedExtensionsPath, `${id}.tar.br`),
31
- Path.join(extensionsPath, id)
32
- )
33
- })
34
- // TODO should this be here? (probably not)
35
- // await ExtensionHost.enableExtension({
36
- // id,
37
- // type: 'marketplace',
38
- // })
39
- } catch (error) {
40
- throw new VError(error, `Failed to install extension "${id}"`)
41
- }
42
- }
43
-
44
- export const uninstall = async (id) => {
45
- try {
46
- Debug.debug(`ExtensionManagement#uninstall ${id}`)
47
- const extensionsPath = Platform.getExtensionsPath()
48
- await rm(Path.join(extensionsPath, id), { recursive: true })
49
- } catch (error) {
50
- // if (error.code === 'ENOENT') {
51
- // return
52
- // }
53
- throw new VError(error, `Failed to uninstall extension "${id}"`)
54
- }
55
- }
7
+ import { VError } from '../VError/VError.js'
56
8
 
57
9
  export const enable = async (id) => {
58
10
  try {
@@ -60,10 +12,7 @@ export const enable = async (id) => {
60
12
  const extensionsPath = Platform.getExtensionsPath()
61
13
  const disabledExtensionsPath = Platform.getDisabledExtensionsPath()
62
14
  await mkdir(extensionsPath, { recursive: true })
63
- await rename(
64
- Path.join(disabledExtensionsPath, id),
65
- Path.join(extensionsPath, id)
66
- )
15
+ await rename(Path.join(disabledExtensionsPath, id), Path.join(extensionsPath, id))
67
16
  } catch (error) {
68
17
  throw new VError(error, `Failed to enable extension "${id}"`)
69
18
  }
@@ -75,10 +24,7 @@ export const disable = async (id) => {
75
24
  const disabledExtensionsPath = Platform.getDisabledExtensionsPath()
76
25
  const extensionsPath = Platform.getExtensionsPath()
77
26
  await mkdir(disabledExtensionsPath, { recursive: true })
78
- await rename(
79
- Path.join(extensionsPath, id),
80
- Path.join(disabledExtensionsPath, id)
81
- )
27
+ await rename(Path.join(extensionsPath, id), Path.join(disabledExtensionsPath, id))
82
28
  } catch (error) {
83
29
  throw new VError(error, `Failed to disable extension ${id}`)
84
30
  }
@@ -131,3 +77,5 @@ export const getDisabledExtensions = () => {
131
77
  },
132
78
  ])
133
79
  }
80
+
81
+ export * from '../ExtensionUninstall/ExtensionUninstall.js'
@@ -1,4 +1,4 @@
1
- import VError from 'verror'
1
+ import * as Assert from '../Assert/Assert.js'
2
2
  import * as Error from '../Error/Error.js'
3
3
  import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
4
4
  import * as FileSystemWatch from '../FileSystemWatch/FileSystemWatch.js'
@@ -6,6 +6,7 @@ import * as ReadJson from '../JsonFile/JsonFile.js'
6
6
  import * as JsonRpcVersion from '../JsonRpcVersion/JsonRpcVersion.js'
7
7
  import * as Path from '../Path/Path.js'
8
8
  import * as Process from '../Process/Process.js'
9
+ import { VError } from '../VError/VError.js'
9
10
  import * as ExtensionManagement from './ExtensionManagement.js'
10
11
 
11
12
  // TODO test this function
@@ -28,6 +29,7 @@ const getColorThemePath = async (extensions, colorThemeId) => {
28
29
  }
29
30
 
30
31
  export const getColorThemeJson = async (colorThemeId) => {
32
+ Assert.string(colorThemeId)
31
33
  const extensions = await ExtensionManagement.getExtensions()
32
34
  const colorThemePath = await getColorThemePath(extensions, colorThemeId)
33
35
  if (!colorThemePath) {
@@ -1,8 +1,8 @@
1
- import VError from 'verror'
2
1
  import * as Error from '../Error/Error.js'
3
2
  import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
4
3
  import * as ReadJson from '../JsonFile/JsonFile.js'
5
4
  import * as Path from '../Path/Path.js'
5
+ import { VError } from '../VError/VError.js'
6
6
  import * as ExtensionManagement from './ExtensionManagement.js'
7
7
 
8
8
  export const getIconTheme = async (iconThemeId) => {
@@ -1,7 +1,8 @@
1
+ // TODO rename file to languageConfiguration.js
1
2
  import { join } from 'node:path'
2
3
  import { pathToFileURL } from 'node:url'
3
- import VError from 'verror'
4
- import * as ReadJson from '../JsonFile/JsonFile.js'
4
+ import * as JsonFile from '../JsonFile/JsonFile.js'
5
+ import { VError } from '../VError/VError.js'
5
6
  import * as ExtensionManagement from './ExtensionManagement.js'
6
7
 
7
8
  const getExtensionLanguages = (extension) => {
@@ -70,7 +71,10 @@ export const getLanguageConfiguration = async (languageId) => {
70
71
  try {
71
72
  const extensions = await ExtensionManagement.getExtensions()
72
73
  const languageConfigurationPath = getLanguageConfigurationPathFromExtensions(extensions, languageId)
73
- return await ReadJson.readJson(languageConfigurationPath)
74
+ if (!languageConfigurationPath) {
75
+ return undefined
76
+ }
77
+ return await JsonFile.readJson(languageConfigurationPath)
74
78
  } catch (error) {
75
79
  throw new VError(error, `Failed to load language configuration for ${languageId}`)
76
80
  }
@@ -1,3 +1,5 @@
1
1
  export const Folder = 1
2
2
 
3
3
  export const OnlyExtension = 2
4
+
5
+ export const LinkedExtensionsFolder = 3
@@ -1,5 +1,6 @@
1
1
  import * as ExtensionManifestInputType from '../ExtensionManifestInputType/ExtensionManifestInputType.js'
2
2
  import * as ExtensionManifestsGetFromFolder from './ExtensionManifestsFromFolder.js'
3
+ import * as ExtensionManifestsGetFromLinkedExtensionsFolder from './ExtensionManifestsFromLinkedExtensionsFolder.js'
3
4
  import * as ExtensionManifestsGetFromOnlyExtension from './ExtensionManifestsFromOnlyExtension.js'
4
5
 
5
6
  const getModule = (type) => {
@@ -8,6 +9,8 @@ const getModule = (type) => {
8
9
  return ExtensionManifestsGetFromFolder
9
10
  case ExtensionManifestInputType.OnlyExtension:
10
11
  return ExtensionManifestsGetFromOnlyExtension
12
+ case ExtensionManifestInputType.LinkedExtensionsFolder:
13
+ return ExtensionManifestsGetFromLinkedExtensionsFolder
11
14
  default:
12
15
  throw new Error('unsupported input type')
13
16
  }
@@ -1,16 +1,8 @@
1
- import VError from 'verror'
1
+ import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
2
2
  import * as ExtensionManifest from '../ExtensionManifest/ExtensionManifest.js'
3
3
  import * as FileSystem from '../FileSystem/FileSystem.js'
4
- import * as Path from '../Path/Path.js'
5
- import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
6
-
7
- const toAbsolutePaths = (path, dirents) => {
8
- const absolutePaths = []
9
- for (const dirent of dirents) {
10
- absolutePaths.push(Path.join(path, dirent))
11
- }
12
- return absolutePaths
13
- }
4
+ import * as ToAbsolutePaths from '../ToAbsolutePaths/ToAbsolutePaths.js'
5
+ import { VError } from '../VError/VError.js'
14
6
 
15
7
  export const getExtensionManifests = async (path) => {
16
8
  try {
@@ -18,10 +10,8 @@ export const getExtensionManifests = async (path) => {
18
10
  return []
19
11
  }
20
12
  const dirents = await FileSystem.readDir(path)
21
- const absolutePaths = toAbsolutePaths(path, dirents)
22
- const manifests = await Promise.all(
23
- absolutePaths.map(ExtensionManifest.get)
24
- )
13
+ const absolutePaths = ToAbsolutePaths.toAbsolutePaths(path, dirents)
14
+ const manifests = await Promise.all(absolutePaths.map(ExtensionManifest.get))
25
15
  return manifests
26
16
  } catch (error) {
27
17
  // TODO how to make typescript happy?
@@ -0,0 +1,56 @@
1
+ import { readlink } from 'fs/promises'
2
+ import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
3
+ import * as ExtensionManifest from '../ExtensionManifest/ExtensionManifest.js'
4
+ import * as ExtensionManifestStatus from '../ExtensionManifestStatus/ExtensionManifestStatus.js'
5
+ import * as FileSystem from '../FileSystem/FileSystem.js'
6
+ import * as ToAbsolutePaths from '../ToAbsolutePaths/ToAbsolutePaths.js'
7
+ import { VError } from '../VError/VError.js'
8
+
9
+ const readSymlink = async (absolutePath) => {
10
+ try {
11
+ const info = await readlink(absolutePath)
12
+ return info
13
+ } catch {
14
+ return ''
15
+ }
16
+ }
17
+
18
+ const readSymlinks = (absolutePaths) => {
19
+ return Promise.all(absolutePaths.map(readSymlink))
20
+ }
21
+
22
+ const mergeWithSymLinks = (manifests, symlinks) => {
23
+ const length = manifests.length
24
+ const merged = []
25
+ for (let i = 0; i < length; i++) {
26
+ const manifest = manifests[i]
27
+ const symlink = symlinks[i]
28
+ if (manifest.status === ExtensionManifestStatus.Rejected) {
29
+ merged.push(manifest)
30
+ } else {
31
+ merged.push({ ...manifest, symlink })
32
+ }
33
+ }
34
+ return merged
35
+ }
36
+
37
+ export const getExtensionManifests = async (path) => {
38
+ try {
39
+ if (!path) {
40
+ return []
41
+ }
42
+ const dirents = await FileSystem.readDir(path)
43
+ const absolutePaths = ToAbsolutePaths.toAbsolutePaths(path, dirents)
44
+ const manifests = await Promise.all(absolutePaths.map(ExtensionManifest.get))
45
+ const symlinks = await readSymlinks(absolutePaths)
46
+ const merged = mergeWithSymLinks(manifests, symlinks)
47
+ return merged
48
+ } catch (error) {
49
+ // TODO how to make typescript happy?
50
+ // @ts-ignore
51
+ if (error.code === ErrorCodes.ENOENT) {
52
+ return []
53
+ }
54
+ throw new VError(error, 'Failed to get extension manifests')
55
+ }
56
+ }
@@ -0,0 +1,18 @@
1
+ import { rm } from 'node:fs/promises'
2
+ import * as Debug from '../Debug/Debug.js'
3
+ import * as Path from '../Path/Path.js'
4
+ import * as Platform from '../Platform/Platform.js'
5
+ import { VError } from '../VError/VError.js'
6
+
7
+ export const uninstall = async (id) => {
8
+ try {
9
+ Debug.debug(`ExtensionManagement#uninstall ${id}`)
10
+ const extensionsPath = Platform.getExtensionsPath()
11
+ await rm(Path.join(extensionsPath, id), { recursive: true })
12
+ } catch (error) {
13
+ // if (error.code === 'ENOENT') {
14
+ // return
15
+ // }
16
+ throw new VError(error, `Failed to uninstall extension "${id}"`)
17
+ }
18
+ }
@@ -1,9 +1,9 @@
1
- import VError from 'verror'
2
1
  import * as ExtensionManifest from '../ExtensionManifest/ExtensionManifest.js'
3
2
  import * as ExtensionManifestStatus from '../ExtensionManifestStatus/ExtensionManifestStatus.js'
4
3
  import * as FileSystem from '../FileSystem/FileSystem.js'
5
4
  import * as Path from '../Path/Path.js'
6
5
  import * as Platform from '../Platform/Platform.js'
6
+ import { VError } from '../VError/VError.js'
7
7
 
8
8
  export const unlink = async (path) => {
9
9
  try {
@@ -3,16 +3,12 @@ import { mkdir } from 'node:fs/promises'
3
3
  import { pipeline } from 'node:stream/promises'
4
4
  import { createBrotliDecompress, createGunzip } from 'node:zlib'
5
5
  import tar from 'tar-fs'
6
- import VError from 'verror'
6
+ import { VError } from '../VError/VError.js'
7
7
 
8
8
  export const extractTarBr = async (inFile, outDir) => {
9
9
  try {
10
10
  await mkdir(outDir, { recursive: true })
11
- await pipeline(
12
- createReadStream(inFile),
13
- createBrotliDecompress(),
14
- tar.extract(outDir)
15
- )
11
+ await pipeline(createReadStream(inFile), createBrotliDecompress(), tar.extract(outDir))
16
12
  } catch (error) {
17
13
  throw new VError(error, `Failed to extract ${inFile}`)
18
14
  }
@@ -1,6 +1,6 @@
1
1
  import { mkdir } from 'node:fs/promises'
2
2
  import extract from 'extract-zip'
3
- import VError from 'verror'
3
+ import { VError } from '../VError/VError.js'
4
4
 
5
5
  export const extractZip = async ({ inFile, outDir }) => {
6
6
  try {