@hydranium/core 1.0.0-next.90 → 1.0.0-next.92

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.
@@ -8,7 +8,7 @@
8
8
  ********************************************************************************/
9
9
  import { type Tracer } from '@hydranium/protocol';
10
10
  import { EmptyFileSystemProvider } from '@hydranium/langium';
11
- import type { URI } from '@hydranium/langium';
11
+ import type { FileSystemNode, URI } from '@hydranium/langium';
12
12
  import { type WritableFileSystemProvider } from '../../documents/ast-document-manager.js';
13
13
  import { type LogNameOptions } from '../diagnostics/logger.js';
14
14
  import { type ServerSharedServicesMinimal } from '../shared-services.js';
@@ -26,5 +26,13 @@ export declare class DefaultEmptyFileSystemProvider extends EmptyFileSystemProvi
26
26
  writeFile(_uri: URI, _content: string): Promise<void>;
27
27
  readFile(uri?: URI): Promise<string>;
28
28
  readFileSync(uri?: URI): string;
29
+ readBinary(uri?: URI): Promise<Uint8Array>;
30
+ readBinarySync(uri?: URI): Uint8Array;
31
+ stat(uri: URI): Promise<FileSystemNode>;
32
+ statSync(uri: URI): FileSystemNode;
33
+ exists(uri?: URI): Promise<boolean>;
34
+ existsSync(uri?: URI): boolean;
35
+ /** Text of the virtual document registered at `uri`, if there is one. */
36
+ protected served(uri: URI | undefined): string | undefined;
29
37
  }
30
38
  //# sourceMappingURL=file-system-provider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-system-provider.d.ts","sourceRoot":"","sources":["../../../src/langium/workspace/file-system-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,KAAK,0BAA0B,EAAE,MAAM,yCAAyC,CAAC;AAC1F,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AAGzE;;;;;;GAMG;AACH,qBAAa,8BAA+B,SAAQ,uBAAwB,YAAW,0BAA0B;IAI3G,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,2BAA2B;IAH3D,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAGZ,QAAQ,EAAE,2BAA2B,EACxD,OAAO,GAAE,cAAmB;IAMzB,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOlD,QAAQ,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC;IAKpC,YAAY,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,MAAM;CAI1C"}
1
+ {"version":3,"file":"file-system-provider.d.ts","sourceRoot":"","sources":["../../../src/langium/workspace/file-system-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,KAAK,0BAA0B,EAAE,MAAM,yCAAyC,CAAC;AAC1F,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AAGzE;;;;;;GAMG;AACH,qBAAa,8BAA+B,SAAQ,uBAAwB,YAAW,0BAA0B;IAI3G,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,2BAA2B;IAH3D,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAGZ,QAAQ,EAAE,2BAA2B,EACxD,OAAO,GAAE,cAAmB;IAMzB,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAc5C,QAAQ,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC;IAK1C,YAAY,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,MAAM;IAKzB,UAAU,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC;IAKhD,cAAc,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,UAAU;IAM/B,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,cAAc,CAAC;IAK7C,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,cAAc;IAI5B,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC;IAIzC,UAAU,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO;IAIvC,yEAAyE;IACzE,SAAS,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS;CAG5D"}
@@ -7,7 +7,7 @@
7
7
  * SPDX-License-Identifier: MIT
8
8
  ********************************************************************************/
9
9
  import { EmptyFileSystemProvider } from '@hydranium/langium';
10
- import { serveVirtualDocument } from './virtual-document.js';
10
+ import { serveVirtualDocument, serveVirtualNode } from './virtual-document.js';
11
11
  /**
12
12
  * Empty-filesystem default {@link WritableFileSystemProvider}. For
13
13
  * in-memory / browser / test / CLI hosts that don't have a real filesystem.
@@ -27,15 +27,48 @@ export class DefaultEmptyFileSystemProvider extends EmptyFileSystemProvider {
27
27
  // no-op
28
28
  }
29
29
  // Serve virtual documents from the registered document (there is no disk to
30
- // read); delegate everything else to the empty base (which throws). The
31
- // base declares these param-less, so the param is optional here.
32
- readFile(uri) {
33
- const served = uri !== undefined ? serveVirtualDocument(this.services, uri) : undefined;
34
- return served !== undefined ? Promise.resolve(served) : super.readFile();
30
+ // read); delegate everything else to the empty base (which throws, or
31
+ // answers "absent"). The base declares these param-less, so the param is
32
+ // optional here.
33
+ //
34
+ // The async reads are `async` so the base's refusal becomes a rejection: it
35
+ // throws SYNCHRONOUSLY from a method declared to return a promise, and a
36
+ // synchronous throw escapes the promise chain — `.catch()` never attaches
37
+ // and `Promise.all` dies while its argument array is still being built, so
38
+ // a caller reading several URIs cannot handle the miss it asked about.
39
+ async readFile(uri) {
40
+ const served = this.served(uri);
41
+ return served !== undefined ? served : super.readFile();
35
42
  }
36
43
  readFileSync(uri) {
37
- const served = uri !== undefined ? serveVirtualDocument(this.services, uri) : undefined;
44
+ const served = this.served(uri);
38
45
  return served !== undefined ? served : super.readFileSync();
39
46
  }
47
+ async readBinary(uri) {
48
+ const served = this.served(uri);
49
+ return served !== undefined ? new TextEncoder().encode(served) : super.readBinary();
50
+ }
51
+ readBinarySync(uri) {
52
+ const served = this.served(uri);
53
+ return served !== undefined ? new TextEncoder().encode(served) : super.readBinarySync();
54
+ }
55
+ // The base declares these two WITH a URI parameter, so they stay required.
56
+ async stat(uri) {
57
+ const served = serveVirtualNode(this.services, uri);
58
+ return served !== undefined ? served : super.stat(uri);
59
+ }
60
+ statSync(uri) {
61
+ return serveVirtualNode(this.services, uri) ?? super.statSync(uri);
62
+ }
63
+ async exists(uri) {
64
+ return this.existsSync(uri);
65
+ }
66
+ existsSync(uri) {
67
+ return this.served(uri) !== undefined;
68
+ }
69
+ /** Text of the virtual document registered at `uri`, if there is one. */
70
+ served(uri) {
71
+ return uri !== undefined ? serveVirtualDocument(this.services, uri) : undefined;
72
+ }
40
73
  }
41
74
  //# sourceMappingURL=file-system-provider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-system-provider.js","sourceRoot":"","sources":["../../../src/langium/workspace/file-system-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAGlF,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAK7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE7D;;;;;;GAMG;AACH,MAAM,OAAO,8BAA+B,SAAQ,uBAAuB;IAIlD;IAHH,MAAM,CAAS;IAElC,YACsB,QAAqC,EACxD,UAA0B,EAAE;QAE5B,KAAK,EAAE,CAAC;QAHW,aAAQ,GAAR,QAAQ,CAA6B;QAIxD,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IACrG,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,IAAS,EAAE,QAAgB;QACxC,QAAQ;IACX,CAAC;IAED,4EAA4E;IAC5E,wEAAwE;IACxE,iEAAiE;IACxD,QAAQ,CAAC,GAAS;QACxB,MAAM,MAAM,GAAG,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,oBAAoB,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACxF,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;IAC5E,CAAC;IAEQ,YAAY,CAAC,GAAS;QAC5B,MAAM,MAAM,GAAG,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,oBAAoB,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACxF,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;IAC/D,CAAC;CACH"}
