@nvl/sveltex-language-server 0.2.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.
- package/LICENSE +21 -0
- package/README.md +288 -0
- package/bin/server.js +10 -0
- package/dist/core/config.d.ts +126 -0
- package/dist/core/config.js +569 -0
- package/dist/core/diagnostics.d.ts +34 -0
- package/dist/core/diagnostics.js +67 -0
- package/dist/core/frontmatter-data.d.ts +74 -0
- package/dist/core/frontmatter-data.js +323 -0
- package/dist/core/frontmatter.d.ts +25 -0
- package/dist/core/frontmatter.js +348 -0
- package/dist/core/lsp-proxy.d.ts +77 -0
- package/dist/core/lsp-proxy.js +165 -0
- package/dist/core/mapper.d.ts +86 -0
- package/dist/core/mapper.js +223 -0
- package/dist/core/mapping.d.ts +59 -0
- package/dist/core/mapping.js +37 -0
- package/dist/core/markdown.d.ts +34 -0
- package/dist/core/markdown.js +215 -0
- package/dist/core/region-forwarding.d.ts +90 -0
- package/dist/core/region-forwarding.js +428 -0
- package/dist/core/region-virtual.d.ts +71 -0
- package/dist/core/region-virtual.js +131 -0
- package/dist/core/regions.d.ts +56 -0
- package/dist/core/regions.js +221 -0
- package/dist/core/remap.d.ts +84 -0
- package/dist/core/remap.js +272 -0
- package/dist/core/server-helpers.d.ts +109 -0
- package/dist/core/server-helpers.js +182 -0
- package/dist/core/server.d.ts +13 -0
- package/dist/core/server.js +604 -0
- package/dist/core/svelte-proxy.d.ts +100 -0
- package/dist/core/svelte-proxy.js +144 -0
- package/dist/core/texlab.d.ts +26 -0
- package/dist/core/texlab.js +121 -0
- package/dist/core/virtual-svelte.d.ts +32 -0
- package/dist/core/virtual-svelte.js +67 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +46 -0
- package/package.json +73 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { ClientCapabilities, CompletionItem, CompletionList, InitializeParams } from 'vscode-languageserver-protocol';
|
|
2
|
+
import type { Region } from './regions.js';
|
|
3
|
+
import type { VirtualSvelteDocument } from './virtual-svelte.js';
|
|
4
|
+
/** State tracked for one open `.sveltex` document. */
|
|
5
|
+
export interface OpenDocument {
|
|
6
|
+
/** The `.sveltex` document URI. */
|
|
7
|
+
uri: string;
|
|
8
|
+
/** Current full text of the source document. */
|
|
9
|
+
text: string;
|
|
10
|
+
/** LSP document version. */
|
|
11
|
+
version: number;
|
|
12
|
+
/** The document's regions (gap-free, sorted), as used to build `virtual`. */
|
|
13
|
+
regions: Region[];
|
|
14
|
+
/** The generated virtual `.svelte` document and its source map. */
|
|
15
|
+
virtual: VirtualSvelteDocument;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Default file extension for a SvelTeX document. The full set is read from
|
|
19
|
+
* the live config (`SveltexConfigSnapshot.extensions`); this fallback is
|
|
20
|
+
* only used before the first config snapshot resolves.
|
|
21
|
+
*/
|
|
22
|
+
export declare const DEFAULT_SVELTEX_EXTENSION = ".sveltex";
|
|
23
|
+
/**
|
|
24
|
+
* Returns a fresh object with the listed keys of `source` whose value is
|
|
25
|
+
* defined; a key whose value is `undefined`, or a missing `source`, is omitted
|
|
26
|
+
* entirely.
|
|
27
|
+
*
|
|
28
|
+
* Used to fold the embedded Svelte server's proxied capabilities into this
|
|
29
|
+
* server's `initialize` response. A capability the child lacks must be
|
|
30
|
+
* *absent*, not present-and-`undefined`: under `exactOptionalPropertyTypes` an
|
|
31
|
+
* explicit `undefined` is a type error, and an editor seeing the key at all
|
|
32
|
+
* would fire requests this server can answer only with `-32601`.
|
|
33
|
+
*/
|
|
34
|
+
export declare function pickDefined<T extends object, K extends keyof T>(source: T | undefined, keys: readonly K[]): Partial<Pick<T, K>>;
|
|
35
|
+
/**
|
|
36
|
+
* Returns a copy of `capabilities` with the pull-diagnostics capability
|
|
37
|
+
* (`textDocument.diagnostic`) removed.
|
|
38
|
+
*
|
|
39
|
+
* `svelte-language-server` switches to pull-only diagnostics — answering
|
|
40
|
+
* `textDocument/diagnostic` requests and no longer *pushing*
|
|
41
|
+
* `publishDiagnostics` — the moment the client claims to support them. This
|
|
42
|
+
* server forwards only pushed diagnostics and advertises no pull
|
|
43
|
+
* `diagnosticProvider` of its own, so it hides the capability from the child,
|
|
44
|
+
* keeping it in push mode; otherwise diagnostics silently never appear.
|
|
45
|
+
*/
|
|
46
|
+
export declare function withoutPullDiagnostics(capabilities: ClientCapabilities): ClientCapabilities;
|
|
47
|
+
/**
|
|
48
|
+
* Tags every item of a completion result with {@link NATIVE_COMPLETION_ORIGIN}
|
|
49
|
+
* — applied to the region-forwarded and frontmatter completion results so
|
|
50
|
+
* their later `completionItem/resolve` is recognised as this server's own.
|
|
51
|
+
*/
|
|
52
|
+
export declare function markNativeCompletion(result: CompletionItem[] | CompletionList | null): CompletionItem[] | CompletionList | null;
|
|
53
|
+
/**
|
|
54
|
+
* Whether `item` was produced by this server itself — see
|
|
55
|
+
* {@link markNativeCompletion}. Such an item is already complete: its
|
|
56
|
+
* `completionItem/resolve` is answered by returning it unchanged.
|
|
57
|
+
*/
|
|
58
|
+
export declare function isNativeCompletionItem(item: CompletionItem): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Extracts a usable filesystem path for the workspace root from `initialize`
|
|
61
|
+
* params, tolerating the several historical shapes (`workspaceFolders`,
|
|
62
|
+
* `rootUri`, the long-deprecated `rootPath`).
|
|
63
|
+
*
|
|
64
|
+
* @returns An absolute path, or `undefined` if none could be determined.
|
|
65
|
+
*/
|
|
66
|
+
export declare function workspaceRootOf(params: InitializeParams): string | undefined;
|
|
67
|
+
/** Converts a `file:` URI to a filesystem path; returns `undefined` otherwise. */
|
|
68
|
+
export declare function uriToPath(uri: string): string | undefined;
|
|
69
|
+
/**
|
|
70
|
+
* Absolute paths of the child servers this server spawns, as a host may
|
|
71
|
+
* optionally supply them. Each field is `undefined` when the host did not
|
|
72
|
+
* provide a path, in which case the corresponding child is resolved from
|
|
73
|
+
* `node_modules` by its proxy.
|
|
74
|
+
*/
|
|
75
|
+
export interface ResolvedServerPaths {
|
|
76
|
+
/** Path of `svelte-language-server`'s `bin/server.js`, if supplied. */
|
|
77
|
+
svelteLanguageServer: string | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* Path of `@nvl/sveltex-math-language-server`'s `bin/server.js`, if
|
|
80
|
+
* supplied.
|
|
81
|
+
*/
|
|
82
|
+
mathLanguageServer: string | undefined;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Extracts the optional child-server paths from an `initialize` request's
|
|
86
|
+
* `initializationOptions`.
|
|
87
|
+
*
|
|
88
|
+
* A host that has bundled the child servers and so cannot resolve them from
|
|
89
|
+
* `node_modules` (the VS Code extension) passes their absolute paths under a
|
|
90
|
+
* `serverPaths` object:
|
|
91
|
+
*
|
|
92
|
+
* ```jsonc
|
|
93
|
+
* "initializationOptions": {
|
|
94
|
+
* "serverPaths": {
|
|
95
|
+
* "svelteLanguageServer": "/abs/path/to/svelte-language-server.js",
|
|
96
|
+
* "mathLanguageServer": "/abs/path/to/sveltex-math-language-server.js"
|
|
97
|
+
* }
|
|
98
|
+
* }
|
|
99
|
+
* ```
|
|
100
|
+
*
|
|
101
|
+
* The field is entirely optional: any standalone client (the Zed extension,
|
|
102
|
+
* the CLI, the test harness) omits it, and every path then resolves from
|
|
103
|
+
* `node_modules` as before. Non-string entries are ignored.
|
|
104
|
+
*
|
|
105
|
+
* @param initializationOptions - The raw `initializationOptions` value, of
|
|
106
|
+
* unknown shape.
|
|
107
|
+
* @returns The resolved paths; fields are `undefined` when not supplied.
|
|
108
|
+
*/
|
|
109
|
+
export declare function readServerPaths(initializationOptions: unknown): ResolvedServerPaths;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// File description: Pure module-level helpers and shared types pulled out of
|
|
2
|
+
// `server.ts`. None of these close over per-connection state, so they have
|
|
3
|
+
// no business living inside the `createServer` factory — and keeping them
|
|
4
|
+
// here makes that factory shorter and easier to read.
|
|
5
|
+
//
|
|
6
|
+
// Three groupings, in order:
|
|
7
|
+
// 1. State shapes used by `createServer` (`OpenDocument`,
|
|
8
|
+
// `DEFAULT_SVELTEX_EXTENSION`).
|
|
9
|
+
// 2. Request-pipeline helpers (`pickDefined`, `withoutPullDiagnostics`,
|
|
10
|
+
// the `markNativeCompletion` / `isNativeCompletionItem` pair).
|
|
11
|
+
// 3. `initialize`-time helpers (`workspaceRootOf`, `uriToPath`,
|
|
12
|
+
// `ResolvedServerPaths`, `readServerPaths`).
|
|
13
|
+
import { URI } from 'vscode-uri';
|
|
14
|
+
/**
|
|
15
|
+
* Default file extension for a SvelTeX document. The full set is read from
|
|
16
|
+
* the live config (`SveltexConfigSnapshot.extensions`); this fallback is
|
|
17
|
+
* only used before the first config snapshot resolves.
|
|
18
|
+
*/
|
|
19
|
+
export const DEFAULT_SVELTEX_EXTENSION = '.sveltex';
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// 2. Request-pipeline helpers
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
/**
|
|
24
|
+
* Returns a fresh object with the listed keys of `source` whose value is
|
|
25
|
+
* defined; a key whose value is `undefined`, or a missing `source`, is omitted
|
|
26
|
+
* entirely.
|
|
27
|
+
*
|
|
28
|
+
* Used to fold the embedded Svelte server's proxied capabilities into this
|
|
29
|
+
* server's `initialize` response. A capability the child lacks must be
|
|
30
|
+
* *absent*, not present-and-`undefined`: under `exactOptionalPropertyTypes` an
|
|
31
|
+
* explicit `undefined` is a type error, and an editor seeing the key at all
|
|
32
|
+
* would fire requests this server can answer only with `-32601`.
|
|
33
|
+
*/
|
|
34
|
+
export function pickDefined(source, keys) {
|
|
35
|
+
const picked = {};
|
|
36
|
+
if (!source)
|
|
37
|
+
return picked;
|
|
38
|
+
for (const key of keys) {
|
|
39
|
+
if (source[key] !== undefined) {
|
|
40
|
+
picked[key] = source[key];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return picked;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Returns a copy of `capabilities` with the pull-diagnostics capability
|
|
47
|
+
* (`textDocument.diagnostic`) removed.
|
|
48
|
+
*
|
|
49
|
+
* `svelte-language-server` switches to pull-only diagnostics — answering
|
|
50
|
+
* `textDocument/diagnostic` requests and no longer *pushing*
|
|
51
|
+
* `publishDiagnostics` — the moment the client claims to support them. This
|
|
52
|
+
* server forwards only pushed diagnostics and advertises no pull
|
|
53
|
+
* `diagnosticProvider` of its own, so it hides the capability from the child,
|
|
54
|
+
* keeping it in push mode; otherwise diagnostics silently never appear.
|
|
55
|
+
*/
|
|
56
|
+
export function withoutPullDiagnostics(capabilities) {
|
|
57
|
+
const textDocument = capabilities.textDocument;
|
|
58
|
+
if (!textDocument?.diagnostic)
|
|
59
|
+
return capabilities;
|
|
60
|
+
const nextTextDocument = {
|
|
61
|
+
...textDocument,
|
|
62
|
+
};
|
|
63
|
+
delete nextTextDocument.diagnostic;
|
|
64
|
+
return { ...capabilities, textDocument: nextTextDocument };
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Origin marker placed on the `data` of every completion item this server
|
|
68
|
+
* produces itself: items forwarded from a region child (TexLab, the math
|
|
69
|
+
* server) and items computed natively for frontmatter.
|
|
70
|
+
*
|
|
71
|
+
* `completionItem/resolve` carries only the item, so its `data` is the sole
|
|
72
|
+
* channel for telling an item's origin apart — which is what lets a resolve
|
|
73
|
+
* request be answered correctly instead of being mis-sent to the embedded
|
|
74
|
+
* Svelte server, which errors on a completion item it never produced.
|
|
75
|
+
*/
|
|
76
|
+
const NATIVE_COMPLETION_ORIGIN = 'sveltex-native';
|
|
77
|
+
/**
|
|
78
|
+
* Tags every item of a completion result with {@link NATIVE_COMPLETION_ORIGIN}
|
|
79
|
+
* — applied to the region-forwarded and frontmatter completion results so
|
|
80
|
+
* their later `completionItem/resolve` is recognised as this server's own.
|
|
81
|
+
*/
|
|
82
|
+
export function markNativeCompletion(result) {
|
|
83
|
+
if (!result)
|
|
84
|
+
return result;
|
|
85
|
+
const mark = (item) => ({
|
|
86
|
+
...item,
|
|
87
|
+
data: { sveltexOrigin: NATIVE_COMPLETION_ORIGIN },
|
|
88
|
+
});
|
|
89
|
+
return Array.isArray(result)
|
|
90
|
+
? result.map(mark)
|
|
91
|
+
: { ...result, items: result.items.map(mark) };
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Whether `item` was produced by this server itself — see
|
|
95
|
+
* {@link markNativeCompletion}. Such an item is already complete: its
|
|
96
|
+
* `completionItem/resolve` is answered by returning it unchanged.
|
|
97
|
+
*/
|
|
98
|
+
export function isNativeCompletionItem(item) {
|
|
99
|
+
const data = item.data;
|
|
100
|
+
return (typeof data === 'object' &&
|
|
101
|
+
data !== null &&
|
|
102
|
+
data['sveltexOrigin'] ===
|
|
103
|
+
NATIVE_COMPLETION_ORIGIN);
|
|
104
|
+
}
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
// 3. `initialize`-time helpers
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
/**
|
|
109
|
+
* Extracts a usable filesystem path for the workspace root from `initialize`
|
|
110
|
+
* params, tolerating the several historical shapes (`workspaceFolders`,
|
|
111
|
+
* `rootUri`, the long-deprecated `rootPath`).
|
|
112
|
+
*
|
|
113
|
+
* @returns An absolute path, or `undefined` if none could be determined.
|
|
114
|
+
*/
|
|
115
|
+
export function workspaceRootOf(params) {
|
|
116
|
+
const folder = params.workspaceFolders?.[0]?.uri;
|
|
117
|
+
if (folder)
|
|
118
|
+
return uriToPath(folder);
|
|
119
|
+
// `rootUri` / `rootPath` are deprecated in the LSP spec but are still the
|
|
120
|
+
// only root information sent by older clients, so they are kept as
|
|
121
|
+
// fallbacks for compatibility.
|
|
122
|
+
/* eslint-disable @typescript-eslint/no-deprecated */
|
|
123
|
+
if (params.rootUri)
|
|
124
|
+
return uriToPath(params.rootUri);
|
|
125
|
+
if (typeof params.rootPath === 'string')
|
|
126
|
+
return params.rootPath;
|
|
127
|
+
/* eslint-enable @typescript-eslint/no-deprecated */
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
/** Converts a `file:` URI to a filesystem path; returns `undefined` otherwise. */
|
|
131
|
+
export function uriToPath(uri) {
|
|
132
|
+
try {
|
|
133
|
+
const parsed = URI.parse(uri);
|
|
134
|
+
return parsed.scheme === 'file' ? parsed.fsPath : undefined;
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Extracts the optional child-server paths from an `initialize` request's
|
|
142
|
+
* `initializationOptions`.
|
|
143
|
+
*
|
|
144
|
+
* A host that has bundled the child servers and so cannot resolve them from
|
|
145
|
+
* `node_modules` (the VS Code extension) passes their absolute paths under a
|
|
146
|
+
* `serverPaths` object:
|
|
147
|
+
*
|
|
148
|
+
* ```jsonc
|
|
149
|
+
* "initializationOptions": {
|
|
150
|
+
* "serverPaths": {
|
|
151
|
+
* "svelteLanguageServer": "/abs/path/to/svelte-language-server.js",
|
|
152
|
+
* "mathLanguageServer": "/abs/path/to/sveltex-math-language-server.js"
|
|
153
|
+
* }
|
|
154
|
+
* }
|
|
155
|
+
* ```
|
|
156
|
+
*
|
|
157
|
+
* The field is entirely optional: any standalone client (the Zed extension,
|
|
158
|
+
* the CLI, the test harness) omits it, and every path then resolves from
|
|
159
|
+
* `node_modules` as before. Non-string entries are ignored.
|
|
160
|
+
*
|
|
161
|
+
* @param initializationOptions - The raw `initializationOptions` value, of
|
|
162
|
+
* unknown shape.
|
|
163
|
+
* @returns The resolved paths; fields are `undefined` when not supplied.
|
|
164
|
+
*/
|
|
165
|
+
export function readServerPaths(initializationOptions) {
|
|
166
|
+
const empty = {
|
|
167
|
+
svelteLanguageServer: undefined,
|
|
168
|
+
mathLanguageServer: undefined,
|
|
169
|
+
};
|
|
170
|
+
if (typeof initializationOptions !== 'object' || !initializationOptions) {
|
|
171
|
+
return empty;
|
|
172
|
+
}
|
|
173
|
+
const serverPaths = initializationOptions['serverPaths'];
|
|
174
|
+
if (typeof serverPaths !== 'object' || !serverPaths)
|
|
175
|
+
return empty;
|
|
176
|
+
const record = serverPaths;
|
|
177
|
+
const asPath = (value) => typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
178
|
+
return {
|
|
179
|
+
svelteLanguageServer: asPath(record['svelteLanguageServer']),
|
|
180
|
+
mathLanguageServer: asPath(record['mathLanguageServer']),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Connection } from 'vscode-languageserver';
|
|
2
|
+
/**
|
|
3
|
+
* Wires a SvelTeX language server onto the given connection.
|
|
4
|
+
*
|
|
5
|
+
* @param connection - An LSP {@link Connection}, already created for whatever
|
|
6
|
+
* transport the host uses. This function never calls `listen()` — the caller
|
|
7
|
+
* (`startServer` in `index.ts`, or the VS Code client) owns the lifecycle.
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* Transport-agnostic by construction: no `vscode` import, no direct stdio
|
|
11
|
+
* access. This is the contract the future Zed extension relies on.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createServer(connection: Connection): void;
|