@lvce-editor/shared-process 0.89.3 → 0.90.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.
@@ -35,12 +35,10 @@
35
35
 
36
36
  "sessionReplay.enabled": false,
37
37
 
38
- "serviceWorker.enabled": false,
39
-
40
38
  "simpleBrowser.suggestions": false,
41
39
 
42
40
  "terminal.backend": "real",
43
- "terminal.renderer": "termterm",
41
+ "terminal.renderer": "xterm",
44
42
  "terminal.separateConnection": false,
45
43
 
46
44
  "window.titleBarStyle": "custom",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/shared-process",
3
- "version": "0.89.3",
3
+ "version": "0.90.2",
4
4
  "main": "index.js",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -19,7 +19,7 @@
19
19
  "dependencies": {
20
20
  "@lvce-editor/assert": "1.7.0",
21
21
  "@lvce-editor/auth-process": "1.9.0",
22
- "@lvce-editor/extension-host-helper-process": "0.89.3",
22
+ "@lvce-editor/extension-host-helper-process": "0.90.2",
23
23
  "@lvce-editor/ipc": "16.3.0",
24
24
  "@lvce-editor/json-rpc": "8.2.0",
25
25
  "@lvce-editor/jsonc-parser": "1.5.0",
@@ -28,6 +28,7 @@
28
28
  "@lvce-editor/rpc-registry": "9.35.0",
29
29
  "@lvce-editor/verror": "1.7.0",
30
30
  "is-object": "^1.0.2",
31
+ "markdown-it": "^14.3.0",
31
32
  "xdg-basedir": "^5.1.0"
32
33
  },