1
+ {"version":3,"file":"file-system-provider.js","sourceRoot":"","sources":["../../../src/langium/workspace/file-system-provider.ts"],"names":[],"mappings":"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"}
@@ -12,12 +12,14 @@ import { type WritableFileSystemProvider } from '../../documents/ast-document-ma
12
12
  import { type LogNameOptions } from '../diagnostics/logger.js';
13
13
  import { type ServerSharedServicesMinimal } from '../shared-services.js';
14
14
  /**
15
- * The browser host's spelling of "the document is not there". Its Node
16
- * counterpart is `NO_LOADABLE_CONTENT`: this provider has no `realpath`, so the
17
- * URI policy cannot answer the existence question ahead of the read and the miss
18
- * surfaces here instead.
15
+ * A provider's spelling of "the document is not there", raised wherever a read
16
+ * finds no content — this filesystem, or a URI naming no location a disk-backed
17
+ * provider can reach. Distinct from `NO_LOADABLE_CONTENT`, which the URI policy
18
+ * raises when it can settle the question AHEAD of the read; a provider with no
19
+ * `realpath` cannot, so the miss surfaces here instead.
19
20
  */
20
21
  export declare const NO_SUCH_FILE: import("@hydranium/protocol").MessageDefinition<"No such file: {uri}">;
22
+ /** The same for a node of any kind, so it also covers a directory. */
21
23
  export declare const NO_SUCH_PATH: import("@hydranium/protocol").MessageDefinition<"No such file or directory: {uri}">;
22
24
  /**
23
25
  * File content keyed by path, for seeding an {@link InMemoryFileSystemProvider}.
@@ -1 +1 @@
1
- {"version":3,"file":"in-memory-file-system-provider.d.ts","sourceRoot":"","sources":["../../../src/langium/workspace/in-memory-file-system-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,cAAc,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,KAAK,0BAA0B,EAAE,MAAM,yCAAyC,CAAC;AAC1F,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAuB,KAAK,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AAG9F;;;;;GAKG;AACH,eAAO,MAAM,YAAY,wEAAsE,CAAC;AAEhG,eAAO,MAAM,YAAY,qFAAmF,CAAC;AAE7G;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE9D,qFAAqF;AACrF,MAAM,WAAW,yBAA0B,SAAQ,cAAc;IAC9D,wEAAwE;IACxE,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,qBAAa,0BAA2B,YAAW,0BAA0B;IAKvE,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,2BAA2B;IAJ3D,SAAS,CAAC,QAAQ,CAAC,KAAK,sBAA6B;IACrD,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAGZ,QAAQ,EAAE,2BAA2B,EACxD,OAAO,GAAE,yBAA8B;IAW1C;;;;OAIG;IACH,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAIxC,+DAA+D;IAC/D,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI;IAIpB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzD,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC;IAInC,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM;IAY9B,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC;IAIzC,cAAc,CAAC,GAAG,EAAE,GAAG,GAAG,UAAU;IAIpC,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,cAAc,CAAC;IAIvC,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,cAAc;IAWlC,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC;IAIlC,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO;IAK7B,aAAa,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAIlD,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,cAAc,EAAE;IAqB7C;;;;;;;;;OASG;IACH,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,MAAM;IAI5C,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;CAS9C;AAYD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,yBAA8B,GAAG;IAC1E,kBAAkB,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,0BAA0B,CAAC;CACxE,CAIA"}
1
+ {"version":3,"file":"in-memory-file-system-provider.d.ts","sourceRoot":"","sources":["../../../src/langium/workspace/in-memory-file-system-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,cAAc,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,KAAK,0BAA0B,EAAE,MAAM,yCAAyC,CAAC;AAC1F,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAuB,KAAK,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AAG9F;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,wEAAsE,CAAC;AAEhG,sEAAsE;AACtE,eAAO,MAAM,YAAY,qFAAmF,CAAC;AAE7G;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE9D,qFAAqF;AACrF,MAAM,WAAW,yBAA0B,SAAQ,cAAc;IAC9D,wEAAwE;IACxE,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,qBAAa,0BAA2B,YAAW,0BAA0B;IAKvE,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,2BAA2B;IAJ3D,SAAS,CAAC,QAAQ,CAAC,KAAK,sBAA6B;IACrD,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAGZ,QAAQ,EAAE,2BAA2B,EACxD,OAAO,GAAE,yBAA8B;IAW1C;;;;OAIG;IACH,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAIxC,+DAA+D;IAC/D,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI;IAIpB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUnD,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC;IAIzC,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM;IAYxB,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC;IAI/C,cAAc,CAAC,GAAG,EAAE,GAAG,GAAG,UAAU;IAI9B,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,cAAc,CAAC;IAI7C,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,cAAc;IAgBlC,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC;IAIlC,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO;IAQ7B,aAAa,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAIlD,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,cAAc,EAAE;IAqB7C;;;;;;;;;OASG;IACH,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,MAAM;IAI5C,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;CAS9C;AAYD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,yBAA8B,GAAG;IAC1E,kBAAkB,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,0BAA0B,CAAC;CACxE,CAIA"}
@@ -9,14 +9,16 @@
9
9
  import { URI } from '@hydranium/langium';
10
10
  import { defineMessage } from '@hydranium/protocol';
11
11
  import { serverSharedFactory } from '../shared-services.js';
12
- import { serveVirtualDocument } from './virtual-document.js';
12
+ import { serveVirtualDocument, serveVirtualNode } from './virtual-document.js';
13
13
  /**
14
- * The browser host's spelling of "the document is not there". Its Node
15
- * counterpart is `NO_LOADABLE_CONTENT`: this provider has no `realpath`, so the
16
- * URI policy cannot answer the existence question ahead of the read and the miss
17
- * surfaces here instead.
14
+ * A provider's spelling of "the document is not there", raised wherever a read
15
+ * finds no content — this filesystem, or a URI naming no location a disk-backed
16
+ * provider can reach. Distinct from `NO_LOADABLE_CONTENT`, which the URI policy
17
+ * raises when it can settle the question AHEAD of the read; a provider with no
18
+ * `realpath` cannot, so the miss surfaces here instead.
18
19
  */
19
20
  export const NO_SUCH_FILE = defineMessage('hydranium/core/no-such-file', 'No such file: {uri}');
21
+ /** The same for a node of any kind, so it also covers a directory. */
20
22
  export const NO_SUCH_PATH = defineMessage('hydranium/core/no-such-path', 'No such file or directory: {uri}');
