@hydranium/core 1.0.0-next.91 → 1.0.0-next.93
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/langium/workspace/file-system-provider.d.ts +9 -1
- package/lib/langium/workspace/file-system-provider.d.ts.map +1 -1
- package/lib/langium/workspace/file-system-provider.js +40 -7
- package/lib/langium/workspace/file-system-provider.js.map +1 -1
- package/lib/langium/workspace/in-memory-file-system-provider.d.ts +6 -4
- package/lib/langium/workspace/in-memory-file-system-provider.d.ts.map +1 -1
- package/lib/langium/workspace/in-memory-file-system-provider.js +27 -11
- package/lib/langium/workspace/in-memory-file-system-provider.js.map +1 -1
- package/lib/langium/workspace/virtual-document.d.ts +18 -3
- package/lib/langium/workspace/virtual-document.d.ts.map +1 -1
- package/lib/langium/workspace/virtual-document.js +19 -2
- package/lib/langium/workspace/virtual-document.js.map +1 -1
- package/lib/node/node-file-system-provider.d.ts +32 -1
- package/lib/node/node-file-system-provider.d.ts.map +1 -1
- package/lib/node/node-file-system-provider.js +112 -5
- package/lib/node/node-file-system-provider.js.map +1 -1
- package/lib/testing/node/scratch-workspace.d.ts.map +1 -1
- package/lib/testing/node/scratch-workspace.js +7 -2
- package/lib/testing/node/scratch-workspace.js.map +1 -1
- package/package.json +5 -5
- package/src/langium/workspace/file-system-provider.ts +48 -8
- package/src/langium/workspace/in-memory-file-system-provider.ts +27 -11
- package/src/langium/workspace/virtual-document.ts +21 -3
- package/src/node/node-file-system-provider.ts +125 -6
- package/src/testing/node/scratch-workspace.ts +7 -2
|
@@ -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;
|
|
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
|
|
31
|
-
// base declares these param-less, so the param is
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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 =
|
|
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;
|
|
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
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
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
|
|
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
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
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
|
-
|
|
97
|
-
|
|
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
|
|
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
|
|
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":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAuB,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAe,MAAM,qBAAqB,CAAC;AAGjE,OAAO,EAAE,mBAAmB,EAAoC,MAAM,uBAAuB,CAAC;AAC9F,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;
|
|
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
|
|
69
|
-
*
|
|
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;
|
|
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
|
|
74
|
-
*
|
|
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,
|
|
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;
|
|
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 {
|
|
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
|
-
|
|
41
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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":"AAAA;;;;;;;kFAOkF;AAGlF,OAAO,
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scratch-workspace.d.ts","sourceRoot":"","sources":["../../../src/testing/node/scratch-workspace.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAgDlF,gDAAgD;AAChD,MAAM,WAAW,uBAAuB;IACrC;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,4CAA4C;AAC5C,MAAM,WAAW,gBAAgB;IAC9B,2CAA2C;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,KAAK,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACrD,2EAA2E;IAC3E,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAAC;IACtC;;;;;;;;;;;;;;OAcG;IACH,GAAG,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACnC;;;OAGG;IACH,OAAO,IAAI,IAAI,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,uBAA4B,GAAG,gBAAgB,
|
|
1
|
+
{"version":3,"file":"scratch-workspace.d.ts","sourceRoot":"","sources":["../../../src/testing/node/scratch-workspace.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAgDlF,gDAAgD;AAChD,MAAM,WAAW,uBAAuB;IACrC;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,4CAA4C;AAC5C,MAAM,WAAW,gBAAgB;IAC9B,2CAA2C;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,KAAK,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACrD,2EAA2E;IAC3E,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAAC;IACtC;;;;;;;;;;;;;;OAcG;IACH,GAAG,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACnC;;;OAGG;IACH,OAAO,IAAI,IAAI,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,uBAA4B,GAAG,gBAAgB,CAkC5F"}
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
* itself often what a test is pinning.
|
|
48
48
|
*/
|
|
49
49
|
import { URI } from '@hydranium/langium';
|
|
50
|
-
import { cpSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
50
|
+
import { cpSync, mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
|
|
51
51
|
import { tmpdir } from 'node:os';
|
|
52
52
|
import * as path from 'node:path';
|
|
53
53
|
/**
|
|
@@ -55,7 +55,12 @@ import * as path from 'node:path';
|
|
|
55
55
|
* returned {@link ScratchWorkspace.dispose} with an `afterEach`.
|
|
56
56
|
*/
|
|
57
57
|
export function makeScratchWorkspace(options = {}) {
|
|
58
|
-
|
|
58
|
+
// RESOLVED, because `tmpdir()` can itself be a symlink — on macOS it answers
|
|
59
|
+
// `/tmp`, which links to `/private/tmp`. A root the server canonicalises to a
|
|
60
|
+
// different path than the one it was handed registers documents under one
|
|
61
|
+
// spelling and reads them under the other, failing initialization with an
|
|
62
|
+
// ENOENT that names neither the link nor this call.
|
|
63
|
+
const root = realpathSync(mkdtempSync(path.join(tmpdir(), options.prefix ?? 'hydranium-scratch-')));
|
|
59
64
|
if (options.seed) {
|
|
60
65
|
cpSync(options.seed, root, { recursive: true });
|
|
61
66
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scratch-workspace.js","sourceRoot":"","sources":["../../../src/testing/node/scratch-workspace.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"scratch-workspace.js","sourceRoot":"","sources":["../../../src/testing/node/scratch-workspace.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC9F,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAkDlC;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,UAAmC,EAAE;IACvE,6EAA6E;IAC7E,8EAA8E;IAC9E,0EAA0E;IAC1E,0EAA0E;IAC1E,oDAAoD;IACpD,MAAM,IAAI,GAAG,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,OAAO,CAAC,MAAM,IAAI,oBAAoB,CAAC,CAAC,CAAC,CAAC;IACpG,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QAChB,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,MAAM,OAAO,GAAG,CAAC,YAAoB,EAAU,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAChF,OAAO;QACJ,IAAI;QACJ,OAAO;QACP,GAAG,CAAC,YAAqB;YACtB,OAAO,GAAG,CAAC,IAAI,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QACzF,CAAC;QACD,KAAK,CAAC,YAAY,EAAE,OAAO;YACxB,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;YACrC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACrD,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;YACvC,OAAO,MAAM,CAAC;QACjB,CAAC;QACD,OAAO;YACJ,IAAI,QAAQ,EAAE,CAAC;gBACZ,OAAO;YACV,CAAC;YACD,QAAQ,GAAG,IAAI,CAAC;YAChB,qEAAqE;YACrE,qDAAqD;YACrD,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,CAAC;KACH,CAAC;AACL,CAAC"}
|
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.93",
|
|
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.93",
|
|
108
|
+
"@hydranium/protocol": "1.0.0-next.93",
|
|
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.93",
|
|
121
|
+
"@hydranium/protocol": "1.0.0-next.93",
|
|
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
|
|
42
|
-
// base declares these param-less, so the param is
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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 =
|
|
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
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
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
|
-
|
|
130
|
-
|
|
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
|
|
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
|
|
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
|
|
80
|
-
*
|
|
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 {
|
|
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
|
-
|
|
50
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
*/
|
|
50
50
|
|
|
51
51
|
import { URI } from '@hydranium/langium';
|
|
52
|
-
import { cpSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
52
|
+
import { cpSync, mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
|
|
53
53
|
import { tmpdir } from 'node:os';
|
|
54
54
|
import * as path from 'node:path';
|
|
55
55
|
|
|
@@ -106,7 +106,12 @@ export interface ScratchWorkspace {
|
|
|
106
106
|
* returned {@link ScratchWorkspace.dispose} with an `afterEach`.
|
|
107
107
|
*/
|
|
108
108
|
export function makeScratchWorkspace(options: ScratchWorkspaceOptions = {}): ScratchWorkspace {
|
|
109
|
-
|
|
109
|
+
// RESOLVED, because `tmpdir()` can itself be a symlink — on macOS it answers
|
|
110
|
+
// `/tmp`, which links to `/private/tmp`. A root the server canonicalises to a
|
|
111
|
+
// different path than the one it was handed registers documents under one
|
|
112
|
+
// spelling and reads them under the other, failing initialization with an
|
|
113
|
+
// ENOENT that names neither the link nor this call.
|
|
114
|
+
const root = realpathSync(mkdtempSync(path.join(tmpdir(), options.prefix ?? 'hydranium-scratch-')));
|
|
110
115
|
if (options.seed) {
|
|
111
116
|
cpSync(options.seed, root, { recursive: true });
|
|
112
117
|
}
|