@lvce-editor/shared-process 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/config/defaultKeyBindings.json +30 -0
  2. package/config/defaultSettings.json +6 -0
  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 +7 -1
  6. package/extensions/builtin.language-basics-html/src/tokenizeHtml.js +77 -27
  7. package/extensions/builtin.language-basics-javascript/src/tokenizeJavaScript.js +29 -1
  8. package/extensions/builtin.language-basics-json/extension.json +4 -2
  9. package/extensions/builtin.language-basics-json/src/tokenizeJson.js +3 -0
  10. package/extensions/builtin.language-basics-jsx/src/tokenizeJsx.js +18 -5
  11. package/extensions/builtin.language-basics-vue/src/tokenizeVue.js +1 -1
  12. package/extensions/builtin.language-basics-xml/extension.json +3 -1
  13. package/package.json +9 -10
  14. package/src/parts/Assert/Assert.js +1 -6
  15. package/src/parts/AssertionError/AssertionError.js +6 -0
  16. package/src/parts/BulkReplacement/BulkReplacement.ipc.js +7 -0
  17. package/src/parts/BulkReplacement/BulkReplacement.js +20 -0
  18. package/src/parts/BulkReplacementContent/BulkReplacementContent.js +30 -0
  19. package/src/parts/ChildProcessError/ChildProcessError.js +45 -0
  20. package/src/parts/ChromeExtension/ChromeExtension.js +2 -5
  21. package/src/parts/CleanStack/CleanStack.js +90 -2
  22. package/src/parts/CliList/CliList.js +3 -0
  23. package/src/parts/ClipBoard/ClipBoard.js +2 -2
  24. package/src/parts/ClipBoard/ClipBoardGnome.js +1 -2
  25. package/src/parts/ClipBoard/ClipBoardNoop.js +2 -2
  26. package/src/parts/ClipBoard/ClipBoardWindows.js +1 -3
  27. package/src/parts/Command/Command.js +5 -10
  28. package/src/parts/Credentials/Credentials.ipc.js +5 -5
  29. package/src/parts/Credentials/Credentials.js +2 -10
  30. package/src/parts/Desktop/Desktop.js +22 -0
  31. package/src/parts/Download/Download.js +2 -2
  32. package/src/parts/Error/Error.js +1 -1
  33. package/src/parts/ErrorCodes/ErrorCodes.js +2 -1
  34. package/src/parts/ErrorHandling/ErrorHandling.js +8 -14
  35. package/src/parts/ExtensionHost/ExtensionHost.js +1 -2
  36. package/src/parts/ExtensionHost/ExtensionHostKeyBindings.js +0 -12
  37. package/src/parts/ExtensionHostRpc/ExtensionHostRpc.js +1 -1
  38. package/src/parts/ExtensionInstallFromFile/ExtensionInstallFromFile.js +1 -1
  39. package/src/parts/ExtensionInstallFromGitHub/ExtensionInstallFromGitHub.js +1 -1
  40. package/src/parts/ExtensionInstallFromUrl/ExtensionInstallFromUrl.js +1 -1
  41. package/src/parts/ExtensionLink/ExtensionLink.js +0 -19
  42. package/src/parts/ExtensionList/ExtensionList.js +11 -2
  43. package/src/parts/ExtensionManagement/ExtensionManagement.js +6 -58
  44. package/src/parts/ExtensionManagement/ExtensionManagementColorTheme.js +3 -1
  45. package/src/parts/ExtensionManagement/ExtensionManagementIconTheme.js +1 -1
  46. package/src/parts/ExtensionManagement/ExtensionManagementLanguages.js +7 -3
  47. package/src/parts/ExtensionManifestInputType/ExtensionManifestInputType.js +2 -0
  48. package/src/parts/ExtensionManifests/ExtensionManifests.js +3 -0
  49. package/src/parts/ExtensionManifests/ExtensionManifestsFromFolder.js +5 -15
  50. package/src/parts/ExtensionManifests/ExtensionManifestsFromLinkedExtensionsFolder.js +56 -0
  51. package/src/parts/ExtensionUninstall/ExtensionUninstall.js +18 -0
  52. package/src/parts/ExtensionUnlink/ExtensionUnlink.js +1 -1
  53. package/src/parts/Extract/Extract.js +2 -6
  54. package/src/parts/ExtractZip/ExtractZip.js +1 -1
  55. package/src/parts/{Error → FileNotFoundError}/FileNotFoundError.js +9 -2
  56. package/src/parts/FileSystem/FileSystem.js +6 -32
  57. package/src/parts/FirstNodeWorkerEventType/FirstNodeWorkerEventType.js +5 -0
  58. package/src/parts/GetDirentType/GetDirentType.js +27 -0
  59. package/src/parts/GetFirstNodeChildProcessEvent/GetFirstNodeChildProcessEvent.js +39 -0
  60. package/src/parts/GetFirstNodeWorkerEvent/GetFirstNodeWorkerEvent.js +21 -0
  61. package/src/parts/GetNewLineIndex/GetNewLineIndex.js +9 -0
  62. package/src/parts/GetResponse/GetResponse.js +16 -6
  63. package/src/parts/GetTextSearchRipGrepArgs/GetTextSearchRipGrepArgs.js +14 -0
  64. package/src/parts/InstallExtension/InstallExtension.ipc.js +6 -0
  65. package/src/parts/InstallExtension/InstallExtension.js +33 -0
  66. package/src/parts/IpcParent/IpcParent.js +9 -0
  67. package/src/parts/IpcParentModule/IpcParentModule.js +12 -0
  68. package/src/parts/IpcParentType/IpcParentType.js +2 -0
  69. package/src/parts/IpcParentWithNodeForkedProcess/IpcParentWithNodeForkedProcess.js +49 -0
  70. package/src/parts/IpcParentWithNodeWorker/IpcParentWithNodeWorker.js +36 -0
  71. package/src/parts/IsEnoentErrorWindows/IsEnoentErrorWindows.js +3 -0
  72. package/src/parts/IsIgnoredError/IsIgnoredError.js +14 -0
  73. package/src/parts/Json/Json.js +3 -5
  74. package/src/parts/JsonError/JsonError.js +8 -14
  75. package/src/parts/JsonParsingError/JsonParsingError.js +17 -0
  76. package/src/parts/Jsonc/Jsonc.js +304 -0
  77. package/src/parts/JsoncCharCode/JsoncCharCode.js +23 -0
  78. package/src/parts/JsoncFile/JsoncFile.js +8 -0
  79. package/src/parts/JsoncTokenType/JsoncTokenType.js +11 -0
  80. package/src/parts/LimitString/LimitString.js +3 -1
  81. package/src/parts/MergeStacks/MergeStacks.js +3 -2
  82. package/src/parts/Module/Module.js +4 -0
  83. package/src/parts/ModuleId/ModuleId.js +2 -0
  84. package/src/parts/ModuleMap/ModuleMap.js +4 -0
  85. package/src/parts/Native/Native.js +1 -1
  86. package/src/parts/ParentIpc/ParentIpc.js +2 -1
  87. package/src/parts/Platform/Platform.js +0 -21
  88. package/src/parts/Preferences/Preferences.js +6 -8
  89. package/src/parts/PrettyError/PrettyError.js +16 -7
  90. package/src/parts/PrintPrettyError/PrintPrettyError.js +3 -1
  91. package/src/parts/RecentlyOpened/RecentlyOpened.js +3 -7
  92. package/src/parts/RequiresSocket/RequiresSocket.js +1 -0
  93. package/src/parts/RipGrep/RipGrep.js +1 -1
  94. package/src/parts/SearchFile/SearchFile.js +4 -9
  95. package/src/parts/Socket/Socket.js +2 -7
  96. package/src/parts/Terminal/Terminal.ipc.js +4 -41
  97. package/src/parts/Terminal/Terminal.js +29 -25
  98. package/src/parts/TextSearch/TextSearch.js +102 -108
  99. package/src/parts/ToAbsolutePaths/ToAbsolutePaths.js +9 -0
  100. package/src/parts/ToTextSearchResult/ToTextSearchResult.js +42 -0
  101. package/src/parts/Trash/Trash.js +1 -2
  102. /package/src/parts/{RgPath/RgPath.js → RipGrepPath/RipGrepPath.js} +0 -0