21
23
  /**
22
24
  * A writable filesystem held in a `Map`, for a host with no disk — a browser
@@ -93,8 +95,14 @@ export class InMemoryFileSystemProvider {
93
95
  async writeFile(uri, content) {
94
96
  this.setFile(uri, content);
95
97
  }
96
- readFile(uri) {
97
- return Promise.resolve(this.readFileSync(uri));
98
+ // `async` on each read whose sync twin can throw, rather than
99
+ // `Promise.resolve(this.<x>Sync(uri))`. That form evaluates the sync call
100
+ // FIRST, so a miss throws before `Promise.resolve` is ever reached — and a
101
+ // synchronous throw escapes the promise chain: `.catch()` never attaches and
102
+ // `Promise.all` dies while its argument array is still being built, so a
103
+ // caller reading several URIs cannot handle the miss it asked about.
104
+ async readFile(uri) {
105
+ return this.readFileSync(uri);
98
106
  }
99
107
  readFileSync(uri) {
100
108
  const served = serveVirtualDocument(this.services, uri);
@@ -107,16 +115,21 @@ export class InMemoryFileSystemProvider {
107
115
  }
108
116
  return content;
109
117
  }
110
- readBinary(uri) {
111
- return Promise.resolve(this.readBinarySync(uri));
118
+ async readBinary(uri) {
119
+ return this.readBinarySync(uri);
112
120
  }
113
121
  readBinarySync(uri) {
114
122
  return new TextEncoder().encode(this.readFileSync(uri));
115
123
  }
116
- stat(uri) {
117
- return Promise.resolve(this.statSync(uri));
124
+ async stat(uri) {
125
+ return this.statSync(uri);
118
126
  }
119
127
  statSync(uri) {
128
+ // Virtual first, on the same terms as `readFileSync`.
129
+ const served = serveVirtualNode(this.services, uri);
130
+ if (served !== undefined) {
131
+ return served;
132
+ }
120
133
  const path = normalize(uri);
121
134
  if (this.files.has(path)) {
122
135
  return { isFile: true, isDirectory: false, uri };
@@ -130,6 +143,9 @@ export class InMemoryFileSystemProvider {
130
143
  return Promise.resolve(this.existsSync(uri));
131
144
  }
132
145
  existsSync(uri) {
146
+ if (serveVirtualDocument(this.services, uri) !== undefined) {
147
+ return true;
148
+ }
133
149
  const path = normalize(uri);
134
150
  return this.files.has(path) || this.hasChildren(path);
135
151
  }
@@ -1 +1 @@
1
- {"version":3,"file":"in-memory-file-system-provider.js","sourceRoot":"","sources":["../../../src/langium/workspace/in-memory-file-system-provider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"in-memory-file-system-provider.js","sourceRoot":"","sources":["../../../src/langium/workspace/in-memory-file-system-provider.ts"],"names":[],"mappings":"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"}
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * SPDX-License-Identifier: MIT
8
8
  ********************************************************************************/
9
- import { URI } from '@hydranium/langium';
9
+ import { type FileSystemNode, URI } from '@hydranium/langium';
10
10
  import { type ServerSharedServicesMinimal } from '../shared-services.js';
11
11
  /**
12
12
  * URI scheme for virtual documents — LangiumDocuments that have no backing
@@ -65,14 +65,29 @@ export declare function isVirtualUri(uri: URI | string): boolean;
65
65
  * is not virtual or no document is registered for it (so a FileSystemProvider
66
66
  * delegates to its real backing).
67
67
  *
68
- * The framework's FileSystemProvider defaults call this at the top of
69
- * `readFile` / `readFileSync` so a virtual document survives a re-read:
68
+ * The framework's FileSystemProvider defaults consult this across their whole
69
+ * read surface, so a virtual document survives a re-read:
70
70
  * `DocumentBuilder.update` / `LangiumDocumentFactory.update` re-read a changed
71
71
  * URI from the FileSystemProvider, and nothing on disk backs a virtual URI. The
72
72
  * text comes from the registered document — the original source for a
73
73
  * `fromString` document, or the serialized form retained by the framework's
74
74
  * `fromModel` (which fills in the text Langium leaves empty). No serializer is
75
75
  * consulted here; the text is already on the document.
76
+ *
77
+ * **Every read method has to agree.** Serving only the text methods leaves one
78
+ * provider answering "here is the content" and "nothing is there" about one
79
+ * URI, which is a worse contract than answering neither: a caller cannot probe
80
+ * before reading.
76
81
  */
77
82
  export declare function serveVirtualDocument(services: ServerSharedServicesMinimal, uri: URI): string | undefined;
83
+ /**
84
+ * The filesystem node a registered virtual document presents as, or `undefined`
85
+ * on the same terms as {@link serveVirtualDocument}.
86
+ *
87
+ * Always a FILE: a virtual document is a leaf carrying text, and nothing is
88
+ * addressable beneath it. Reporting it as a directory instead would put it in
89
+ * front of a workspace walk that would then try to enumerate children it has
90
+ * none of.
91
+ */
92
+ export declare function serveVirtualNode(services: ServerSharedServicesMinimal, uri: URI): FileSystemNode | undefined;
78
93
  //# sourceMappingURL=virtual-document.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"virtual-document.d.ts","sourceRoot":"","sources":["../../../src/langium/workspace/virtual-document.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AACzC,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AAEzE;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,YAAY,CAAC;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAG,CAG1E;AAED,4FAA4F;AAC5F,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,OAAO,CAGvD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,2BAA2B,EAAE,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAMxG"}
