@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.
Files changed (40) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +288 -0
  3. package/bin/server.js +10 -0
  4. package/dist/core/config.d.ts +126 -0
  5. package/dist/core/config.js +569 -0
  6. package/dist/core/diagnostics.d.ts +34 -0
  7. package/dist/core/diagnostics.js +67 -0
  8. package/dist/core/frontmatter-data.d.ts +74 -0
  9. package/dist/core/frontmatter-data.js +323 -0
  10. package/dist/core/frontmatter.d.ts +25 -0
  11. package/dist/core/frontmatter.js +348 -0
  12. package/dist/core/lsp-proxy.d.ts +77 -0
  13. package/dist/core/lsp-proxy.js +165 -0
  14. package/dist/core/mapper.d.ts +86 -0
  15. package/dist/core/mapper.js +223 -0
  16. package/dist/core/mapping.d.ts +59 -0
  17. package/dist/core/mapping.js +37 -0
  18. package/dist/core/markdown.d.ts +34 -0
  19. package/dist/core/markdown.js +215 -0
  20. package/dist/core/region-forwarding.d.ts +90 -0
  21. package/dist/core/region-forwarding.js +428 -0
  22. package/dist/core/region-virtual.d.ts +71 -0
  23. package/dist/core/region-virtual.js +131 -0
  24. package/dist/core/regions.d.ts +56 -0
  25. package/dist/core/regions.js +221 -0
  26. package/dist/core/remap.d.ts +84 -0
  27. package/dist/core/remap.js +272 -0
  28. package/dist/core/server-helpers.d.ts +109 -0
  29. package/dist/core/server-helpers.js +182 -0
  30. package/dist/core/server.d.ts +13 -0
  31. package/dist/core/server.js +604 -0
  32. package/dist/core/svelte-proxy.d.ts +100 -0
  33. package/dist/core/svelte-proxy.js +144 -0
  34. package/dist/core/texlab.d.ts +26 -0
  35. package/dist/core/texlab.js +121 -0
  36. package/dist/core/virtual-svelte.d.ts +32 -0
  37. package/dist/core/virtual-svelte.js +67 -0
  38. package/dist/index.d.ts +29 -0
  39. package/dist/index.js +46 -0
  40. 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;