@hydranium/glsp-client-vscode 0.0.0-stage → 1.0.0-next
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +132 -2
- package/lib/browser/glsp-starter.d.ts +27 -0
- package/lib/browser/glsp-starter.d.ts.map +1 -0
- package/lib/browser/glsp-starter.js +38 -0
- package/lib/browser/glsp-starter.js.map +1 -0
- package/lib/browser/index.d.ts +10 -0
- package/lib/browser/index.d.ts.map +1 -0
- package/lib/browser/index.js +26 -0
- package/lib/browser/index.js.map +1 -0
- package/lib/diagram-container.d.ts +15 -0
- package/lib/diagram-container.d.ts.map +1 -0
- package/lib/diagram-container.js +18 -0
- package/lib/diagram-container.js.map +1 -0
- package/lib/index.d.ts +10 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +29 -0
- package/lib/index.js.map +1 -0
- package/lib/node/glsp-editor-provider.d.ts +57 -0
- package/lib/node/glsp-editor-provider.d.ts.map +1 -0
- package/lib/node/glsp-editor-provider.js +131 -0
- package/lib/node/glsp-editor-provider.js.map +1 -0
- package/lib/node/glsp-vscode-server.d.ts +46 -0
- package/lib/node/glsp-vscode-server.d.ts.map +1 -0
- package/lib/node/glsp-vscode-server.js +93 -0
- package/lib/node/glsp-vscode-server.js.map +1 -0
- package/lib/node/index.d.ts +11 -0
- package/lib/node/index.d.ts.map +1 -0
- package/lib/node/index.js +27 -0
- package/lib/node/index.js.map +1 -0
- package/package.json +89 -4
- package/src/browser/glsp-starter.ts +39 -0
- package/src/browser/index.ts +10 -0
- package/src/diagram-container.ts +15 -0
- package/src/index.ts +13 -0
- package/src/node/glsp-editor-provider.ts +110 -0
- package/src/node/glsp-vscode-server.ts +73 -0
- package/src/node/index.ts +11 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,133 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@hydranium/glsp-client-vscode`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The GLSP head's client side in a VS Code extension built on
|
|
4
|
+
[Hydranium](https://github.com/eclipse-emfcloud/hydranium). Install it when
|
|
5
|
+
your extension opens a diagram in a custom editor: it connects GLSP's VS Code
|
|
6
|
+
integration to the head's socket and hosts the diagram in a webview with the
|
|
7
|
+
framework's client classes.
|
|
8
|
+
|
|
9
|
+
## What it gives you
|
|
10
|
+
|
|
11
|
+
- GLSP's VS Code server over the head's socket, with the port looked up when
|
|
12
|
+
the server starts rather than during activation.
|
|
13
|
+
- A custom editor whose webview document carries a Content-Security-Policy
|
|
14
|
+
that grants sprotty what it needs and no `eval`, and the element the diagram
|
|
15
|
+
mounts into.
|
|
16
|
+
- A webview starter that adds `@hydranium/glsp-client`'s classes to the
|
|
17
|
+
diagram container, after GLSP's VS Code modules and before your diagram's.
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @hydranium/glsp-client-vscode
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
| Peer | Range |
|
|
26
|
+
| ------------------------------------------ | ------------- |
|
|
27
|
+
| `@eclipse-glsp/client` | `^2.6.0` |
|
|
28
|
+
| `@eclipse-glsp/vscode-integration` | `^2.6.0` |
|
|
29
|
+
| `@eclipse-glsp/vscode-integration-webview` | `^2.6.0` |
|
|
30
|
+
| `@hydranium/glsp-client` | `^1.0.0-next` |
|
|
31
|
+
| `@hydranium/protocol` | `^1.0.0-next` |
|
|
32
|
+
| `inversify` | `^6.0.0` |
|
|
33
|
+
| `vscode-jsonrpc` | `^9.0.0` |
|
|
34
|
+
|
|
35
|
+
## Wiring
|
|
36
|
+
|
|
37
|
+
In the extension host, give GLSP's connector the server, start it without
|
|
38
|
+
awaiting it, report a failure off `onReady`, and register your editor, a
|
|
39
|
+
subclass naming the diagram type, the webview bundle and a title. `findPort`
|
|
40
|
+
is your lookup of the head's port, such as `findPort` from
|
|
41
|
+
`@hydranium/client-vscode/node` on your language client:
|
|
42
|
+
|
|
43
|
+
<!-- snippet-preamble
|
|
44
|
+
declare function findGlspPort(): Promise<number>;
|
|
45
|
+
-->
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import { GlspVscodeConnector } from '@eclipse-glsp/vscode-integration';
|
|
49
|
+
import { HydraniumGlspEditorProvider, HydraniumGlspVscodeServer } from '@hydranium/glsp-client-vscode/node';
|
|
50
|
+
import { ConsoleLogger } from '@hydranium/protocol';
|
|
51
|
+
import { window, type ExtensionContext } from 'vscode';
|
|
52
|
+
|
|
53
|
+
class MyDiagramEditorProvider extends HydraniumGlspEditorProvider {
|
|
54
|
+
override diagramType = 'my-diagram';
|
|
55
|
+
protected override readonly scriptPath = 'out/webview/diagram.js';
|
|
56
|
+
protected override readonly stylePath = 'out/webview/diagram.css';
|
|
57
|
+
protected override readonly title = 'My Diagram';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function activate(context: ExtensionContext): void {
|
|
61
|
+
const server = new HydraniumGlspVscodeServer({
|
|
62
|
+
clientId: 'my-language-glsp',
|
|
63
|
+
clientName: 'My Language',
|
|
64
|
+
findPort: findGlspPort,
|
|
65
|
+
logger: new ConsoleLogger()
|
|
66
|
+
});
|
|
67
|
+
const connector = new GlspVscodeConnector({ server });
|
|
68
|
+
context.subscriptions.push(server, connector);
|
|
69
|
+
void server.start();
|
|
70
|
+
server.onReady.catch((error: unknown) => window.showErrorMessage(`Diagram unavailable: ${String(error)}`));
|
|
71
|
+
context.subscriptions.push(
|
|
72
|
+
window.registerCustomEditorProvider('myLanguage.diagram', new MyDiagramEditorProvider(connector, context.extensionUri), {
|
|
73
|
+
webviewOptions: { retainContextWhenHidden: true }
|
|
74
|
+
})
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The webview may load from the script's directory and the stylesheet's. The
|
|
80
|
+
diagram mounts into an element of class `DIAGRAM_CONTAINER_CLASS`, from the
|
|
81
|
+
package root, which your webview stylesheet sizes. In the webview bundle,
|
|
82
|
+
start the diagram with a `HydraniumGlspStarter` whose container appends your
|
|
83
|
+
diagram's own container module last:
|
|
84
|
+
|
|
85
|
+
<!-- snippet-preamble
|
|
86
|
+
import type { ContainerModule } from 'inversify';
|
|
87
|
+
declare const myDiagramModule: ContainerModule;
|
|
88
|
+
-->
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
import { initializeDiagramContainer, type ContainerConfiguration } from '@eclipse-glsp/client';
|
|
92
|
+
import { HydraniumGlspStarter } from '@hydranium/glsp-client-vscode/browser';
|
|
93
|
+
import { Container } from 'inversify';
|
|
94
|
+
|
|
95
|
+
class MyDiagramStarter extends HydraniumGlspStarter {
|
|
96
|
+
createContainer(...containerConfiguration: ContainerConfiguration): Container {
|
|
97
|
+
// `myDiagramModule` is yours: the model and view registrations of your diagram.
|
|
98
|
+
return initializeDiagramContainer(new Container(), ...containerConfiguration, myDiagramModule);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
new MyDiagramStarter();
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The extension host's tier never reaches `@eclipse-glsp/client`, whose
|
|
105
|
+
stylesheets Node cannot load. Keep your own extension host code off your
|
|
106
|
+
diagram module for the same reason.
|
|
107
|
+
|
|
108
|
+
For the whole setup, see *Host in VS Code* in
|
|
109
|
+
[Adopting Hydranium](https://github.com/eclipse-emfcloud/hydranium/blob/main/docs/ADOPTING.md).
|
|
110
|
+
|
|
111
|
+
## Entry points
|
|
112
|
+
|
|
113
|
+
| Subpath | Use it for | Runs in |
|
|
114
|
+
| ----------- | ----------------------------------------------- | -------------------------- |
|
|
115
|
+
| `.` | The class name both tiers share | anywhere |
|
|
116
|
+
| `./node` | The GLSP server and the diagram's custom editor | the VS Code extension host |
|
|
117
|
+
| `./browser` | The diagram webview's starter | a webview |
|
|
118
|
+
|
|
119
|
+
The subpaths need a TypeScript `moduleResolution` that reads `exports`
|
|
120
|
+
(`NodeNext` or `Bundler`); see *Requirements* in
|
|
121
|
+
[Adopting Hydranium](https://github.com/eclipse-emfcloud/hydranium/blob/main/docs/ADOPTING.md).
|
|
122
|
+
|
|
123
|
+
## Status
|
|
124
|
+
|
|
125
|
+
Alpha: every release is a prerelease that may break the API, so pin an exact
|
|
126
|
+
version. Guides and known limitations:
|
|
127
|
+
[Adopting Hydranium](https://github.com/eclipse-emfcloud/hydranium/blob/main/docs/ADOPTING.md).
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
`MIT` — see this package's [`LICENSE`](./LICENSE), and the repository
|
|
132
|
+
[`NOTICE.md`](https://github.com/eclipse-emfcloud/hydranium/blob/main/NOTICE.md)
|
|
133
|
+
for third-party notices.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
import type { ContainerConfiguration } from '@eclipse-glsp/client';
|
|
10
|
+
import { GLSPStarter } from '@eclipse-glsp/vscode-integration-webview';
|
|
11
|
+
import { type GlspClientModuleOptions } from '@hydranium/glsp-client';
|
|
12
|
+
/**
|
|
13
|
+
* The diagram webview's starter: GLSP's handshake with the extension host,
|
|
14
|
+
* with the framework's client module among the modules the container is built
|
|
15
|
+
* from.
|
|
16
|
+
*
|
|
17
|
+
* The module follows the host's own, since it replaces tokens they bind, and
|
|
18
|
+
* comes before whatever `createContainer` appends: GLSP's model and view
|
|
19
|
+
* registries give an element type to the module that registers it last, so a
|
|
20
|
+
* subclass appends its diagram definition last.
|
|
21
|
+
*/
|
|
22
|
+
export declare abstract class HydraniumGlspStarter extends GLSPStarter {
|
|
23
|
+
protected getContainerConfiguration(): ContainerConfiguration;
|
|
24
|
+
/** Options for the framework's client module. Without a logger it logs to the webview's console, the only sink a webview has. */
|
|
25
|
+
protected glspClientModuleOptions(): GlspClientModuleOptions;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=glsp-starter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glsp-starter.d.ts","sourceRoot":"","sources":["../../src/browser/glsp-starter.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,0CAA0C,CAAC;AACvE,OAAO,EAA0B,KAAK,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAG9F;;;;;;;;;GASG;AACH,8BAAsB,oBAAqB,SAAQ,WAAW;IAC3D,UAAmB,yBAAyB,IAAI,sBAAsB,CAOrE;IAED,iIAAiI;IACjI,SAAS,CAAC,uBAAuB,IAAI,uBAAuB,CAE3D;CACH"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/********************************************************************************
|
|
3
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
4
|
+
*
|
|
5
|
+
* This program and the accompanying materials are made available under the
|
|
6
|
+
* terms of the MIT License which is available in the project root.
|
|
7
|
+
*
|
|
8
|
+
* SPDX-License-Identifier: MIT
|
|
9
|
+
********************************************************************************/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.HydraniumGlspStarter = void 0;
|
|
12
|
+
const vscode_integration_webview_1 = require("@eclipse-glsp/vscode-integration-webview");
|
|
13
|
+
const glsp_client_1 = require("@hydranium/glsp-client");
|
|
14
|
+
const inversify_1 = require("inversify");
|
|
15
|
+
/**
|
|
16
|
+
* The diagram webview's starter: GLSP's handshake with the extension host,
|
|
17
|
+
* with the framework's client module among the modules the container is built
|
|
18
|
+
* from.
|
|
19
|
+
*
|
|
20
|
+
* The module follows the host's own, since it replaces tokens they bind, and
|
|
21
|
+
* comes before whatever `createContainer` appends: GLSP's model and view
|
|
22
|
+
* registries give an element type to the module that registers it last, so a
|
|
23
|
+
* subclass appends its diagram definition last.
|
|
24
|
+
*/
|
|
25
|
+
class HydraniumGlspStarter extends vscode_integration_webview_1.GLSPStarter {
|
|
26
|
+
getContainerConfiguration() {
|
|
27
|
+
return [
|
|
28
|
+
...super.getContainerConfiguration(),
|
|
29
|
+
new inversify_1.ContainerModule((bind, unbind, isBound, rebind) => (0, glsp_client_1.createGlspClientModule)({ bind, unbind, isBound, rebind }, this.glspClientModuleOptions()))
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
/** Options for the framework's client module. Without a logger it logs to the webview's console, the only sink a webview has. */
|
|
33
|
+
glspClientModuleOptions() {
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.HydraniumGlspStarter = HydraniumGlspStarter;
|
|
38
|
+
//# sourceMappingURL=glsp-starter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glsp-starter.js","sourceRoot":"","sources":["../../src/browser/glsp-starter.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;AAGlF,yFAAuE;AACvE,wDAA8F;AAC9F,yCAA4C;AAE5C;;;;;;;;;GASG;AACH,0BAA2C,SAAQ,wCAAW;IACxC,yBAAyB;QACzC,OAAO;YACJ,GAAG,KAAK,CAAC,yBAAyB,EAAE;YACpC,IAAI,2BAAe,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,CACnD,IAAA,oCAAsB,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,uBAAuB,EAAE,CAAC,CAC3F;SACH,CAAC;IACL,CAAC;IAED,iIAAiI;IACvH,uBAAuB;QAC9B,OAAO,EAAE,CAAC;IACb,CAAC;CACH"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
export * from './glsp-starter';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/browser/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/********************************************************************************
|
|
3
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
4
|
+
*
|
|
5
|
+
* This program and the accompanying materials are made available under the
|
|
6
|
+
* terms of the MIT License which is available in the project root.
|
|
7
|
+
*
|
|
8
|
+
* SPDX-License-Identifier: MIT
|
|
9
|
+
********************************************************************************/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
22
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
23
|
+
};
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
__exportStar(require("./glsp-starter"), exports);
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/browser/index.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;;;;;;;;;;;AAElF,iDAA+B"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
/**
|
|
10
|
+
* The class on the element the diagram mounts into. The extension host writes
|
|
11
|
+
* it into the webview document and the webview's stylesheet sizes it, so it
|
|
12
|
+
* lives on the neutral root both tiers reach.
|
|
13
|
+
*/
|
|
14
|
+
export declare const DIAGRAM_CONTAINER_CLASS = "hydranium-diagram-container";
|
|
15
|
+
//# sourceMappingURL=diagram-container.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagram-container.d.ts","sourceRoot":"","sources":["../src/diagram-container.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,gCAAgC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/********************************************************************************
|
|
3
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
4
|
+
*
|
|
5
|
+
* This program and the accompanying materials are made available under the
|
|
6
|
+
* terms of the MIT License which is available in the project root.
|
|
7
|
+
*
|
|
8
|
+
* SPDX-License-Identifier: MIT
|
|
9
|
+
********************************************************************************/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.DIAGRAM_CONTAINER_CLASS = void 0;
|
|
12
|
+
/**
|
|
13
|
+
* The class on the element the diagram mounts into. The extension host writes
|
|
14
|
+
* it into the webview document and the webview's stylesheet sizes it, so it
|
|
15
|
+
* lives on the neutral root both tiers reach.
|
|
16
|
+
*/
|
|
17
|
+
exports.DIAGRAM_CONTAINER_CLASS = 'hydranium-diagram-container';
|
|
18
|
+
//# sourceMappingURL=diagram-container.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagram-container.js","sourceRoot":"","sources":["../src/diagram-container.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;AAElF;;;;GAIG;AACU,QAAA,uBAAuB,GAAG,6BAA6B,CAAC"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
export * from './diagram-container';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAKlF,cAAc,qBAAqB,CAAC"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/********************************************************************************
|
|
3
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
4
|
+
*
|
|
5
|
+
* This program and the accompanying materials are made available under the
|
|
6
|
+
* terms of the MIT License which is available in the project root.
|
|
7
|
+
*
|
|
8
|
+
* SPDX-License-Identifier: MIT
|
|
9
|
+
********************************************************************************/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
22
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
23
|
+
};
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
// Neutral: what both tiers name. `./node` is the extension host's, and never
|
|
26
|
+
// reaches `@eclipse-glsp/client`, whose stylesheets Node cannot load;
|
|
27
|
+
// `./browser` is the webview's.
|
|
28
|
+
__exportStar(require("./diagram-container"), exports);
|
|
29
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;;;;;;;;;;;AAElF,6EAA6E;AAC7E,sEAAsE;AACtE,gCAAgC;AAChC,sDAAoC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
import { GlspEditorProvider, type GlspVscodeConnector } from '@eclipse-glsp/vscode-integration';
|
|
10
|
+
import * as vscode from 'vscode';
|
|
11
|
+
/**
|
|
12
|
+
* A custom editor whose webview hosts a GLSP diagram: the webview document,
|
|
13
|
+
* its Content-Security-Policy and the element the diagram mounts into.
|
|
14
|
+
*
|
|
15
|
+
* `GlspEditorProvider` already mints the per-view `clientId`, registers the
|
|
16
|
+
* client on the connector and routes save, revert and dirty state; a subclass
|
|
17
|
+
* names the diagram type, the bundle and the title.
|
|
18
|
+
*
|
|
19
|
+
* The connector's messenger reaches each webview's endpoint through the base
|
|
20
|
+
* class. `GlspVscodeConnector` constructs it with `ignoreHiddenViews: false`;
|
|
21
|
+
* a messenger handed to the connector must repeat that, or a hidden diagram tab
|
|
22
|
+
* misses every message sent to it.
|
|
23
|
+
*/
|
|
24
|
+
export declare abstract class HydraniumGlspEditorProvider extends GlspEditorProvider {
|
|
25
|
+
protected readonly extensionUri: vscode.Uri;
|
|
26
|
+
/** The webview's script bundle, relative to the extension root. */
|
|
27
|
+
protected abstract readonly scriptPath: string;
|
|
28
|
+
/** The webview's stylesheet, relative to the extension root, if the bundler emits one. */
|
|
29
|
+
protected readonly stylePath?: string;
|
|
30
|
+
/** The webview document's title. */
|
|
31
|
+
protected abstract readonly title: string;
|
|
32
|
+
constructor(connector: GlspVscodeConnector, extensionUri: vscode.Uri);
|
|
33
|
+
/**
|
|
34
|
+
* Populate the webview for one diagram view.
|
|
35
|
+
*
|
|
36
|
+
* `clientId` is the connector's: the diagram widget mounts into
|
|
37
|
+
* `#<clientId>_container`, so a document naming another id loads and renders
|
|
38
|
+
* nothing.
|
|
39
|
+
*/
|
|
40
|
+
setUpWebview(_document: vscode.CustomDocument, webviewPanel: vscode.WebviewPanel, _token: vscode.CancellationToken, clientId: string): void;
|
|
41
|
+
/**
|
|
42
|
+
* Where the webview may load from: the script's directory and the
|
|
43
|
+
* stylesheet's. VS Code blocks anything outside them without an error, so a
|
|
44
|
+
* stylesheet elsewhere would leave the diagram unstyled.
|
|
45
|
+
*/
|
|
46
|
+
protected localResourceRoots(): vscode.Uri[];
|
|
47
|
+
/**
|
|
48
|
+
* The webview document.
|
|
49
|
+
*
|
|
50
|
+
* The CSP relaxations are sprotty's: `style-src 'unsafe-inline'` because it
|
|
51
|
+
* writes inline `style` attributes on the SVG, without which every element is
|
|
52
|
+
* laid out at the origin, and `font-src data:` for the codicon font a bundler
|
|
53
|
+
* inlines. `'unsafe-eval'` is not granted; nothing in a GLSP bundle needs it.
|
|
54
|
+
*/
|
|
55
|
+
protected render(webview: vscode.Webview, clientId: string): string;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=glsp-editor-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glsp-editor-provider.d.ts","sourceRoot":"","sources":["../../src/node/glsp-editor-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAEhG,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAGjC;;;;;;;;;;;;GAYG;AACH,8BAAsB,2BAA4B,SAAQ,kBAAkB;IAUtE,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,GAAG;IAT9C,mEAAmE;IACnE,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC/C,0FAA0F;IAC1F,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IACtC,oCAAoC;IACpC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAE1C,YACG,SAAS,EAAE,mBAAmB,EACX,YAAY,EAAE,MAAM,CAAC,GAAG,EAG7C;IAED;;;;;;OAMG;IACH,YAAY,CACT,SAAS,EAAE,MAAM,CAAC,cAAc,EAChC,YAAY,EAAE,MAAM,CAAC,YAAY,EACjC,MAAM,EAAE,MAAM,CAAC,iBAAiB,EAChC,QAAQ,EAAE,MAAM,GAChB,IAAI,CAIN;IAED;;;;OAIG;IACH,SAAS,CAAC,kBAAkB,IAAI,MAAM,CAAC,GAAG,EAAE,CAS3C;IAED;;;;;;;OAOG;IACH,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAoBlE;CACH"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/********************************************************************************
|
|
3
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
4
|
+
*
|
|
5
|
+
* This program and the accompanying materials are made available under the
|
|
6
|
+
* terms of the MIT License which is available in the project root.
|
|
7
|
+
*
|
|
8
|
+
* SPDX-License-Identifier: MIT
|
|
9
|
+
********************************************************************************/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
22
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
23
|
+
}) : function(o, v) {
|
|
24
|
+
o["default"] = v;
|
|
25
|
+
});
|
|
26
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
27
|
+
var ownKeys = function(o) {
|
|
28
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
29
|
+
var ar = [];
|
|
30
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
31
|
+
return ar;
|
|
32
|
+
};
|
|
33
|
+
return ownKeys(o);
|
|
34
|
+
};
|
|
35
|
+
return function (mod) {
|
|
36
|
+
if (mod && mod.__esModule) return mod;
|
|
37
|
+
var result = {};
|
|
38
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
39
|
+
__setModuleDefault(result, mod);
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
})();
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.HydraniumGlspEditorProvider = void 0;
|
|
45
|
+
const vscode_integration_1 = require("@eclipse-glsp/vscode-integration");
|
|
46
|
+
const node_crypto_1 = require("node:crypto");
|
|
47
|
+
const vscode = __importStar(require("vscode"));
|
|
48
|
+
const diagram_container_1 = require("../diagram-container");
|
|
49
|
+
/**
|
|
50
|
+
* A custom editor whose webview hosts a GLSP diagram: the webview document,
|
|
51
|
+
* its Content-Security-Policy and the element the diagram mounts into.
|
|
52
|
+
*
|
|
53
|
+
* `GlspEditorProvider` already mints the per-view `clientId`, registers the
|
|
54
|
+
* client on the connector and routes save, revert and dirty state; a subclass
|
|
55
|
+
* names the diagram type, the bundle and the title.
|
|
56
|
+
*
|
|
57
|
+
* The connector's messenger reaches each webview's endpoint through the base
|
|
58
|
+
* class. `GlspVscodeConnector` constructs it with `ignoreHiddenViews: false`;
|
|
59
|
+
* a messenger handed to the connector must repeat that, or a hidden diagram tab
|
|
60
|
+
* misses every message sent to it.
|
|
61
|
+
*/
|
|
62
|
+
class HydraniumGlspEditorProvider extends vscode_integration_1.GlspEditorProvider {
|
|
63
|
+
extensionUri;
|
|
64
|
+
/** The webview's stylesheet, relative to the extension root, if the bundler emits one. */
|
|
65
|
+
stylePath;
|
|
66
|
+
constructor(connector, extensionUri) {
|
|
67
|
+
super(connector);
|
|
68
|
+
this.extensionUri = extensionUri;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Populate the webview for one diagram view.
|
|
72
|
+
*
|
|
73
|
+
* `clientId` is the connector's: the diagram widget mounts into
|
|
74
|
+
* `#<clientId>_container`, so a document naming another id loads and renders
|
|
75
|
+
* nothing.
|
|
76
|
+
*/
|
|
77
|
+
setUpWebview(_document, webviewPanel, _token, clientId) {
|
|
78
|
+
const webview = webviewPanel.webview;
|
|
79
|
+
webview.options = { enableScripts: true, localResourceRoots: this.localResourceRoots() };
|
|
80
|
+
webview.html = this.render(webview, clientId);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Where the webview may load from: the script's directory and the
|
|
84
|
+
* stylesheet's. VS Code blocks anything outside them without an error, so a
|
|
85
|
+
* stylesheet elsewhere would leave the diagram unstyled.
|
|
86
|
+
*/
|
|
87
|
+
localResourceRoots() {
|
|
88
|
+
const roots = [vscode.Uri.joinPath(this.extensionUri, this.scriptPath, '..')];
|
|
89
|
+
if (this.stylePath) {
|
|
90
|
+
const styleRoot = vscode.Uri.joinPath(this.extensionUri, this.stylePath, '..');
|
|
91
|
+
if (styleRoot.path !== roots[0].path) {
|
|
92
|
+
roots.push(styleRoot);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return roots;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* The webview document.
|
|
99
|
+
*
|
|
100
|
+
* The CSP relaxations are sprotty's: `style-src 'unsafe-inline'` because it
|
|
101
|
+
* writes inline `style` attributes on the SVG, without which every element is
|
|
102
|
+
* laid out at the origin, and `font-src data:` for the codicon font a bundler
|
|
103
|
+
* inlines. `'unsafe-eval'` is not granted; nothing in a GLSP bundle needs it.
|
|
104
|
+
*/
|
|
105
|
+
render(webview, clientId) {
|
|
106
|
+
const script = webview.asWebviewUri(vscode.Uri.joinPath(this.extensionUri, this.scriptPath));
|
|
107
|
+
const style = this.stylePath ? webview.asWebviewUri(vscode.Uri.joinPath(this.extensionUri, this.stylePath)) : undefined;
|
|
108
|
+
const nonce = (0, node_crypto_1.randomBytes)(16).toString('base64');
|
|
109
|
+
return `<!DOCTYPE html>
|
|
110
|
+
<html lang="en">
|
|
111
|
+
<head>
|
|
112
|
+
<meta charset="UTF-8" />
|
|
113
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
114
|
+
<meta
|
|
115
|
+
http-equiv="Content-Security-Policy"
|
|
116
|
+
content="default-src 'none'; style-src ${webview.cspSource} 'unsafe-inline'; font-src ${webview.cspSource} data:; img-src ${webview.cspSource} data:; script-src 'nonce-${nonce}';"
|
|
117
|
+
/>
|
|
118
|
+
<title>${escapeHtml(this.title)}</title>${style ? `\n <link rel="stylesheet" href="${style}" />` : ''}
|
|
119
|
+
</head>
|
|
120
|
+
<body>
|
|
121
|
+
<div id="${clientId}_container" class="${diagram_container_1.DIAGRAM_CONTAINER_CLASS}"></div>
|
|
122
|
+
<script nonce="${nonce}" src="${script}"></script>
|
|
123
|
+
</body>
|
|
124
|
+
</html>`;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
exports.HydraniumGlspEditorProvider = HydraniumGlspEditorProvider;
|
|
128
|
+
function escapeHtml(text) {
|
|
129
|
+
return text.replace(/[&<>"']/g, character => `&#${character.charCodeAt(0)};`);
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=glsp-editor-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glsp-editor-provider.js","sourceRoot":"","sources":["../../src/node/glsp-editor-provider.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAElF,yEAAgG;AAChG,6CAA0C;AAC1C,MAAY,MAAM,mCAAe;AACjC,4DAA+D;AAE/D;;;;;;;;;;;;GAYG;AACH,iCAAkD,SAAQ,uCAAkB;IAUnD,YAAY;IAPlC,0FAA0F;IACvE,SAAS,CAAU;IAItC,YACG,SAA8B,EACX,YAAwB;QAE3C,KAAK,CAAC,SAAS,CAAC,CAAC;4BAFE,YAAY;IAGlC,CAAC;IAED;;;;;;OAMG;IACH,YAAY,CACT,SAAgC,EAChC,YAAiC,EACjC,MAAgC,EAChC,QAAgB;QAEhB,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC;QACrC,OAAO,CAAC,OAAO,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,CAAC,kBAAkB,EAAE,EAAE,CAAC;QACzF,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACjD,CAAC;IAED;;;;OAIG;IACO,kBAAkB;QACzB,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC;QAC9E,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YAClB,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YAC/E,IAAI,SAAS,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBACpC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACzB,CAAC;QACJ,CAAC;QACD,OAAO,KAAK,CAAC;IAChB,CAAC;IAED;;;;;;;OAOG;IACO,MAAM,CAAC,OAAuB,EAAE,QAAgB;QACvD,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAC7F,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACxH,MAAM,KAAK,GAAG,IAAA,yBAAW,EAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACjD,OAAO;;;;;;;kDAOqC,OAAO,CAAC,SAAS,8BAA8B,OAAO,CAAC,SAAS,mBAAmB,OAAO,CAAC,SAAS,6BAA6B,KAAK;;eAEzK,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,CAAC,CAAC,CAAC,wCAAwC,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE;;;iBAG/F,QAAQ,sBAAsB,2CAAuB;uBAC/C,KAAK,UAAU,MAAM;;QAEpC,CAAC;IACN,CAAC;CACH;;AAED,SAAS,UAAU,CAAC,IAAY;IAC7B,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,SAAS,CAAC,EAAE,CAAC,KAAK,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AACjF,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
import { SocketGlspVscodeServer } from '@eclipse-glsp/vscode-integration';
|
|
10
|
+
import { type Logger } from '@hydranium/protocol';
|
|
11
|
+
/** What {@link HydraniumGlspVscodeServer} needs beyond the GLSP client identity. */
|
|
12
|
+
export interface HydraniumGlspVscodeServerOptions {
|
|
13
|
+
readonly clientId: string;
|
|
14
|
+
readonly clientName: string;
|
|
15
|
+
/**
|
|
16
|
+
* Resolve the GLSP head's listening port, typically `findPort` from
|
|
17
|
+
* `@hydranium/client-vscode/node`. Called when the connection is opened, so
|
|
18
|
+
* the poll runs at `start()` rather than during activation.
|
|
19
|
+
*/
|
|
20
|
+
readonly findPort: () => Promise<number>;
|
|
21
|
+
/** Where the connection to the head logs its protocol faults. */
|
|
22
|
+
readonly logger: Logger;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The GLSP head reached over its ephemeral socket, with the port discovered
|
|
26
|
+
* rather than configured.
|
|
27
|
+
*
|
|
28
|
+
* `SocketGlspVscodeServer` takes a fixed `connectionOptions` at construction,
|
|
29
|
+
* but the head's port is assigned when it binds and published as an LSP
|
|
30
|
+
* request. Awaiting it in `activate` would block activation behind a poll that
|
|
31
|
+
* can take seconds, even for a user who never opens a diagram, so the lookup
|
|
32
|
+
* moves to `createConnection`, which the base class calls from `start()`.
|
|
33
|
+
* The `connectionOptions` handed to `super` is never read, and is an unusable
|
|
34
|
+
* port so that a refactor reintroducing the base implementation fails loudly
|
|
35
|
+
* instead of dialling something.
|
|
36
|
+
*
|
|
37
|
+
* Report a failure off `onReady`, not off `start()`: `start()` routes its own
|
|
38
|
+
* error into the readiness promise and resolves anyway.
|
|
39
|
+
*/
|
|
40
|
+
export declare class HydraniumGlspVscodeServer extends SocketGlspVscodeServer {
|
|
41
|
+
protected readonly findPort: () => Promise<number>;
|
|
42
|
+
protected readonly logger: Logger;
|
|
43
|
+
constructor(options: HydraniumGlspVscodeServerOptions);
|
|
44
|
+
protected createConnection(): ReturnType<SocketGlspVscodeServer['createConnection']>;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=glsp-vscode-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glsp-vscode-server.d.ts","sourceRoot":"","sources":["../../src/node/glsp-vscode-server.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EAAoB,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAIpE,oFAAoF;AACpF,MAAM,WAAW,gCAAgC;IAC9C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,iEAAiE;IACjE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,yBAA0B,SAAQ,sBAAsB;IAClE,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAElC,YAAY,OAAO,EAAE,gCAAgC,EAQpD;IAED,UAAyB,gBAAgB,IAAI,UAAU,CAAC,sBAAsB,CAAC,kBAAkB,CAAC,CAAC,CAalG;CACH"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/********************************************************************************
|
|
3
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
4
|
+
*
|
|
5
|
+
* This program and the accompanying materials are made available under the
|
|
6
|
+
* terms of the MIT License which is available in the project root.
|
|
7
|
+
*
|
|
8
|
+
* SPDX-License-Identifier: MIT
|
|
9
|
+
********************************************************************************/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
22
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
23
|
+
}) : function(o, v) {
|
|
24
|
+
o["default"] = v;
|
|
25
|
+
});
|
|
26
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
27
|
+
var ownKeys = function(o) {
|
|
28
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
29
|
+
var ar = [];
|
|
30
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
31
|
+
return ar;
|
|
32
|
+
};
|
|
33
|
+
return ownKeys(o);
|
|
34
|
+
};
|
|
35
|
+
return function (mod) {
|
|
36
|
+
if (mod && mod.__esModule) return mod;
|
|
37
|
+
var result = {};
|
|
38
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
39
|
+
__setModuleDefault(result, mod);
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
})();
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.HydraniumGlspVscodeServer = void 0;
|
|
45
|
+
const vscode_integration_1 = require("@eclipse-glsp/vscode-integration");
|
|
46
|
+
const protocol_1 = require("@hydranium/protocol");
|
|
47
|
+
const net = __importStar(require("node:net"));
|
|
48
|
+
const node_1 = require("vscode-jsonrpc/node");
|
|
49
|
+
/**
|
|
50
|
+
* The GLSP head reached over its ephemeral socket, with the port discovered
|
|
51
|
+
* rather than configured.
|
|
52
|
+
*
|
|
53
|
+
* `SocketGlspVscodeServer` takes a fixed `connectionOptions` at construction,
|
|
54
|
+
* but the head's port is assigned when it binds and published as an LSP
|
|
55
|
+
* request. Awaiting it in `activate` would block activation behind a poll that
|
|
56
|
+
* can take seconds, even for a user who never opens a diagram, so the lookup
|
|
57
|
+
* moves to `createConnection`, which the base class calls from `start()`.
|
|
58
|
+
* The `connectionOptions` handed to `super` is never read, and is an unusable
|
|
59
|
+
* port so that a refactor reintroducing the base implementation fails loudly
|
|
60
|
+
* instead of dialling something.
|
|
61
|
+
*
|
|
62
|
+
* Report a failure off `onReady`, not off `start()`: `start()` routes its own
|
|
63
|
+
* error into the readiness promise and resolves anyway.
|
|
64
|
+
*/
|
|
65
|
+
class HydraniumGlspVscodeServer extends vscode_integration_1.SocketGlspVscodeServer {
|
|
66
|
+
findPort;
|
|
67
|
+
logger;
|
|
68
|
+
constructor(options) {
|
|
69
|
+
super({
|
|
70
|
+
clientId: options.clientId,
|
|
71
|
+
clientName: options.clientName,
|
|
72
|
+
connectionOptions: { port: 0 }
|
|
73
|
+
});
|
|
74
|
+
this.findPort = options.findPort;
|
|
75
|
+
this.logger = options.logger;
|
|
76
|
+
}
|
|
77
|
+
async createConnection() {
|
|
78
|
+
const port = await this.findPort();
|
|
79
|
+
// `127.0.0.1`, not `localhost`, and it has to match the head: `startGlspServer`
|
|
80
|
+
// binds `127.0.0.1` by default, so on a dual-stack machine where `localhost`
|
|
81
|
+
// resolves to `::1` first the dial fails as ECONNREFUSED with nothing in the
|
|
82
|
+
// message naming the address family as the cause.
|
|
83
|
+
// Built here rather than by the base's `createSocketConnection`, which
|
|
84
|
+
// passes no logger. GLSP's client sends typed messages built by
|
|
85
|
+
// `@eclipse-glsp/protocol`'s copy of `vscode-jsonrpc`, so they go by name.
|
|
86
|
+
const socket = new net.Socket();
|
|
87
|
+
const connection = (0, node_1.createMessageConnection)(new node_1.SocketMessageReader(socket), new node_1.SocketMessageWriter(socket), this.logger);
|
|
88
|
+
socket.connect({ port, host: '127.0.0.1' });
|
|
89
|
+
return (0, protocol_1.sendByMethodName)(connection);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
exports.HydraniumGlspVscodeServer = HydraniumGlspVscodeServer;
|
|
93
|
+
//# sourceMappingURL=glsp-vscode-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glsp-vscode-server.js","sourceRoot":"","sources":["../../src/node/glsp-vscode-server.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAElF,yEAA0E;AAC1E,kDAAoE;AACpE,MAAY,GAAG,qCAAiB;AAChC,8CAAwG;AAgBxG;;;;;;;;;;;;;;;GAeG;AACH,+BAAuC,SAAQ,2CAAsB;IAC/C,QAAQ,CAAwB;IAChC,MAAM,CAAS;IAElC,YAAY,OAAyC;QAClD,KAAK,CAAC;YACH,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,iBAAiB,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE;SAChC,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACjC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAChC,CAAC;IAEkB,KAAK,CAAC,gBAAgB;QACtC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACnC,gFAAgF;QAChF,6EAA6E;QAC7E,6EAA6E;QAC7E,kDAAkD;QAClD,uEAAuE;QACvE,gEAAgE;QAChE,2EAA2E;QAC3E,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QAChC,MAAM,UAAU,GAAG,IAAA,8BAAuB,EAAC,IAAI,0BAAmB,CAAC,MAAM,CAAC,EAAE,IAAI,0BAAmB,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1H,MAAM,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;QAC5C,OAAO,IAAA,2BAAgB,EAAC,UAAU,CAAC,CAAC;IACvC,CAAC;CACH"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
export * from './glsp-editor-provider';
|
|
10
|
+
export * from './glsp-vscode-server';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/********************************************************************************
|
|
3
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
4
|
+
*
|
|
5
|
+
* This program and the accompanying materials are made available under the
|
|
6
|
+
* terms of the MIT License which is available in the project root.
|
|
7
|
+
*
|
|
8
|
+
* SPDX-License-Identifier: MIT
|
|
9
|
+
********************************************************************************/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
22
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
23
|
+
};
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
__exportStar(require("./glsp-editor-provider"), exports);
|
|
26
|
+
__exportStar(require("./glsp-vscode-server"), exports);
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;;;;;;;;;;;AAElF,yDAAuC;AACvC,uDAAqC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,91 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hydranium/glsp-client-vscode",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0-next",
|
|
4
|
+
"description": "VS Code client primitives for GLSP heads built on @hydranium/glsp-server: the extension host's GLSP server over a discovered socket port and a custom editor whose webview hosts the diagram, and a webview starter that binds @hydranium/glsp-client's host-neutral classes; companion of @hydranium/glsp-server.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"diagram",
|
|
7
|
+
"glsp",
|
|
8
|
+
"hydranium",
|
|
9
|
+
"langium",
|
|
10
|
+
"language-server",
|
|
11
|
+
"lsp",
|
|
12
|
+
"vscode",
|
|
13
|
+
"vscode-extension",
|
|
14
|
+
"webview"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://github.com/eclipse-emfcloud/hydranium/tree/main/packages/glsp-client-vscode",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/eclipse-emfcloud/hydranium/issues"
|
|
19
|
+
},
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"author": {
|
|
22
|
+
"name": "Hydranium Team"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://github.com/eclipse-emfcloud/hydranium.git",
|
|
27
|
+
"directory": "packages/glsp-client-vscode"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"lib",
|
|
31
|
+
"src",
|
|
32
|
+
"!lib/**/*.tsbuildinfo"
|
|
33
|
+
],
|
|
34
|
+
"sideEffects": false,
|
|
35
|
+
"main": "lib/index.js",
|
|
36
|
+
"types": "lib/index.d.ts",
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./lib/index.d.ts",
|
|
40
|
+
"default": "./lib/index.js"
|
|
41
|
+
},
|
|
42
|
+
"./browser": {
|
|
43
|
+
"types": "./lib/browser/index.d.ts",
|
|
44
|
+
"default": "./lib/browser/index.js"
|
|
45
|
+
},
|
|
46
|
+
"./node": {
|
|
47
|
+
"types": "./lib/node/index.d.ts",
|
|
48
|
+
"default": "./lib/node/index.js"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"access": "public"
|
|
53
|
+
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"build": "tsc -b",
|
|
56
|
+
"clean": "rimraf lib tsconfig.tsbuildinfo",
|
|
57
|
+
"lint": "oxlint --format stylish --config ../../oxlint.config.cjs src test --max-warnings 0",
|
|
58
|
+
"prepack": "node -e \"const m=require('./package.json'),fs=require('node:fs');const missing=[m.main,...Object.values(m.bin||{})].filter(entry=>entry&&!fs.existsSync(entry));if(missing.length){console.error('prepack '+m.name+': not built ('+missing.join(', ')+' missing). Run the build before packing: a files entry that matches nothing is skipped silently, so the tarball would ship src only.');process.exit(1);}\"",
|
|
59
|
+
"test": "npm run typecheck:test && vitest run",
|
|
60
|
+
"typecheck:test": "tsc --noEmit -p tsconfig.test.json",
|
|
61
|
+
"watch": "tsc -b -w --preserveWatchOutput"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@eclipse-glsp/client": "2.7.0",
|
|
65
|
+
"@eclipse-glsp/vscode-integration": "2.7.0",
|
|
66
|
+
"@eclipse-glsp/vscode-integration-webview": "2.7.0",
|
|
67
|
+
"@hydranium/glsp-client": "1.0.0-next",
|
|
68
|
+
"@hydranium/protocol": "1.0.0-next",
|
|
69
|
+
"@types/node": "^22.0.0",
|
|
70
|
+
"@types/vscode": "^1.101.0",
|
|
71
|
+
"inversify": "6.2.2",
|
|
72
|
+
"rimraf": "^5.0.0",
|
|
73
|
+
"typescript": "^7.0.2",
|
|
74
|
+
"vscode-jsonrpc": "9.0.0"
|
|
75
|
+
},
|
|
76
|
+
"peerDependencies": {
|
|
77
|
+
"@eclipse-glsp/client": "^2.6.0",
|
|
78
|
+
"@eclipse-glsp/vscode-integration": "^2.6.0",
|
|
79
|
+
"@eclipse-glsp/vscode-integration-webview": "^2.6.0",
|
|
80
|
+
"@hydranium/glsp-client": "^1.0.0-next",
|
|
81
|
+
"@hydranium/protocol": "^1.0.0-next",
|
|
82
|
+
"inversify": "^6.0.0",
|
|
83
|
+
"vscode-jsonrpc": "^9.0.0"
|
|
84
|
+
},
|
|
85
|
+
"engines": {
|
|
86
|
+
"node": ">=22.13",
|
|
87
|
+
"vscode": "^1.101.0"
|
|
88
|
+
},
|
|
89
|
+
"//peerDependencies": "`vscode-jsonrpc` takes a caret, so the framework shares the transport the LSP connection resolves, which an `init` scaffold pins: each `vscode-languageserver-protocol` release pins its transport exactly, so an exact peer would name a copy a fresh install rarely holds. The caret excludes 8.x, so a tree whose top holds GLSP's copy fails the peer with a named ERESOLVE warning, an error under `--strict-peer-deps`, rather than resolving silently. No peer reaches a NESTED copy, such as GLSP's or one the LSP packages nest. The wire compares message types and `ResponseError`s by copy identity, so the framework sends typed messages by method name and recognises errors with `isResponseError` rather than `instanceof`.",
|
|
90
|
+
"//prepack": "The publish guard, a `prepack` rather than a `prepare`: `prepack` runs only when a tarball is made (`npm pack`, `npm publish`) and never on install, so it cannot break the install it has no business touching. What it defends against: `files` lists `lib`, `lib` is gitignored, and a `files` entry matching nothing is skipped SILENTLY — so `npm publish` from an unbuilt tree emits a tarball of `src` and nothing else, with no error."
|
|
91
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
|
|
10
|
+
import type { ContainerConfiguration } from '@eclipse-glsp/client';
|
|
11
|
+
import { GLSPStarter } from '@eclipse-glsp/vscode-integration-webview';
|
|
12
|
+
import { createGlspClientModule, type GlspClientModuleOptions } from '@hydranium/glsp-client';
|
|
13
|
+
import { ContainerModule } from 'inversify';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The diagram webview's starter: GLSP's handshake with the extension host,
|
|
17
|
+
* with the framework's client module among the modules the container is built
|
|
18
|
+
* from.
|
|
19
|
+
*
|
|
20
|
+
* The module follows the host's own, since it replaces tokens they bind, and
|
|
21
|
+
* comes before whatever `createContainer` appends: GLSP's model and view
|
|
22
|
+
* registries give an element type to the module that registers it last, so a
|
|
23
|
+
* subclass appends its diagram definition last.
|
|
24
|
+
*/
|
|
25
|
+
export abstract class HydraniumGlspStarter extends GLSPStarter {
|
|
26
|
+
protected override getContainerConfiguration(): ContainerConfiguration {
|
|
27
|
+
return [
|
|
28
|
+
...super.getContainerConfiguration(),
|
|
29
|
+
new ContainerModule((bind, unbind, isBound, rebind) =>
|
|
30
|
+
createGlspClientModule({ bind, unbind, isBound, rebind }, this.glspClientModuleOptions())
|
|
31
|
+
)
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Options for the framework's client module. Without a logger it logs to the webview's console, the only sink a webview has. */
|
|
36
|
+
protected glspClientModuleOptions(): GlspClientModuleOptions {
|
|
37
|
+
return {};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
|
|
10
|
+
export * from './glsp-starter';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The class on the element the diagram mounts into. The extension host writes
|
|
12
|
+
* it into the webview document and the webview's stylesheet sizes it, so it
|
|
13
|
+
* lives on the neutral root both tiers reach.
|
|
14
|
+
*/
|
|
15
|
+
export const DIAGRAM_CONTAINER_CLASS = 'hydranium-diagram-container';
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
|
|
10
|
+
// Neutral: what both tiers name. `./node` is the extension host's, and never
|
|
11
|
+
// reaches `@eclipse-glsp/client`, whose stylesheets Node cannot load;
|
|
12
|
+
// `./browser` is the webview's.
|
|
13
|
+
export * from './diagram-container';
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
|
|
10
|
+
import { GlspEditorProvider, type GlspVscodeConnector } from '@eclipse-glsp/vscode-integration';
|
|
11
|
+
import { randomBytes } from 'node:crypto';
|
|
12
|
+
import * as vscode from 'vscode';
|
|
13
|
+
import { DIAGRAM_CONTAINER_CLASS } from '../diagram-container';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A custom editor whose webview hosts a GLSP diagram: the webview document,
|
|
17
|
+
* its Content-Security-Policy and the element the diagram mounts into.
|
|
18
|
+
*
|
|
19
|
+
* `GlspEditorProvider` already mints the per-view `clientId`, registers the
|
|
20
|
+
* client on the connector and routes save, revert and dirty state; a subclass
|
|
21
|
+
* names the diagram type, the bundle and the title.
|
|
22
|
+
*
|
|
23
|
+
* The connector's messenger reaches each webview's endpoint through the base
|
|
24
|
+
* class. `GlspVscodeConnector` constructs it with `ignoreHiddenViews: false`;
|
|
25
|
+
* a messenger handed to the connector must repeat that, or a hidden diagram tab
|
|
26
|
+
* misses every message sent to it.
|
|
27
|
+
*/
|
|
28
|
+
export abstract class HydraniumGlspEditorProvider extends GlspEditorProvider {
|
|
29
|
+
/** The webview's script bundle, relative to the extension root. */
|
|
30
|
+
protected abstract readonly scriptPath: string;
|
|
31
|
+
/** The webview's stylesheet, relative to the extension root, if the bundler emits one. */
|
|
32
|
+
protected readonly stylePath?: string;
|
|
33
|
+
/** The webview document's title. */
|
|
34
|
+
protected abstract readonly title: string;
|
|
35
|
+
|
|
36
|
+
constructor(
|
|
37
|
+
connector: GlspVscodeConnector,
|
|
38
|
+
protected readonly extensionUri: vscode.Uri
|
|
39
|
+
) {
|
|
40
|
+
super(connector);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Populate the webview for one diagram view.
|
|
45
|
+
*
|
|
46
|
+
* `clientId` is the connector's: the diagram widget mounts into
|
|
47
|
+
* `#<clientId>_container`, so a document naming another id loads and renders
|
|
48
|
+
* nothing.
|
|
49
|
+
*/
|
|
50
|
+
setUpWebview(
|
|
51
|
+
_document: vscode.CustomDocument,
|
|
52
|
+
webviewPanel: vscode.WebviewPanel,
|
|
53
|
+
_token: vscode.CancellationToken,
|
|
54
|
+
clientId: string
|
|
55
|
+
): void {
|
|
56
|
+
const webview = webviewPanel.webview;
|
|
57
|
+
webview.options = { enableScripts: true, localResourceRoots: this.localResourceRoots() };
|
|
58
|
+
webview.html = this.render(webview, clientId);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Where the webview may load from: the script's directory and the
|
|
63
|
+
* stylesheet's. VS Code blocks anything outside them without an error, so a
|
|
64
|
+
* stylesheet elsewhere would leave the diagram unstyled.
|
|
65
|
+
*/
|
|
66
|
+
protected localResourceRoots(): vscode.Uri[] {
|
|
67
|
+
const roots = [vscode.Uri.joinPath(this.extensionUri, this.scriptPath, '..')];
|
|
68
|
+
if (this.stylePath) {
|
|
69
|
+
const styleRoot = vscode.Uri.joinPath(this.extensionUri, this.stylePath, '..');
|
|
70
|
+
if (styleRoot.path !== roots[0].path) {
|
|
71
|
+
roots.push(styleRoot);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return roots;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The webview document.
|
|
79
|
+
*
|
|
80
|
+
* The CSP relaxations are sprotty's: `style-src 'unsafe-inline'` because it
|
|
81
|
+
* writes inline `style` attributes on the SVG, without which every element is
|
|
82
|
+
* laid out at the origin, and `font-src data:` for the codicon font a bundler
|
|
83
|
+
* inlines. `'unsafe-eval'` is not granted; nothing in a GLSP bundle needs it.
|
|
84
|
+
*/
|
|
85
|
+
protected render(webview: vscode.Webview, clientId: string): string {
|
|
86
|
+
const script = webview.asWebviewUri(vscode.Uri.joinPath(this.extensionUri, this.scriptPath));
|
|
87
|
+
const style = this.stylePath ? webview.asWebviewUri(vscode.Uri.joinPath(this.extensionUri, this.stylePath)) : undefined;
|
|
88
|
+
const nonce = randomBytes(16).toString('base64');
|
|
89
|
+
return `<!DOCTYPE html>
|
|
90
|
+
<html lang="en">
|
|
91
|
+
<head>
|
|
92
|
+
<meta charset="UTF-8" />
|
|
93
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
94
|
+
<meta
|
|
95
|
+
http-equiv="Content-Security-Policy"
|
|
96
|
+
content="default-src 'none'; style-src ${webview.cspSource} 'unsafe-inline'; font-src ${webview.cspSource} data:; img-src ${webview.cspSource} data:; script-src 'nonce-${nonce}';"
|
|
97
|
+
/>
|
|
98
|
+
<title>${escapeHtml(this.title)}</title>${style ? `\n <link rel="stylesheet" href="${style}" />` : ''}
|
|
99
|
+
</head>
|
|
100
|
+
<body>
|
|
101
|
+
<div id="${clientId}_container" class="${DIAGRAM_CONTAINER_CLASS}"></div>
|
|
102
|
+
<script nonce="${nonce}" src="${script}"></script>
|
|
103
|
+
</body>
|
|
104
|
+
</html>`;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function escapeHtml(text: string): string {
|
|
109
|
+
return text.replace(/[&<>"']/g, character => `&#${character.charCodeAt(0)};`);
|
|
110
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
|
|
10
|
+
import { SocketGlspVscodeServer } from '@eclipse-glsp/vscode-integration';
|
|
11
|
+
import { sendByMethodName, type Logger } from '@hydranium/protocol';
|
|
12
|
+
import * as net from 'node:net';
|
|
13
|
+
import { createMessageConnection, SocketMessageReader, SocketMessageWriter } from 'vscode-jsonrpc/node';
|
|
14
|
+
|
|
15
|
+
/** What {@link HydraniumGlspVscodeServer} needs beyond the GLSP client identity. */
|
|
16
|
+
export interface HydraniumGlspVscodeServerOptions {
|
|
17
|
+
readonly clientId: string;
|
|
18
|
+
readonly clientName: string;
|
|
19
|
+
/**
|
|
20
|
+
* Resolve the GLSP head's listening port, typically `findPort` from
|
|
21
|
+
* `@hydranium/client-vscode/node`. Called when the connection is opened, so
|
|
22
|
+
* the poll runs at `start()` rather than during activation.
|
|
23
|
+
*/
|
|
24
|
+
readonly findPort: () => Promise<number>;
|
|
25
|
+
/** Where the connection to the head logs its protocol faults. */
|
|
26
|
+
readonly logger: Logger;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The GLSP head reached over its ephemeral socket, with the port discovered
|
|
31
|
+
* rather than configured.
|
|
32
|
+
*
|
|
33
|
+
* `SocketGlspVscodeServer` takes a fixed `connectionOptions` at construction,
|
|
34
|
+
* but the head's port is assigned when it binds and published as an LSP
|
|
35
|
+
* request. Awaiting it in `activate` would block activation behind a poll that
|
|
36
|
+
* can take seconds, even for a user who never opens a diagram, so the lookup
|
|
37
|
+
* moves to `createConnection`, which the base class calls from `start()`.
|
|
38
|
+
* The `connectionOptions` handed to `super` is never read, and is an unusable
|
|
39
|
+
* port so that a refactor reintroducing the base implementation fails loudly
|
|
40
|
+
* instead of dialling something.
|
|
41
|
+
*
|
|
42
|
+
* Report a failure off `onReady`, not off `start()`: `start()` routes its own
|
|
43
|
+
* error into the readiness promise and resolves anyway.
|
|
44
|
+
*/
|
|
45
|
+
export class HydraniumGlspVscodeServer extends SocketGlspVscodeServer {
|
|
46
|
+
protected readonly findPort: () => Promise<number>;
|
|
47
|
+
protected readonly logger: Logger;
|
|
48
|
+
|
|
49
|
+
constructor(options: HydraniumGlspVscodeServerOptions) {
|
|
50
|
+
super({
|
|
51
|
+
clientId: options.clientId,
|
|
52
|
+
clientName: options.clientName,
|
|
53
|
+
connectionOptions: { port: 0 }
|
|
54
|
+
});
|
|
55
|
+
this.findPort = options.findPort;
|
|
56
|
+
this.logger = options.logger;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
protected override async createConnection(): ReturnType<SocketGlspVscodeServer['createConnection']> {
|
|
60
|
+
const port = await this.findPort();
|
|
61
|
+
// `127.0.0.1`, not `localhost`, and it has to match the head: `startGlspServer`
|
|
62
|
+
// binds `127.0.0.1` by default, so on a dual-stack machine where `localhost`
|
|
63
|
+
// resolves to `::1` first the dial fails as ECONNREFUSED with nothing in the
|
|
64
|
+
// message naming the address family as the cause.
|
|
65
|
+
// Built here rather than by the base's `createSocketConnection`, which
|
|
66
|
+
// passes no logger. GLSP's client sends typed messages built by
|
|
67
|
+
// `@eclipse-glsp/protocol`'s copy of `vscode-jsonrpc`, so they go by name.
|
|
68
|
+
const socket = new net.Socket();
|
|
69
|
+
const connection = createMessageConnection(new SocketMessageReader(socket), new SocketMessageWriter(socket), this.logger);
|
|
70
|
+
socket.connect({ port, host: '127.0.0.1' });
|
|
71
|
+
return sendByMethodName(connection);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
|
|
10
|
+
export * from './glsp-editor-provider';
|
|
11
|
+
export * from './glsp-vscode-server';
|