@hydranium/core 1.0.0-next.6 → 1.0.0-next.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/documents/ast-document-manager.d.ts +42 -5
- package/lib/documents/ast-document-manager.d.ts.map +1 -1
- package/lib/documents/ast-document-manager.js +18 -13
- package/lib/documents/ast-document-manager.js.map +1 -1
- package/lib/documents/hydranium-text-documents.d.ts +42 -17
- package/lib/documents/hydranium-text-documents.d.ts.map +1 -1
- package/lib/documents/hydranium-text-documents.js +118 -39
- package/lib/documents/hydranium-text-documents.js.map +1 -1
- package/lib/documents/language-client-text-shadow.d.ts +41 -9
- package/lib/documents/language-client-text-shadow.d.ts.map +1 -1
- package/lib/documents/language-client-text-shadow.js +56 -11
- package/lib/documents/language-client-text-shadow.js.map +1 -1
- package/lib/documents/self-save-registry.d.ts +37 -6
- package/lib/documents/self-save-registry.d.ts.map +1 -1
- package/lib/documents/self-save-registry.js +28 -15
- package/lib/documents/self-save-registry.js.map +1 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +5 -0
- package/lib/index.js.map +1 -1
- package/lib/langium/ast-extension/ast-node-builder.d.ts +32 -9
- package/lib/langium/ast-extension/ast-node-builder.d.ts.map +1 -1
- package/lib/langium/ast-extension/ast-node-builder.js +60 -22
- package/lib/langium/ast-extension/ast-node-builder.js.map +1 -1
- package/lib/langium/bootstrap.d.ts.map +1 -1
- package/lib/langium/bootstrap.js +16 -9
- package/lib/langium/bootstrap.js.map +1 -1
- package/lib/langium/config/configuration-provider.d.ts +61 -0
- package/lib/langium/config/configuration-provider.d.ts.map +1 -0
- package/lib/langium/config/configuration-provider.js +89 -0
- package/lib/langium/config/configuration-provider.js.map +1 -0
- package/lib/langium/config/index.d.ts +1 -0
- package/lib/langium/config/index.d.ts.map +1 -1
- package/lib/langium/config/index.js +1 -0
- package/lib/langium/config/index.js.map +1 -1
- package/lib/langium/diagnostics/lsp-logger.d.ts +17 -0
- package/lib/langium/diagnostics/lsp-logger.d.ts.map +1 -1
- package/lib/langium/diagnostics/lsp-logger.js +40 -6
- package/lib/langium/diagnostics/lsp-logger.js.map +1 -1
- package/lib/langium/document-builder/build-pipeline-integration.d.ts +13 -1
- package/lib/langium/document-builder/build-pipeline-integration.d.ts.map +1 -1
- package/lib/langium/document-builder/build-pipeline-integration.js +1 -1
- package/lib/langium/document-builder/build-pipeline-integration.js.map +1 -1
- package/lib/langium/document-builder/build-session.d.ts +93 -0
- package/lib/langium/document-builder/build-session.d.ts.map +1 -0
- package/lib/langium/document-builder/build-session.js +72 -0
- package/lib/langium/document-builder/build-session.js.map +1 -0
- package/lib/langium/document-builder/document-builder.d.ts +150 -7
- package/lib/langium/document-builder/document-builder.d.ts.map +1 -1
- package/lib/langium/document-builder/document-builder.js +298 -11
- package/lib/langium/document-builder/document-builder.js.map +1 -1
- package/lib/langium/document-builder/index.d.ts +1 -0
- package/lib/langium/document-builder/index.d.ts.map +1 -1
- package/lib/langium/document-builder/index.js +1 -0
- package/lib/langium/document-builder/index.js.map +1 -1
- package/lib/langium/integration-services.d.ts +45 -1
- package/lib/langium/integration-services.d.ts.map +1 -1
- package/lib/langium/integration-services.js +10 -5
- package/lib/langium/integration-services.js.map +1 -1
- package/lib/langium/integrity/integrity-service.d.ts +5 -0
- package/lib/langium/integrity/integrity-service.d.ts.map +1 -1
- package/lib/langium/integrity/integrity-service.js +34 -1
- package/lib/langium/integrity/integrity-service.js.map +1 -1
- package/lib/langium/keys/containment.d.ts +64 -0
- package/lib/langium/keys/containment.d.ts.map +1 -0
- package/lib/langium/keys/containment.js +53 -0
- package/lib/langium/keys/containment.js.map +1 -0
- package/lib/langium/keys/index.d.ts +1 -0
- package/lib/langium/keys/index.d.ts.map +1 -1
- package/lib/langium/keys/index.js +1 -0
- package/lib/langium/keys/index.js.map +1 -1
- package/lib/langium/keys/name-based-key-provider.d.ts +4 -0
- package/lib/langium/keys/name-based-key-provider.d.ts.map +1 -1
- package/lib/langium/keys/name-based-key-provider.js +4 -0
- package/lib/langium/keys/name-based-key-provider.js.map +1 -1
- package/lib/langium/model-service/model-service.d.ts +103 -7
- package/lib/langium/model-service/model-service.d.ts.map +1 -1
- package/lib/langium/model-service/model-service.js +70 -89
- package/lib/langium/model-service/model-service.js.map +1 -1
- package/lib/langium/module.d.ts +82 -13
- package/lib/langium/module.d.ts.map +1 -1
- package/lib/langium/module.js +26 -12
- package/lib/langium/module.js.map +1 -1
- package/lib/langium/naming/name-provider.d.ts +10 -0
- package/lib/langium/naming/name-provider.d.ts.map +1 -1
- package/lib/langium/naming/name-provider.js.map +1 -1
- package/lib/langium/naming/name-separator-validation.d.ts +23 -0
- package/lib/langium/naming/name-separator-validation.d.ts.map +1 -1
- package/lib/langium/naming/name-separator-validation.js +30 -1
- package/lib/langium/naming/name-separator-validation.js.map +1 -1
- package/lib/langium/residency/cst-residency-service.d.ts +31 -9
- package/lib/langium/residency/cst-residency-service.d.ts.map +1 -1
- package/lib/langium/residency/cst-residency-service.js +13 -56
- package/lib/langium/residency/cst-residency-service.js.map +1 -1
- package/lib/langium/scope/hydranium-scope-provider.d.ts +32 -13
- package/lib/langium/scope/hydranium-scope-provider.d.ts.map +1 -1
- package/lib/langium/scope/hydranium-scope-provider.js +37 -20
- package/lib/langium/scope/hydranium-scope-provider.js.map +1 -1
- package/lib/langium/shared-services.d.ts +15 -2
- package/lib/langium/shared-services.d.ts.map +1 -1
- package/lib/langium/shared-services.js.map +1 -1
- package/lib/langium/transfer/transfer-encoder.d.ts +33 -2
- package/lib/langium/transfer/transfer-encoder.d.ts.map +1 -1
- package/lib/langium/transfer/transfer-encoder.js +14 -3
- package/lib/langium/transfer/transfer-encoder.js.map +1 -1
- package/lib/langium/validation/document-validator.d.ts +145 -6
- package/lib/langium/validation/document-validator.d.ts.map +1 -1
- package/lib/langium/validation/document-validator.js +211 -4
- package/lib/langium/validation/document-validator.js.map +1 -1
- package/lib/langium/workspace/document-uri-policy.d.ts +3 -4
- package/lib/langium/workspace/document-uri-policy.d.ts.map +1 -1
- package/lib/langium/workspace/document-uri-policy.js +3 -4
- package/lib/langium/workspace/document-uri-policy.js.map +1 -1
- package/lib/langium/workspace/hydranium-langium-document-factory.d.ts +25 -0
- package/lib/langium/workspace/hydranium-langium-document-factory.d.ts.map +1 -1
- package/lib/langium/workspace/hydranium-langium-document-factory.js +25 -0
- package/lib/langium/workspace/hydranium-langium-document-factory.js.map +1 -1
- package/lib/langium/workspace/hydranium-workspace-manager.d.ts +21 -1
- package/lib/langium/workspace/hydranium-workspace-manager.d.ts.map +1 -1
- package/lib/langium/workspace/hydranium-workspace-manager.js +28 -0
- package/lib/langium/workspace/hydranium-workspace-manager.js.map +1 -1
- package/lib/langium/workspace/in-memory-file-system-provider.d.ts +8 -0
- package/lib/langium/workspace/in-memory-file-system-provider.d.ts.map +1 -1
- package/lib/langium/workspace/in-memory-file-system-provider.js +11 -2
- package/lib/langium/workspace/in-memory-file-system-provider.js.map +1 -1
- package/lib/langium/workspace/initialize-workspace.d.ts +22 -2
- package/lib/langium/workspace/initialize-workspace.d.ts.map +1 -1
- package/lib/langium/workspace/initialize-workspace.js +13 -5
- package/lib/langium/workspace/initialize-workspace.js.map +1 -1
- package/lib/langium/workspace/langium-documents.d.ts +79 -17
- package/lib/langium/workspace/langium-documents.d.ts.map +1 -1
- package/lib/langium/workspace/langium-documents.js +83 -28
- package/lib/langium/workspace/langium-documents.js.map +1 -1
- package/lib/locale/index.d.ts +10 -0
- package/lib/locale/index.d.ts.map +1 -0
- package/lib/locale/index.js +10 -0
- package/lib/locale/index.js.map +1 -0
- package/lib/locale/server-locale.d.ts +73 -0
- package/lib/locale/server-locale.d.ts.map +1 -0
- package/lib/locale/server-locale.js +61 -0
- package/lib/locale/server-locale.js.map +1 -0
- package/lib/lsp/hydranium-document-update-handler.js +1 -1
- package/lib/lsp/hydranium-document-update-handler.js.map +1 -1
- package/lib/messages/carriers.d.ts +54 -0
- package/lib/messages/carriers.d.ts.map +1 -0
- package/lib/messages/carriers.js +62 -0
- package/lib/messages/carriers.js.map +1 -0
- package/lib/messages/index.d.ts +25 -0
- package/lib/messages/index.d.ts.map +1 -0
- package/lib/messages/index.js +25 -0
- package/lib/messages/index.js.map +1 -0
- package/lib/messages/renderer.d.ts +136 -0
- package/lib/messages/renderer.d.ts.map +1 -0
- package/lib/messages/renderer.js +159 -0
- package/lib/messages/renderer.js.map +1 -0
- package/lib/node/node-file-system-provider.d.ts.map +1 -1
- package/lib/node/node-file-system-provider.js +1 -40
- package/lib/node/node-file-system-provider.js.map +1 -1
- package/lib/node/profiling-run.js +1 -1
- package/lib/node/profiling-run.js.map +1 -1
- package/lib/node/rename-over-open-readers.d.ts +52 -0
- package/lib/node/rename-over-open-readers.d.ts.map +1 -0
- package/lib/node/rename-over-open-readers.js +66 -0
- package/lib/node/rename-over-open-readers.js.map +1 -0
- package/lib/testing/fake-document.d.ts +14 -3
- package/lib/testing/fake-document.d.ts.map +1 -1
- package/lib/testing/fake-document.js +18 -3
- package/lib/testing/fake-document.js.map +1 -1
- package/lib/testing/make-noop-shared-services.d.ts +14 -0
- package/lib/testing/make-noop-shared-services.d.ts.map +1 -1
- package/lib/testing/make-noop-shared-services.js +28 -2
- package/lib/testing/make-noop-shared-services.js.map +1 -1
- package/lib/testing/make-test-services.d.ts +31 -4
- package/lib/testing/make-test-services.d.ts.map +1 -1
- package/lib/testing/make-test-services.js +19 -3
- package/lib/testing/make-test-services.js.map +1 -1
- package/lib/testing/node/spawned-server.d.ts +14 -0
- package/lib/testing/node/spawned-server.d.ts.map +1 -1
- package/lib/testing/node/spawned-server.js +33 -1
- package/lib/testing/node/spawned-server.js.map +1 -1
- package/lib/testing/playwright/flaky-network-proxy.d.ts +76 -0
- package/lib/testing/playwright/flaky-network-proxy.d.ts.map +1 -0
- package/lib/testing/playwright/flaky-network-proxy.js +164 -0
- package/lib/testing/playwright/flaky-network-proxy.js.map +1 -0
- package/lib/testing/playwright/index.d.ts +1 -0
- package/lib/testing/playwright/index.d.ts.map +1 -1
- package/lib/testing/playwright/index.js +1 -0
- package/lib/testing/playwright/index.js.map +1 -1
- package/lib/testing/playwright/server-log-capture.d.ts +14 -4
- package/lib/testing/playwright/server-log-capture.d.ts.map +1 -1
- package/lib/testing/playwright/server-log-capture.js +21 -4
- package/lib/testing/playwright/server-log-capture.js.map +1 -1
- package/lib/testing/playwright/server-log-rename-reporter.d.ts.map +1 -1
- package/lib/testing/playwright/server-log-rename-reporter.js +10 -1
- package/lib/testing/playwright/server-log-rename-reporter.js.map +1 -1
- package/lib/testing/stub-ast-document-manager.d.ts +3 -4
- package/lib/testing/stub-ast-document-manager.d.ts.map +1 -1
- package/lib/testing/stub-ast-document-manager.js +2 -5
- package/lib/testing/stub-ast-document-manager.js.map +1 -1
- package/lib/testing/stub-document-builder.d.ts +8 -0
- package/lib/testing/stub-document-builder.d.ts.map +1 -1
- package/lib/testing/stub-document-builder.js +22 -3
- package/lib/testing/stub-document-builder.js.map +1 -1
- package/lib/testing/stub-model-service.d.ts +1 -1
- package/lib/testing/stub-model-service.d.ts.map +1 -1
- package/lib/testing/stub-model-service.js +2 -2
- package/lib/testing/stub-model-service.js.map +1 -1
- package/package.json +17 -8
- package/src/documents/ast-document-manager.ts +63 -15
- package/src/documents/hydranium-text-documents.ts +135 -54
- package/src/documents/language-client-text-shadow.ts +59 -11
- package/src/documents/self-save-registry.ts +52 -13
- package/src/index.ts +5 -0
- package/src/langium/ast-extension/ast-node-builder.ts +66 -22
- package/src/langium/bootstrap.ts +16 -9
- package/src/langium/config/configuration-provider.ts +96 -0
- package/src/langium/config/index.ts +1 -0
- package/src/langium/diagnostics/lsp-logger.ts +41 -6
- package/src/langium/document-builder/build-pipeline-integration.ts +14 -1
- package/src/langium/document-builder/build-session.ts +87 -0
- package/src/langium/document-builder/document-builder.ts +339 -11
- package/src/langium/document-builder/index.ts +1 -0
- package/src/langium/integration-services.ts +67 -6
- package/src/langium/integrity/integrity-service.ts +35 -1
- package/src/langium/keys/containment.ts +87 -0
- package/src/langium/keys/index.ts +1 -0
- package/src/langium/keys/name-based-key-provider.ts +4 -0
- package/src/langium/model-service/model-service.ts +145 -22
- package/src/langium/module.ts +104 -19
- package/src/langium/naming/name-provider.ts +10 -0
- package/src/langium/naming/name-separator-validation.ts +34 -5
- package/src/langium/residency/cst-residency-service.ts +36 -12
- package/src/langium/scope/hydranium-scope-provider.ts +40 -22
- package/src/langium/shared-services.ts +19 -2
- package/src/langium/transfer/transfer-encoder.ts +45 -3
- package/src/langium/validation/document-validator.ts +255 -8
- package/src/langium/workspace/document-uri-policy.ts +3 -4
- package/src/langium/workspace/hydranium-langium-document-factory.ts +34 -0
- package/src/langium/workspace/hydranium-workspace-manager.ts +30 -1
- package/src/langium/workspace/in-memory-file-system-provider.ts +13 -3
- package/src/langium/workspace/initialize-workspace.ts +34 -5
- package/src/langium/workspace/langium-documents.ts +106 -33
- package/src/locale/index.ts +10 -0
- package/src/locale/server-locale.ts +86 -0
- package/src/lsp/hydranium-document-update-handler.ts +1 -1
- package/src/messages/carriers.ts +78 -0
- package/src/messages/index.ts +27 -0
- package/src/messages/renderer.ts +204 -0
- package/src/node/node-file-system-provider.ts +1 -41
- package/src/node/profiling-run.ts +1 -1
- package/src/node/rename-over-open-readers.ts +78 -0
- package/src/testing/fake-document.ts +22 -4
- package/src/testing/make-noop-shared-services.ts +50 -2
- package/src/testing/make-test-services.ts +49 -7
- package/src/testing/node/spawned-server.ts +35 -1
- package/src/testing/playwright/flaky-network-proxy.ts +240 -0
- package/src/testing/playwright/index.ts +1 -0
- package/src/testing/playwright/server-log-capture.ts +24 -5
- package/src/testing/playwright/server-log-rename-reporter.ts +12 -1
- package/src/testing/stub-ast-document-manager.ts +5 -10
- package/src/testing/stub-document-builder.ts +32 -3
- package/src/testing/stub-model-service.ts +2 -2
|
@@ -34,6 +34,7 @@ function reraise(result) {
|
|
|
34
34
|
*/
|
|
35
35
|
export function makeStubDocumentBuilder() {
|
|
36
36
|
const phaseListeners = new Map();
|
|
37
|
+
const buildPhaseListeners = new Map();
|
|
37
38
|
const onUpdateListeners = [];
|
|
38
39
|
const gates = [];
|
|
39
40
|
const updateCalls = [];
|
|
@@ -95,6 +96,27 @@ export function makeStubDocumentBuilder() {
|
|
|
95
96
|
reraise(listener(changed, deleted));
|
|
96
97
|
}
|
|
97
98
|
},
|
|
99
|
+
onBuildPhase(state, listener) {
|
|
100
|
+
const list = buildPhaseListeners.get(state) ?? [];
|
|
101
|
+
list.push(listener);
|
|
102
|
+
buildPhaseListeners.set(state, list);
|
|
103
|
+
return Disposable.create(() => {
|
|
104
|
+
const idx = list.indexOf(listener);
|
|
105
|
+
if (idx >= 0) {
|
|
106
|
+
list.splice(idx, 1);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
},
|
|
110
|
+
fireBuildPhase(state, built, cancelToken) {
|
|
111
|
+
const token = cancelToken ??
|
|
112
|
+
{
|
|
113
|
+
isCancellationRequested: false,
|
|
114
|
+
onCancellationRequested: () => Disposable.create(() => undefined)
|
|
115
|
+
};
|
|
116
|
+
for (const listener of buildPhaseListeners.get(state) ?? []) {
|
|
117
|
+
reraise(listener(built, token));
|
|
118
|
+
}
|
|
119
|
+
},
|
|
98
120
|
gateNextWaitUntil() {
|
|
99
121
|
let release;
|
|
100
122
|
const entry = {
|
|
@@ -123,9 +145,6 @@ export function makeStubDocumentBuilder() {
|
|
|
123
145
|
build() {
|
|
124
146
|
return notSupported('build');
|
|
125
147
|
},
|
|
126
|
-
onBuildPhase() {
|
|
127
|
-
return notSupported('onBuildPhase');
|
|
128
|
-
},
|
|
129
148
|
resetToState() {
|
|
130
149
|
return notSupported('resetToState');
|
|
131
150
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stub-document-builder.js","sourceRoot":"","sources":["../../src/testing/stub-document-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;
|
|
1
|
+
{"version":3,"file":"stub-document-builder.js","sourceRoot":"","sources":["../../src/testing/stub-document-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
********************************************************************************/
|
|
9
9
|
import type { TransferDiagnostic, TransferElement } from '@hydranium/protocol';
|
|
10
10
|
import type { AstNode } from '@hydranium/langium';
|
|
11
|
-
import { ModelService, type ModelServiceOptions } from '../langium/model-service/model-service.js';
|
|
11
|
+
import { type ModelService, type ModelServiceOptions } from '../langium/model-service/model-service.js';
|
|
12
12
|
import type { ServerSharedServices } from '../langium/module.js';
|
|
13
13
|
/** The type of the model-service test double produced by {@link makeStubModelService}. */
|
|
14
14
|
export type StubModelService<TAst extends AstNode, TDiagnostic extends TransferDiagnostic = TransferDiagnostic, TTransfer extends TransferElement = TransferElement> = ModelService<TAst, TDiagnostic, TTransfer>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stub-model-service.d.ts","sourceRoot":"","sources":["../../src/testing/stub-model-service.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,
|
|
1
|
+
{"version":3,"file":"stub-model-service.d.ts","sourceRoot":"","sources":["../../src/testing/stub-model-service.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAuB,KAAK,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,2CAA2C,CAAC;AAC7H,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AA2BjE,0FAA0F;AAC1F,MAAM,MAAM,gBAAgB,CACzB,IAAI,SAAS,OAAO,EACpB,WAAW,SAAS,kBAAkB,GAAG,kBAAkB,EAC3D,SAAS,SAAS,eAAe,GAAG,eAAe,IAClD,YAAY,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;AAE/C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CACjC,IAAI,SAAS,OAAO,EACpB,WAAW,SAAS,kBAAkB,GAAG,kBAAkB,EAC3D,SAAS,SAAS,eAAe,GAAG,eAAe,EAEnD,QAAQ,EAAE,oBAAoB,EAC9B,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,KAAK,MAAM,EACnD,OAAO,CAAC,EAAE,mBAAmB,GAC7B,gBAAgB,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,CAAC,CAEhD"}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* SPDX-License-Identifier: MIT
|
|
8
8
|
********************************************************************************/
|
|
9
|
-
import {
|
|
9
|
+
import { DefaultModelService } from '../langium/model-service/model-service.js';
|
|
10
10
|
/**
|
|
11
11
|
* Implementation detail of {@link makeStubModelService}. A {@link ModelService}
|
|
12
12
|
* subclass that takes `serialize` as a constructor callback — the test stub
|
|
@@ -14,7 +14,7 @@ import { ModelService } from '../langium/model-service/model-service.js';
|
|
|
14
14
|
* path would fail. Construct it through the factory; the {@link StubModelService}
|
|
15
15
|
* type alias is the public type name.
|
|
16
16
|
*/
|
|
17
|
-
class StubModelServiceImpl extends
|
|
17
|
+
class StubModelServiceImpl extends DefaultModelService {
|
|
18
18
|
serializeFn;
|
|
19
19
|
constructor(services, serializeFn, options) {
|
|
20
20
|
super(services, options);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stub-model-service.js","sourceRoot":"","sources":["../../src/testing/stub-model-service.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAIlF,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"stub-model-service.js","sourceRoot":"","sources":["../../src/testing/stub-model-service.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAIlF,OAAO,EAAE,mBAAmB,EAA+C,MAAM,2CAA2C,CAAC;AAG7H;;;;;;GAMG;AACH,MAAM,oBAIJ,SAAQ,mBAAiD;IAGlC;IAFtB,YACG,QAA8B,EACX,WAAqD,EACxE,OAA6B;QAE7B,KAAK,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAHN,gBAAW,GAAX,WAAW,CAA0C;IAI3E,CAAC;IAEkB,SAAS,CAAC,GAAW,EAAE,IAAe;QACtD,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACtC,CAAC;CACH;AASD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,oBAAoB,CAKjC,QAA8B,EAC9B,SAAmD,EACnD,OAA6B;IAE7B,OAAO,IAAI,oBAAoB,CAA+B,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;AAC/F,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.60",
|
|
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",
|
|
@@ -72,6 +72,14 @@
|
|
|
72
72
|
"./lib/testing/playwright": {
|
|
73
73
|
"types": "./lib/testing/playwright/index.d.ts",
|
|
74
74
|
"default": "./lib/testing/playwright/index.js"
|
|
75
|
+
},
|
|
76
|
+
"./messages": {
|
|
77
|
+
"types": "./lib/messages/index.d.ts",
|
|
78
|
+
"default": "./lib/messages/index.js"
|
|
79
|
+
},
|
|
80
|
+
"./lib/messages": {
|
|
81
|
+
"types": "./lib/messages/index.d.ts",
|
|
82
|
+
"default": "./lib/messages/index.js"
|
|
75
83
|
}
|
|
76
84
|
},
|
|
77
85
|
"main": "lib/index.js",
|
|
@@ -96,8 +104,8 @@
|
|
|
96
104
|
"diff": "^5.2.0"
|
|
97
105
|
},
|
|
98
106
|
"devDependencies": {
|
|
99
|
-
"@hydranium/langium": "1.0.0-next.
|
|
100
|
-
"@hydranium/protocol": "1.0.0-next.
|
|
107
|
+
"@hydranium/langium": "1.0.0-next.60",
|
|
108
|
+
"@hydranium/protocol": "1.0.0-next.60",
|
|
101
109
|
"@playwright/test": "^1.40.0",
|
|
102
110
|
"@types/diff": "^5.2.0",
|
|
103
111
|
"rimraf": "^5.0.0",
|
|
@@ -109,12 +117,12 @@
|
|
|
109
117
|
"vscode-languageserver-types": "^3.17.5"
|
|
110
118
|
},
|
|
111
119
|
"peerDependencies": {
|
|
112
|
-
"@hydranium/langium": "1.0.0-next.
|
|
113
|
-
"@hydranium/protocol": "1.0.0-next.
|
|
120
|
+
"@hydranium/langium": "1.0.0-next.60",
|
|
121
|
+
"@hydranium/protocol": "1.0.0-next.60",
|
|
114
122
|
"@playwright/test": "^1.40.0",
|
|
115
|
-
"vscode-jsonrpc": "
|
|
116
|
-
"vscode-languageserver": "
|
|
117
|
-
"vscode-languageserver-protocol": "
|
|
123
|
+
"vscode-jsonrpc": "9.0.1",
|
|
124
|
+
"vscode-languageserver": "~10.0.1",
|
|
125
|
+
"vscode-languageserver-protocol": "~3.18.1",
|
|
118
126
|
"vscode-languageserver-textdocument": "^1.0.12",
|
|
119
127
|
"vscode-languageserver-types": "^3.17.5"
|
|
120
128
|
},
|
|
@@ -129,6 +137,7 @@
|
|
|
129
137
|
"publishConfig": {
|
|
130
138
|
"access": "public"
|
|
131
139
|
},
|
|
140
|
+
"//peerDependencies": "`vscode-jsonrpc` is EXACT rather than a range, because it is one link of an atomic chain with no independently movable link: `vscode-languageserver-protocol` depends on it at exactly 9.0.1, so any other value an adopter supplies is a SECOND physical copy rather than an upgrade. This wire stack breaks on copy identity rather than on structure — `ParameterStructures.auto` is a singleton compared by `===` in connection.js, so a request type built by one copy and sent over a connection owned by the other throws `Unknown parameter structure auto`. A caret or union range was rejected because npm then resolves a `vscode-jsonrpc@8.2.0` tree SILENTLY, with no diagnostic at all, and the failure surfaces only later at server init. Exact does not fail the install either — npm downgrades an unsatisfiable peer to a warning — but it is a NAMED ERESOLVE warning printing the required version beside the found one, and a hard error for anyone installing with `--strict-peer-deps`. It does NOT prevent a NESTED copy — `@eclipse-glsp/*` carries its own exact `vscode-jsonrpc@8.2.0` dependency and root `overrides` do not ship — so a consumer of the GLSP head must pin the chain in its own manifest, and docs/adopting/requirements.md carries the block to paste. This manifest declares the two links ABOVE the transport as well, and they carry `~` for the same reason: each admits exactly what `langium@4.3.1` itself admits, and a wider range reaches a `vscode-languageserver@9` / `vscode-languageserver-protocol@3.17.x` that depends on the 8.x transport, which is the same split one level up. `vscode-languageserver-types` and `vscode-languageserver-textdocument` are deliberately NOT narrowed: both declare zero dependencies and expose structural APIs, so a duplicate of either drags no transport in and no identity check reads it.",
|
|
132
141
|
"//prepack": "The publish guard, and it deliberately is NOT a `prepare`: npm runs a workspace `prepare` BEFORE the root `postinstall` that applies patches/vscode-jsonrpc+9.0.1.patch, so building there fails on a cold clone and npm rolls the entire install back. `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. It FAILS rather than rebuilds, because the rebuild is exactly the part that ordering defeats. 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.",
|
|
133
142
|
"//sideEffects": "NOT `false`: two barrels do work at module load that their re-exports do not account for, and a bundler skips an unflagged re-export barrel outright. `node/index.js` calls `installNodeLogFileSink()` and `installNodeWriteLockScope()`, which is how a Node host gets the log file-tee and write-lock reentrancy detection merely by importing `@hydranium/core/node`. `util/index.js` carries a bare `import '@hydranium/langium'` so the `UriUtils` namespace augmentation stays loaded for anything importing from here. Both failures are runtime-only and silent — a missing log file, a `UriUtils.toUri` that is `undefined`."
|
|
134
143
|
}
|
|
@@ -166,6 +166,51 @@ export type AstDocumentSavedEvent<TAst extends AstNode, TDiagnostic> = TransferS
|
|
|
166
166
|
/** Construction options for {@link AstDocumentManager}. */
|
|
167
167
|
export type AstDocumentManagerOptions = LogNameOptions;
|
|
168
168
|
|
|
169
|
+
/**
|
|
170
|
+
* The document slot the model server and the integrity service talk to:
|
|
171
|
+
* open/close/update/save plus the AST-typed event streams, with the LSP
|
|
172
|
+
* plumbing hidden.
|
|
173
|
+
*
|
|
174
|
+
* Generic over `<TAst extends AstNode, TDiagnostic>` so each consumer projects
|
|
175
|
+
* its own AST root type and diagnostic shape into the emitted
|
|
176
|
+
* {@link AstDocument} envelopes.
|
|
177
|
+
*
|
|
178
|
+
* **URI contract.** Every URI-accepting member takes a URI in *any* spelling
|
|
179
|
+
* (canonical, symlinked, `..`/case-divergent) and canonicalizes internally
|
|
180
|
+
* through the {@link DocumentUriPolicy}, so a caller never has to canonicalize
|
|
181
|
+
* first and an implementation may not require it.
|
|
182
|
+
*/
|
|
183
|
+
export interface AstDocumentManager<TAst extends AstNode, TDiagnostic = unknown> {
|
|
184
|
+
open(args: OpenModelArgs): Promise<Disposable>;
|
|
185
|
+
close(args: CloseModelArgs): Promise<void>;
|
|
186
|
+
isOpen(uri: string): boolean;
|
|
187
|
+
|
|
188
|
+
/** Apply `text` as `clientId`'s edit. Resolves to the resulting text-document version. */
|
|
189
|
+
update(uri: string, text: string, clientId: string): Promise<number>;
|
|
190
|
+
save(uri: string, clientId: string): Promise<void>;
|
|
191
|
+
|
|
192
|
+
onUpdate(uri: string, listener: (event: AstDocumentUpdatedEvent<TAst, TDiagnostic>) => void): Disposable;
|
|
193
|
+
onSave(uri: string, listener: (event: AstDocumentSavedEvent<TAst, TDiagnostic>) => void | Promise<void>): Disposable;
|
|
194
|
+
onClientClosed(uri: string, clientId: string, listener: () => void): Disposable;
|
|
195
|
+
|
|
196
|
+
getDocument(uri: string): LangiumDocument | undefined;
|
|
197
|
+
|
|
198
|
+
/** Client id that authored the document's current version, or `undefined` for a framework-internal build. */
|
|
199
|
+
getAuthor(document: LangiumDocument): string | undefined;
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Whether `uri` is one of the URIs the most recent build request named, as
|
|
203
|
+
* opposed to a document that build swept in as a dependent. Deletions are
|
|
204
|
+
* excluded: they never reach this layer, since a deleted document is
|
|
205
|
+
* removed before the build set is computed.
|
|
206
|
+
*
|
|
207
|
+
* The answer refers to the latest request, which may still be building, and
|
|
208
|
+
* it is retained between builds — so outside a build it describes whichever
|
|
209
|
+
* one ran last.
|
|
210
|
+
*/
|
|
211
|
+
isTriggeringEdit(uri: string): boolean;
|
|
212
|
+
}
|
|
213
|
+
|
|
169
214
|
/**
|
|
170
215
|
* Higher-level facade over {@link HydraniumTextDocuments} that speaks the
|
|
171
216
|
* model-server protocol (open/close/update/save with the transfer-model event
|
|
@@ -186,7 +231,7 @@ export type AstDocumentManagerOptions = LogNameOptions;
|
|
|
186
231
|
* resolution (the egress `applyEditToLanguageClient`) stay on
|
|
187
232
|
* {@link HydraniumTextDocuments}, their owner.
|
|
188
233
|
*/
|
|
189
|
-
export class
|
|
234
|
+
export class DefaultAstDocumentManager<TAst extends AstNode, TDiagnostic = unknown> implements AstDocumentManager<TAst, TDiagnostic> {
|
|
190
235
|
protected lastUpdate?: UpdateInfo;
|
|
191
236
|
|
|
192
237
|
protected readonly textDocuments: HydraniumTextDocuments<TextDocument>;
|
|
@@ -311,11 +356,12 @@ export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = un
|
|
|
311
356
|
const event: TransferUpdatedEvent<AstDocument<TAst, TDiagnostic>> = {
|
|
312
357
|
document: this.toAstDocument(document),
|
|
313
358
|
sourceClientId,
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
359
|
+
// No `'deleted'` arm: `DocumentBuilder.update` drops a deleted
|
|
360
|
+
// document from `LangiumDocuments` before deriving the rebuild set
|
|
361
|
+
// from it, so a deleted URI is never built and never reaches this
|
|
362
|
+
// phase listener. A subscriber needing deletions has to be told on
|
|
363
|
+
// a channel that does not require a built document.
|
|
364
|
+
reason: this.lastUpdate?.changed.some(changed => UriUtils.equals(changed, document.uri)) ? 'changed' : 'rebuilt'
|
|
319
365
|
};
|
|
320
366
|
this.tracer.with(uri).trace(`emitUpdate start: source=${sourceClientId}, reason=${event.reason}`);
|
|
321
367
|
listener(event);
|
|
@@ -334,7 +380,7 @@ export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = un
|
|
|
334
380
|
* concrete value (the `onUpdate` event's `sourceClientId`, the data-server's
|
|
335
381
|
* `resolveSourceClientId`).
|
|
336
382
|
*/
|
|
337
|
-
getAuthor(document: LangiumDocument
|
|
383
|
+
getAuthor(document: LangiumDocument): string | undefined {
|
|
338
384
|
return this.textDocuments.getAuthor(document.textDocument.uri, document.textDocument.version);
|
|
339
385
|
}
|
|
340
386
|
|
|
@@ -355,10 +401,17 @@ export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = un
|
|
|
355
401
|
// transiently breaks cross-document linking mid-rebuild (a dependent briefly
|
|
356
402
|
// seeing an `extends`/`type` reference unresolved). And because the constructor
|
|
357
403
|
// wires `onDidOpen -> this.open`, it would fire a second, identical rebuild on
|
|
358
|
-
// every first open.
|
|
404
|
+
// every first open.
|
|
405
|
+
//
|
|
406
|
+
// So an already-open `open()` records the attaching client's hold and nothing
|
|
407
|
+
// else. The hold is per `(uri, clientId)` and the last-close revert counts down
|
|
408
|
+
// to it, so skipping it lets the first holder's close tear down a document
|
|
409
|
+
// another client is still reading.
|
|
359
410
|
if (!this.isOpen(args.uri)) {
|
|
360
411
|
const textDocument = await this.createDocumentFromTextOrFileSystem(args.uri, args.languageId, args.version, args.text);
|
|
361
412
|
this.textDocuments.notifyDidOpenTextDocument({ textDocument }, args.clientId);
|
|
413
|
+
} else {
|
|
414
|
+
this.textDocuments.attachClient(args.uri, args.clientId);
|
|
362
415
|
}
|
|
363
416
|
return Disposable.create(() => this.close(args));
|
|
364
417
|
}
|
|
@@ -414,8 +467,7 @@ export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = un
|
|
|
414
467
|
return !!this.textDocuments.get(uri);
|
|
415
468
|
}
|
|
416
469
|
|
|
417
|
-
|
|
418
|
-
isDirectChange(uri: string): boolean {
|
|
470
|
+
isTriggeringEdit(uri: string): boolean {
|
|
419
471
|
const canonical = this.uriPolicy.canonicalUri(uri);
|
|
420
472
|
return this.lastUpdate?.changed.some(changed => this.uriPolicy.canonicalUri(changed) === canonical) ?? false;
|
|
421
473
|
}
|
|
@@ -437,11 +489,7 @@ export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = un
|
|
|
437
489
|
version = 0,
|
|
438
490
|
text?: string
|
|
439
491
|
): Promise<TextDocumentItem> {
|
|
440
|
-
return { uri, languageId, version, text: text ?? (await this.readFile(uri)) };
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
async readFile(uri: string): Promise<string> {
|
|
444
|
-
return this.fileSystemProvider.readFile(UriUtils.toUri(uri));
|
|
492
|
+
return { uri, languageId, version, text: text ?? (await this.fileSystemProvider.readFile(UriUtils.toUri(uri))) };
|
|
445
493
|
}
|
|
446
494
|
|
|
447
495
|
/**
|
|
@@ -165,15 +165,15 @@ interface ConnectionWithTextDocumentSync {
|
|
|
165
165
|
*/
|
|
166
166
|
interface PendingPush {
|
|
167
167
|
/**
|
|
168
|
-
* The text the client held BEFORE this push
|
|
169
|
-
*
|
|
170
|
-
*
|
|
168
|
+
* The text the client held BEFORE this push, and therefore the text its
|
|
169
|
+
* echo addresses with its ranges. Wider than the baseline the push's edits
|
|
170
|
+
* were diffed against: a full replace is sent with no diff baseline and
|
|
171
|
+
* still lands on a buffer the echo is keyed to.
|
|
171
172
|
*
|
|
172
|
-
* `undefined` when
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
* application is position-independent.
|
|
173
|
+
* `undefined` only when that buffer is unknown — the client never declared
|
|
174
|
+
* one, or a rejection invalidated what was tracked. The echo is then
|
|
175
|
+
* reconstructed against the synced text, which is sound only for a
|
|
176
|
+
* position-independent (full-text) change.
|
|
177
177
|
*/
|
|
178
178
|
readonly before: string | undefined;
|
|
179
179
|
/** {@link contentHash} of the text this push moves the client to. */
|
|
@@ -182,16 +182,16 @@ interface PendingPush {
|
|
|
182
182
|
|
|
183
183
|
/**
|
|
184
184
|
* What an incoming language-client change turns out to be once reconstructed
|
|
185
|
-
* against the
|
|
185
|
+
* against the buffer its ranges address — the return of
|
|
186
186
|
* {@link HydraniumTextDocuments.classifyLanguageClientChange}.
|
|
187
187
|
*/
|
|
188
188
|
type LanguageClientChangeOrigin =
|
|
189
189
|
/** The client is reporting a text we pushed it. The synced document is already there. */
|
|
190
190
|
| { readonly kind: 'echo' }
|
|
191
191
|
/**
|
|
192
|
-
* The client's buffer
|
|
193
|
-
* a
|
|
194
|
-
* reconstructed text is what it now holds, and is authoritative.
|
|
192
|
+
* The client's buffer holds a text we did not push it — a keystroke that
|
|
193
|
+
* raced a push, or an edit to a buffer the store has already been written
|
|
194
|
+
* past. The reconstructed text is what it now holds, and is authoritative.
|
|
195
195
|
*/
|
|
196
196
|
| { readonly kind: 'divergent'; readonly text: string };
|
|
197
197
|
|
|
@@ -471,15 +471,16 @@ export class HydraniumTextDocuments<T extends TextDocument = TextDocument> exten
|
|
|
471
471
|
}
|
|
472
472
|
record.clientVersions.set(clientId, td.version);
|
|
473
473
|
|
|
474
|
-
// A language-client change
|
|
475
|
-
//
|
|
476
|
-
//
|
|
474
|
+
// A language-client change is keyed to the buffer that client holds,
|
|
475
|
+
// which is the synced text only while the two agree — an authored
|
|
476
|
+
// write advances the synced text without the client knowing, and a
|
|
477
|
+
// push in flight moves the client without the store knowing.
|
|
477
478
|
// Resolve which it is, and against what, before touching anything.
|
|
478
|
-
const
|
|
479
|
+
const origin =
|
|
479
480
|
clientId === LANGUAGE_CLIENT_ID
|
|
480
481
|
? this.classifyLanguageClientChange(this.toLanguageClientUri(td.uri), document, changes)
|
|
481
482
|
: undefined;
|
|
482
|
-
if (
|
|
483
|
+
if (origin?.kind === 'echo') {
|
|
483
484
|
// The client is reporting a text we pushed it, so the synced
|
|
484
485
|
// document is ALREADY there and the changes must not be applied a
|
|
485
486
|
// second time. Nothing is minted and no rebuild fires. The
|
|
@@ -498,12 +499,12 @@ export class HydraniumTextDocuments<T extends TextDocument = TextDocument> exten
|
|
|
498
499
|
// apply at a tentative +1 and roll the version back on an identical
|
|
499
500
|
// result (an empty-changes update only re-stamps the version).
|
|
500
501
|
//
|
|
501
|
-
// A divergent
|
|
502
|
-
//
|
|
503
|
-
//
|
|
502
|
+
// A divergent change is applied as its RECONSTRUCTED text rather than
|
|
503
|
+
// as its own ranges: those ranges address the client's own buffer, so
|
|
504
|
+
// applying them here would splice the wrong lines.
|
|
504
505
|
const previousText = document.getText();
|
|
505
506
|
const sharedVersion = document.version;
|
|
506
|
-
document = this.configuration.update(document,
|
|
507
|
+
document = this.configuration.update(document, origin === undefined ? changes : [{ text: origin.text }], sharedVersion + 1);
|
|
507
508
|
const changed = document.getText() !== previousText;
|
|
508
509
|
if (!changed) {
|
|
509
510
|
document = this.configuration.update(document, [], sharedVersion);
|
|
@@ -644,18 +645,20 @@ export class HydraniumTextDocuments<T extends TextDocument = TextDocument> exten
|
|
|
644
645
|
if (this.isOpenInClient(uri, clientId)) {
|
|
645
646
|
// Already open for this client under this canonical identity. If this is a
|
|
646
647
|
// NEW client-facing URI for the same file (a second tab reached via a
|
|
647
|
-
// divergent path, e.g. a symlink and its real path), record it
|
|
648
|
-
//
|
|
649
|
-
//
|
|
648
|
+
// divergent path, e.g. a symlink and its real path), record it so outbound
|
|
649
|
+
// edits reach this tab too — but do NOT re-fire open/rebuild; the document
|
|
650
|
+
// is already live.
|
|
650
651
|
if (clientId === LANGUAGE_CLIENT_ID) {
|
|
651
652
|
const clientFacing = this.toLanguageClientUri(td.uri);
|
|
652
653
|
const record = this.__documents.get(uri);
|
|
653
654
|
if (record && !record.languageClientUris?.has(clientFacing)) {
|
|
654
655
|
(record.languageClientUris ??= new Set<LanguageClientUri>()).add(clientFacing);
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
656
|
+
// This tab's own buffer, NOT the synced text: a second tab is a second
|
|
657
|
+
// client model, read from disk, so a server-authored write already
|
|
658
|
+
// applied to the first tab leaves it BEHIND the synced document. Keying
|
|
659
|
+
// a diff to the synced text here addresses lines this tab does not have
|
|
660
|
+
// and drops content it does.
|
|
661
|
+
this.__shadow.setOpenedText(clientFacing, td.text);
|
|
659
662
|
}
|
|
660
663
|
}
|
|
661
664
|
return;
|
|
@@ -694,22 +697,77 @@ export class HydraniumTextDocuments<T extends TextDocument = TextDocument> exten
|
|
|
694
697
|
// Baseline the shadow to what Monaco just opened so the next outbound
|
|
695
698
|
// applyEditToLanguageClient diffs against the right starting point. Keyed by the
|
|
696
699
|
// language-client URI (what Monaco holds), not the canonical document key.
|
|
697
|
-
|
|
700
|
+
//
|
|
701
|
+
// The CLIENT's declared text, never the synced document: staged content
|
|
702
|
+
// consumed above leaves the two different, and a baseline asserting the
|
|
703
|
+
// client already holds the staged text suppresses the one sync that would
|
|
704
|
+
// deliver it. Skipped entirely when a push is already outstanding for this
|
|
705
|
+
// URI — an `applyEdit` to a closed file has the client open from disk and
|
|
706
|
+
// apply afterwards, so that shadow records what it is about to hold and
|
|
707
|
+
// disk text would key the next diff to a buffer nobody has.
|
|
708
|
+
const clientFacing = this.toLanguageClientUri(td.uri);
|
|
709
|
+
if (!this.__shadow.isTracked(clientFacing)) {
|
|
710
|
+
this.__shadow.set(clientFacing, td.text);
|
|
711
|
+
}
|
|
698
712
|
}
|
|
699
713
|
const toFire = Object.freeze({ document, clientId });
|
|
700
714
|
this.__onDidOpen.fire(toFire);
|
|
701
715
|
this.__onDidChangeContent.fire(toFire);
|
|
702
716
|
} else {
|
|
703
717
|
// An additional client attaches to a document already open by another client.
|
|
704
|
-
this.
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
718
|
+
this.logClientJoined(uri, clientId, document.version, existingClients);
|
|
719
|
+
if (clientId === LANGUAGE_CLIENT_ID) {
|
|
720
|
+
// Monaco's own buffer, which on this path is NOT the synced text — another
|
|
721
|
+
// client opened the document and may already have changed it. Recorded as
|
|
722
|
+
// an equality-only baseline (never a diff one, see `setOpenedText`) so the
|
|
723
|
+
// refresh below does not push a full replace of content Monaco already
|
|
724
|
+
// holds, which would dirty the file on open.
|
|
725
|
+
this.__shadow.setOpenedText(this.toLanguageClientUri(td.uri), td.text);
|
|
726
|
+
}
|
|
709
727
|
this.refreshContent(uri, clientId);
|
|
710
728
|
}
|
|
711
729
|
}
|
|
712
730
|
|
|
731
|
+
/**
|
|
732
|
+
* Record `clientId` as an additional holder of a document another client
|
|
733
|
+
* already has open.
|
|
734
|
+
*
|
|
735
|
+
* Unlike the attach branch of {@link notifyDidOpenTextDocument} this does
|
|
736
|
+
* not refresh. That branch re-renders an attaching TEXTUAL view; a client
|
|
737
|
+
* reaching a document through a non-textual route has nothing to re-render,
|
|
738
|
+
* and refreshing per attach turns each into a Langium rebuild and dependent
|
|
739
|
+
* relink cascade.
|
|
740
|
+
*
|
|
741
|
+
* The staleness guard baselines at the SYNCED version, not a declared buffer
|
|
742
|
+
* version, because a client arriving this way holds no buffer of its own.
|
|
743
|
+
* Unifying the two routes therefore rebaselines a textual client's guard to a
|
|
744
|
+
* version it never declared.
|
|
745
|
+
*
|
|
746
|
+
* Returns whether a hold was added — `false` when `uri` is not open, or
|
|
747
|
+
* `clientId` already holds it.
|
|
748
|
+
*/
|
|
749
|
+
attachClient(uri: DocumentUri, clientId: string): boolean {
|
|
750
|
+
const key = this.documentKey(uri);
|
|
751
|
+
const document = this.__syncedDocuments.get(key);
|
|
752
|
+
if (!document || this.isOpenInClient(key, clientId)) {
|
|
753
|
+
return false;
|
|
754
|
+
}
|
|
755
|
+
const record = this.trackingFor(key);
|
|
756
|
+
const existingClients = [...record.clients];
|
|
757
|
+
record.clients.add(clientId);
|
|
758
|
+
record.clientVersions.set(clientId, document.version);
|
|
759
|
+
this.logClientJoined(key, clientId, document.version, existingClients);
|
|
760
|
+
return true;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
protected logClientJoined(uri: DocumentUri, clientId: string, version: number, existingClients: readonly string[]): void {
|
|
764
|
+
this.log(
|
|
765
|
+
uri,
|
|
766
|
+
`Attach client: ${clientId} joined existing document (version ${version}, ` +
|
|
767
|
+
`now open in: ${[...existingClients, clientId].join(', ')})`
|
|
768
|
+
);
|
|
769
|
+
}
|
|
770
|
+
|
|
713
771
|
refreshContent(uri: DocumentUri, clientId: string): void {
|
|
714
772
|
const syncedDocument = this.__syncedDocuments.get(this.documentKey(uri));
|
|
715
773
|
if (syncedDocument) {
|
|
@@ -967,10 +1025,11 @@ export class HydraniumTextDocuments<T extends TextDocument = TextDocument> exten
|
|
|
967
1025
|
const targets: Iterable<LanguageClientUri> = recorded && recorded.size > 0 ? recorded : [this.toLanguageClientUri(uri)];
|
|
968
1026
|
let lastResult: ApplyWorkspaceEditResult | undefined;
|
|
969
1027
|
for (const targetUri of targets) {
|
|
970
|
-
// Read BEFORE computeEdits, which overwrites
|
|
971
|
-
//
|
|
972
|
-
// echo of
|
|
973
|
-
|
|
1028
|
+
// Read BEFORE computeEdits, which overwrites the baseline and drops
|
|
1029
|
+
// the opened snapshot. This is the text the client holds, and
|
|
1030
|
+
// therefore the only text its echo of this push can be reconstructed
|
|
1031
|
+
// against — whether or not the push below is keyed to it.
|
|
1032
|
+
const before = this.__shadow.clientText(targetUri);
|
|
974
1033
|
const edits = this.__shadow.computeEdits(targetUri, newText);
|
|
975
1034
|
if (edits.length === 0) {
|
|
976
1035
|
continue;
|
|
@@ -985,9 +1044,20 @@ export class HydraniumTextDocuments<T extends TextDocument = TextDocument> exten
|
|
|
985
1044
|
// it is exactly what the caller retries with after a rejection, so
|
|
986
1045
|
// gating it there would refuse the recovery too.
|
|
987
1046
|
const version = isFullReplace(edits) ? UNKNOWN_CLIENT_VERSION : this.languageClientVersion(uri);
|
|
1047
|
+
// A full `ApplyWorkspaceEditParams`, `edit` and all — NOT a bare
|
|
1048
|
+
// `WorkspaceEdit` with a `label` beside it. `applyEdit` takes
|
|
1049
|
+
// `ApplyWorkspaceEditParams | WorkspaceEdit` and discriminates on
|
|
1050
|
+
// `!!value.edit`, so `{ label, documentChanges }` is wrapped as
|
|
1051
|
+
// `{ edit: { label, documentChanges } }` — putting the label inside
|
|
1052
|
+
// the edit, where LSP defines no such field and no client reads it.
|
|
1053
|
+
// The union is also what hides it at compile time: excess-property
|
|
1054
|
+
// checking admits a property present in EITHER member, so an object
|
|
1055
|
+
// matching neither type-checks against the union.
|
|
988
1056
|
const result = await connection.workspace.applyEdit({
|
|
989
1057
|
label: options?.label,
|
|
990
|
-
|
|
1058
|
+
edit: {
|
|
1059
|
+
documentChanges: [TextDocumentEdit.create(OptionalVersionedTextDocumentIdentifier.create(targetUri, version), edits)]
|
|
1060
|
+
}
|
|
991
1061
|
});
|
|
992
1062
|
if (result && result.applied === false) {
|
|
993
1063
|
this.__shadow.invalidate(targetUri);
|
|
@@ -1043,12 +1113,17 @@ export class HydraniumTextDocuments<T extends TextDocument = TextDocument> exten
|
|
|
1043
1113
|
|
|
1044
1114
|
/**
|
|
1045
1115
|
* Decide what an incoming language-client change actually is, by
|
|
1046
|
-
* reconstructing the client's resulting buffer against the
|
|
1047
|
-
* in flight for
|
|
1116
|
+
* reconstructing the client's resulting buffer against the text its ranges
|
|
1117
|
+
* address — the pre-push buffer of the OLDEST push still in flight for
|
|
1118
|
+
* `clientFacing`, else whatever that client is believed to hold.
|
|
1048
1119
|
*
|
|
1049
|
-
* `undefined` when
|
|
1050
|
-
*
|
|
1051
|
-
*
|
|
1120
|
+
* `undefined` when the client's ranges address the synced text itself —
|
|
1121
|
+
* nothing in flight, and no evidence the client holds anything else. That
|
|
1122
|
+
* is the ordinary path, and the caller then applies the ranges directly.
|
|
1123
|
+
* The two texts part company without a push in flight whenever a client
|
|
1124
|
+
* attaches to a document another client has already written: it opened
|
|
1125
|
+
* from disk, so applying its ranges to the synced text splices lines they
|
|
1126
|
+
* never addressed.
|
|
1052
1127
|
*
|
|
1053
1128
|
* **Why the oldest, and why reconstruct at all.** The client applies our
|
|
1054
1129
|
* pushes in order and echoes each against the buffer it held before that
|
|
@@ -1079,22 +1154,28 @@ export class HydraniumTextDocuments<T extends TextDocument = TextDocument> exten
|
|
|
1079
1154
|
document: T,
|
|
1080
1155
|
changes: TextDocumentContentChangeEvent[]
|
|
1081
1156
|
): LanguageClientChangeOrigin | undefined {
|
|
1082
|
-
const
|
|
1083
|
-
|
|
1157
|
+
const queued = this.__pendingPushes.get(clientFacing);
|
|
1158
|
+
const pending = queued?.length ? queued : undefined;
|
|
1159
|
+
// The text the client's ranges address: the buffer it held before the
|
|
1160
|
+
// oldest push still in flight, else the buffer it is believed to hold.
|
|
1161
|
+
const clientText = pending?.[0].before ?? this.__shadow.clientText(clientFacing);
|
|
1162
|
+
if (pending === undefined && (clientText === undefined || clientText === document.getText())) {
|
|
1084
1163
|
return undefined;
|
|
1085
1164
|
}
|
|
1086
1165
|
// Through the configured factories, not `TextDocument` directly, so an
|
|
1087
1166
|
// adopter's custom text-document type governs how the ranges are applied
|
|
1088
1167
|
// here exactly as it does on the synced document.
|
|
1089
|
-
const probe = this.create(clientFacing, document.languageId, 0,
|
|
1090
|
-
const
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1168
|
+
const probe = this.create(clientFacing, document.languageId, 0, clientText ?? document.getText());
|
|
1169
|
+
const reconstructed = this.update(probe, changes, 0).getText();
|
|
1170
|
+
if (pending !== undefined) {
|
|
1171
|
+
const matchIndex = pending.findIndex(push => push.afterHash === contentHash(reconstructed));
|
|
1172
|
+
if (matchIndex >= 0) {
|
|
1173
|
+
pending.splice(0, matchIndex + 1);
|
|
1174
|
+
return { kind: 'echo' };
|
|
1175
|
+
}
|
|
1176
|
+
pending.length = 0;
|
|
1095
1177
|
}
|
|
1096
|
-
|
|
1097
|
-
return { kind: 'divergent', text: clientText };
|
|
1178
|
+
return { kind: 'divergent', text: reconstructed };
|
|
1098
1179
|
}
|
|
1099
1180
|
|
|
1100
1181
|
/**
|