@hydranium/core 1.0.0-next.155 → 1.0.0-next.157
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/lib/documents/ast-document-manager.d.ts +3 -2
- package/lib/documents/ast-document-manager.d.ts.map +1 -1
- package/lib/documents/ast-document-manager.js.map +1 -1
- package/lib/documents/hydranium-text-documents.d.ts +3 -2
- package/lib/documents/hydranium-text-documents.d.ts.map +1 -1
- package/lib/documents/hydranium-text-documents.js +3 -2
- package/lib/documents/hydranium-text-documents.js.map +1 -1
- package/lib/langium/module.d.ts +38 -12
- package/lib/langium/module.d.ts.map +1 -1
- package/lib/langium/module.js +15 -22
- package/lib/langium/module.js.map +1 -1
- package/lib/langium/workspace/document-uri-policy.d.ts +7 -5
- package/lib/langium/workspace/document-uri-policy.d.ts.map +1 -1
- package/lib/langium/workspace/document-uri-policy.js +7 -5
- package/lib/langium/workspace/document-uri-policy.js.map +1 -1
- package/lib/langium/workspace/file-not-found.d.ts +17 -0
- package/lib/langium/workspace/file-not-found.d.ts.map +1 -0
- package/lib/langium/workspace/file-not-found.js +20 -0
- package/lib/langium/workspace/file-not-found.js.map +1 -0
- package/lib/langium/workspace/file-system-provider.d.ts +81 -13
- package/lib/langium/workspace/file-system-provider.d.ts.map +1 -1
- package/lib/langium/workspace/file-system-provider.js +81 -35
- package/lib/langium/workspace/file-system-provider.js.map +1 -1
- package/lib/langium/workspace/hydranium-workspace-manager.d.ts +51 -2
- package/lib/langium/workspace/hydranium-workspace-manager.d.ts.map +1 -1
- package/lib/langium/workspace/hydranium-workspace-manager.js +82 -4
- package/lib/langium/workspace/hydranium-workspace-manager.js.map +1 -1
- package/lib/langium/workspace/in-memory-file-system-provider.d.ts +2 -2
- package/lib/langium/workspace/in-memory-file-system-provider.d.ts.map +1 -1
- package/lib/langium/workspace/in-memory-file-system-provider.js +3 -23
- package/lib/langium/workspace/in-memory-file-system-provider.js.map +1 -1
- package/lib/langium/workspace/persistent-file-system-provider.d.ts +0 -7
- package/lib/langium/workspace/persistent-file-system-provider.d.ts.map +1 -1
- package/lib/langium/workspace/persistent-file-system-provider.js +0 -7
- package/lib/langium/workspace/persistent-file-system-provider.js.map +1 -1
- package/lib/langium/workspace/virtual-document.d.ts +44 -26
- package/lib/langium/workspace/virtual-document.d.ts.map +1 -1
- package/lib/langium/workspace/virtual-document.js +76 -33
- package/lib/langium/workspace/virtual-document.js.map +1 -1
- package/lib/node/node-file-system-provider.d.ts +10 -9
- package/lib/node/node-file-system-provider.d.ts.map +1 -1
- package/lib/node/node-file-system-provider.js +12 -47
- package/lib/node/node-file-system-provider.js.map +1 -1
- package/package.json +5 -5
- package/src/documents/ast-document-manager.ts +3 -2
- package/src/documents/hydranium-text-documents.ts +3 -2
- package/src/langium/module.ts +56 -34
- package/src/langium/workspace/document-uri-policy.ts +7 -5
- package/src/langium/workspace/file-not-found.ts +23 -0
- package/src/langium/workspace/file-system-provider.ts +136 -39
- package/src/langium/workspace/hydranium-workspace-manager.ts +98 -6
- package/src/langium/workspace/in-memory-file-system-provider.ts +3 -24
- package/src/langium/workspace/persistent-file-system-provider.ts +0 -7
- package/src/langium/workspace/virtual-document.ts +92 -33
- package/src/node/node-file-system-provider.ts +12 -48
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-file-system-provider.js","sourceRoot":"","sources":["../../src/node/node-file-system-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAGlF,OAAO,EAAuB,GAAG,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,KAAK,GAAG,MAAM,kBAAkB,CAAC;AAGxC,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAEtE,OAAO,EAAE,mBAAmB,EAAoC,MAAM,+BAA+B,CAAC;AACtG,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,wDAAwD,CAAC;
|
|
1
|
+
{"version":3,"file":"node-file-system-provider.js","sourceRoot":"","sources":["../../src/node/node-file-system-provider.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hydranium/core",
|
|
3
|
-
"version": "1.0.0-next.
|
|
3
|
+
"version": "1.0.0-next.157",
|
|
4
4
|
"description": "Foundational runtime of the hydranium framework: AST coordination layer (services, integrity, AST extension, serialization, multi-client documents) plus the LSP textual head at the /lsp subpath. Consumed by protocol-head packages (@hydranium/data-server, @hydranium/glsp-server).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"hydranium",
|
|
@@ -104,8 +104,8 @@
|
|
|
104
104
|
"diff": "^5.2.0"
|
|
105
105
|
},
|
|
106
106
|
"devDependencies": {
|
|
107
|
-
"@hydranium/langium": "1.0.0-next.
|
|
108
|
-
"@hydranium/protocol": "1.0.0-next.
|
|
107
|
+
"@hydranium/langium": "1.0.0-next.157",
|
|
108
|
+
"@hydranium/protocol": "1.0.0-next.157",
|
|
109
109
|
"@playwright/test": "^1.40.0",
|
|
110
110
|
"@types/diff": "^5.2.0",
|
|
111
111
|
"rimraf": "^5.0.0",
|
|
@@ -117,8 +117,8 @@
|
|
|
117
117
|
"vscode-languageserver-types": "^3.17.5"
|
|
118
118
|
},
|
|
119
119
|
"peerDependencies": {
|
|
120
|
-
"@hydranium/langium": "1.0.0-next.
|
|
121
|
-
"@hydranium/protocol": "1.0.0-next.
|
|
120
|
+
"@hydranium/langium": "1.0.0-next.157",
|
|
121
|
+
"@hydranium/protocol": "1.0.0-next.157",
|
|
122
122
|
"@playwright/test": "^1.40.0",
|
|
123
123
|
"vscode-jsonrpc": "9.0.1",
|
|
124
124
|
"vscode-languageserver": "~10.0.1",
|
|
@@ -65,8 +65,9 @@ export interface WritableFileSystemProvider extends FileSystemProvider {
|
|
|
65
65
|
* - A non-`file:` URI (or any URI the provider cannot stat) passes through
|
|
66
66
|
* **unchanged** — it is treated as present, never reported absent.
|
|
67
67
|
* - A provider with no disk to check (in-memory / browser / empty) simply
|
|
68
|
-
* omits this method; `
|
|
69
|
-
*
|
|
68
|
+
* omits this method; the framework's `FileSystemProviderRegistry` then
|
|
69
|
+
* returns the URI unchanged, and `RealpathDocumentUriPolicy` answers as
|
|
70
|
+
* the syntactic `DefaultDocumentUriPolicy` does.
|
|
70
71
|
*
|
|
71
72
|
* Synchronous (a `realpath` is a kernel-cached syscall) and optional — the
|
|
72
73
|
* only consumers are the document-identity policy's `canonicalUri`/`loadUri`.
|
|
@@ -819,8 +819,9 @@ export class HydraniumTextDocuments<T extends TextDocument = TextDocument> exten
|
|
|
819
819
|
* serve is rebuilt from its text, and any other — an editor's `untitled:`
|
|
820
820
|
* buffer, a file never saved, or one deleted meanwhile — is removed
|
|
821
821
|
* from the workspace. A `virtual:` document survives, since the framework's
|
|
822
|
-
*
|
|
823
|
-
*
|
|
822
|
+
* provider for that scheme serves it from the index, whatever provider the
|
|
823
|
+
* host passes as `context.fileSystemProvider`; an edited one therefore keeps
|
|
824
|
+
* its last client's text, and keeping it read-only is the client's job.
|
|
824
825
|
*
|
|
825
826
|
* The answer is read in the document's disk queue, so the rebuild follows
|
|
826
827
|
* any save still queued rather than reverting past it; a file that goes
|
package/src/langium/module.ts
CHANGED
|
@@ -37,7 +37,12 @@ import { HydraniumTextDocuments } from '../documents/hydranium-text-documents.js
|
|
|
37
37
|
import { DefaultAstDocumentManager, type AstDocumentManager, type WritableFileSystemProvider } from '../documents/ast-document-manager.js';
|
|
38
38
|
import { DefaultSelfSaveRegistry, type SelfSaveRegistry } from '../documents/self-save-registry.js';
|
|
39
39
|
import { DefaultFileSystemTaskQueue, type FileSystemTaskQueue } from '../documents/file-system-task-queue.js';
|
|
40
|
-
import {
|
|
40
|
+
import {
|
|
41
|
+
DefaultEmptyFileSystemProvider,
|
|
42
|
+
DefaultFileSystemProviderRegistry,
|
|
43
|
+
type FileSystemProviderRegistry
|
|
44
|
+
} from './workspace/file-system-provider.js';
|
|
45
|
+
import { VIRTUAL_SCHEME, VirtualFileSystemProvider } from './workspace/virtual-document.js';
|
|
41
46
|
import { type ServerLanguageServices } from './language-module.js';
|
|
42
47
|
import { ExtendedServiceRegistry } from './service-registry.js';
|
|
43
48
|
|
|
@@ -178,20 +183,36 @@ export interface ServerAddedSharedServices<
|
|
|
178
183
|
*/
|
|
179
184
|
/* override */ WorkspaceLock: HydraniumWorkspaceLock;
|
|
180
185
|
/**
|
|
181
|
-
* Tighten Langium's read-only `FileSystemProvider` slot to
|
|
182
|
-
* {@link
|
|
183
|
-
* ({@link AstDocumentManager.save}, integrity
|
|
184
|
-
* a session's `save`) requires write semantics
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
* {@link
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
186
|
+
* Tighten Langium's read-only `FileSystemProvider` slot to a
|
|
187
|
+
* {@link FileSystemProviderRegistry}, which is writable: the
|
|
188
|
+
* framework's save path ({@link AstDocumentManager.save}, integrity
|
|
189
|
+
* corrections, a session's `save`) requires write semantics, and a
|
|
190
|
+
* read-only slot type defers the failure of a read-only
|
|
191
|
+
* implementation to the first save.
|
|
192
|
+
*
|
|
193
|
+
* Bound to {@link DefaultFileSystemProviderRegistry}, which dispatches
|
|
194
|
+
* by scheme to the {@link ServerAddedSharedServices.fileSystemProviders}
|
|
195
|
+
* group and sends every other scheme to its `host`: the provider
|
|
196
|
+
* `context.fileSystemProvider` returns when it is writable, or else
|
|
197
|
+
* `DefaultEmptyFileSystemProvider`, which is what keeps the core
|
|
198
|
+
* barrel free of `node:fs` and therefore browser-bundleable. A Node
|
|
199
|
+
* host passes `@hydranium/core/node`'s Node-backed provider (wired to
|
|
200
|
+
* {@link SelfSaveRegistry}) instead, and adopters pass their own
|
|
192
201
|
* writable implementation when neither fits.
|
|
202
|
+
*
|
|
203
|
+
* To reach the members of its own provider, an adopter declares this
|
|
204
|
+
* slot as `FileSystemProviderRegistry<MyProvider>` through
|
|
205
|
+
* {@link WithServiceOverrides}, binds a
|
|
206
|
+
* `DefaultFileSystemProviderRegistry` with that host from a factory
|
|
207
|
+
* whose return type names the narrowed slot (a module's `DeepPartial`
|
|
208
|
+
* checks no host member otherwise), and reads
|
|
209
|
+
* `FileSystemProvider.host`. A
|
|
210
|
+
* registry that serves a seeded document under none of its providers
|
|
211
|
+
* loses the document at its last close, which
|
|
212
|
+
* {@link HydraniumWorkspaceManager.warnIfDocumentsUnserved} reports
|
|
213
|
+
* once at startup.
|
|
193
214
|
*/
|
|
194
|
-
/* override */ FileSystemProvider:
|
|
215
|
+
/* override */ FileSystemProvider: FileSystemProviderRegistry;
|
|
195
216
|
ProjectManager: ProjectManager<TProject>;
|
|
196
217
|
SelfSaveRegistry: SelfSaveRegistry;
|
|
197
218
|
/**
|
|
@@ -307,6 +328,15 @@ export interface ServerAddedSharedServices<
|
|
|
307
328
|
* contribute none never touch it.
|
|
308
329
|
*/
|
|
309
330
|
additionalDocuments: Record<string, AdditionalDocumentContribution>;
|
|
331
|
+
/**
|
|
332
|
+
* Shared contribution group of file system providers keyed by the URI
|
|
333
|
+
* scheme each answers for, which {@link FileSystemProviderRegistry}
|
|
334
|
+
* dispatches to. The framework registers {@link VirtualFileSystemProvider}
|
|
335
|
+
* under `virtual`; an adopter deep-merges a provider for a scheme of its
|
|
336
|
+
* own, and an entry under `virtual` replaces the framework's. A scheme with
|
|
337
|
+
* no entry goes to the registry's `host`.
|
|
338
|
+
*/
|
|
339
|
+
fileSystemProviders: Record<string, WritableFileSystemProvider>;
|
|
310
340
|
}
|
|
311
341
|
|
|
312
342
|
/**
|
|
@@ -491,7 +521,7 @@ export function createServerSharedModule(
|
|
|
491
521
|
ConfigurationProvider: services => new HydraniumConfigurationProvider(services),
|
|
492
522
|
// Override Langium's factory so a `fromModel` (code-built) virtual
|
|
493
523
|
// document retains serialized text via the per-language Serializer,
|
|
494
|
-
// making it re-read-safe through
|
|
524
|
+
// making it re-read-safe through `VirtualFileSystemProvider`.
|
|
495
525
|
LangiumDocumentFactory: services => new HydraniumLangiumDocumentFactory(services),
|
|
496
526
|
// Langium's default routes through no identity seam and treats every
|
|
497
527
|
// failed load alike, so leaving this unbound opts a server out of both
|
|
@@ -504,27 +534,16 @@ export function createServerSharedModule(
|
|
|
504
534
|
ProjectManager: services => new SingleProjectManager(services),
|
|
505
535
|
SelfSaveRegistry: services => new DefaultSelfSaveRegistry(services),
|
|
506
536
|
DocumentUriPolicy: () => new DefaultDocumentUriPolicy(),
|
|
507
|
-
//
|
|
508
|
-
//
|
|
509
|
-
//
|
|
510
|
-
//
|
|
511
|
-
// (in-memory, browser, test stub like `DefaultEmptyFileSystemProvider`).
|
|
512
|
-
// - Otherwise — the portable default `DefaultEmptyFileSystemProvider`
|
|
513
|
-
// (no-op writes, no disk access). Node hosts opt into real disk I/O
|
|
514
|
-
// by binding `@hydranium/core/node`'s `DefaultFileSystemProvider`
|
|
515
|
-
// (Node-backed, wired to `SelfSaveRegistry` so framework `writeFile`
|
|
516
|
-
// calls register their mtime and adopters can suppress the
|
|
517
|
-
// `didChangeWatchedFiles` echo) — typically via this same
|
|
518
|
-
// `context.fileSystemProvider` channel or by rebinding
|
|
519
|
-
// the slot. Keeping the `.`-entry default empty is what lets the
|
|
520
|
-
// core barrel stay free of `node:fs` (browser-bundleable); see the
|
|
521
|
-
// `@hydranium/core/node` carve.
|
|
537
|
+
// The host is the provider `context.fileSystemProvider` returns
|
|
538
|
+
// when it is writable (has `writeFile`); anything narrower gets the
|
|
539
|
+
// empty provider, which is what keeps the core barrel free of
|
|
540
|
+
// `node:fs`.
|
|
522
541
|
FileSystemProvider: services => {
|
|
523
542
|
const fromContext = context.fileSystemProvider?.(services);
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
543
|
+
const writable = typeof (fromContext as Partial<WritableFileSystemProvider> | undefined)?.writeFile === 'function';
|
|
544
|
+
return new DefaultFileSystemProviderRegistry(services, {
|
|
545
|
+
host: writable ? (fromContext as WritableFileSystemProvider) : new DefaultEmptyFileSystemProvider(services)
|
|
546
|
+
});
|
|
528
547
|
},
|
|
529
548
|
AstDocumentManager: services => new DefaultAstDocumentManager(services),
|
|
530
549
|
FileSystemTaskQueue: services => new DefaultFileSystemTaskQueue(services),
|
|
@@ -548,6 +567,9 @@ export function createServerSharedModule(
|
|
|
548
567
|
// profiler passes self-register imperatively, not here.
|
|
549
568
|
buildPhasePasses: {},
|
|
550
569
|
// Empty default so `services.additionalDocuments` always resolves.
|
|
551
|
-
additionalDocuments: {}
|
|
570
|
+
additionalDocuments: {},
|
|
571
|
+
fileSystemProviders: {
|
|
572
|
+
[VIRTUAL_SCHEME]: services => new VirtualFileSystemProvider(services)
|
|
573
|
+
}
|
|
552
574
|
};
|
|
553
575
|
}
|
|
@@ -156,11 +156,13 @@ export class DefaultDocumentUriPolicy implements DocumentUriPolicy {
|
|
|
156
156
|
* `loadUri` returns `undefined` for an absent path (honest about existence, so a
|
|
157
157
|
* caller about to read the filesystem skips it).
|
|
158
158
|
*
|
|
159
|
-
* If the
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
* `
|
|
159
|
+
* If the provider for a URI's scheme has no `realpath` (in-memory / browser /
|
|
160
|
+
* empty), the framework's `FileSystemProviderRegistry` returns the URI
|
|
161
|
+
* unchanged and both methods answer as {@link DefaultDocumentUriPolicy} does. A
|
|
162
|
+
* slot bound to a provider without `realpath` degrades the same way: the
|
|
163
|
+
* `loadUri` ternary tests the *method's presence*, not its return, so
|
|
164
|
+
* `loadUri` returns `undefined` only when `realpath` is present and reports the
|
|
165
|
+
* path absent.
|
|
164
166
|
*/
|
|
165
167
|
export class RealpathDocumentUriPolicy extends DefaultDocumentUriPolicy {
|
|
166
168
|
protected readonly fs: RealpathCapableFileSystem;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
|
|
10
|
+
import { type URI } from '@hydranium/langium';
|
|
11
|
+
|
|
12
|
+
// Not re-exported from the workspace barrel: the framework's providers share
|
|
13
|
+
// it, and it is no API of theirs.
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A missing-file error shaped as a Node file system raises it, with code
|
|
17
|
+
* `ENOENT` and the path: callers tell a missing file from any other failure by
|
|
18
|
+
* those two fields, whichever provider is bound. The last close relies on it to
|
|
19
|
+
* tell a document gone meanwhile from any other failed rebuild.
|
|
20
|
+
*/
|
|
21
|
+
export function notFound(message: string, uri: URI): Error {
|
|
22
|
+
return Object.assign(new Error(message), { code: 'ENOENT', path: uri.fsPath });
|
|
23
|
+
}
|
|
@@ -13,14 +13,14 @@ import type { FileSystemNode, URI } from '@hydranium/langium';
|
|
|
13
13
|
import { type WritableFileSystemProvider } from '../../documents/ast-document-manager.js';
|
|
14
14
|
import { type LogNameOptions } from '../diagnostics/logger.js';
|
|
15
15
|
import { type ServerSharedServicesMinimal } from '../shared-services.js';
|
|
16
|
-
import { serveVirtualDocument, serveVirtualNode } from './virtual-document.js';
|
|
17
16
|
|
|
18
17
|
/**
|
|
19
|
-
* Empty-filesystem
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* Node-backed
|
|
23
|
-
* lives in `@hydranium/core/node` (it pulls
|
|
18
|
+
* Empty-filesystem {@link WritableFileSystemProvider}. For browser / test / CLI
|
|
19
|
+
* hosts that don't have a real filesystem. All writes are no-ops. On the
|
|
20
|
+
* portable `.` entry it is the {@link FileSystemProviderRegistry.host} when
|
|
21
|
+
* `context.fileSystemProvider` gives no writable provider; the Node-backed
|
|
22
|
+
* `DefaultFileSystemProvider` lives in `@hydranium/core/node` (it pulls
|
|
23
|
+
* `node:fs`).
|
|
24
24
|
*/
|
|
25
25
|
export class DefaultEmptyFileSystemProvider extends EmptyFileSystemProvider implements WritableFileSystemProvider {
|
|
26
26
|
protected readonly tracer: Tracer;
|
|
@@ -37,56 +37,153 @@ export class DefaultEmptyFileSystemProvider extends EmptyFileSystemProvider impl
|
|
|
37
37
|
// no-op
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
// answers "absent"). The base declares these param-less, so the param is
|
|
43
|
-
// optional here.
|
|
44
|
-
//
|
|
45
|
-
// The async reads are `async` so the base's refusal becomes a rejection: it
|
|
46
|
-
// throws SYNCHRONOUSLY from a method declared to return a promise, and a
|
|
40
|
+
// `async` so the base's refusal becomes a rejection: it throws
|
|
41
|
+
// SYNCHRONOUSLY from a method declared to return a promise, and a
|
|
47
42
|
// synchronous throw escapes the promise chain — `.catch()` never attaches
|
|
48
43
|
// and `Promise.all` dies while its argument array is still being built, so
|
|
49
|
-
// a caller reading several URIs cannot handle the miss it asked about.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
// a caller reading several URIs cannot handle the miss it asked about. The
|
|
45
|
+
// base declares `readFile` and `readBinary` param-less, so the param is
|
|
46
|
+
// optional there.
|
|
47
|
+
override async readFile(_uri?: URI): Promise<string> {
|
|
48
|
+
return super.readFile();
|
|
53
49
|
}
|
|
54
50
|
|
|
55
|
-
override
|
|
56
|
-
|
|
57
|
-
return served !== undefined ? served : super.readFileSync();
|
|
51
|
+
override async readBinary(_uri?: URI): Promise<Uint8Array> {
|
|
52
|
+
return super.readBinary();
|
|
58
53
|
}
|
|
59
54
|
|
|
60
|
-
override async
|
|
61
|
-
|
|
62
|
-
|
|
55
|
+
override async stat(uri: URI): Promise<FileSystemNode> {
|
|
56
|
+
return super.stat(uri);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The provider bound on `workspace.FileSystemProvider`: it dispatches each call
|
|
62
|
+
* by the URI's scheme to the provider registered for it in the shared
|
|
63
|
+
* `fileSystemProviders` group, and to the {@link host} for any scheme without
|
|
64
|
+
* one.
|
|
65
|
+
*
|
|
66
|
+
* So one provider answers for each scheme, and a host's provider needs to know
|
|
67
|
+
* only its own: the framework registers `virtual:` there, and an adopter adds a
|
|
68
|
+
* scheme by contributing to the group. The host takes every unclaimed scheme
|
|
69
|
+
* rather than `file:` alone, which keeps an in-memory workspace under `memory:`
|
|
70
|
+
* or any other scheme on the host's provider.
|
|
71
|
+
*
|
|
72
|
+
* `THost` types the host, so an adopter whose own provider has more members
|
|
73
|
+
* than the base declares the slot as `FileSystemProviderRegistry<MyProvider>`,
|
|
74
|
+
* binds a {@link DefaultFileSystemProviderRegistry} with that host, and reads
|
|
75
|
+
* those members through `services.workspace.FileSystemProvider.host`.
|
|
76
|
+
*/
|
|
77
|
+
export interface FileSystemProviderRegistry<
|
|
78
|
+
THost extends WritableFileSystemProvider = WritableFileSystemProvider
|
|
79
|
+
> extends WritableFileSystemProvider {
|
|
80
|
+
/** The provider for every scheme no entry of `fileSystemProviders` claims. */
|
|
81
|
+
readonly host: THost;
|
|
82
|
+
/** The provider that answers for `uri`. */
|
|
83
|
+
providerFor(uri: URI): WritableFileSystemProvider;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Options for {@link DefaultFileSystemProviderRegistry}. */
|
|
87
|
+
export interface FileSystemProviderRegistryOptions<
|
|
88
|
+
THost extends WritableFileSystemProvider = WritableFileSystemProvider
|
|
89
|
+
> extends LogNameOptions {
|
|
90
|
+
/**
|
|
91
|
+
* The provider for every scheme no entry of `fileSystemProviders` claims.
|
|
92
|
+
* The framework passes the provider `context.fileSystemProvider` returns,
|
|
93
|
+
* or a {@link DefaultEmptyFileSystemProvider} when that is not writable.
|
|
94
|
+
*/
|
|
95
|
+
host: THost;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* The framework's {@link FileSystemProviderRegistry}.
|
|
100
|
+
*
|
|
101
|
+
* A directory is listed by the provider of its own scheme, so a workspace
|
|
102
|
+
* root's tree comes from that provider alone.
|
|
103
|
+
*
|
|
104
|
+
* `realpath` and `mtimeMs` are always present and forward to the scheme's
|
|
105
|
+
* provider. Where that provider lacks one, `realpath` returns the URI unchanged
|
|
106
|
+
* and `mtimeMs` returns `undefined`: the answers `RealpathDocumentUriPolicy`
|
|
107
|
+
* and the self-save filter already give a provider without them.
|
|
108
|
+
*/
|
|
109
|
+
export class DefaultFileSystemProviderRegistry<
|
|
110
|
+
THost extends WritableFileSystemProvider = WritableFileSystemProvider
|
|
111
|
+
> implements FileSystemProviderRegistry<THost> {
|
|
112
|
+
readonly host: THost;
|
|
113
|
+
protected readonly tracer: Tracer;
|
|
114
|
+
|
|
115
|
+
constructor(
|
|
116
|
+
protected readonly services: ServerSharedServicesMinimal & { fileSystemProviders: Record<string, WritableFileSystemProvider> },
|
|
117
|
+
options: FileSystemProviderRegistryOptions<THost>
|
|
118
|
+
) {
|
|
119
|
+
this.host = options.host;
|
|
120
|
+
this.tracer = services.Tracer.for(options.logName ?? this.constructor.name).trace('instantiated');
|
|
63
121
|
}
|
|
64
122
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
123
|
+
/**
|
|
124
|
+
* The group is read per call, not in the constructor, so a registered
|
|
125
|
+
* provider is built on first use and may read slots that reach back to this
|
|
126
|
+
* one. Only an OWN key of the group counts: the DI container resolves any
|
|
127
|
+
* key found on the prototype chain, so a scheme such as `constructor` would
|
|
128
|
+
* otherwise dispatch to a function.
|
|
129
|
+
*/
|
|
130
|
+
providerFor(uri: URI): WritableFileSystemProvider {
|
|
131
|
+
const providers = this.services.fileSystemProviders;
|
|
132
|
+
return Object.hasOwn(providers, uri.scheme) ? providers[uri.scheme] : this.host;
|
|
68
133
|
}
|
|
69
134
|
|
|
70
|
-
// The
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
return
|
|
135
|
+
// The async methods are `async` so a provider that throws synchronously from
|
|
136
|
+
// one still rejects, for the reason `DefaultEmptyFileSystemProvider` gives.
|
|
137
|
+
async writeFile(uri: URI, content: string): Promise<void> {
|
|
138
|
+
return this.providerFor(uri).writeFile(uri, content);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async mtimeMs(uri: URI): Promise<number | undefined> {
|
|
142
|
+
return this.providerFor(uri).mtimeMs?.(uri);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
realpath(uri: URI): URI | undefined {
|
|
146
|
+
const provider = this.providerFor(uri);
|
|
147
|
+
return provider.realpath ? provider.realpath(uri) : uri;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async stat(uri: URI): Promise<FileSystemNode> {
|
|
151
|
+
return this.providerFor(uri).stat(uri);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
statSync(uri: URI): FileSystemNode {
|
|
155
|
+
return this.providerFor(uri).statSync(uri);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async exists(uri: URI): Promise<boolean> {
|
|
159
|
+
return this.providerFor(uri).exists(uri);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
existsSync(uri: URI): boolean {
|
|
163
|
+
return this.providerFor(uri).existsSync(uri);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async readBinary(uri: URI): Promise<Uint8Array> {
|
|
167
|
+
return this.providerFor(uri).readBinary(uri);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
readBinarySync(uri: URI): Uint8Array {
|
|
171
|
+
return this.providerFor(uri).readBinarySync(uri);
|
|
74
172
|
}
|
|
75
173
|
|
|
76
|
-
|
|
77
|
-
return
|
|
174
|
+
async readFile(uri: URI): Promise<string> {
|
|
175
|
+
return this.providerFor(uri).readFile(uri);
|
|
78
176
|
}
|
|
79
177
|
|
|
80
|
-
|
|
81
|
-
return this.
|
|
178
|
+
readFileSync(uri: URI): string {
|
|
179
|
+
return this.providerFor(uri).readFileSync(uri);
|
|
82
180
|
}
|
|
83
181
|
|
|
84
|
-
|
|
85
|
-
return this.
|
|
182
|
+
async readDirectory(uri: URI): Promise<FileSystemNode[]> {
|
|
183
|
+
return this.providerFor(uri).readDirectory(uri);
|
|
86
184
|
}
|
|
87
185
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
return uri !== undefined ? serveVirtualDocument(this.services, uri) : undefined;
|
|
186
|
+
readDirectorySync(uri: URI): FileSystemNode[] {
|
|
187
|
+
return this.providerFor(uri).readDirectorySync(uri);
|
|
91
188
|
}
|
|
92
189
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
********************************************************************************/
|
|
9
9
|
|
|
10
10
|
import { Deferred, type Logger, type Tracer } from '@hydranium/protocol';
|
|
11
|
-
import { DefaultWorkspaceManager, DocumentState, type LangiumDocument, UriUtils, type URI } from '@hydranium/langium';
|
|
11
|
+
import { DefaultWorkspaceManager, DocumentState, type LangiumDocument, type Stream, UriUtils, type URI } from '@hydranium/langium';
|
|
12
12
|
import { type CancellationToken, type InitializeParams } from 'vscode-languageserver';
|
|
13
13
|
import type { WorkspaceFolder } from 'vscode-languageserver-types';
|
|
14
14
|
import { type LogNameOptions, resolveLogFilePlaceholder, toLogFileWorkspaceToken } from '../diagnostics/logger.js';
|
|
@@ -93,6 +93,18 @@ export function installOperationCancelledSuppression(logger: Logger): void {
|
|
|
93
93
|
});
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
/** Options for {@link HydraniumWorkspaceManager}. */
|
|
97
|
+
export interface HydraniumWorkspaceManagerOptions extends LogNameOptions {
|
|
98
|
+
/**
|
|
99
|
+
* Whether startup warns about seeded documents the bound
|
|
100
|
+
* `FileSystemProvider` cannot serve (see
|
|
101
|
+
* {@link HydraniumWorkspaceManager.warnIfDocumentsUnserved}). Defaults to
|
|
102
|
+
* `true`; turn it off for a host that drops such documents at their last
|
|
103
|
+
* close on purpose.
|
|
104
|
+
*/
|
|
105
|
+
warnUnservedDocuments?: boolean;
|
|
106
|
+
}
|
|
107
|
+
|
|
96
108
|
/**
|
|
97
109
|
* Framework {@link DefaultWorkspaceManager} subclass that integrates the
|
|
98
110
|
* project tier with Langium's workspace startup.
|
|
@@ -163,8 +175,12 @@ export class HydraniumWorkspaceManager extends DefaultWorkspaceManager {
|
|
|
163
175
|
protected readonly additionalDocuments: Record<string, AdditionalDocumentContribution>;
|
|
164
176
|
/** Registry consulted by {@link warnIfUnroutable} to check a seeded document routes. */
|
|
165
177
|
protected readonly languageRegistry: ServerSharedServicesMinimal['ServiceRegistry'];
|
|
178
|
+
/** Whether startup runs {@link warnIfDocumentsUnserved}. */
|
|
179
|
+
protected readonly warnUnservedDocuments: boolean;
|
|
180
|
+
/** URIs of the documents the running startup's file traversal loaded; see {@link loadWorkspaceDocuments}. */
|
|
181
|
+
protected readonly traversedUris = new Set<string>();
|
|
166
182
|
|
|
167
|
-
constructor(services: ServerSharedServicesMinimal, options:
|
|
183
|
+
constructor(services: ServerSharedServicesMinimal, options: HydraniumWorkspaceManagerOptions = {}) {
|
|
168
184
|
super(services);
|
|
169
185
|
this.projectManager = services.workspace.ProjectManager;
|
|
170
186
|
this.projectManager.onProjectsChanged(event => this.onProjectsChanged(event));
|
|
@@ -173,6 +189,7 @@ export class HydraniumWorkspaceManager extends DefaultWorkspaceManager {
|
|
|
173
189
|
this.writableFileSystemProvider = services.workspace.FileSystemProvider;
|
|
174
190
|
this.additionalDocuments = services.additionalDocuments;
|
|
175
191
|
this.languageRegistry = services.ServiceRegistry;
|
|
192
|
+
this.warnUnservedDocuments = options.warnUnservedDocuments ?? true;
|
|
176
193
|
this.tracer = services.Tracer.for(options.logName ?? 'WorkspaceManager').trace('instantiated');
|
|
177
194
|
installOperationCancelledSuppression(this.tracer);
|
|
178
195
|
}
|
|
@@ -201,16 +218,16 @@ export class HydraniumWorkspaceManager extends DefaultWorkspaceManager {
|
|
|
201
218
|
// seeded. `tags` is read at the done-emit, so the document count pushed
|
|
202
219
|
// inside the callback appears in the log line.
|
|
203
220
|
const tags: string[] = [`${contributions.length} contributions`];
|
|
204
|
-
|
|
221
|
+
const seeded: LangiumDocument[] = [];
|
|
205
222
|
await this.tracer.time(
|
|
206
223
|
'Load additional documents',
|
|
207
224
|
async () => {
|
|
208
225
|
await collectAdditionalDocuments(this.additionalDocuments, folders, document => {
|
|
209
|
-
|
|
226
|
+
seeded.push(document);
|
|
210
227
|
this.warnIfUnroutable(document);
|
|
211
228
|
collector(document);
|
|
212
229
|
});
|
|
213
|
-
tags.push(`${
|
|
230
|
+
tags.push(`${seeded.length} documents`);
|
|
214
231
|
},
|
|
215
232
|
'info',
|
|
216
233
|
{ logAfterMs: 0, tags }
|
|
@@ -272,11 +289,86 @@ export class HydraniumWorkspaceManager extends DefaultWorkspaceManager {
|
|
|
272
289
|
discovered.push(document);
|
|
273
290
|
}
|
|
274
291
|
}
|
|
275
|
-
|
|
292
|
+
this.traversedUris.clear();
|
|
293
|
+
let documents: LangiumDocument[];
|
|
294
|
+
try {
|
|
295
|
+
documents = await super.performStartup(folders);
|
|
296
|
+
if (this.warnUnservedDocuments) {
|
|
297
|
+
await this.warnIfDocumentsUnserved(documents.filter(document => !this.traversedUris.has(document.uri.toString())));
|
|
298
|
+
}
|
|
299
|
+
} finally {
|
|
300
|
+
this.traversedUris.clear();
|
|
301
|
+
}
|
|
276
302
|
this.probePathDivergence(folders);
|
|
277
303
|
return this.withDiscoveredDescriptors(documents, discovered);
|
|
278
304
|
}
|
|
279
305
|
|
|
306
|
+
/**
|
|
307
|
+
* Record each document the file traversal loads, so startup can tell them
|
|
308
|
+
* from the documents `loadAdditionalDocuments` seeded, through the
|
|
309
|
+
* `additionalDocuments` group or an override of its own.
|
|
310
|
+
*
|
|
311
|
+
* The traversal found each of its documents through the provider, so asking
|
|
312
|
+
* it again whether they exist costs one call per workspace file and cannot
|
|
313
|
+
* come out false. Telling them apart by scheme does not work either: the
|
|
314
|
+
* registry's host answers every scheme no other provider claims, a seeded
|
|
315
|
+
* scheme nobody serves included. An override that loads documents without
|
|
316
|
+
* delegating here leaves them unrecorded, so startup asks the provider
|
|
317
|
+
* about each of them.
|
|
318
|
+
*/
|
|
319
|
+
protected override async loadWorkspaceDocuments(uris: Stream<URI>, collector: (document: LangiumDocument) => void): Promise<void> {
|
|
320
|
+
await super.loadWorkspaceDocuments(uris, document => {
|
|
321
|
+
this.traversedUris.add(document.uri.toString());
|
|
322
|
+
collector(document);
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Warn once when the bound `FileSystemProvider` cannot serve a seeded
|
|
328
|
+
* document, naming each such document's scheme.
|
|
329
|
+
*
|
|
330
|
+
* The last close keeps a document only if the provider says it `exists`, so
|
|
331
|
+
* each such document leaves the workspace the first time an editor closes
|
|
332
|
+
* it, and whatever resolved against it breaks. The framework's registry
|
|
333
|
+
* serves `virtual:` through the `fileSystemProviders` group and every other
|
|
334
|
+
* scheme through its host, which knows nothing of a scheme an adopter
|
|
335
|
+
* invented for its seeded documents, and nothing else reports the loss. A
|
|
336
|
+
* provider that throws counts as not serving the document, since a startup
|
|
337
|
+
* that failed on a diagnostic would be worse than the loss.
|
|
338
|
+
*
|
|
339
|
+
* Runs over every document startup collected outside the file traversal,
|
|
340
|
+
* which is what `loadAdditionalDocuments` seeded, through the
|
|
341
|
+
* `additionalDocuments` group or an override of that method, once startup
|
|
342
|
+
* has added them to the workspace, unless `warnUnservedDocuments` is
|
|
343
|
+
* `false`.
|
|
344
|
+
*/
|
|
345
|
+
protected async warnIfDocumentsUnserved(documents: readonly LangiumDocument[]): Promise<void> {
|
|
346
|
+
const unserved: URI[] = [];
|
|
347
|
+
for (const document of documents) {
|
|
348
|
+
let served = false;
|
|
349
|
+
try {
|
|
350
|
+
served = await this.writableFileSystemProvider.exists(document.uri);
|
|
351
|
+
} catch {
|
|
352
|
+
// Counted as unserved, below.
|
|
353
|
+
}
|
|
354
|
+
if (!served) {
|
|
355
|
+
unserved.push(document.uri);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (unserved.length === 0) {
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
const schemes = [...new Set(unserved.map(uri => uri.scheme))];
|
|
362
|
+
const named = unserved.slice(0, 3).map(uri => uri.toString());
|
|
363
|
+
this.tracer.warn(
|
|
364
|
+
`${unserved.length} seeded document(s) under ${schemes.map(scheme => `${scheme}:`).join(', ')} cannot be served by the bound workspace.FileSystemProvider ` +
|
|
365
|
+
`(${named.join(', ')}${unserved.length > 3 ? ', …' : ''}), so each leaves the workspace at its ` +
|
|
366
|
+
`last close. Register a provider under the key ${schemes.map(scheme => `'${scheme}'`).join(', ')} in the shared ` +
|
|
367
|
+
'fileSystemProviders group, or serve the scheme from the host provider; set warnUnservedDocuments: false ' +
|
|
368
|
+
'to accept the loss.'
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
|
|
280
372
|
/**
|
|
281
373
|
* Add back the documents project discovery created that Langium's file
|
|
282
374
|
* traversal then filtered out.
|