@@ -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 {
@@ -1,9 +1,16 @@
1
- import VError from 'verror'
2
1
  import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
2
+ import { VError } from '../VError/VError.js'
3
+
4
+ const getDisplayPath = (path) => {
5
+ if (path === '') {
6
+ return '<empty string>'
7
+ }
8
+ return path
9
+ }
3
10
 
4
11
  export class FileNotFoundError extends VError {
5
12
  constructor(path) {
6
- super(`File not found '${path}'`)
13
+ super(`File not found: '${getDisplayPath(path)}'`)
7
14
  this.name = 'FileNotFoundError'
8
15
  this.code = ErrorCodes.ENOENT
9
16
  }
@@ -1,14 +1,14 @@
1
1
  // TODO lazyload chokidar and trash (but doesn't work currently because of bug with jest)
2
2
  import * as fs from 'node:fs/promises'
3
3
  import * as os from 'node:os'
4
- import VError from 'verror'
5
- import * as DirentType from '../DirentType/DirentType.js'
6
- import { FileNotFoundError } from '../Error/FileNotFoundError.js'
4
+ import * as EncodingType from '../EncodingType/EncodingType.js'
5
+ import { FileNotFoundError } from '../FileNotFoundError/FileNotFoundError.js'
7
6
  import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
7
+ import * as GetDirentType from '../GetDirentType/GetDirentType.js'
8
8
  import * as Path from '../Path/Path.js'
9
9
  import * as Platform from '../Platform/Platform.js'
10
10
  import * as Trash from '../Trash/Trash.js'
11
- import * as EncodingType from '../EncodingType/EncodingType.js'
11
+ import { VError } from '../VError/VError.js'
12
12
 
13
13
  export const state = {
14
14
  watcherMap: Object.create(null),
@@ -132,39 +132,13 @@ export const exists = async (path) => {
132
132
  }
133
133
  }
134
134
 
135
- /**
136
- * @param {import('fs').Dirent|import('fs').StatsBase} dirent
137
- */
138
- const getType = (dirent) => {
139
- if (dirent.isFile()) {
140
- return DirentType.File
141
- }
142
- if (dirent.isDirectory()) {
143
- return DirentType.Directory
144
- }
145
- if (dirent.isSymbolicLink()) {
146
- return DirentType.Symlink
147
- }
148
- if (dirent.isSocket()) {
149
- return DirentType.Socket
150
- }
151
- if (dirent.isBlockDevice()) {
152
- return DirentType.BlockDevice
153
- }
154
- if (dirent.isCharacterDevice()) {
155
- return DirentType.CharacterDevice
156
- }
157
- console.log({ dirent })
158
- return DirentType.Unknown
159
- }
160
-
161
135
  /**
162
136
  * @param {import('fs').Dirent} dirent
163
137
  */
164
138
  const toPrettyDirent = (dirent) => {
165
139
  return {
166
140
  name: dirent.name,
167
- type: getType(dirent),
141
+ type: GetDirentType.getDirentType(dirent),
168
142
  }
169
143
  }
170
144
 
@@ -264,7 +238,7 @@ export const getRealPath = async (path) => {
264
238
  // TODO handle error
265
239
  export const stat = async (path) => {
266
240
  const stats = await fs.stat(path)
267
- const type = getType(stats)
241
+ const type = GetDirentType.getDirentType(stats)
268
242
  return type
269
243
  }
270
244
 
@@ -0,0 +1,5 @@
1
+ export const Exit = 'exit'
2
+
3
+ export const Error = 'error'
4
+
5
+ export const Message = 'message'
@@ -0,0 +1,27 @@
1
+ import * as DirentType from '../DirentType/DirentType.js'
2
+
3
+ /**
4
+ * @param {import('fs').Dirent|import('fs').StatsBase} dirent
5
+ */
6
+ export const getDirentType = (dirent) => {
7
+ if (dirent.isFile()) {
8
+ return DirentType.File
9
+ }
10
+ if (dirent.isDirectory()) {
11
+ return DirentType.Directory
12
+ }
13
+ if (dirent.isSymbolicLink()) {
14
+ return DirentType.Symlink
15
+ }
16
+ if (dirent.isSocket()) {
17
+ return DirentType.Socket
18
+ }
19
+ if (dirent.isBlockDevice()) {
20
+ return DirentType.BlockDevice
21
+ }
22
+ if (dirent.isCharacterDevice()) {
23
+ return DirentType.CharacterDevice
24
+ }
25
+ console.log({ dirent })
26
+ return DirentType.Unknown
27
+ }
@@ -0,0 +1,39 @@
1
+ import * as FirstNodeWorkerEventType from '../FirstNodeWorkerEventType/FirstNodeWorkerEventType.js'
2
+
3
+ export const getFirstNodeChildProcessEvent = async (childProcess) => {
4
+ const { type, event, stdout, stderr } = await new Promise((resolve, reject) => {
5
+ let stderr = ''
6
+ let stdout = ''
7
+ const cleanup = () => {
8
+ childProcess.stderr.off('data', handleStdErrData)
9
+ childProcess.stdout.off('data', handleStdoutData)
10
+ childProcess.off('message', handleMessage)
11
+ childProcess.off('exit', handleExit)
12
+ childProcess.off('error', handleError)
13
+ }
14
+ const handleStdErrData = (data) => {
15
+ stderr += data
16
+ }
17
+ const handleStdoutData = (data) => {
18
+ stdout += data
19
+ }
20
+ const handleMessage = (event) => {
21
+ cleanup()
22
+ resolve({ type: FirstNodeWorkerEventType.Message, event, stdout, stderr })
23
+ }
24
+ const handleExit = (event) => {
25
+ cleanup()
26
+ resolve({ type: FirstNodeWorkerEventType.Exit, event, stdout, stderr })
27
+ }
28
+ const handleError = (event) => {
29
+ cleanup()
30
+ resolve({ type: FirstNodeWorkerEventType.Error, event, stdout, stderr })
31
+ }
32
+ childProcess.stderr.on('data', handleStdErrData)
33
+ childProcess.stdout.on('data', handleStdoutData)
34
+ childProcess.on('message', handleMessage)
35
+ childProcess.on('exit', handleExit)
36
+ childProcess.on('error', handleError)
37
+ })
38
+ return { type, event, stdout, stderr }
39
+ }
@@ -0,0 +1,21 @@
1
+ import * as FirstNodeWorkerEventType from '../FirstNodeWorkerEventType/FirstNodeWorkerEventType.js'
2
+
3
+ export const getFirstNodeWorkerEvent = async (worker) => {
4
+ const { type, event } = await new Promise((resolve, reject) => {
5
+ const cleanup = () => {
6
+ worker.off('exit', handleExit)
7
+ worker.off('error', handleError)
8
+ }
9
+ const handleExit = (event) => {
10
+ cleanup()
11
+ resolve({ type: FirstNodeWorkerEventType.Exit, event })
12
+ }
13
+ const handleError = (event) => {
14
+ cleanup()
15
+ resolve({ type: FirstNodeWorkerEventType.Error, event })
16
+ }
17
+ worker.on('exit', handleExit)
18
+ worker.on('error', handleError)
19
+ })
20
+ return { type, event }
21
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ *
3
+ * @param {string} string
4
+ * @param {number|undefined} startIndex
5
+ * @returns
6
+ */
7
+ export const getNewLineIndex = (string, startIndex = undefined) => {
8
+ return string.indexOf('\n', startIndex)
9
+ }
@@ -1,24 +1,31 @@
1
1
  import * as Command from '../Command/Command.js'
2
+ import { CommandNotFoundError } from '../CommandNotFoundError/CommandNotFoundError.js'
2
3
  import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
3
4
  import * as JsonRpcErrorCode from '../JsonRpcErrorCode/JsonRpcErrorCode.js'
4
5
  import * as JsonRpcVersion from '../JsonRpcVersion/JsonRpcVersion.js'
5
6
  import * as PrettyError from '../PrettyError/PrettyError.js'
6
7
  import * as PrintPrettyError from '../PrintPrettyError/PrintPrettyError.js'
7
- import { requiresSocket } from '../RequiresSocket/RequiresSocket.js'
8
+ import * as RequiresSocket from '../RequiresSocket/RequiresSocket.js'
9
+
10
+ const shouldLogError = (error) => {
11
+ if (error && error.code === ErrorCodes.ENOENT) {
12
+ return false
13
+ }
14
+ return true
15
+ }
8
16
 
9
17
  export const getResponse = async (message, handle) => {
10
18
  try {
11
- const result = requiresSocket(message.method)
19
+ const result = RequiresSocket.requiresSocket(message.method)
12
20
  ? await Command.execute(message.method, handle, ...message.params)
13
21
  : await Command.execute(message.method, ...message.params)
14
-
15
22
  return {
16
23
  jsonrpc: JsonRpcVersion.Two,
17
24
  id: message.id,
18
25
  result: result ?? null,
19
26
  }
20
27
  } catch (error) {
21
- if (error && error instanceof Error && error.message && error.message.startsWith('method not found')) {
28
+ if (error && error instanceof CommandNotFoundError) {
22
29
  return {
23
30
  jsonrpc: JsonRpcVersion.Two,
24
31
  id: message.id,
@@ -29,14 +36,16 @@ export const getResponse = async (message, handle) => {
29
36
  },
30
37
  }
31
38
  }
32
- // @ts-ignore
33
- if (error && error instanceof Error && error.code === ErrorCodes.ENOENT) {
39
+ if (!shouldLogError(error)) {
34
40
  return {
35
41
  jsonrpc: JsonRpcVersion.Two,
36
42
  id: message.id,
37
43
  error: {
38
44
  code: JsonRpcErrorCode.Custom,
39
45
  message: `${error}`,
46
+ data: {
47
+ code: error.code,
48
+ },
40
49
  },
41
50
  }
42
51
  }
@@ -51,6 +60,7 @@ export const getResponse = async (message, handle) => {
51
60
  data: {
52
61
  stack: prettyError.stack,
53
62
  codeFrame: prettyError.codeFrame,
63
+ type: prettyError.type,
54
64
  },
55
65
  },
56
66
  }
@@ -0,0 +1,14 @@
1
+ export const getRipGrepArgs = ({ threads, isCaseSensitive, searchString }) => {
2
+ const ripGrepArgs = ['--smart-case', '--stats', '--json']
3
+ ripGrepArgs.push('--threads', `${threads}`)
4
+ if (isCaseSensitive) {
5
+ ripGrepArgs.push('--case-sensitive')
6
+ } else {
7
+ ripGrepArgs.push('--ignore-case')
8
+ }
9
+ ripGrepArgs.push('--fixed-strings')
10
+ ripGrepArgs.push('--')
11
+ ripGrepArgs.push(searchString)
12
+ ripGrepArgs.push('.')
13
+ return ripGrepArgs
14
+ }
@@ -0,0 +1,6 @@
1
+ import * as InstallExtension from './InstallExtension.js'
2
+
3
+ // prettier-ignore
4
+ export const Commands = {
5
+ 'InstallExtension.installExtension': InstallExtension.installExtension,
6
+ }
@@ -0,0 +1,33 @@
1
+ import * as Debug from '../Debug/Debug.js'
2
+ import * as Download from '../Download/Download.js'
3
+ import * as Extract from '../Extract/Extract.js'
4
+ import * as Path from '../Path/Path.js'
5
+ import * as Platform from '../Platform/Platform.js'
6
+ import * as Queue from '../Queue/Queue.js'
7
+ import { VError } from '../VError/VError.js'
8
+
9
+ export const installExtension = async (id) => {
10
+ // TODO this should be a stateless function, renderer-worker should have info on marketplace url
11
+ // TODO use command.execute
12
+ try {
13
+ const marketplaceUrl = Platform.getMarketplaceUrl()
14
+ Debug.debug(`ExtensionManagement#install ${id}`)
15
+ const cachedExtensionsPath = Platform.getCachedExtensionsPath()
16
+ const extensionsPath = Platform.getExtensionsPath()
17
+ // TODO maybe a queue is over engineering here
18
+ await Queue.add('download', async () => {
19
+ Debug.debug(`ExtensionManagement#download ${id}`)
20
+ // TODO use command.execute
21
+ await Download.download(`${marketplaceUrl}/download/${id}`, Path.join(cachedExtensionsPath, `${id}.tar.br`))
22
+ Debug.debug(`ExtensionManagement#extract ${id}`)
23
+ await Extract.extractTarBr(Path.join(cachedExtensionsPath, `${id}.tar.br`), Path.join(extensionsPath, id))
24
+ })
25
+ // TODO should this be here? (probably not)
26
+ // await ExtensionHost.enableExtension({
27
+ // id,
28
+ // type: 'marketplace',
29
+ // })
30
+ } catch (error) {
31
+ throw new VError(error, `Failed to install extension "${id}"`)
32
+ }
33
+ }
@@ -0,0 +1,9 @@
1
+ import * as IpcParentModule from '../IpcParentModule/IpcParentModule.js'
2
+
3
+ export const create = async ({ method, ...options }) => {
4
+ const module = await IpcParentModule.getModule(method)
5
+ // @ts-ignore
6
+ const rawIpc = await module.create(options)
7
+ const ipc = module.wrap(rawIpc)
8
+ return ipc
9
+ }
@@ -0,0 +1,12 @@
1
+ import * as IpcParentType from '../IpcParentType/IpcParentType.js'
2
+
3
+ export const getModule = (method) => {
4
+ switch (method) {
5
+ case IpcParentType.NodeWorker:
6
+ return import('../IpcParentWithNodeWorker/IpcParentWithNodeWorker.js')
7
+ case IpcParentType.NodeForkedProcess:
8
+ return import('../IpcParentWithNodeForkedProcess/IpcParentWithNodeForkedProcess.js')
9
+ default:
10
+ throw new Error('unexpected ipc type')
11
+ }
12
+ }
@@ -0,0 +1,2 @@
1
+ export const NodeWorker = 1
2
+ export const NodeForkedProcess = 2
@@ -0,0 +1,49 @@
1
+ import * as Assert from '../Assert/Assert.js'
2
+ import { fork } from 'node:child_process'
3
+ import * as GetFirstNodeChildProcessEvent from '../GetFirstNodeChildProcessEvent/GetFirstNodeChildProcessEvent.js'
4
+ import * as FirstNodeWorkerEventType from '../FirstNodeWorkerEventType/FirstNodeWorkerEventType.js'
5
+ import { ChildProcessError } from '../ChildProcessError/ChildProcessError.js'
6
+ import { VError } from '../VError/VError.js'
7
+
8
+ export const create = async ({ path, argv = [], env, execArgv = [], stdio = 'inherit', name = 'child process' }) => {
9
+ try {
10
+ Assert.string(path)
11
+ const childProcess = fork(path, argv, {
12
+ env,
13
+ execArgv,
14
+ stdio: 'pipe',
15
+ })
16
+ const { type, event, stdout, stderr } = await GetFirstNodeChildProcessEvent.getFirstNodeChildProcessEvent(childProcess)
17
+ if (type === FirstNodeWorkerEventType.Exit) {
18
+ throw new ChildProcessError(stderr)
19
+ }
20
+ if (type === FirstNodeWorkerEventType.Error) {
21
+ throw new Error(`child process had an error ${event}`)
22
+ }
23
+ if (stdio === 'inherit' && childProcess.stdout && childProcess.stderr) {
24
+ childProcess.stdout.pipe(process.stdout)
25
+ childProcess.stderr.pipe(process.stderr)
26
+ }
27
+ return childProcess
28
+ } catch (error) {
29
+ throw new VError(error, `Failed to launch ${name}`)
30
+ }
31
+ }
32
+
33
+ export const wrap = (childProcess) => {
34
+ return {
35
+ childProcess,
36
+ on(event, listener) {
37
+ this.childProcess.on(event, listener)
38
+ },
39
+ send(message) {
40
+ this.childProcess.send(message)
41
+ },
42
+ sendAndTransfer(message, transfer) {
43
+ throw new Error('transfer is not supported')
44
+ },
45
+ dispose() {
46
+ this.childProcess.kill()
47
+ },
48
+ }
49
+ }
@@ -0,0 +1,36 @@
1
+ import { Worker } from 'node:worker_threads'
2
+ import * as Assert from '../Assert/Assert.js'
3
+ import * as FirstNodeWorkerEventType from '../FirstNodeWorkerEventType/FirstNodeWorkerEventType.js'
4
+ import * as GetFirstNodeWorkerEvent from '../GetFirstNodeWorkerEvent/GetFirstNodeWorkerEvent.js'
5
+
6
+ export const create = async ({ path, argv, env, execArgv }) => {
7
+ Assert.string(path)
8
+ const worker = new Worker(path, {
9
+ argv,
10
+ env,
11
+ execArgv,
12
+ })
13
+ const { type, event } = await GetFirstNodeWorkerEvent.getFirstNodeWorkerEvent(worker)
14
+ if (type === FirstNodeWorkerEventType.Error) {
15
+ throw event
16
+ }
17
+ return worker
18
+ }
19
+
20
+ export const wrap = (worker) => {
21
+ return {
22
+ worker,
23
+ on(event, listener) {
24
+ this.worker.on(event, listener)
25
+ },
26
+ send(message) {
27
+ this.worker.postMessage(message)
28
+ },
29
+ sendAndTransfer(message, transfer) {
30
+ this.worker.postMessage(message, transfer)
31
+ },
32
+ dispose() {
33
+ this.worker.terminate()
34
+ },
35
+ }
36
+ }