33
34
  "optionalDependencies": {
@@ -3,6 +3,6 @@ import { fileURLToPath } from 'url'
3
3
 
4
4
  export const getBuiltinExtensionsPath = () => {
5
5
  const staticServerPath = fileURLToPath(import.meta.resolve('@lvce-editor/static-server'))
6
- const builtinExtensionsPath = join(staticServerPath, '..', '..', 'static', 'f1db6cb', 'extensions')
6
+ const builtinExtensionsPath = join(staticServerPath, '..', '..', 'static', '6faf35c', 'extensions')
7
7
  return builtinExtensionsPath
8
8
  }
@@ -1,7 +1,11 @@
1
1
  import { spawn, } from 'node:child_process'
2
- import { basename } from 'node:path'
2
+ import { basename, extname } from 'node:path'
3
3
  import { fileURLToPath } from 'node:url'
4
4
  import { LanguageServerMessageParser } from '../LanguageServerMessageParser/LanguageServerMessageParser.js'
5
+ import {
6
+ executeMarkdownLanguageServerRequest,
7
+ isMarkdownLanguageServerRequest,
8
+ } from '../MarkdownLanguageServerRequest/MarkdownLanguageServerRequest.js'
5
9
 
6
10
 
7
11
 
@@ -36,6 +40,21 @@ import { LanguageServerMessageParser } from '../LanguageServerMessageParser/Lang
36
40
 
37
41
 
38
42
 
43
+
44
+ const getSpawnOptions = (uri, argv) => {
45
+ const executablePath = fileURLToPath(uri)
46
+ const extension = extname(executablePath).toLowerCase()
47
+ if (extension === '.js' || extension === '.mjs' || extension === '.cjs') {
48
+ return {
49
+ args: [executablePath, ...argv],
50
+ command: process.execPath,
51
+ }
52
+ }
53
+ return {
54
+ args: argv,
55
+ command: executablePath,
56
+ }
57
+ }
39
58
 
40
59
  const getPosition = (text, offset) => {
41
60
  const safeOffset = Math.max(0, Math.min(offset, text.length))
@@ -62,13 +81,15 @@ export class LanguageServerConnection {
62
81
  pendingRequests = new Map ()
63
82
  ready
64
83
  rootUri
84
+ markdownConfigured = false
65
85
  nextRequestId = 1
66
86
  running = true
67
87
  stderr = ''
68
88
 
69
89
  constructor({ argv, rootUri, uri } ) {
70
90
  this.rootUri = rootUri
71
- this.child = spawn(fileURLToPath(uri), [...argv], {
91
+ const { args, command } = getSpawnOptions(uri, argv)
92
+ this.child = spawn(command, [...args], {
72
93
  stdio: ['pipe', 'pipe', 'pipe'],
73
94
  })
74
95
  this.child.stdout.on('data', (chunk) => {
@@ -103,6 +124,7 @@ export class LanguageServerConnection {
103
124
 
104
125
  async complete(textDocument, offset) {
105
126
  await this.ready
127
+ this.configureMarkdown(textDocument.languageId)
106
128
  this.syncDocument(textDocument)
107
129
  const result = await this.sendRequest('textDocument/completion', {
108
130
  context: {
@@ -122,6 +144,35 @@ export class LanguageServerConnection {
122
144
  return []
123
145
  }
124
146
 
147
+ configureMarkdown(languageId) {
148
+ if (languageId !== 'markdown' || this.markdownConfigured) {
149
+ return
150
+ }
151
+ this.markdownConfigured = true
152
+ this.sendNotification('workspace/didChangeConfiguration', {
153
+ settings: {
154
+ markdown: {
155
+ occurrencesHighlight: {
156
+ enabled: true,
157
+ },
158
+ preferredMdPathExtensionStyle: 'auto',
159
+ server: {
160
+ log: 'off',
161
+ },
162
+ suggest: {
163
+ paths: {
164
+ enabled: true,
165
+ includeWorkspaceHeaderCompletions: 'never',
166
+ },
167
+ },
168
+ validate: {
169
+ enabled: false,
170
+ },
171
+ },
172
+ },
173
+ })
174
+ }
175
+
125
176
  async initialize() {
126
177
  await this.sendRequest('initialize', {
127
178
  capabilities: {
@@ -217,7 +268,7 @@ export class LanguageServerConnection {
217
268
 
218
269
  handleMessage(message) {
219
270
  if (message.method && message.id !== undefined && message.id !== null) {
220
- this.handleServerRequest(message)
271
+ void this.handleServerRequest(message)
221
272
  return
222
273
  }
223
274
  if (message.id === undefined || message.id === null) {
@@ -235,24 +286,40 @@ export class LanguageServerConnection {
235
286
  pending.resolve(message.result)
236
287
  }
237
288
 
238
- handleServerRequest(message) {
239
- let result = null
240
- if (message.method === 'workspace/configuration') {
241
- const itemCount = Array.isArray(message.params?.items) ? message.params.items.length : 0
242
- result = Array.from({ length: itemCount }).fill(null)
243
- } else if (message.method === 'workspace/workspaceFolders') {
244
- result = [
245
- {
246
- name: getWorkspaceName(this.rootUri),
247
- uri: this.rootUri,
289
+ async handleServerRequest(message) {
290
+ try {
291
+ let result = null
292
+ if (message.method === 'workspace/configuration') {
293
+ const itemCount = Array.isArray(message.params?.items) ? message.params.items.length : 0
294
+ result = Array.from({ length: itemCount }).fill(null)
295
+ } else if (message.method === 'workspace/workspaceFolders') {
296
+ result = [
297
+ {
298
+ name: getWorkspaceName(this.rootUri),
299
+ uri: this.rootUri,
300
+ },
301
+ ]
302
+ } else if (isMarkdownLanguageServerRequest(message.method || '')) {
303
+ result = await executeMarkdownLanguageServerRequest(message.method || '', message.params || {}, {
304
+ documents: this.documents,
305
+ rootUri: this.rootUri,
306
+ })
307
+ }
308
+ this.sendMessage({
309
+ id: message.id,
310
+ jsonrpc: '2.0',
311
+ result,
312
+ })
313
+ } catch (error) {
314
+ this.sendMessage({
315
+ error: {
316
+ code: -32_603,
317
+ message: error instanceof Error ? error.message : String(error),
248
318
  },
249
- ]
319
+ id: message.id,
320
+ jsonrpc: '2.0',
321
+ })
250
322
  }
251
- this.sendMessage({
252
- id: message.id,
253
- jsonrpc: '2.0',
254
- result,
255
- })
256
323
  }
257
324
 
258
325
  handleExit(error) {
@@ -0,0 +1,116 @@
1
+ import MarkdownIt from 'markdown-it'
2
+ import { readFile, readdir, stat } from 'node:fs/promises'
3
+ import { isAbsolute, relative, resolve, sep } from 'node:path'
4
+ import { fileURLToPath, pathToFileURL } from 'node:url'
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+ const markdownFileExtensions = new Set(['.markdown', '.md', '.mdown', '.mdtext', '.mdtxt', '.mdwn', '.mkd', '.mkdn'])
21
+ const ignoredDirectories = new Set(['.git', 'node_modules'])
22
+ const markdownIt = new MarkdownIt({ html: true })
23
+
24
+ export const isMarkdownLanguageServerRequest = (method) => {
25
+ return (
26
+ method === 'markdown/parse' ||
27
+ method === 'markdown/fs/readFile' ||
28
+ method === 'markdown/fs/readDirectory' ||
29
+ method === 'markdown/fs/stat' ||
30
+ method === 'markdown/findMarkdownFilesInWorkspace'
31
+ )
32
+ }
33
+
34
+ const getWorkspacePath = (uri, rootUri) => {
35
+ const rootPath = resolve(fileURLToPath(rootUri))
36
+ const targetPath = resolve(fileURLToPath(uri))
37
+ const relativePath = relative(rootPath, targetPath)
38
+ if (relativePath === '..' || relativePath.startsWith(`..${sep}`) || isAbsolute(relativePath)) {
39
+ throw new Error(`Language server file request is outside the workspace`)
40
+ }
41
+ return targetPath
42
+ }
43
+
44
+ const getMarkdownText = async (params, context) => {
45
+ if (typeof params.text === 'string') {
46
+ return params.text
47
+ }
48
+ if (!params.uri) {
49
+ throw new Error(`Markdown parse request is missing a uri`)
50
+ }
51
+ const document = context.documents.get(params.uri)
52
+ if (document) {
53
+ return document.text
54
+ }
55
+ const path = getWorkspacePath(params.uri, context.rootUri)
56
+ return readFile(path, 'utf8')
57
+ }
58
+
59
+ const findMarkdownFiles = async (rootPath) => {
60
+ const result = []
61
+ const visit = async (directory) => {
62
+ const entries = await readdir(directory, { withFileTypes: true })
63
+ await Promise.all(
64
+ entries.map(async (entry) => {
65
+ const path = resolve(directory, entry.name)
66
+ if (entry.isDirectory()) {
67
+ if (ignoredDirectories.has(entry.name)) {
68
+ return
69
+ }
70
+ await visit(path)
71
+ return
72
+ }
73
+ const extensionIndex = entry.name.lastIndexOf('.')
74
+ const extension = extensionIndex === -1 ? '' : entry.name.slice(extensionIndex).toLowerCase()
75
+ if (markdownFileExtensions.has(extension)) {
76
+ result.push(pathToFileURL(path).href)
77
+ }
78
+ }),
79
+ )
80
+ }
81
+ await visit(rootPath)
82
+ return result.sort()
83
+ }
84
+
85
+ export const executeMarkdownLanguageServerRequest = async (
86
+ method,
87
+ params,
88
+ context,
89
+ ) => {
90
+ if (method === 'markdown/parse') {
91
+ return markdownIt.parse(await getMarkdownText(params, context), {})
92
+ }
93
+ if (method === 'markdown/findMarkdownFilesInWorkspace') {
94
+ return findMarkdownFiles(getWorkspacePath(context.rootUri, context.rootUri))
95
+ }
96
+ if (!params.uri) {
97
+ throw new Error(`Markdown file request is missing a uri`)
98
+ }
99
+ const path = getWorkspacePath(params.uri, context.rootUri)
100
+ if (method === 'markdown/fs/readFile') {
101
+ return [...(await readFile(path))]
102
+ }
103
+ if (method === 'markdown/fs/readDirectory') {
104
+ const entries = await readdir(path, { withFileTypes: true })
105
+ return entries.map((entry) => [entry.name, { isDirectory: entry.isDirectory() }])
106
+ }
107
+ if (method === 'markdown/fs/stat') {
108
+ try {
109
+ const fileStat = await stat(path)
110
+ return { isDirectory: fileStat.isDirectory() }
111
+ } catch {
112
+ return undefined
113
+ }
114
+ }
115
+ throw new Error(`Unsupported Markdown language server request: ${method}`)
116
+ }
@@ -61,11 +61,11 @@ export const getSetupName = () => {
61
61
  return 'Lvce-Setup'
62
62
  }
63
63
 
64
- export const version = '0.89.3'
64
+ export const version = '0.90.2'
65
65
 
66
- export const commit = 'f1db6cb'
66
+ export const commit = '6faf35c'
67
67
 
68
- export const date = '2026-07-14T11:58:48.000Z'
68
+ export const date = '2026-07-15T08:29:42.000Z'
69
69
 
70
70
  export const getVersion = () => {
71
71
  return version
@@ -2,5 +2,5 @@ import { join } from 'node:path'
2
2
  import * as Root from '../Root/Root.js'
3
3
 
4
4
  export const getPreloadUrl = () => {
5
- return join(Root.root, 'static', 'f1db6cb', 'packages', 'preload', 'dist', 'index.js')
5
+ return join(Root.root, 'static', '6faf35c', 'packages', 'preload', 'dist', 'index.js')
6
6
  }