@nicodoggie/mdx-language-server 0.6.3
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/LICENSE +21 -0
- package/README.md +403 -0
- package/lib/frontmatter-schemas.js +189 -0
- package/lib/index.js +158 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Remco Haszing <remcohaszing@gmail.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
# `@mdx-js/language-server`
|
|
2
|
+
|
|
3
|
+
[![Build][build-badge]][build]
|
|
4
|
+
[![Coverage][coverage-badge]][coverage]
|
|
5
|
+
[![Downloads][downloads-badge]][downloads]
|
|
6
|
+
[![Sponsors][sponsors-badge]][collective]
|
|
7
|
+
[![Backers][backers-badge]][collective]
|
|
8
|
+
[![Chat][chat-badge]][chat]
|
|
9
|
+
|
|
10
|
+
A [language server][lsp] for [MDX][].
|
|
11
|
+
|
|
12
|
+
## Contents
|
|
13
|
+
|
|
14
|
+
* [What is this?](#what-is-this)
|
|
15
|
+
* [When should I use this?](#when-should-i-use-this)
|
|
16
|
+
* [Install](#install)
|
|
17
|
+
* [Use](#use)
|
|
18
|
+
* [Language server features](#language-server-features)
|
|
19
|
+
* [Initialize Options](#initialize-options)
|
|
20
|
+
* [Configuration](#configuration)
|
|
21
|
+
* [TypeScript](#typescript)
|
|
22
|
+
* [Plugins](#plugins)
|
|
23
|
+
* [Editors](#editors)
|
|
24
|
+
* [Emacs](#emacs)
|
|
25
|
+
* [Neovim](#neovim)
|
|
26
|
+
* [Visual Studio Code](#visual-studio-code)
|
|
27
|
+
* [Compatibility](#compatibility)
|
|
28
|
+
* [Security](#security)
|
|
29
|
+
* [Contribute](#contribute)
|
|
30
|
+
* [Sponsor](#sponsor)
|
|
31
|
+
* [Changelog](#changelog)
|
|
32
|
+
* [License](#license)
|
|
33
|
+
|
|
34
|
+
## What is this?
|
|
35
|
+
|
|
36
|
+
This package provides a [language server][lsp] for [MDX][].
|
|
37
|
+
The language server provides editor support based on [Volar][].
|
|
38
|
+
This includes support for [TypeScript][] as well as some MDX specific features.
|
|
39
|
+
|
|
40
|
+
## When should I use this?
|
|
41
|
+
|
|
42
|
+
You can use this package if you want to enhance your editor for [MDX][] files
|
|
43
|
+
with features such as autocomplete and error diagnostics.
|
|
44
|
+
Some editors can consume this package directly, others need a plugin in order to
|
|
45
|
+
consume this package.
|
|
46
|
+
|
|
47
|
+
## Install
|
|
48
|
+
|
|
49
|
+
In Node.js (version 16+), install with [npm][]:
|
|
50
|
+
|
|
51
|
+
```sh
|
|
52
|
+
npm install @mdx-js/language-server
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Use
|
|
56
|
+
|
|
57
|
+
How to use this package depends on your editor integration.
|
|
58
|
+
|
|
59
|
+
This package provides the `mdx-language-server` CLI.
|
|
60
|
+
Because this is based on [`vscode-languageserver`][vscode-languageserver], the
|
|
61
|
+
same transports are supported.
|
|
62
|
+
|
|
63
|
+
### Language server features
|
|
64
|
+
|
|
65
|
+
This language server supports all features supported by
|
|
66
|
+
[`volar-service-markdown`][volar-service-markdown] and
|
|
67
|
+
[`volar-service-typescript`][volar-service-typescript], plus some additional
|
|
68
|
+
features specific to MDX.
|
|
69
|
+
|
|
70
|
+
#### Commands
|
|
71
|
+
|
|
72
|
+
The language server supports the following [LSP commands][]:
|
|
73
|
+
|
|
74
|
+
##### `mdx.toggleDelete`
|
|
75
|
+
|
|
76
|
+
Toggle delete syntax at the cursor position.
|
|
77
|
+
It uses the `workspace/applyEdit` command to apply edits.
|
|
78
|
+
|
|
79
|
+
###### Arguments
|
|
80
|
+
|
|
81
|
+
* `uri` — The URI of the document to apply changes to.
|
|
82
|
+
* `range` — The current selection range of the user.
|
|
83
|
+
|
|
84
|
+
###### Returns
|
|
85
|
+
|
|
86
|
+
`null`
|
|
87
|
+
|
|
88
|
+
##### `mdx.toggleEmphasis`
|
|
89
|
+
|
|
90
|
+
Toggle emphasis syntax at the cursor position.
|
|
91
|
+
It uses the `workspace/applyEdit` command to apply edits.
|
|
92
|
+
|
|
93
|
+
###### Arguments
|
|
94
|
+
|
|
95
|
+
* `uri` — The URI of the document to apply changes to.
|
|
96
|
+
* `range` — The current selection range of the user.
|
|
97
|
+
|
|
98
|
+
###### Returns
|
|
99
|
+
|
|
100
|
+
`null`
|
|
101
|
+
|
|
102
|
+
##### `mdx.toggleInlineCode`
|
|
103
|
+
|
|
104
|
+
Toggle inline code syntax at the cursor position.
|
|
105
|
+
It uses the `workspace/applyEdit` command to apply edits.
|
|
106
|
+
|
|
107
|
+
###### Arguments
|
|
108
|
+
|
|
109
|
+
* `uri` — The URI of the document to apply changes to.
|
|
110
|
+
* `range` — The current selection range of the user.
|
|
111
|
+
|
|
112
|
+
###### Returns
|
|
113
|
+
|
|
114
|
+
`null`
|
|
115
|
+
|
|
116
|
+
##### `mdx.toggleStrong`
|
|
117
|
+
|
|
118
|
+
Toggle strong syntax at the cursor position.
|
|
119
|
+
It uses the `workspace/applyEdit` command to apply edits.
|
|
120
|
+
|
|
121
|
+
###### Arguments
|
|
122
|
+
|
|
123
|
+
* `uri` — The URI of the document to apply changes to.
|
|
124
|
+
* `range` — The current selection range of the user.
|
|
125
|
+
|
|
126
|
+
###### Returns
|
|
127
|
+
|
|
128
|
+
`null`
|
|
129
|
+
|
|
130
|
+
### Initialize Options
|
|
131
|
+
|
|
132
|
+
MDX language server supports the following LSP initialization options:
|
|
133
|
+
|
|
134
|
+
* `typescript.enabled` (`boolean`, default: `false`) —
|
|
135
|
+
If true, enable TypeScript.
|
|
136
|
+
* `typescript.tsdk` (`string`, required) —
|
|
137
|
+
The path from which to load TypeScript.
|
|
138
|
+
* `locale` (`string`, optional) —
|
|
139
|
+
The locale to use for TypeScript error messages.
|
|
140
|
+
|
|
141
|
+
### Configuration
|
|
142
|
+
|
|
143
|
+
MDX language server supports the following LSP configuration options:
|
|
144
|
+
|
|
145
|
+
* `mdx.trace.server.verbosity` (`"off"` | `"messages"` | `"compact"` |
|
|
146
|
+
`"verbose"`, default: `"off"`) —
|
|
147
|
+
Trace MDX language server requests in the output console.
|
|
148
|
+
* `mdx.trace.server.format` (`"text"` | `"json"`, default: `"text"`) —
|
|
149
|
+
How to format traced MDX language server requests.
|
|
150
|
+
* `mdx.validate.validateReferences` (`"ignore"` | `"hint"` | `"warning"` |
|
|
151
|
+
`"error"`, default: `"warning"`) —
|
|
152
|
+
Diagnostic level for invalid reference links, e.g. `[text][no-such-ref]`.
|
|
153
|
+
* `mdx.validate.validateFragmentLinks` (`"ignore"` | `"hint"` | `"warning"` |
|
|
154
|
+
`"error"`, default: `"warning"`) —
|
|
155
|
+
Diagnostic level for fragments links to headers in the current file that don’t
|
|
156
|
+
exist, e.g. `[text](#no-such-header)`
|
|
157
|
+
* `mdx.validate.validateFileLinks` (`"ignore"` | `"hint"` | `"warning"` |
|
|
158
|
+
`"error"`, default: `"warning"`) —
|
|
159
|
+
Diagnostic level for links to local files that don’t exist, e.g.
|
|
160
|
+
`[text](./no-such-file.png)`.
|
|
161
|
+
* `mdx.validate.validateMarkdownFileLinkFragments` (`"ignore"` | `"hint"` |
|
|
162
|
+
`"warning"` | `"error"`, default: `"warning"`) —
|
|
163
|
+
Diagnostic level for the fragment part of links to other local markdown files,
|
|
164
|
+
e.g. `[text](./no-such-file.png)`.
|
|
165
|
+
* `mdx.validate.validateUnusedLinkDefinitions` (`"ignore"` | `"hint"` |
|
|
166
|
+
`"warning"` | `"error"`, default: `"warning"`) —
|
|
167
|
+
Diagnostic level for link definitions that aren’t used anywhere.
|
|
168
|
+
`[never-used]: http://example.com`.
|
|
169
|
+
* `mdx.validate.validateDuplicateLinkDefinitions` (`"ignore"` | `"hint"` |
|
|
170
|
+
`"warning"` | `"error"`, default: `"warning"`) —
|
|
171
|
+
Diagnostic level for duplicate link definitions.
|
|
172
|
+
* `mdx.validate.ignoreLinks` (`Array<string>`, optional) —
|
|
173
|
+
Glob of links that should not be validated.
|
|
174
|
+
* `mdx.frontmatter.schemas` (`Array<object>`, optional) —
|
|
175
|
+
JSON schemas for YAML frontmatter in matching MDX files. Each item accepts
|
|
176
|
+
`fileMatch` as a string or array of strings, and either `url` for a schema
|
|
177
|
+
file or `schema` for an inline JSON schema object.
|
|
178
|
+
|
|
179
|
+
For example, configure schema-aware completions, hovers, and diagnostics for
|
|
180
|
+
YAML frontmatter in matching MDX files:
|
|
181
|
+
|
|
182
|
+
```json
|
|
183
|
+
{
|
|
184
|
+
"mdx.frontmatter.schemas": [
|
|
185
|
+
{
|
|
186
|
+
"fileMatch": ["astro/src/content/docs/**/*.mdx"],
|
|
187
|
+
"url": "./.generated/mdx-frontmatter/docs.schema.json"
|
|
188
|
+
}
|
|
189
|
+
]
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
This applies to YAML frontmatter embedded in MDX files. TOML frontmatter is
|
|
194
|
+
parsed but does not use these YAML schema settings.
|
|
195
|
+
|
|
196
|
+
### TypeScript
|
|
197
|
+
|
|
198
|
+
This extension offers type safety for MDX files based on TypeScript’s
|
|
199
|
+
[types in JSDoc][jsdoc].
|
|
200
|
+
For MDX specific details, see the
|
|
201
|
+
[TypeScript section](https://github.com/mdx-js/mdx-analyzer#typescript) of the
|
|
202
|
+
repository readme.
|
|
203
|
+
|
|
204
|
+
### Plugins
|
|
205
|
+
|
|
206
|
+
For information on plugin support, see the
|
|
207
|
+
[Plugins section](https://github.com/mdx-js/mdx-analyzer#plugins) of the
|
|
208
|
+
repository readme.
|
|
209
|
+
|
|
210
|
+
## Editors
|
|
211
|
+
|
|
212
|
+
MDX language server can be integrated with any editor that supports
|
|
213
|
+
[language servers][lsp].
|
|
214
|
+
Does your editor support MDX language server, but is it not in this list?
|
|
215
|
+
Feel free to add it.
|
|
216
|
+
|
|
217
|
+
### Emacs
|
|
218
|
+
|
|
219
|
+
Use [`lsp-mode`][lsp-mode] to use the MDX language server with Emacs.
|
|
220
|
+
|
|
221
|
+
### Neovim
|
|
222
|
+
|
|
223
|
+
You can add MDX support to MDX via [`nvim-lspconfig`][nvim-lspconfig].
|
|
224
|
+
After installing MDX language server, add the language server setup to your
|
|
225
|
+
`init.lua`.
|
|
226
|
+
|
|
227
|
+
```lua
|
|
228
|
+
require'lspconfig'.mdx_analyzer.setup{}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
For more details, see the
|
|
232
|
+
[`nvim-lspconfig` MDX analyzer][nvim-lspconfig mdx-analyzer] documentation.
|
|
233
|
+
|
|
234
|
+
### Visual Studio Code
|
|
235
|
+
|
|
236
|
+
Use [`unifiedjs.vscode-mdx`][vscode-mdx] to use the MDX language server with
|
|
237
|
+
[Visual Studio Code][vscode].
|
|
238
|
+
|
|
239
|
+
## Compatibility
|
|
240
|
+
|
|
241
|
+
This project is compatible Node.js 20.19+.
|
|
242
|
+
|
|
243
|
+
This project uses [`vscode-languageserver`][vscode-languageserver] 9, which
|
|
244
|
+
implements language server protocol 3.17.4.
|
|
245
|
+
It should work anywhere where LSP 3.6.0 or later is implemented.
|
|
246
|
+
|
|
247
|
+
## Security
|
|
248
|
+
|
|
249
|
+
This package provides IntelliSense for [MDX][] files.
|
|
250
|
+
Some IntelliSense features modify your source code, for example suggestions and
|
|
251
|
+
automatic refactors.
|
|
252
|
+
It is recommended to keep your source code under version control.
|
|
253
|
+
|
|
254
|
+
## Contribute
|
|
255
|
+
|
|
256
|
+
See [§ Contribute][contribute] on our website for ways to get started.
|
|
257
|
+
See [§ Support][support] for ways to get help.
|
|
258
|
+
|
|
259
|
+
This project has a [code of conduct][].
|
|
260
|
+
By interacting with this repository, organization, or community you agree to
|
|
261
|
+
abide by its terms.
|
|
262
|
+
|
|
263
|
+
## Sponsor
|
|
264
|
+
|
|
265
|
+
See [§ Sponsor][sponsor] on our site for how to help financially.
|
|
266
|
+
|
|
267
|
+
<table>
|
|
268
|
+
<tr valign="middle">
|
|
269
|
+
<td width="20%" align="center" rowspan="2" colspan="2">
|
|
270
|
+
<a href="https://vercel.com">Vercel</a><br><br>
|
|
271
|
+
<a href="https://vercel.com"><img src="https://avatars1.githubusercontent.com/u/14985020?s=256&v=4" width="128"></a>
|
|
272
|
+
</td>
|
|
273
|
+
<td width="20%" align="center" rowspan="2" colspan="2">
|
|
274
|
+
<a href="https://motif.land">Motif</a><br><br>
|
|
275
|
+
<a href="https://motif.land"><img src="https://avatars1.githubusercontent.com/u/74457950?s=256&v=4" width="128"></a>
|
|
276
|
+
</td>
|
|
277
|
+
<td width="20%" align="center" rowspan="2" colspan="2">
|
|
278
|
+
<a href="https://www.hashicorp.com">HashiCorp</a><br><br>
|
|
279
|
+
<a href="https://www.hashicorp.com"><img src="https://avatars1.githubusercontent.com/u/761456?s=256&v=4" width="128"></a>
|
|
280
|
+
</td>
|
|
281
|
+
<td width="20%" align="center" rowspan="2" colspan="2">
|
|
282
|
+
<a href="https://www.gitbook.com">GitBook</a><br><br>
|
|
283
|
+
<a href="https://www.gitbook.com"><img src="https://avatars1.githubusercontent.com/u/7111340?s=256&v=4" width="128"></a>
|
|
284
|
+
</td>
|
|
285
|
+
<td width="20%" align="center" rowspan="2" colspan="2">
|
|
286
|
+
<a href="https://www.gatsbyjs.org">Gatsby</a><br><br>
|
|
287
|
+
<a href="https://www.gatsbyjs.org"><img src="https://avatars1.githubusercontent.com/u/12551863?s=256&v=4" width="128"></a>
|
|
288
|
+
</td>
|
|
289
|
+
</tr>
|
|
290
|
+
<tr valign="middle"></tr>
|
|
291
|
+
<tr valign="middle">
|
|
292
|
+
<td width="20%" align="center" rowspan="2" colspan="2">
|
|
293
|
+
<a href="https://www.netlify.com">Netlify</a><br><br>
|
|
294
|
+
<!--OC has a sharper image-->
|
|
295
|
+
<a href="https://www.netlify.com"><img src="https://images.opencollective.com/netlify/4087de2/logo/256.png" width="128"></a>
|
|
296
|
+
</td>
|
|
297
|
+
<td width="10%" align="center">
|
|
298
|
+
<a href="https://www.coinbase.com">Coinbase</a><br><br>
|
|
299
|
+
<a href="https://www.coinbase.com"><img src="https://avatars1.githubusercontent.com/u/1885080?s=256&v=4" width="64"></a>
|
|
300
|
+
</td>
|
|
301
|
+
<td width="10%" align="center">
|
|
302
|
+
<a href="https://themeisle.com">ThemeIsle</a><br><br>
|
|
303
|
+
<a href="https://themeisle.com"><img src="https://avatars1.githubusercontent.com/u/58979018?s=128&v=4" width="64"></a>
|
|
304
|
+
</td>
|
|
305
|
+
<td width="10%" align="center">
|
|
306
|
+
<a href="https://expo.io">Expo</a><br><br>
|
|
307
|
+
<a href="https://expo.io"><img src="https://avatars1.githubusercontent.com/u/12504344?s=128&v=4" width="64"></a>
|
|
308
|
+
</td>
|
|
309
|
+
<td width="10%" align="center">
|
|
310
|
+
<a href="https://boostnote.io">Boost Note</a><br><br>
|
|
311
|
+
<a href="https://boostnote.io"><img src="https://images.opencollective.com/boosthub/6318083/logo/128.png" width="64"></a>
|
|
312
|
+
</td>
|
|
313
|
+
<td width="10%" align="center">
|
|
314
|
+
<a href="https://markdown.space">Markdown Space</a><br><br>
|
|
315
|
+
<a href="https://markdown.space"><img src="https://images.opencollective.com/markdown-space/e1038ed/logo/128.png" width="64"></a>
|
|
316
|
+
</td>
|
|
317
|
+
<td width="10%" align="center">
|
|
318
|
+
<a href="https://www.holloway.com">Holloway</a><br><br>
|
|
319
|
+
<a href="https://www.holloway.com"><img src="https://avatars1.githubusercontent.com/u/35904294?s=128&v=4" width="64"></a>
|
|
320
|
+
</td>
|
|
321
|
+
<td width="10%"></td>
|
|
322
|
+
<td width="10%"></td>
|
|
323
|
+
</tr>
|
|
324
|
+
<tr valign="middle">
|
|
325
|
+
<td width="100%" align="center" colspan="8">
|
|
326
|
+
<br>
|
|
327
|
+
<a href="https://opencollective.com/unified"><strong>You?</strong></a>
|
|
328
|
+
<br><br>
|
|
329
|
+
</td>
|
|
330
|
+
</tr>
|
|
331
|
+
</table>
|
|
332
|
+
|
|
333
|
+
## Changelog
|
|
334
|
+
|
|
335
|
+
Detailed changes for each release are documented in [CHANGELOG.md](./CHANGELOG.md).
|
|
336
|
+
|
|
337
|
+
## License
|
|
338
|
+
|
|
339
|
+
[MIT][] © [Remco Haszing][author]
|
|
340
|
+
|
|
341
|
+
[author]: https://github.com/remcohaszing
|
|
342
|
+
|
|
343
|
+
[backers-badge]: https://opencollective.com/unified/backers/badge.svg
|
|
344
|
+
|
|
345
|
+
[build]: https://github.com/mdx-js/mdx-analyzer/actions
|
|
346
|
+
|
|
347
|
+
[build-badge]: https://github.com/mdx-js/mdx-analyzer/workflows/main/badge.svg
|
|
348
|
+
|
|
349
|
+
[chat]: https://github.com/mdx-js/mdx/discussions
|
|
350
|
+
|
|
351
|
+
[chat-badge]: https://img.shields.io/badge/chat-discussions-success.svg
|
|
352
|
+
|
|
353
|
+
[code of conduct]: https://github.com/mdx-js/.github/blob/main/code-of-conduct.md
|
|
354
|
+
|
|
355
|
+
[collective]: https://opencollective.com/unified
|
|
356
|
+
|
|
357
|
+
[contribute]: https://mdxjs.com/community/contribute/
|
|
358
|
+
|
|
359
|
+
[coverage]: https://codecov.io/github/mdx-js/mdx-analyzer
|
|
360
|
+
|
|
361
|
+
[coverage-badge]: https://img.shields.io/codecov/c/github/mdx-js/mdx-analyzer/main.svg
|
|
362
|
+
|
|
363
|
+
[downloads]: https://www.npmjs.com/package/@mdx-js/language-server
|
|
364
|
+
|
|
365
|
+
[downloads-badge]: https://img.shields.io/npm/dm/@mdx-js/language-server.svg
|
|
366
|
+
|
|
367
|
+
[jsdoc]: https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html
|
|
368
|
+
|
|
369
|
+
[lsp]: https://microsoft.github.io/language-server-protocol
|
|
370
|
+
|
|
371
|
+
[lsp commands]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#command
|
|
372
|
+
|
|
373
|
+
[lsp-mode]: https://github.com/emacs-lsp/lsp-mode
|
|
374
|
+
|
|
375
|
+
[mdx]: https://mdxjs.com
|
|
376
|
+
|
|
377
|
+
[mit]: LICENSE
|
|
378
|
+
|
|
379
|
+
[npm]: https://docs.npmjs.com/cli/install
|
|
380
|
+
|
|
381
|
+
[nvim-lspconfig]: https://github.com/neovim/nvim-lspconfig
|
|
382
|
+
|
|
383
|
+
[nvim-lspconfig mdx-analyzer]: https://github.com/neovim/nvim-lspconfig/blob/master/doc/configs.md#mdx_analyzer
|
|
384
|
+
|
|
385
|
+
[sponsor]: https://mdxjs.com/community/sponsor/
|
|
386
|
+
|
|
387
|
+
[sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg
|
|
388
|
+
|
|
389
|
+
[support]: https://mdxjs.com/community/support/
|
|
390
|
+
|
|
391
|
+
[typescript]: https://typescriptlang.org
|
|
392
|
+
|
|
393
|
+
[volar]: https://volarjs.dev
|
|
394
|
+
|
|
395
|
+
[volar-service-markdown]: https://github.com/volarjs/services/tree/master/packages/markdown
|
|
396
|
+
|
|
397
|
+
[volar-service-typescript]: https://github.com/volarjs/services/tree/master/packages/typescript
|
|
398
|
+
|
|
399
|
+
[vscode]: https://code.visualstudio.com
|
|
400
|
+
|
|
401
|
+
[vscode-languageserver]: https://github.com/microsoft/vscode-languageserver-node/tree/main/server
|
|
402
|
+
|
|
403
|
+
[vscode-mdx]: https://marketplace.visualstudio.com/items?itemName=unifiedjs.vscode-mdx
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @import {LanguageServiceContext} from '@volar/language-service'
|
|
3
|
+
* @import {LanguageSettings} from 'yaml-language-server'
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {URI, Utils} from 'vscode-uri'
|
|
7
|
+
|
|
8
|
+
/** @type {LanguageSettings} */
|
|
9
|
+
const defaultYamlSettings = {
|
|
10
|
+
completion: true,
|
|
11
|
+
customTags: [],
|
|
12
|
+
disableAdditionalProperties: false,
|
|
13
|
+
disableDefaultProperties: false,
|
|
14
|
+
flowMapping: 'allow',
|
|
15
|
+
flowSequence: 'allow',
|
|
16
|
+
format: true,
|
|
17
|
+
hover: true,
|
|
18
|
+
hoverAnchor: true,
|
|
19
|
+
hoverSchemaSource: true,
|
|
20
|
+
isKubernetes: false,
|
|
21
|
+
indentation: ' ',
|
|
22
|
+
keyOrdering: false,
|
|
23
|
+
parentSkeletonSelectedFirst: false,
|
|
24
|
+
validate: true,
|
|
25
|
+
yamlVersion: '1.2'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {unknown} value
|
|
30
|
+
* @returns {value is Record<string, unknown>}
|
|
31
|
+
*/
|
|
32
|
+
function isRecord(value) {
|
|
33
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @param {unknown} value
|
|
38
|
+
* @returns {string[]}
|
|
39
|
+
*/
|
|
40
|
+
function normalizeFileMatch(value) {
|
|
41
|
+
if (typeof value === 'string') {
|
|
42
|
+
return [value]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (Array.isArray(value)) {
|
|
46
|
+
return value.filter((item) => typeof item === 'string')
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return []
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @param {string} url
|
|
54
|
+
* @param {URI | undefined} workspaceUri
|
|
55
|
+
* @returns {string}
|
|
56
|
+
*/
|
|
57
|
+
function normalizeSchemaUrl(url, workspaceUri) {
|
|
58
|
+
if (/^[a-z][a-z+.-]*:/i.test(url)) {
|
|
59
|
+
return url
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!workspaceUri) {
|
|
63
|
+
return url
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return Utils.resolvePath(workspaceUri, url).toString()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @param {unknown} workspaceFolder
|
|
71
|
+
* @returns {URI | undefined}
|
|
72
|
+
*/
|
|
73
|
+
function normalizeWorkspaceUri(workspaceFolder) {
|
|
74
|
+
if (workspaceFolder instanceof URI) {
|
|
75
|
+
return workspaceFolder
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (typeof workspaceFolder === 'string') {
|
|
79
|
+
return URI.parse(workspaceFolder)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (isRecord(workspaceFolder) && typeof workspaceFolder.uri === 'string') {
|
|
83
|
+
return URI.parse(workspaceFolder.uri)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (
|
|
87
|
+
isRecord(workspaceFolder) &&
|
|
88
|
+
typeof workspaceFolder.external === 'string'
|
|
89
|
+
) {
|
|
90
|
+
return URI.parse(workspaceFolder.external)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param {string[]} fileMatch
|
|
96
|
+
* @returns {string[]}
|
|
97
|
+
*/
|
|
98
|
+
function expandMdxFileMatchesForEmbeddedYaml(fileMatch) {
|
|
99
|
+
const expanded = new Set(fileMatch)
|
|
100
|
+
|
|
101
|
+
for (const pattern of fileMatch) {
|
|
102
|
+
if (pattern.endsWith('.mdx')) {
|
|
103
|
+
expanded.add(pattern.replace(/\.mdx$/u, '.yaml'))
|
|
104
|
+
expanded.add(pattern.replace(/\.mdx$/u, '.yml'))
|
|
105
|
+
expanded.add(
|
|
106
|
+
`volar-embedded-content://yaml/*${pattern.replaceAll('/', '*')}`
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return [...expanded]
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* @param {unknown} rawSchemas
|
|
116
|
+
* @param {URI | undefined} workspaceUri
|
|
117
|
+
*/
|
|
118
|
+
export function normalizeFrontmatterSchemas(rawSchemas, workspaceUri) {
|
|
119
|
+
if (!Array.isArray(rawSchemas)) {
|
|
120
|
+
return []
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const schemas = []
|
|
124
|
+
|
|
125
|
+
for (const [index, entry] of rawSchemas.entries()) {
|
|
126
|
+
if (!isRecord(entry)) {
|
|
127
|
+
continue
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const fileMatch = normalizeFileMatch(entry.fileMatch)
|
|
131
|
+
if (fileMatch.length === 0) {
|
|
132
|
+
continue
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const schema = isRecord(entry.schema) ? entry.schema : undefined
|
|
136
|
+
const uri =
|
|
137
|
+
typeof entry.url === 'string'
|
|
138
|
+
? normalizeSchemaUrl(entry.url, workspaceUri)
|
|
139
|
+
: schema
|
|
140
|
+
? `mdx-frontmatter-inline-schema://${index}`
|
|
141
|
+
: undefined
|
|
142
|
+
|
|
143
|
+
if (!uri) {
|
|
144
|
+
continue
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** @type {{fileMatch: string[], uri: string, schema?: Record<string, unknown>}} */
|
|
148
|
+
const schemaSetting = {
|
|
149
|
+
fileMatch: expandMdxFileMatchesForEmbeddedYaml(fileMatch),
|
|
150
|
+
uri
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (schema) {
|
|
154
|
+
schemaSetting.schema = schema
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
schemas.push(schemaSetting)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return schemas
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* @param {LanguageServiceContext} context
|
|
165
|
+
* @param {unknown} fallbackWorkspaceFolder
|
|
166
|
+
* @returns {Promise<LanguageSettings>}
|
|
167
|
+
*/
|
|
168
|
+
export async function getFrontmatterYamlSettings(
|
|
169
|
+
context,
|
|
170
|
+
fallbackWorkspaceFolder
|
|
171
|
+
) {
|
|
172
|
+
const frontmatterConfig =
|
|
173
|
+
(await context.env.getConfiguration?.('mdx.frontmatter')) || {}
|
|
174
|
+
const workspaceFolder =
|
|
175
|
+
fallbackWorkspaceFolder ?? context.env.workspaceFolders?.[0]
|
|
176
|
+
const workspaceUri =
|
|
177
|
+
typeof workspaceFolder === 'string'
|
|
178
|
+
? URI.parse(workspaceFolder)
|
|
179
|
+
: normalizeWorkspaceUri(workspaceFolder)
|
|
180
|
+
const rawSchemas = isRecord(frontmatterConfig)
|
|
181
|
+
? frontmatterConfig.schemas
|
|
182
|
+
: undefined
|
|
183
|
+
const schemas = normalizeFrontmatterSchemas(rawSchemas, workspaceUri)
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
...defaultYamlSettings,
|
|
187
|
+
schemas
|
|
188
|
+
}
|
|
189
|
+
}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @import {VirtualCodePlugin} from '@mdx-js/language-service'
|
|
5
|
+
* @import {PluggableList} from 'unified'
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import assert from 'node:assert'
|
|
9
|
+
import {createRequire} from 'node:module'
|
|
10
|
+
import path from 'node:path'
|
|
11
|
+
import process from 'node:process'
|
|
12
|
+
import {
|
|
13
|
+
createMdxLanguagePlugin,
|
|
14
|
+
createMdxServicePlugin,
|
|
15
|
+
resolvePlugins
|
|
16
|
+
} from '@mdx-js/language-service'
|
|
17
|
+
import {
|
|
18
|
+
createConnection,
|
|
19
|
+
createServer,
|
|
20
|
+
createTypeScriptProject,
|
|
21
|
+
loadTsdkByPath
|
|
22
|
+
} from '@volar/language-server/node.js'
|
|
23
|
+
import remarkFrontmatter from 'remark-frontmatter'
|
|
24
|
+
import remarkGfm from 'remark-gfm'
|
|
25
|
+
import {create as createMarkdownServicePlugin} from 'volar-service-markdown'
|
|
26
|
+
import {create as createTypeScriptServicePlugin} from 'volar-service-typescript'
|
|
27
|
+
import {create as createTypeScriptSyntacticServicePlugin} from 'volar-service-typescript/lib/plugins/syntactic.js'
|
|
28
|
+
import {create as createYamlServicePlugin} from 'volar-service-yaml'
|
|
29
|
+
import {getFrontmatterYamlSettings} from './frontmatter-schemas.js'
|
|
30
|
+
|
|
31
|
+
process.title = 'mdx-language-server'
|
|
32
|
+
|
|
33
|
+
/** @type {PluggableList} */
|
|
34
|
+
const defaultPlugins = [[remarkFrontmatter, ['toml', 'yaml']], remarkGfm]
|
|
35
|
+
const connection = createConnection()
|
|
36
|
+
const server = createServer(connection)
|
|
37
|
+
let tsEnabled = false
|
|
38
|
+
|
|
39
|
+
connection.onInitialize(async (parameters) => {
|
|
40
|
+
const tsdk = parameters.initializationOptions?.typescript?.tsdk
|
|
41
|
+
tsEnabled = Boolean(parameters.initializationOptions?.typescript?.enabled)
|
|
42
|
+
assert.ok(
|
|
43
|
+
typeof tsdk === 'string',
|
|
44
|
+
'Missing initialization option typescript.tsdk'
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
const {typescript, diagnosticMessages} = loadTsdkByPath(
|
|
48
|
+
tsdk,
|
|
49
|
+
parameters.locale
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
return server.initialize(
|
|
53
|
+
parameters,
|
|
54
|
+
createTypeScriptProject(
|
|
55
|
+
typescript,
|
|
56
|
+
diagnosticMessages,
|
|
57
|
+
({configFileName}) => ({
|
|
58
|
+
languagePlugins: getLanguagePlugins(configFileName)
|
|
59
|
+
})
|
|
60
|
+
),
|
|
61
|
+
getLanguageServicePlugins()
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
function getLanguageServicePlugins() {
|
|
65
|
+
const plugins = [
|
|
66
|
+
createMarkdownServicePlugin({
|
|
67
|
+
getDiagnosticOptions(document, context) {
|
|
68
|
+
return context.env.getConfiguration?.('mdx.validate')
|
|
69
|
+
}
|
|
70
|
+
}),
|
|
71
|
+
createYamlServicePlugin({
|
|
72
|
+
documentSelector: ['yaml'],
|
|
73
|
+
getLanguageSettings(context) {
|
|
74
|
+
return getFrontmatterYamlSettings(
|
|
75
|
+
context,
|
|
76
|
+
parameters.workspaceFolders?.[0]?.uri ?? parameters.rootUri
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
}),
|
|
80
|
+
createMdxServicePlugin(/** @type {any} */ (connection.workspace))
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
if (tsEnabled) {
|
|
84
|
+
plugins.push(...createTypeScriptServicePlugin(typescript, {}))
|
|
85
|
+
} else {
|
|
86
|
+
plugins.push(createTypeScriptSyntacticServicePlugin(typescript))
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return plugins
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @param {string | undefined} tsconfig
|
|
94
|
+
*/
|
|
95
|
+
function getLanguagePlugins(tsconfig) {
|
|
96
|
+
/** @type {PluggableList | undefined} */
|
|
97
|
+
let remarkPlugins
|
|
98
|
+
/** @type {VirtualCodePlugin[] | undefined} */
|
|
99
|
+
let virtualCodePlugins
|
|
100
|
+
let checkMdx = false
|
|
101
|
+
let jsxImportSource = 'react'
|
|
102
|
+
|
|
103
|
+
if (tsconfig) {
|
|
104
|
+
const cwd = path.dirname(tsconfig)
|
|
105
|
+
const configSourceFile = typescript.readJsonConfigFile(
|
|
106
|
+
tsconfig,
|
|
107
|
+
typescript.sys.readFile
|
|
108
|
+
)
|
|
109
|
+
const commandLine = typescript.parseJsonSourceFileConfigFileContent(
|
|
110
|
+
configSourceFile,
|
|
111
|
+
typescript.sys,
|
|
112
|
+
cwd,
|
|
113
|
+
undefined,
|
|
114
|
+
tsconfig
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
const require = createRequire(tsconfig)
|
|
118
|
+
|
|
119
|
+
;[remarkPlugins, virtualCodePlugins] = resolvePlugins(
|
|
120
|
+
commandLine.raw?.mdx,
|
|
121
|
+
(name) => require(name).default
|
|
122
|
+
)
|
|
123
|
+
checkMdx = Boolean(commandLine.raw?.mdx?.checkMdx)
|
|
124
|
+
jsxImportSource = commandLine.options.jsxImportSource || jsxImportSource
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return [
|
|
128
|
+
createMdxLanguagePlugin(
|
|
129
|
+
remarkPlugins || defaultPlugins,
|
|
130
|
+
virtualCodePlugins,
|
|
131
|
+
checkMdx,
|
|
132
|
+
jsxImportSource
|
|
133
|
+
)
|
|
134
|
+
]
|
|
135
|
+
}
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
connection.onInitialized(() => {
|
|
139
|
+
const extensions = ['mdx']
|
|
140
|
+
if (tsEnabled) {
|
|
141
|
+
extensions.push(
|
|
142
|
+
'cjs',
|
|
143
|
+
'cts',
|
|
144
|
+
'js',
|
|
145
|
+
'jsx',
|
|
146
|
+
'json',
|
|
147
|
+
'mjs',
|
|
148
|
+
'mts',
|
|
149
|
+
'ts',
|
|
150
|
+
'tsx'
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
server.initialized()
|
|
155
|
+
server.fileWatcher.watchFiles([`**/*.{${extensions.join(',')}}`])
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
connection.listen()
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nicodoggie/mdx-language-server",
|
|
3
|
+
"version": "0.6.3",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "A language server for MDX",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/mdx-js/mdx-analyzer.git",
|
|
9
|
+
"directory": "packages/language-server"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://mdxjs.com",
|
|
12
|
+
"bugs": "https://github.com/mdx-js/mdx-analyzer/issues",
|
|
13
|
+
"author": "Remco Haszing <remcohaszing@gmail.com>",
|
|
14
|
+
"funding": "https://opencollective.com/unified",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"exports": "./lib/index.js",
|
|
17
|
+
"bin": {
|
|
18
|
+
"mdx-language-server": "./lib/index.js"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"lib"
|
|
22
|
+
],
|
|
23
|
+
"keywords": [
|
|
24
|
+
"IntelliSense",
|
|
25
|
+
"mdx",
|
|
26
|
+
"typescript",
|
|
27
|
+
"unified"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"test-api": "node --test",
|
|
31
|
+
"test": "npm run test-api"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@mdx-js/language-service": "0.7.3",
|
|
35
|
+
"@volar/language-server": "~2.4.0",
|
|
36
|
+
"remark-frontmatter": "^5.0.0",
|
|
37
|
+
"remark-gfm": "^4.0.0",
|
|
38
|
+
"volar-service-markdown": "0.0.65",
|
|
39
|
+
"volar-service-typescript": "0.0.65",
|
|
40
|
+
"volar-service-yaml": "0.0.71"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/node": "^22.0.0",
|
|
44
|
+
"@volar/test-utils": "~2.4.0",
|
|
45
|
+
"unified": "^11.0.0",
|
|
46
|
+
"vscode-uri": "^3.0.0"
|
|
47
|
+
}
|
|
48
|
+
}
|