1
+ {"version":3,"file":"virtual-document.d.ts","sourceRoot":"","sources":["../../../src/langium/workspace/virtual-document.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,cAAc,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AAEzE;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,YAAY,CAAC;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAG,CAG1E;AAED,4FAA4F;AAC5F,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,OAAO,CAGvD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,2BAA2B,EAAE,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAMxG;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,2BAA2B,EAAE,GAAG,EAAE,GAAG,GAAG,cAAc,GAAG,SAAS,CAE5G"}
@@ -70,14 +70,19 @@ export function isVirtualUri(uri) {
70
70
  * is not virtual or no document is registered for it (so a FileSystemProvider
71
71
  * delegates to its real backing).
72
72
  *
73
- * The framework's FileSystemProvider defaults call this at the top of
74
- * `readFile` / `readFileSync` so a virtual document survives a re-read:
73
+ * The framework's FileSystemProvider defaults consult this across their whole
74
+ * read surface, so a virtual document survives a re-read:
75
75
  * `DocumentBuilder.update` / `LangiumDocumentFactory.update` re-read a changed
76
76
  * URI from the FileSystemProvider, and nothing on disk backs a virtual URI. The
77
77
  * text comes from the registered document — the original source for a
78
78
  * `fromString` document, or the serialized form retained by the framework's
79
79
  * `fromModel` (which fills in the text Langium leaves empty). No serializer is
80
80
  * consulted here; the text is already on the document.
81
+ *
82
+ * **Every read method has to agree.** Serving only the text methods leaves one
83
+ * provider answering "here is the content" and "nothing is there" about one
84
+ * URI, which is a worse contract than answering neither: a caller cannot probe
85
+ * before reading.
81
86
  */
82
87
  export function serveVirtualDocument(services, uri) {
83
88
  if (!isVirtualUri(uri)) {
@@ -86,4 +91,16 @@ export function serveVirtualDocument(services, uri) {
86
91
  const document = services.workspace.LangiumDocuments.getDocument(uri);
87
92
  return document ? document.textDocument.getText() : undefined;
88
93
  }
94
+ /**
95
+ * The filesystem node a registered virtual document presents as, or `undefined`
96
+ * on the same terms as {@link serveVirtualDocument}.
97
+ *
98
+ * Always a FILE: a virtual document is a leaf carrying text, and nothing is
99
+ * addressable beneath it. Reporting it as a directory instead would put it in
100
+ * front of a workspace walk that would then try to enumerate children it has
101
+ * none of.
102
+ */
103
+ export function serveVirtualNode(services, uri) {
104
+ return serveVirtualDocument(services, uri) === undefined ? undefined : { isFile: true, isDirectory: false, uri };
105
+ }
89
106
  //# sourceMappingURL=virtual-document.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"virtual-document.js","sourceRoot":"","sources":["../../../src/langium/workspace/virtual-document.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAGzC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,CAAC;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,MAAM,UAAU,UAAU,CAAC,WAAmB,EAAE,GAAG,QAAkB;IAClE,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACjE,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,cAAc,IAAI,WAAW,GAAG,IAAI,EAAE,CAAC,CAAC;AAC/D,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,YAAY,CAAC,GAAiB;IAC3C,MAAM,MAAM,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;IAC5E,OAAO,MAAM,KAAK,cAAc,CAAC;AACpC,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAqC,EAAE,GAAQ;IACjF,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO,SAAS,CAAC;IACpB,CAAC;IACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS,CAAC,gBAAgB,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACtE,OAAO,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AACjE,CAAC"}
1
+ {"version":3,"file":"virtual-document.js","sourceRoot":"","sources":["../../../src/langium/workspace/virtual-document.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAuB,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAG9D;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,CAAC;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,MAAM,UAAU,UAAU,CAAC,WAAmB,EAAE,GAAG,QAAkB;IAClE,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACjE,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,cAAc,IAAI,WAAW,GAAG,IAAI,EAAE,CAAC,CAAC;AAC/D,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,YAAY,CAAC,GAAiB;IAC3C,MAAM,MAAM,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;IAC5E,OAAO,MAAM,KAAK,cAAc,CAAC;AACpC,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAqC,EAAE,GAAQ;IACjF,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO,SAAS,CAAC;IACpB,CAAC;IACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS,CAAC,gBAAgB,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACtE,OAAO,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AACjE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAqC,EAAE,GAAQ;IAC7E,OAAO,oBAAoB,CAAC,QAAQ,EAAE,GAAG,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;AACpH,CAAC"}
@@ -7,7 +7,7 @@
7
7
  * SPDX-License-Identifier: MIT
8
8
  ********************************************************************************/
9
9
  import { type Tracer } from '@hydranium/protocol';
10
- import { URI } from '@hydranium/langium';
10
+ import { type FileSystemNode, URI } from '@hydranium/langium';
11
11
  import { NodeFileSystemProvider } from '@hydranium/langium/node';
12
12
  import { type WritableFileSystemProvider } from '../documents/ast-document-manager.js';
13
13
  import { type SelfSaveRegistry } from '../documents/self-save-registry.js';
@@ -21,6 +21,10 @@ import { type ServerSharedServicesMinimal } from '../langium/shared-services.js'
21
21
  * {@link SelfSaveRegistry} bound at `services.workspace.SelfSaveRegistry` — so
22
22
  * consumers can suppress the `didChangeWatchedFiles` echo for their own writes.
23
23
  *
24
+ * Its read surface answers for registered virtual documents and refuses to
25
+ * derive a disk path from a URI that names no disk location — see
26
+ * {@link servesFromDisk}, which is the one place that judgement is made.
27
+ *
24
28
  * Server-only (`@hydranium/core/node`): pulls `node:fs`. The portable `.`
25
29
  * entry binds `DefaultEmptyFileSystemProvider` by default, so a Node host
26
30
  * must rebind this slot — through `context.fileSystemProvider` or directly — to
@@ -31,8 +35,35 @@ export declare class DefaultFileSystemProvider extends NodeFileSystemProvider im
31
35
  readonly selfSaveRegistry: SelfSaveRegistry;
32
36
  protected readonly tracer: Tracer;
33
37
  constructor(services: ServerSharedServicesMinimal, options?: LogNameOptions);
38
+ /**
39
+ * Whether `uri` names something this provider can reach on disk.
40
+ *
41
+ * Only a `file:` URI does. `URI.fsPath` yields a path for ANY scheme — for a
42
+ * hierarchical one it is the path component, which for a schemed URI with no
43
+ * authority comes out RELATIVE — so delegating an unrecognised scheme to Node
44
+ * does not fail, it probes `<cwd>/<path>` and answers about whatever
45
+ * unrelated file happens to sit there. A server whose working directory is
46
+ * the workspace root makes that collision ordinary rather than exotic.
47
+ *
48
+ * Note the deliberate disagreement with {@link realpath}, which treats a
49
+ * non-`file:` URI as PRESENT. The two degrade in opposite directions because
50
+ * they answer different questions: identity has to hand back a usable URI, so
51
+ * its safe answer is the one it was given, while occupancy and content must
52
+ * not be invented from an unrelated path, so their safe answer is "nothing
53
+ * here". A subclass adding a second on-disk scheme widens this and nothing
54
+ * else.
55
+ */
56
+ protected servesFromDisk(uri: URI): boolean;
34
57
  readFile(uri: URI): Promise<string>;
35
58
  readFileSync(uri: URI): string;
59
+ readBinary(uri: URI): Promise<Uint8Array>;
60
+ readBinarySync(uri: URI): Uint8Array;
61
+ stat(uri: URI): Promise<FileSystemNode>;
62
+ statSync(uri: URI): FileSystemNode;
63
+ exists(uri: URI): Promise<boolean>;
64
+ existsSync(uri: URI): boolean;
65
+ readDirectory(uri: URI): Promise<FileSystemNode[]>;
66
+ readDirectorySync(uri: URI): FileSystemNode[];
36
67
  /**
37
68
  * Write `content` to `uri` via a staging file and a `rename` — or, onto a
38
69
  * destination carrying more than one hard link, in place — then register the
@@ -1 +1 @@
1
- {"version":3,"file":"node-file-system-provider.d.ts","sourceRoot":"","sources":["../../src/node/node-file-system-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,GAAG,EAAY,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAIjE,OAAO,EAAE,KAAK,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AACvF,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAE3E,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAuB,KAAK,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAGtG;;;;;;;;;;;;GAYG;AACH,qBAAa,yBAA0B,SAAQ,sBAAuB,YAAW,0BAA0B;IAKrG,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,2BAA2B;IAJ3D,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAC5C,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAGZ,QAAQ,EAAE,2BAA2B,EACxD,OAAO,GAAE,cAAmB;IAStB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC;IAKnC,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM;IAIvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6CG;IACG,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgCnD,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAUpD;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,SAAS;CAUrC;AA6BD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,cAAc;;CAE1B,CAAC"}
1
+ {"version":3,"file":"node-file-system-provider.d.ts","sourceRoot":"","sources":["../../src/node/node-file-system-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,KAAK,cAAc,EAAE,GAAG,EAAY,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAIjE,OAAO,EAAE,KAAK,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AACvF,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAE3E,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAuB,KAAK,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAItG;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,yBAA0B,SAAQ,sBAAuB,YAAW,0BAA0B;IAKrG,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,2BAA2B;IAJ3D,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAC5C,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAGZ,QAAQ,EAAE,2BAA2B,EACxD,OAAO,GAAE,cAAmB;IAO/B;;;;;;;;;;;;;;;;;OAiBG;IACH,SAAS,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO;IAQlC,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC;IAQnC,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM;IAW9B,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC;IAQzC,cAAc,CAAC,GAAG,EAAE,GAAG,GAAG,UAAU;IAWpC,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,cAAc,CAAC;IAQvC,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,cAAc;IAa5B,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC;IAOxC,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO;IAU7B,aAAa,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAIlD,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,cAAc,EAAE;IAItD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6CG;IACG,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgCnD,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAUpD;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,SAAS;CAUrC;AA4CD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,cAAc;;CAE1B,CAAC"}
@@ -13,7 +13,8 @@ import { realpathSync } from 'node:fs';
13
13
  import * as fsp from 'node:fs/promises';
14
14
  import { renameOverOpenReaders } from './rename-over-open-readers.js';
15
15
  import { serverSharedFactory } from '../langium/shared-services.js';
16
- import { serveVirtualDocument } from '../langium/workspace/virtual-document.js';
16
+ import { NO_SUCH_FILE, NO_SUCH_PATH } from '../langium/workspace/in-memory-file-system-provider.js';
17
+ import { serveVirtualDocument, serveVirtualNode } from '../langium/workspace/virtual-document.js';
17
18
  /**
18
19
  * Node-based default {@link WritableFileSystemProvider}. Extends Langium's
19
20
  * {@link NodeFileSystemProvider} with an async {@link writeFile} that
@@ -22,6 +23,10 @@ import { serveVirtualDocument } from '../langium/workspace/virtual-document.js';
22
23
  * {@link SelfSaveRegistry} bound at `services.workspace.SelfSaveRegistry` — so
23
24
  * consumers can suppress the `didChangeWatchedFiles` echo for their own writes.
24
25
  *
26
+ * Its read surface answers for registered virtual documents and refuses to
27
+ * derive a disk path from a URI that names no disk location — see
28
+ * {@link servesFromDisk}, which is the one place that judgement is made.
29
+ *
25
30
  * Server-only (`@hydranium/core/node`): pulls `node:fs`. The portable `.`
26
31
  * entry binds `DefaultEmptyFileSystemProvider` by default, so a Node host
27
32
  * must rebind this slot — through `context.fileSystemProvider` or directly — to
@@ -37,14 +42,104 @@ export class DefaultFileSystemProvider extends NodeFileSystemProvider {
37
42
  this.selfSaveRegistry = services.workspace.SelfSaveRegistry;
38
43
  this.tracer = services.Tracer.for(options.logName ?? this.constructor.name).trace('instantiated');
39
44
  }
40
- // Serve virtual documents from the registered document before touching disk
41
- // (a virtual URI has no `fsPath` backing); delegate everything else to Node.
45
+ /**
46
+ * Whether `uri` names something this provider can reach on disk.
47
+ *
48
+ * Only a `file:` URI does. `URI.fsPath` yields a path for ANY scheme — for a
49
+ * hierarchical one it is the path component, which for a schemed URI with no
50
+ * authority comes out RELATIVE — so delegating an unrecognised scheme to Node
51
+ * does not fail, it probes `<cwd>/<path>` and answers about whatever
52
+ * unrelated file happens to sit there. A server whose working directory is
53
+ * the workspace root makes that collision ordinary rather than exotic.
54
+ *
55
+ * Note the deliberate disagreement with {@link realpath}, which treats a
56
+ * non-`file:` URI as PRESENT. The two degrade in opposite directions because
57
+ * they answer different questions: identity has to hand back a usable URI, so
58
+ * its safe answer is the one it was given, while occupancy and content must
59
+ * not be invented from an unrelated path, so their safe answer is "nothing
60
+ * here". A subclass adding a second on-disk scheme widens this and nothing
61
+ * else.
62
+ */
63
+ servesFromDisk(uri) {
64
+ return uri.scheme === 'file';
65
+ }
66
+ // Each read resolves in the same order: a registered virtual document first
67
+ // (it has no `fsPath` backing), then disk for a path this provider can
68
+ // reach, then the filesystem's own "nothing here" answer — never a probe
69
+ // against a path derived from a URI that names no disk location.
42
70
  readFile(uri) {
43
71
  const served = serveVirtualDocument(this.services, uri);
44
- return served !== undefined ? Promise.resolve(served) : super.readFile(uri);
72
+ if (served !== undefined) {
73
+ return Promise.resolve(served);
74
+ }
75
+ return this.servesFromDisk(uri) ? super.readFile(uri) : Promise.reject(noSuchFile(uri));
45
76
  }
46
77
  readFileSync(uri) {
47
- return serveVirtualDocument(this.services, uri) ?? super.readFileSync(uri);
78
+ const served = serveVirtualDocument(this.services, uri);
79
+ if (served !== undefined) {
80
+ return served;
81
+ }
82
+ if (!this.servesFromDisk(uri)) {
83
+ throw noSuchFile(uri);
84
+ }
85
+ return super.readFileSync(uri);
86
+ }
87
+ readBinary(uri) {
88
+ const served = serveVirtualDocument(this.services, uri);
89
+ if (served !== undefined) {
90
+ return Promise.resolve(encode(served));
91
+ }
92
+ return this.servesFromDisk(uri) ? super.readBinary(uri) : Promise.reject(noSuchFile(uri));
93
+ }
94
+ readBinarySync(uri) {
95
+ const served = serveVirtualDocument(this.services, uri);
96
+ if (served !== undefined) {
97
+ return encode(served);
98
+ }
99
+ if (!this.servesFromDisk(uri)) {
100
+ throw noSuchFile(uri);
101
+ }
102
+ return super.readBinarySync(uri);
103
+ }
104
+ stat(uri) {
105
+ const served = serveVirtualNode(this.services, uri);
106
+ if (served !== undefined) {
107
+ return Promise.resolve(served);
108
+ }
109
+ return this.servesFromDisk(uri) ? super.stat(uri) : Promise.reject(noSuchPath(uri));
110
+ }
111
+ statSync(uri) {
112
+ const served = serveVirtualNode(this.services, uri);
113
+ if (served !== undefined) {
114
+ return served;
115
+ }
116
+ if (!this.servesFromDisk(uri)) {
117
+ throw noSuchPath(uri);
118
+ }
119
+ return super.statSync(uri);
120
+ }
121
+ // Delegating to `existsSync` would be shorter and would put a blocking stat
122
+ // on the async path.
123
+ async exists(uri) {
124
+ if (serveVirtualDocument(this.services, uri) !== undefined) {
125
+ return true;
126
+ }
127
+ return this.servesFromDisk(uri) ? super.exists(uri) : false;
128
+ }
129
+ existsSync(uri) {
130
+ if (serveVirtualDocument(this.services, uri) !== undefined) {
131
+ return true;
132
+ }
133
+ return this.servesFromDisk(uri) ? super.existsSync(uri) : false;
134
+ }
135
+ // A URI this provider cannot reach on disk has no children rather than an
136
+ // error: a workspace walk enumerates folders it was handed, and failing one
137
+ // aborts the walk where an empty listing simply contributes nothing.
138
+ readDirectory(uri) {
139
+ return this.servesFromDisk(uri) ? super.readDirectory(uri) : Promise.resolve([]);
140
+ }
141
+ readDirectorySync(uri) {
142
+ return this.servesFromDisk(uri) ? super.readDirectorySync(uri) : [];
48
143
  }
49
144
  /**
50
145
  * Write `content` to `uri` via a staging file and a `rename` — or, onto a
@@ -159,6 +254,18 @@ export class DefaultFileSystemProvider extends NodeFileSystemProvider {
159
254
  }
160
255
  }
161
256
  }
257
+ /** The "no content here" rejection, for a URI naming no readable file. */
258
+ function noSuchFile(uri) {
259
+ return new Error(NO_SUCH_FILE.format({ uri: uri.toString() }));
260
+ }
261
+ /** The "nothing occupies this" rejection, for a URI naming no filesystem node. */
262
+ function noSuchPath(uri) {
263
+ return new Error(NO_SUCH_PATH.format({ uri: uri.toString() }));
264
+ }
265
+ /** A virtual document's text as the bytes a binary read returns. */
266
+ function encode(text) {
267
+ return new TextEncoder().encode(text);
268
+ }
162
269
  /**
163
270
  * Facts about the regular file `path` replaces, or `undefined` when there is
164
271
  * nothing to replace — the path is absent (a create, which takes the process
@@ -1 +1 @@
1
- {"version":3,"file":"node-file-system-provider.js","sourceRoot":"","sources":["../../src/node/node-file-system-provider.ts"],"names":[],"mappings":"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"}
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.90",
3
+ "version": "1.0.0-next.92",
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.90",
108
- "@hydranium/protocol": "1.0.0-next.90",
107
+ "@hydranium/langium": "1.0.0-next.92",
108
+ "@hydranium/protocol": "1.0.0-next.92",
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.90",
121
- "@hydranium/protocol": "1.0.0-next.90",
120
+ "@hydranium/langium": "1.0.0-next.92",
121
+ "@hydranium/protocol": "1.0.0-next.92",
122
122
  "@playwright/test": "^1.40.0",
123
123
  "vscode-jsonrpc": "9.0.1",
124
124
  "vscode-languageserver": "~10.0.1",
@@ -9,11 +9,11 @@
9
9
 
10
10
  import { type Tracer } from '@hydranium/protocol';
11
11
  import { EmptyFileSystemProvider } from '@hydranium/langium';
12
- import type { URI } from '@hydranium/langium';
12
+ 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 } from './virtual-document.js';
16
+ import { serveVirtualDocument, serveVirtualNode } from './virtual-document.js';
17
17
 
18
18
  /**
19
19
  * Empty-filesystem default {@link WritableFileSystemProvider}. For
@@ -38,15 +38,55 @@ export class DefaultEmptyFileSystemProvider extends EmptyFileSystemProvider impl
38
38
  }
39
39
 
40
40
  // Serve virtual documents from the registered document (there is no disk to
41
- // read); delegate everything else to the empty base (which throws). The
42
- // base declares these param-less, so the param is optional here.
43
- override readFile(uri?: URI): Promise<string> {
44
- const served = uri !== undefined ? serveVirtualDocument(this.services, uri) : undefined;
45
- return served !== undefined ? Promise.resolve(served) : super.readFile();
41
+ // read); delegate everything else to the empty base (which throws, or
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
47
+ // synchronous throw escapes the promise chain — `.catch()` never attaches
48
+ // 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
+ override async readFile(uri?: URI): Promise<string> {
51
+ const served = this.served(uri);
52
+ return served !== undefined ? served : super.readFile();
46
53
  }
47
54
 
48
55
  override readFileSync(uri?: URI): string {
49
- const served = uri !== undefined ? serveVirtualDocument(this.services, uri) : undefined;
56
+ const served = this.served(uri);
50
57
  return served !== undefined ? served : super.readFileSync();
51
58
  }
59
+
60
+ override async readBinary(uri?: URI): Promise<Uint8Array> {
61
+ const served = this.served(uri);
62
+ return served !== undefined ? new TextEncoder().encode(served) : super.readBinary();
63
+ }
64
+
65
+ override readBinarySync(uri?: URI): Uint8Array {
66
+ const served = this.served(uri);
67
+ return served !== undefined ? new TextEncoder().encode(served) : super.readBinarySync();
68
+ }
69
+
70
+ // The base declares these two WITH a URI parameter, so they stay required.
71
+ override async stat(uri: URI): Promise<FileSystemNode> {
72
+ const served = serveVirtualNode(this.services, uri);
73
+ return served !== undefined ? served : super.stat(uri);
74
+ }
75
+
76
+ override statSync(uri: URI): FileSystemNode {
77
+ return serveVirtualNode(this.services, uri) ?? super.statSync(uri);
78
+ }
79
+
80
+ override async exists(uri?: URI): Promise<boolean> {
81
+ return this.existsSync(uri);
82
+ }
83
+
84
+ override existsSync(uri?: URI): boolean {
85
+ return this.served(uri) !== undefined;
86
+ }
87
+
88
+ /** Text of the virtual document registered at `uri`, if there is one. */
89
+ protected served(uri: URI | undefined): string | undefined {
90
+ return uri !== undefined ? serveVirtualDocument(this.services, uri) : undefined;
91
+ }
52
92
  }
@@ -12,16 +12,18 @@ import { defineMessage, type Tracer } from '@hydranium/protocol';
12
12
  import { type WritableFileSystemProvider } from '../../documents/ast-document-manager.js';
13
13
  import { type LogNameOptions } from '../diagnostics/logger.js';
14
14
  import { serverSharedFactory, type ServerSharedServicesMinimal } from '../shared-services.js';
15
- import { serveVirtualDocument } from './virtual-document.js';
15
+ import { serveVirtualDocument, serveVirtualNode } from './virtual-document.js';
16
16
 
17
17
  /**
18
- * The browser host's spelling of "the document is not there". Its Node
19
- * counterpart is `NO_LOADABLE_CONTENT`: this provider has no `realpath`, so the
20
- * URI policy cannot answer the existence question ahead of the read and the miss
21
- * surfaces here instead.
18
+ * A provider's spelling of "the document is not there", raised wherever a read
19
+ * finds no content — this filesystem, or a URI naming no location a disk-backed
20
+ * provider can reach. Distinct from `NO_LOADABLE_CONTENT`, which the URI policy
21
+ * raises when it can settle the question AHEAD of the read; a provider with no
22
+ * `realpath` cannot, so the miss surfaces here instead.
22
23
  */
23
24
  export const NO_SUCH_FILE = defineMessage('hydranium/core/no-such-file', 'No such file: {uri}');
24
25
 
26
+ /** The same for a node of any kind, so it also covers a directory. */
25
27
  export const NO_SUCH_PATH = defineMessage('hydranium/core/no-such-path', 'No such file or directory: {uri}');
26
28
 
27
29
  /**
@@ -126,8 +128,14 @@ export class InMemoryFileSystemProvider implements WritableFileSystemProvider {
126
128
  this.setFile(uri, content);
127
129
  }
128
130
 
129
- readFile(uri: URI): Promise<string> {
130
- return Promise.resolve(this.readFileSync(uri));
131
+ // `async` on each read whose sync twin can throw, rather than
132
+ // `Promise.resolve(this.<x>Sync(uri))`. That form evaluates the sync call
133
+ // FIRST, so a miss throws before `Promise.resolve` is ever reached — and a
134
+ // synchronous throw escapes the promise chain: `.catch()` never attaches and
135
+ // `Promise.all` dies while its argument array is still being built, so a
136
+ // caller reading several URIs cannot handle the miss it asked about.
137
+ async readFile(uri: URI): Promise<string> {
138
+ return this.readFileSync(uri);
131
139
  }
132
140
 
133
141
  readFileSync(uri: URI): string {
@@ -142,19 +150,24 @@ export class InMemoryFileSystemProvider implements WritableFileSystemProvider {
142
150
  return content;
143
151
  }
144
152
 
145
- readBinary(uri: URI): Promise<Uint8Array> {
146
- return Promise.resolve(this.readBinarySync(uri));
153
+ async readBinary(uri: URI): Promise<Uint8Array> {
154
+ return this.readBinarySync(uri);
147
155
  }
148
156
 
149
157
  readBinarySync(uri: URI): Uint8Array {
150
158
  return new TextEncoder().encode(this.readFileSync(uri));
151
159
  }
152
160
 
153
- stat(uri: URI): Promise<FileSystemNode> {
154
- return Promise.resolve(this.statSync(uri));
161
+ async stat(uri: URI): Promise<FileSystemNode> {
162
+ return this.statSync(uri);
155
163
  }
156
164
 
157
165
  statSync(uri: URI): FileSystemNode {
166
+ // Virtual first, on the same terms as `readFileSync`.
167
+ const served = serveVirtualNode(this.services, uri);
168
+ if (served !== undefined) {
169
+ return served;
170
+ }
158
171
  const path = normalize(uri);
159
172
  if (this.files.has(path)) {
160
173
  return { isFile: true, isDirectory: false, uri };
@@ -170,6 +183,9 @@ export class InMemoryFileSystemProvider implements WritableFileSystemProvider {
170
183
  }
171
184
 
172
185
  existsSync(uri: URI): boolean {
186
+ if (serveVirtualDocument(this.services, uri) !== undefined) {
187
+ return true;
188
+ }
173
189
  const path = normalize(uri);
174
190
  return this.files.has(path) || this.hasChildren(path);
175
191
  }
@@ -7,7 +7,7 @@
7
7
  * SPDX-License-Identifier: MIT
8
8
  ********************************************************************************/
9
9
 
10
- import { URI } from '@hydranium/langium';
10
+ import { type FileSystemNode, URI } from '@hydranium/langium';
11
11
  import { type ServerSharedServicesMinimal } from '../shared-services.js';
12
12
 
13
13
  /**
@@ -76,14 +76,19 @@ export function isVirtualUri(uri: URI | string): boolean {
76
76
  * is not virtual or no document is registered for it (so a FileSystemProvider
77
77
  * delegates to its real backing).
78
78
  *
79
- * The framework's FileSystemProvider defaults call this at the top of
80
- * `readFile` / `readFileSync` so a virtual document survives a re-read:
79
+ * The framework's FileSystemProvider defaults consult this across their whole
80
+ * read surface, so a virtual document survives a re-read:
81
81
  * `DocumentBuilder.update` / `LangiumDocumentFactory.update` re-read a changed
82
82
  * URI from the FileSystemProvider, and nothing on disk backs a virtual URI. The
83
83
  * text comes from the registered document — the original source for a
84
84
  * `fromString` document, or the serialized form retained by the framework's
85
85
  * `fromModel` (which fills in the text Langium leaves empty). No serializer is
86
86
  * consulted here; the text is already on the document.
87
+ *
88
+ * **Every read method has to agree.** Serving only the text methods leaves one
89
+ * provider answering "here is the content" and "nothing is there" about one
90
+ * URI, which is a worse contract than answering neither: a caller cannot probe
91
+ * before reading.
87
92
  */
88
93
  export function serveVirtualDocument(services: ServerSharedServicesMinimal, uri: URI): string | undefined {
89
94
  if (!isVirtualUri(uri)) {
@@ -92,3 +97,16 @@ export function serveVirtualDocument(services: ServerSharedServicesMinimal, uri:
92
97
  const document = services.workspace.LangiumDocuments.getDocument(uri);
93
98
  return document ? document.textDocument.getText() : undefined;
94
99
  }
100
+
101
+ /**
102
+ * The filesystem node a registered virtual document presents as, or `undefined`
103
+ * on the same terms as {@link serveVirtualDocument}.
104
+ *
105
+ * Always a FILE: a virtual document is a leaf carrying text, and nothing is
106
+ * addressable beneath it. Reporting it as a directory instead would put it in
107
+ * front of a workspace walk that would then try to enumerate children it has
108
+ * none of.
109
+ */
110
+ export function serveVirtualNode(services: ServerSharedServicesMinimal, uri: URI): FileSystemNode | undefined {
111
+ return serveVirtualDocument(services, uri) === undefined ? undefined : { isFile: true, isDirectory: false, uri };
112
+ }
@@ -8,7 +8,7 @@
8
8
  ********************************************************************************/
9
9
 
10
10
  import { type Tracer } from '@hydranium/protocol';
11
- import { URI, UriUtils } from '@hydranium/langium';
11
+ import { type FileSystemNode, URI, UriUtils } from '@hydranium/langium';
12
12
  import { NodeFileSystemProvider } from '@hydranium/langium/node';
13
13
  import { randomUUID } from 'node:crypto';
14
14
  import { realpathSync } from 'node:fs';
@@ -18,7 +18,8 @@ import { type SelfSaveRegistry } from '../documents/self-save-registry.js';
18
18
  import { renameOverOpenReaders } from './rename-over-open-readers.js';
19
19
  import { type LogNameOptions } from '../langium/diagnostics/logger.js';
20
20
  import { serverSharedFactory, type ServerSharedServicesMinimal } from '../langium/shared-services.js';
21
- import { serveVirtualDocument } from '../langium/workspace/virtual-document.js';
21
+ import { NO_SUCH_FILE, NO_SUCH_PATH } from '../langium/workspace/in-memory-file-system-provider.js';
22
+ import { serveVirtualDocument, serveVirtualNode } from '../langium/workspace/virtual-document.js';
22
23
 
23
24
  /**
24
25
  * Node-based default {@link WritableFileSystemProvider}. Extends Langium's
@@ -28,6 +29,10 @@ import { serveVirtualDocument } from '../langium/workspace/virtual-document.js';
28
29
  * {@link SelfSaveRegistry} bound at `services.workspace.SelfSaveRegistry` — so
29
30
  * consumers can suppress the `didChangeWatchedFiles` echo for their own writes.
30
31
  *
32
+ * Its read surface answers for registered virtual documents and refuses to
33
+ * derive a disk path from a URI that names no disk location — see
34
+ * {@link servesFromDisk}, which is the one place that judgement is made.
35
+ *
31
36
  * Server-only (`@hydranium/core/node`): pulls `node:fs`. The portable `.`
32
37
  * entry binds `DefaultEmptyFileSystemProvider` by default, so a Node host
33
38
  * must rebind this slot — through `context.fileSystemProvider` or directly — to
@@ -46,15 +51,114 @@ export class DefaultFileSystemProvider extends NodeFileSystemProvider implements
46
51
  this.tracer = services.Tracer.for(options.logName ?? this.constructor.name).trace('instantiated');
47
52
  }
48
53
 
49
- // Serve virtual documents from the registered document before touching disk
50
- // (a virtual URI has no `fsPath` backing); delegate everything else to Node.
54
+ /**
55
+ * Whether `uri` names something this provider can reach on disk.
56
+ *
57
+ * Only a `file:` URI does. `URI.fsPath` yields a path for ANY scheme — for a
58
+ * hierarchical one it is the path component, which for a schemed URI with no
59
+ * authority comes out RELATIVE — so delegating an unrecognised scheme to Node
60
+ * does not fail, it probes `<cwd>/<path>` and answers about whatever
61
+ * unrelated file happens to sit there. A server whose working directory is
62
+ * the workspace root makes that collision ordinary rather than exotic.
63
+ *
64
+ * Note the deliberate disagreement with {@link realpath}, which treats a
65
+ * non-`file:` URI as PRESENT. The two degrade in opposite directions because
66
+ * they answer different questions: identity has to hand back a usable URI, so
67
+ * its safe answer is the one it was given, while occupancy and content must
68
+ * not be invented from an unrelated path, so their safe answer is "nothing
69
+ * here". A subclass adding a second on-disk scheme widens this and nothing
70
+ * else.
71
+ */
72
+ protected servesFromDisk(uri: URI): boolean {
73
+ return uri.scheme === 'file';
74
+ }
75
+
76
+ // Each read resolves in the same order: a registered virtual document first
77
+ // (it has no `fsPath` backing), then disk for a path this provider can
78
+ // reach, then the filesystem's own "nothing here" answer — never a probe
79
+ // against a path derived from a URI that names no disk location.
51
80
  override readFile(uri: URI): Promise<string> {
52
81
  const served = serveVirtualDocument(this.services, uri);
53
- return served !== undefined ? Promise.resolve(served) : super.readFile(uri);
82
+ if (served !== undefined) {
83
+ return Promise.resolve(served);
84
+ }
85
+ return this.servesFromDisk(uri) ? super.readFile(uri) : Promise.reject(noSuchFile(uri));
54
86
  }
55
87
 
56
88
  override readFileSync(uri: URI): string {
57
- return serveVirtualDocument(this.services, uri) ?? super.readFileSync(uri);
89
+ const served = serveVirtualDocument(this.services, uri);
90
+ if (served !== undefined) {
91
+ return served;
92
+ }
93
+ if (!this.servesFromDisk(uri)) {
94
+ throw noSuchFile(uri);
95
+ }
96
+ return super.readFileSync(uri);
97
+ }
98
+
99
+ override readBinary(uri: URI): Promise<Uint8Array> {
100
+ const served = serveVirtualDocument(this.services, uri);
101
+ if (served !== undefined) {
102
+ return Promise.resolve(encode(served));
103
+ }
104
+ return this.servesFromDisk(uri) ? super.readBinary(uri) : Promise.reject(noSuchFile(uri));
105
+ }
106
+
107
+ override readBinarySync(uri: URI): Uint8Array {
108
+ const served = serveVirtualDocument(this.services, uri);
109
+ if (served !== undefined) {
110
+ return encode(served);
111
+ }
112
+ if (!this.servesFromDisk(uri)) {
113
+ throw noSuchFile(uri);
114
+ }
115
+ return super.readBinarySync(uri);
116
+ }
117
+
118
+ override stat(uri: URI): Promise<FileSystemNode> {
119
+ const served = serveVirtualNode(this.services, uri);
120
+ if (served !== undefined) {
121
+ return Promise.resolve(served);
122
+ }
123
+ return this.servesFromDisk(uri) ? super.stat(uri) : Promise.reject(noSuchPath(uri));
124
+ }
125
+
126
+ override statSync(uri: URI): FileSystemNode {
127
+ const served = serveVirtualNode(this.services, uri);
128
+ if (served !== undefined) {
129
+ return served;
130
+ }
131
+ if (!this.servesFromDisk(uri)) {
132
+ throw noSuchPath(uri);
133
+ }
134
+ return super.statSync(uri);
135
+ }
136
+
137
+ // Delegating to `existsSync` would be shorter and would put a blocking stat
138
+ // on the async path.
139
+ override async exists(uri: URI): Promise<boolean> {
140
+ if (serveVirtualDocument(this.services, uri) !== undefined) {
141
+ return true;
142
+ }
143
+ return this.servesFromDisk(uri) ? super.exists(uri) : false;
144
+ }
145
+
146
+ override existsSync(uri: URI): boolean {
147
+ if (serveVirtualDocument(this.services, uri) !== undefined) {
148
+ return true;
149
+ }
150
+ return this.servesFromDisk(uri) ? super.existsSync(uri) : false;
151
+ }
152
+
153
+ // A URI this provider cannot reach on disk has no children rather than an
154
+ // error: a workspace walk enumerates folders it was handed, and failing one
155
+ // aborts the walk where an empty listing simply contributes nothing.
156
+ override readDirectory(uri: URI): Promise<FileSystemNode[]> {
157
+ return this.servesFromDisk(uri) ? super.readDirectory(uri) : Promise.resolve([]);
158
+ }
159
+
160
+ override readDirectorySync(uri: URI): FileSystemNode[] {
161
+ return this.servesFromDisk(uri) ? super.readDirectorySync(uri) : [];
58
162
  }
59
163
 
60
164
  /**
@@ -169,6 +273,21 @@ export class DefaultFileSystemProvider extends NodeFileSystemProvider implements
169
273
  }
170
274
  }
171
275
 
276
+ /** The "no content here" rejection, for a URI naming no readable file. */
277
+ function noSuchFile(uri: URI): Error {
278
+ return new Error(NO_SUCH_FILE.format({ uri: uri.toString() }));
279
+ }
280
+
281
+ /** The "nothing occupies this" rejection, for a URI naming no filesystem node. */
282
+ function noSuchPath(uri: URI): Error {
283
+ return new Error(NO_SUCH_PATH.format({ uri: uri.toString() }));
284
+ }
285
+
286
+ /** A virtual document's text as the bytes a binary read returns. */
287
+ function encode(text: string): Uint8Array {
288
+ return new TextEncoder().encode(text);
289
+ }
290
+
172
291
  /**
173
292
  * What a write has to know about the regular file at `path` before replacing
174
293
  * it: the permission bits to carry over, and how many names share its inode.