@hydranium/core 1.0.0-next.11 → 1.0.0-next.112
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 +75 -16
- package/lib/documents/ast-document-manager.d.ts.map +1 -1
- package/lib/documents/ast-document-manager.js +57 -19
- package/lib/documents/ast-document-manager.js.map +1 -1
- package/lib/documents/client-ids.d.ts +5 -19
- package/lib/documents/client-ids.d.ts.map +1 -1
- package/lib/documents/client-ids.js +5 -19
- package/lib/documents/client-ids.js.map +1 -1
- package/lib/documents/hydranium-text-documents.d.ts +132 -42
- package/lib/documents/hydranium-text-documents.d.ts.map +1 -1
- package/lib/documents/hydranium-text-documents.js +199 -57
- 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 +3 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +6 -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 +81 -0
- package/lib/langium/config/configuration-provider.d.ts.map +1 -0
- package/lib/langium/config/configuration-provider.js +112 -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 +21 -1
- package/lib/langium/document-builder/build-pipeline-integration.d.ts.map +1 -1
- package/lib/langium/document-builder/build-pipeline-integration.js +32 -5
- 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 +16 -0
- package/lib/langium/integrity/integrity-service.d.ts.map +1 -1
- package/lib/langium/integrity/integrity-service.js +110 -2
- 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/language-module.d.ts +25 -0
- package/lib/langium/language-module.d.ts.map +1 -1
- package/lib/langium/language-module.js +14 -0
- package/lib/langium/language-module.js.map +1 -1
- package/lib/langium/model-service/model-service.d.ts +161 -10
- package/lib/langium/model-service/model-service.d.ts.map +1 -1
- package/lib/langium/model-service/model-service.js +176 -97
- package/lib/langium/model-service/model-service.js.map +1 -1
- package/lib/langium/module.d.ts +84 -15
- 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 +25 -4
- package/lib/langium/naming/name-provider.d.ts.map +1 -1
- package/lib/langium/naming/name-provider.js +2 -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 -11
- 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 +48 -13
- package/lib/langium/scope/hydranium-scope-provider.d.ts.map +1 -1
- package/lib/langium/scope/hydranium-scope-provider.js +56 -20
- package/lib/langium/scope/hydranium-scope-provider.js.map +1 -1
- package/lib/langium/serialization/abstract-serializer.d.ts +11 -20
- package/lib/langium/serialization/abstract-serializer.d.ts.map +1 -1
- package/lib/langium/serialization/abstract-serializer.js +12 -21
- package/lib/langium/serialization/abstract-serializer.js.map +1 -1
- package/lib/langium/service-registry.d.ts +15 -1
- package/lib/langium/service-registry.d.ts.map +1 -1
- package/lib/langium/service-registry.js +16 -0
- package/lib/langium/service-registry.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 +60 -17
- package/lib/langium/transfer/transfer-encoder.d.ts.map +1 -1
- package/lib/langium/transfer/transfer-encoder.js +38 -16
- package/lib/langium/transfer/transfer-encoder.js.map +1 -1
- package/lib/langium/trivia/comment-preserver.d.ts +423 -0
- package/lib/langium/trivia/comment-preserver.d.ts.map +1 -0
- package/lib/langium/trivia/comment-preserver.js +906 -0
- package/lib/langium/trivia/comment-preserver.js.map +1 -0
- package/lib/langium/trivia/document-ending-preserver.d.ts +43 -0
- package/lib/langium/trivia/document-ending-preserver.d.ts.map +1 -0
- package/lib/langium/trivia/document-ending-preserver.js +48 -0
- package/lib/langium/trivia/document-ending-preserver.js.map +1 -0
- package/lib/langium/trivia/index.d.ts +14 -0
- package/lib/langium/trivia/index.d.ts.map +1 -0
- package/lib/langium/trivia/index.js +14 -0
- package/lib/langium/trivia/index.js.map +1 -0
- package/lib/langium/trivia/trivia-contribution.d.ts +37 -0
- package/lib/langium/trivia/trivia-contribution.d.ts.map +1 -0
- package/lib/langium/trivia/trivia-contribution.js +10 -0
- package/lib/langium/trivia/trivia-contribution.js.map +1 -0
- package/lib/langium/trivia/trivia-preserver.d.ts +50 -0
- package/lib/langium/trivia/trivia-preserver.d.ts.map +1 -0
- package/lib/langium/trivia/trivia-preserver.js +10 -0
- package/lib/langium/trivia/trivia-preserver.js.map +1 -0
- package/lib/langium/trivia/trivia-service.d.ts +70 -0
- package/lib/langium/trivia/trivia-service.d.ts.map +1 -0
- package/lib/langium/trivia/trivia-service.js +56 -0
- package/lib/langium/trivia/trivia-service.js.map +1 -0
- package/lib/langium/validation/document-validator.d.ts +294 -10
- package/lib/langium/validation/document-validator.d.ts.map +1 -1
- package/lib/langium/validation/document-validator.js +448 -5
- 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/file-system-provider.d.ts +9 -1
- package/lib/langium/workspace/file-system-provider.d.ts.map +1 -1
- package/lib/langium/workspace/file-system-provider.js +40 -7
- package/lib/langium/workspace/file-system-provider.js.map +1 -1
- package/lib/langium/workspace/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 +23 -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 +47 -9
- package/lib/langium/workspace/in-memory-file-system-provider.js.map +1 -1
- package/lib/langium/workspace/initialize-workspace.d.ts +23 -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/langium/workspace/virtual-document.d.ts +18 -3
- package/lib/langium/workspace/virtual-document.d.ts.map +1 -1
- package/lib/langium/workspace/virtual-document.js +19 -2
- package/lib/langium/workspace/virtual-document.js.map +1 -1
- package/lib/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/completion/hydranium-completion-provider.d.ts +44 -2
- package/lib/lsp/completion/hydranium-completion-provider.d.ts.map +1 -1
- package/lib/lsp/completion/hydranium-completion-provider.js +68 -0
- package/lib/lsp/completion/hydranium-completion-provider.js.map +1 -1
- package/lib/lsp/connection-features.d.ts +23 -0
- package/lib/lsp/connection-features.d.ts.map +1 -0
- package/lib/lsp/connection-features.js +60 -0
- package/lib/lsp/connection-features.js.map +1 -0
- package/lib/lsp/diagnostics-connection.d.ts +27 -0
- package/lib/lsp/diagnostics-connection.d.ts.map +1 -0
- package/lib/lsp/diagnostics-connection.js +53 -0
- package/lib/lsp/diagnostics-connection.js.map +1 -0
- package/lib/lsp/hydranium-document-update-handler.d.ts.map +1 -1
- package/lib/lsp/hydranium-document-update-handler.js +10 -1
- package/lib/lsp/hydranium-document-update-handler.js.map +1 -1
- package/lib/lsp/index.d.ts +3 -1
- package/lib/lsp/index.d.ts.map +1 -1
- package/lib/lsp/index.js +3 -1
- package/lib/lsp/index.js.map +1 -1
- package/lib/lsp/lsp-latency.d.ts +39 -0
- package/lib/lsp/lsp-latency.d.ts.map +1 -0
- package/lib/lsp/lsp-latency.js +58 -0
- package/lib/lsp/lsp-latency.js.map +1 -0
- package/lib/lsp/semantic-token-provider.d.ts +34 -1
- package/lib/lsp/semantic-token-provider.d.ts.map +1 -1
- package/lib/lsp/semantic-token-provider.js +55 -8
- package/lib/lsp/semantic-token-provider.js.map +1 -1
- package/lib/lsp/start-language-server.d.ts +5 -3
- package/lib/lsp/start-language-server.d.ts.map +1 -1
- package/lib/lsp/start-language-server.js +10 -3
- package/lib/lsp/start-language-server.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/heap-ceiling.d.ts +61 -0
- package/lib/node/heap-ceiling.d.ts.map +1 -0
- package/lib/node/heap-ceiling.js +72 -0
- package/lib/node/heap-ceiling.js.map +1 -0
- package/lib/node/index.d.ts +1 -0
- package/lib/node/index.d.ts.map +1 -1
- package/lib/node/index.js +1 -0
- package/lib/node/index.js.map +1 -1
- package/lib/node/latency-from-env.d.ts +1 -1
- package/lib/node/latency-from-env.js +1 -1
- package/lib/node/measure-memory.d.ts.map +1 -1
- package/lib/node/measure-memory.js +1 -0
- package/lib/node/measure-memory.js.map +1 -1
- package/lib/node/node-file-system-provider.d.ts +35 -1
- package/lib/node/node-file-system-provider.d.ts.map +1 -1
- package/lib/node/node-file-system-provider.js +140 -45
- package/lib/node/node-file-system-provider.js.map +1 -1
- package/lib/node/profile-capture.d.ts +8 -2
- package/lib/node/profile-capture.d.ts.map +1 -1
- package/lib/node/profile-capture.js.map +1 -1
- package/lib/node/profiling-run.d.ts +2 -2
- 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/node/socket-launcher.d.ts +15 -0
- package/lib/node/socket-launcher.d.ts.map +1 -1
- package/lib/node/socket-launcher.js +3 -2
- package/lib/node/socket-launcher.js.map +1 -1
- package/lib/testing/fake-document.d.ts +16 -4
- 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 +45 -9
- 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/index.d.ts +1 -0
- package/lib/testing/node/index.d.ts.map +1 -1
- package/lib/testing/node/index.js +1 -0
- package/lib/testing/node/index.js.map +1 -1
- package/lib/testing/node/lsp-harness.d.ts.map +1 -1
- package/lib/testing/node/lsp-harness.js +2 -0
- package/lib/testing/node/lsp-harness.js.map +1 -1
- package/lib/testing/node/lsp-server-connection.d.ts +10 -2
- package/lib/testing/node/lsp-server-connection.d.ts.map +1 -1
- package/lib/testing/node/lsp-server-connection.js +42 -9
- package/lib/testing/node/lsp-server-connection.js.map +1 -1
- package/lib/testing/node/scratch-workspace.d.ts.map +1 -1
- package/lib/testing/node/scratch-workspace.js +9 -4
- package/lib/testing/node/scratch-workspace.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/node/unhandled-rejections.d.ts +20 -0
- package/lib/testing/node/unhandled-rejections.d.ts.map +1 -0
- package/lib/testing/node/unhandled-rejections.js +32 -0
- package/lib/testing/node/unhandled-rejections.js.map +1 -0
- 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 +5 -5
- package/lib/testing/stub-ast-document-manager.d.ts.map +1 -1
- package/lib/testing/stub-ast-document-manager.js +4 -6
- 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-langium-documents.d.ts +3 -2
- package/lib/testing/stub-langium-documents.d.ts.map +1 -1
- package/lib/testing/stub-langium-documents.js.map +1 -1
- package/lib/testing/stub-model-service.d.ts +5 -4
- 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/lib/util/connection-liveness.d.ts +7 -6
- package/lib/util/connection-liveness.d.ts.map +1 -1
- package/lib/util/connection-liveness.js +35 -14
- package/lib/util/connection-liveness.js.map +1 -1
- package/package.json +17 -8
- package/src/documents/ast-document-manager.ts +129 -36
- package/src/documents/client-ids.ts +5 -22
- package/src/documents/hydranium-text-documents.ts +256 -81
- package/src/documents/language-client-text-shadow.ts +59 -11
- package/src/documents/self-save-registry.ts +52 -13
- package/src/index.ts +6 -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 +119 -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 +50 -5
- 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 +116 -2
- 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/language-module.ts +38 -0
- package/src/langium/model-service/model-service.ts +266 -34
- package/src/langium/module.ts +106 -21
- package/src/langium/naming/name-provider.ts +27 -5
- package/src/langium/naming/name-separator-validation.ts +34 -5
- package/src/langium/residency/cst-residency-service.ts +36 -14
- package/src/langium/scope/hydranium-scope-provider.ts +60 -22
- package/src/langium/serialization/abstract-serializer.ts +13 -32
- package/src/langium/service-registry.ts +19 -2
- package/src/langium/shared-services.ts +19 -2
- package/src/langium/transfer/transfer-encoder.ts +85 -24
- package/src/langium/trivia/comment-preserver.ts +1100 -0
- package/src/langium/trivia/document-ending-preserver.ts +55 -0
- package/src/langium/trivia/index.ts +14 -0
- package/src/langium/trivia/trivia-contribution.ts +39 -0
- package/src/langium/trivia/trivia-preserver.ts +54 -0
- package/src/langium/trivia/trivia-service.ts +99 -0
- package/src/langium/validation/document-validator.ts +537 -11
- package/src/langium/workspace/document-uri-policy.ts +3 -4
- package/src/langium/workspace/file-system-provider.ts +48 -8
- 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 +53 -10
- package/src/langium/workspace/initialize-workspace.ts +35 -5
- package/src/langium/workspace/langium-documents.ts +106 -33
- package/src/langium/workspace/virtual-document.ts +21 -3
- package/src/locale/index.ts +10 -0
- package/src/locale/server-locale.ts +86 -0
- package/src/lsp/completion/hydranium-completion-provider.ts +82 -2
- package/src/lsp/connection-features.ts +67 -0
- package/src/lsp/diagnostics-connection.ts +56 -0
- package/src/lsp/hydranium-document-update-handler.ts +10 -1
- package/src/lsp/index.ts +3 -1
- package/src/lsp/lsp-latency.ts +62 -0
- package/src/lsp/semantic-token-provider.ts +74 -7
- package/src/lsp/start-language-server.ts +10 -3
- package/src/messages/carriers.ts +78 -0
- package/src/messages/index.ts +36 -0
- package/src/messages/renderer.ts +206 -0
- package/src/node/heap-ceiling.ts +108 -0
- package/src/node/index.ts +1 -0
- package/src/node/latency-from-env.ts +1 -1
- package/src/node/measure-memory.ts +1 -0
- package/src/node/node-file-system-provider.ts +154 -47
- package/src/node/profile-capture.ts +8 -2
- package/src/node/profiling-run.ts +3 -3
- package/src/node/rename-over-open-readers.ts +78 -0
- package/src/node/socket-launcher.ts +18 -2
- package/src/testing/fake-document.ts +24 -5
- package/src/testing/make-noop-shared-services.ts +50 -2
- package/src/testing/make-test-services.ts +74 -18
- package/src/testing/node/index.ts +1 -0
- package/src/testing/node/lsp-harness.ts +2 -0
- package/src/testing/node/lsp-server-connection.ts +60 -10
- package/src/testing/node/scratch-workspace.ts +9 -4
- package/src/testing/node/spawned-server.ts +35 -1
- package/src/testing/node/unhandled-rejections.ts +31 -0
- 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 +10 -14
- package/src/testing/stub-document-builder.ts +32 -3
- package/src/testing/stub-langium-documents.ts +3 -2
- package/src/testing/stub-model-service.ts +7 -6
- package/src/util/connection-liveness.ts +37 -14
- package/lib/lsp/instrument-connection.d.ts +0 -36
- package/lib/lsp/instrument-connection.d.ts.map +0 -1
- package/lib/lsp/instrument-connection.js +0 -62
- package/lib/lsp/instrument-connection.js.map +0 -1
- package/src/lsp/instrument-connection.ts +0 -66
|
@@ -55,8 +55,8 @@ export interface ProfilingRunOptions {
|
|
|
55
55
|
/**
|
|
56
56
|
* Optional latency collector. When present, {@link ProfilingRun.finish} writes
|
|
57
57
|
* its report to `server-latency.json` and records a `server-latency` manifest artefact. A
|
|
58
|
-
* head feeds it via the RPC binding / `
|
|
59
|
-
*
|
|
58
|
+
* head feeds it via the RPC binding / `lspLatencyOptions`; a pure headless
|
|
59
|
+
* build with no request traffic leaves it empty.
|
|
60
60
|
*/
|
|
61
61
|
latency?: LatencyCollector;
|
|
62
62
|
}
|
|
@@ -97,7 +97,7 @@ export class ProfilingRun {
|
|
|
97
97
|
// `HYDRANIUM_LOG_FILE` env, which every `@hydranium/core` copy reads when
|
|
98
98
|
// its logger is CONSTRUCTED — so `ProfilingRun.start` must run before the
|
|
99
99
|
// head's services are created (as `measureModelMemory` does). This is the
|
|
100
|
-
// only mechanism that crosses
|
|
100
|
+
// only mechanism that crosses an adopter's separate core copy; a
|
|
101
101
|
// process-local `setLogFilePath` would only reach this module's own copy.
|
|
102
102
|
this.previousLogFileEnv = process.env[DEFAULT_LOG_FILE_ENV];
|
|
103
103
|
process.env[DEFAULT_LOG_FILE_ENV] = this.serverLogPath;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
|
|
10
|
+
import * as fsp from 'node:fs/promises';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Errnos Windows raises when a replacing `rename` meets a handle already on the
|
|
14
|
+
* destination open. POSIX renames are unaffected by open handles, so these
|
|
15
|
+
* cannot fire there and the retry below costs nothing.
|
|
16
|
+
*/
|
|
17
|
+
export const RENAME_CONTENTION_CODES = new Set(['EPERM', 'EACCES', 'EBUSY']);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* How long a replacing rename may keep retrying before it gives up.
|
|
21
|
+
*
|
|
22
|
+
* BOUNDED, not open-ended: a genuine permission fault raises the same errno as
|
|
23
|
+
* contention and is distinguishable from it only by never clearing, so an
|
|
24
|
+
* unbounded wait would convert a hard error into a hang.
|
|
25
|
+
*
|
|
26
|
+
* The figure is a judgement, not a measurement, and the honest bound on it is
|
|
27
|
+
* that the previous 2s was observed EXHAUSTED on a loaded Windows CI runner
|
|
28
|
+
* while no upper bound has been established. What would settle it is recording
|
|
29
|
+
* how long a real contended rename takes to clear. graceful-fs tolerates 60s
|
|
30
|
+
* for Windows rename contention, but that is weaker support than it looks: it
|
|
31
|
+
* retries only where the destination has GONE, which is the opposite of
|
|
32
|
+
* replacing one a reader holds open.
|
|
33
|
+
*/
|
|
34
|
+
export const RENAME_BUDGET_MS = 10_000;
|
|
35
|
+
|
|
36
|
+
/** Seams for the test, which cannot make a real rename fail on demand. */
|
|
37
|
+
export interface RenameOverOpenReadersOptions {
|
|
38
|
+
readonly rename?: (from: string, to: string) => Promise<void>;
|
|
39
|
+
readonly budgetMs?: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* `rename` the staged content over `destination`, retrying while Windows
|
|
44
|
+
* reports the destination as held open.
|
|
45
|
+
*
|
|
46
|
+
* The staging file exists so a reader never sees a half-written file, and on
|
|
47
|
+
* Windows the very presence of that reader is what makes the replacing rename
|
|
48
|
+
* fail — so the indivisible write breaks under exactly the contention it was
|
|
49
|
+
* built for, and it breaks intermittently, which is worse than never working.
|
|
50
|
+
* A reader's handle is released in milliseconds, so waiting turns a spurious
|
|
51
|
+
* failure into a slightly later success.
|
|
52
|
+
*
|
|
53
|
+
* Exhausting the budget rethrows the last failure, leaving the caller's cleanup
|
|
54
|
+
* and error contract unchanged. An errno OUTSIDE the contention set is rethrown
|
|
55
|
+
* without waiting at all: retrying a fault that will not clear only delays it.
|
|
56
|
+
*/
|
|
57
|
+
export async function renameOverOpenReaders(
|
|
58
|
+
staging: string,
|
|
59
|
+
destination: string,
|
|
60
|
+
options: RenameOverOpenReadersOptions = {}
|
|
61
|
+
): Promise<void> {
|
|
62
|
+
const rename = options.rename ?? fsp.rename;
|
|
63
|
+
const deadline = Date.now() + (options.budgetMs ?? RENAME_BUDGET_MS);
|
|
64
|
+
for (let attempt = 0; ; attempt++) {
|
|
65
|
+
try {
|
|
66
|
+
await rename(staging, destination);
|
|
67
|
+
return;
|
|
68
|
+
} catch (err: unknown) {
|
|
69
|
+
const code = err instanceof Error && 'code' in err ? String((err as NodeJS.ErrnoException).code) : undefined;
|
|
70
|
+
if (code === undefined || !RENAME_CONTENTION_CODES.has(code) || Date.now() >= deadline) {
|
|
71
|
+
throw err;
|
|
72
|
+
}
|
|
73
|
+
// Backs off to keep a long contention window from spinning, capped so
|
|
74
|
+
// a late attempt still lands promptly once the handle is released.
|
|
75
|
+
await new Promise(resolve => setTimeout(resolve, Math.min(2 ** attempt, 50)));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -24,6 +24,21 @@ export interface SocketServerOptions {
|
|
|
24
24
|
* resolves (only then is the address info available).
|
|
25
25
|
*/
|
|
26
26
|
readonly port?: number;
|
|
27
|
+
/**
|
|
28
|
+
* Interface to bind. Default `'127.0.0.1'` (LOCAL ONLY) — a head whose
|
|
29
|
+
* port is OS-assigned and announced over the LSP connection is
|
|
30
|
+
* reachable only by a client on the same machine anyway, so a wider
|
|
31
|
+
* binding exposes a port nothing off-box can address. Matches
|
|
32
|
+
* `startGlspServer`'s default, so the two socket heads agree.
|
|
33
|
+
*
|
|
34
|
+
* Pass `'::'` for every interface: that is the dual-stack any-address,
|
|
35
|
+
* so both IPv4 and IPv6 clients connect. `'0.0.0.0'` is NOT the same —
|
|
36
|
+
* it takes IPv4 only and refuses `::1`.
|
|
37
|
+
*
|
|
38
|
+
* An address no local interface holds fails the bind, so `started`
|
|
39
|
+
* rejects with `EADDRNOTAVAIL` rather than falling back to a wider one.
|
|
40
|
+
*/
|
|
41
|
+
readonly host?: string;
|
|
27
42
|
/**
|
|
28
43
|
* Optional logger. If omitted, the launcher runs silently — the
|
|
29
44
|
* adopter is expected to surface lifecycle events through their own
|
|
@@ -88,6 +103,7 @@ export interface StartedSocketServer extends IntegratedServer {
|
|
|
88
103
|
*/
|
|
89
104
|
export function startSocketServer(options: SocketServerOptions, onClientConnection: OnClientConnection): StartedSocketServer {
|
|
90
105
|
const port = options.port ?? 0;
|
|
106
|
+
const host = options.host ?? '127.0.0.1';
|
|
91
107
|
const logger = options.logger;
|
|
92
108
|
const tag = options.logTag ?? 'SocketServer';
|
|
93
109
|
const started = new Deferred<void>();
|
|
@@ -128,7 +144,7 @@ export function startSocketServer(options: SocketServerOptions, onClientConnecti
|
|
|
128
144
|
connection.listen();
|
|
129
145
|
});
|
|
130
146
|
|
|
131
|
-
netServer.listen(port);
|
|
147
|
+
netServer.listen(port, host);
|
|
132
148
|
netServer.on('listening', () => {
|
|
133
149
|
const addressInfo = netServer.address();
|
|
134
150
|
if (!addressInfo) {
|
|
@@ -144,7 +160,7 @@ export function startSocketServer(options: SocketServerOptions, onClientConnecti
|
|
|
144
160
|
return;
|
|
145
161
|
}
|
|
146
162
|
handle.port = addressInfo.port;
|
|
147
|
-
logger?.info(`[${tag}] Ready to accept new client requests on port: ${addressInfo.port}`);
|
|
163
|
+
logger?.info(`[${tag}] Ready to accept new client requests on ${addressInfo.address} port: ${addressInfo.port}`);
|
|
148
164
|
started.resolve();
|
|
149
165
|
});
|
|
150
166
|
netServer.on('error', err => {
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
* SPDX-License-Identifier: MIT
|
|
8
8
|
********************************************************************************/
|
|
9
9
|
|
|
10
|
-
import { DocumentState, type AstNode, type LangiumDocument, UriUtils, type URI } from '@hydranium/langium';
|
|
10
|
+
import { DocumentState, type AstNode, type AstReflection, type LangiumDocument, UriUtils, type URI } from '@hydranium/langium';
|
|
11
|
+
import { buildAstNode } from '../langium/ast-extension/ast-node-builder.js';
|
|
12
|
+
import { type AstDiagnostic } from '../langium/validation/document-validator.js';
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* Build a typed AST-node fixture for unit tests.
|
|
@@ -23,12 +25,29 @@ import { DocumentState, type AstNode, type LangiumDocument, UriUtils, type URI }
|
|
|
23
25
|
* framework synthetic node, and marking it would change scope/index behaviour.
|
|
24
26
|
* A test that wants a genuine synthetic node calls `markSynthetic` explicitly.
|
|
25
27
|
*
|
|
28
|
+
* **Without a `reflection`, the fixture carries only what the test spells out**,
|
|
29
|
+
* which is a shape production never produces: a parsed or built node always has
|
|
30
|
+
* its grammar-declared containment arrays, so a fixture that omits one lets a
|
|
31
|
+
* test pass against an impossible node, and lets code that walks a list crash
|
|
32
|
+
* only under test. Pass the grammar's reflection whenever the type is a real
|
|
33
|
+
* one and the code under test reads a collection off it. Fixtures typed against
|
|
34
|
+
* ad-hoc names have no reflection to pass and keep the plain form.
|
|
35
|
+
*
|
|
26
36
|
* @param node the node shape — `$type` is required; every other property is a
|
|
27
37
|
* value the test cares about (`$container`, cross-reference values, internal
|
|
28
|
-
* `_id` fields, …).
|
|
38
|
+
* `_id` fields, …).
|
|
39
|
+
* @param reflection when given, pre-fills the grammar's declared defaults the
|
|
40
|
+
* same way {@link buildAstNode} does, and the result is a fresh object rather
|
|
41
|
+
* than `node` itself. Omitted, `node` is returned by reference.
|
|
29
42
|
*/
|
|
30
|
-
export function makeFakeAstNode<TAst extends AstNode = AstNode>(
|
|
31
|
-
|
|
43
|
+
export function makeFakeAstNode<TAst extends AstNode = AstNode>(
|
|
44
|
+
node: { $type: string } & Record<string, unknown>,
|
|
45
|
+
reflection?: AstReflection
|
|
46
|
+
): TAst {
|
|
47
|
+
if (!reflection) {
|
|
48
|
+
return node as unknown as TAst;
|
|
49
|
+
}
|
|
50
|
+
return buildAstNode<TAst>(reflection, node.$type, node);
|
|
32
51
|
}
|
|
33
52
|
|
|
34
53
|
/**
|
|
@@ -86,7 +105,7 @@ function stringifyFakeRoot(root: unknown): string {
|
|
|
86
105
|
* staging. Override via `options.state` for tests that gate on earlier
|
|
87
106
|
* phases.
|
|
88
107
|
*/
|
|
89
|
-
export function makeFakeDocument<TAst extends AstNode = AstNode, TDiagnostic =
|
|
108
|
+
export function makeFakeDocument<TAst extends AstNode = AstNode, TDiagnostic extends AstDiagnostic = AstDiagnostic>(
|
|
90
109
|
uri: string | URI,
|
|
91
110
|
root: TAst,
|
|
92
111
|
options: FakeDocumentOptions<TAst, TDiagnostic> = {}
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
import { type Clock, DefaultTracer, type Logger, NoopLogger, SystemClock, type Tracer } from '@hydranium/protocol';
|
|
11
11
|
import type { ServerSharedServicesMinimal } from '../langium/shared-services.js';
|
|
12
|
+
import { DefaultServerLocale, type ServerLocale } from '../locale/server-locale.js';
|
|
13
|
+
import { DefaultMessageRenderer, type MessageRenderer } from '../messages/renderer.js';
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* Overrides for {@link makeNoopSharedServices}. The three observability slots
|
|
@@ -29,6 +31,18 @@ export interface NoopSharedServicesOverrides {
|
|
|
29
31
|
Logger?: Logger;
|
|
30
32
|
/** Bound on the top-level `Tracer` slot. Default: a `DefaultTracer` over `Logger` + `Clock`. */
|
|
31
33
|
Tracer?: Tracer;
|
|
34
|
+
/** Factory for the `ServerLocale` slot. Default: a real one, reporting no locale. */
|
|
35
|
+
ServerLocale?: (services: ServerSharedServicesMinimal) => ServerLocale;
|
|
36
|
+
/**
|
|
37
|
+
* Factory for the `MessageRenderer` slot. Default: the real
|
|
38
|
+
* {@link DefaultMessageRenderer}, whose no-catalogue behaviour is a
|
|
39
|
+
* pass-through — so the default is the framework's own behaviour, not a stub.
|
|
40
|
+
*
|
|
41
|
+
* A factory rather than an instance, because a renderer reads the tree it is
|
|
42
|
+
* bound into. Both slots are resolved lazily, so an override is honoured
|
|
43
|
+
* however late the caller reads them.
|
|
44
|
+
*/
|
|
45
|
+
MessageRenderer?: (services: ServerSharedServicesMinimal) => MessageRenderer;
|
|
32
46
|
/** Per-slot `workspace` overrides. Slots left out resolve to `undefined`. */
|
|
33
47
|
workspace?: Record<string, unknown>;
|
|
34
48
|
/** Any other minimal slot (`ServiceRegistry`, `AstReflection`, `additionalDocuments`, …). */
|
|
@@ -63,11 +77,21 @@ export interface NoopSharedServicesOverrides {
|
|
|
63
77
|
export function makeNoopSharedServices<T extends ServerSharedServicesMinimal = ServerSharedServicesMinimal>(
|
|
64
78
|
overrides: NoopSharedServicesOverrides = {}
|
|
65
79
|
): T {
|
|
66
|
-
const {
|
|
80
|
+
const {
|
|
81
|
+
Clock: clock,
|
|
82
|
+
Logger: logger,
|
|
83
|
+
Tracer: tracer,
|
|
84
|
+
ServerLocale: serverLocale,
|
|
85
|
+
MessageRenderer: messageRenderer,
|
|
86
|
+
workspace,
|
|
87
|
+
additionalDocuments,
|
|
88
|
+
...restTop
|
|
89
|
+
} = overrides;
|
|
67
90
|
const resolvedClock = clock ?? new SystemClock();
|
|
68
91
|
const resolvedLogger = logger ?? new NoopLogger();
|
|
69
92
|
const resolvedTracer = tracer ?? new DefaultTracer(resolvedLogger, resolvedClock);
|
|
70
|
-
|
|
93
|
+
// Assembled in two steps, because both defaults read the tree they belong to.
|
|
94
|
+
const services = {
|
|
71
95
|
Clock: resolvedClock,
|
|
72
96
|
Logger: resolvedLogger,
|
|
73
97
|
Tracer: resolvedTracer,
|
|
@@ -75,4 +99,28 @@ export function makeNoopSharedServices<T extends ServerSharedServicesMinimal = S
|
|
|
75
99
|
...restTop,
|
|
76
100
|
workspace: { ...(workspace ?? {}) }
|
|
77
101
|
} as unknown as T;
|
|
102
|
+
// Lazy, like Langium's own per-slot construction — and load-bearing here:
|
|
103
|
+
// both services emit an `instantiated` trace, so building them eagerly puts
|
|
104
|
+
// two lines into the capture of every test that passes a capturing logger
|
|
105
|
+
// and asserts on emptiness.
|
|
106
|
+
defineLazySlot(services, 'ServerLocale', () => serverLocale?.(services) ?? new DefaultServerLocale(services));
|
|
107
|
+
defineLazySlot(services, 'MessageRenderer', () => messageRenderer?.(services) ?? new DefaultMessageRenderer(services));
|
|
108
|
+
return services;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Install `name` as a memoized getter, so nothing is constructed until it is read. */
|
|
112
|
+
function defineLazySlot(target: object, name: string, create: () => unknown): void {
|
|
113
|
+
let resolved: unknown;
|
|
114
|
+
let built = false;
|
|
115
|
+
Object.defineProperty(target, name, {
|
|
116
|
+
configurable: true,
|
|
117
|
+
enumerable: true,
|
|
118
|
+
get: () => {
|
|
119
|
+
if (!built) {
|
|
120
|
+
resolved = create();
|
|
121
|
+
built = true;
|
|
122
|
+
}
|
|
123
|
+
return resolved;
|
|
124
|
+
}
|
|
125
|
+
});
|
|
78
126
|
}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import {
|
|
11
11
|
type Clock,
|
|
12
12
|
DefaultTracer,
|
|
13
|
+
type Locale,
|
|
13
14
|
type Logger,
|
|
14
15
|
NoopLogger,
|
|
15
16
|
type Project,
|
|
@@ -18,11 +19,14 @@ import {
|
|
|
18
19
|
type TransferDiagnostic,
|
|
19
20
|
type TransferElement
|
|
20
21
|
} from '@hydranium/protocol';
|
|
22
|
+
import { DefaultServerLocale, type ServerLocale } from '../locale/server-locale.js';
|
|
23
|
+
import { DefaultMessageRenderer, type MessageRenderer } from '../messages/renderer.js';
|
|
21
24
|
import type { Harness } from '@hydranium/protocol/testing';
|
|
22
25
|
import { type AstNode, type AstNodeDescription, type WorkspaceLock } from '@hydranium/langium';
|
|
23
26
|
import type { ModelService, ModelServiceOptions } from '../langium/model-service/model-service.js';
|
|
24
27
|
import type { ServerSharedServices } from '../langium/module.js';
|
|
25
|
-
import {
|
|
28
|
+
import type { AstDiagnostic } from '../langium/validation/document-validator.js';
|
|
29
|
+
import { DefaultTransferEncoder, type TransferEncoder } from '../langium/transfer/transfer-encoder.js';
|
|
26
30
|
import { DefaultDocumentUriPolicy, type DocumentUriPolicy } from '../langium/workspace/document-uri-policy.js';
|
|
27
31
|
import { HydraniumWorkspaceLock } from '../langium/workspace/hydranium-workspace-lock.js';
|
|
28
32
|
import type { FakeDocumentOptions } from './fake-document.js';
|
|
@@ -46,12 +50,21 @@ import { makeStubWritableFileSystem, type StubWritableFileSystem } from './stub-
|
|
|
46
50
|
* to `ServerSharedServices` in {@link makeTestServices} is therefore the
|
|
47
51
|
* single named place where the "stub stands in for the full service tree"
|
|
48
52
|
* assertion happens.
|
|
53
|
+
*
|
|
54
|
+
* **`TDiagnostic` and `TTransferDiagnostic` are the two ends of a conversion
|
|
55
|
+
* and must stay separate.** The first is what the build left on
|
|
56
|
+
* `LangiumDocument.diagnostics` and what `ModelService` hands back on an
|
|
57
|
+
* `AstDocument`; the second is what `TransferEncoder.toTransferDiagnostic`
|
|
58
|
+
* produces for the wire. One parameter serving both makes the tree
|
|
59
|
+
* unbindable for an adopter who extends either shape, since extending one
|
|
60
|
+
* says nothing about the other.
|
|
49
61
|
*/
|
|
50
62
|
export interface TestSharedServices<
|
|
51
63
|
TAst extends AstNode = AstNode,
|
|
52
|
-
TDiagnostic extends
|
|
64
|
+
TDiagnostic extends AstDiagnostic = AstDiagnostic,
|
|
53
65
|
TTransfer extends TransferElement = TransferElement,
|
|
54
|
-
TProject extends Project = Project
|
|
66
|
+
TProject extends Project = Project,
|
|
67
|
+
TTransferDiagnostic extends TransferDiagnostic = TransferDiagnostic
|
|
55
68
|
> {
|
|
56
69
|
readonly Clock: Clock;
|
|
57
70
|
readonly Logger: Logger;
|
|
@@ -90,17 +103,27 @@ export interface TestSharedServices<
|
|
|
90
103
|
WorkspaceLock: WorkspaceLock;
|
|
91
104
|
};
|
|
92
105
|
readonly model: {
|
|
93
|
-
TransferEncoder: TransferEncoder<
|
|
106
|
+
TransferEncoder: TransferEncoder<TTransferDiagnostic>;
|
|
94
107
|
ModelService: ModelService<TAst, TDiagnostic, TTransfer>;
|
|
95
108
|
};
|
|
109
|
+
/**
|
|
110
|
+
* The REAL services, not stubs — the framework renderer's no-catalogue
|
|
111
|
+
* behaviour is a pass-through, so the stub tree agrees with a production one
|
|
112
|
+
* unless a test installs a catalogue. Bound rather than omitted because
|
|
113
|
+
* `HydraniumDocumentBuilder` renders through the renderer on every
|
|
114
|
+
* `Validated` phase, where an omitted slot is a `TypeError`.
|
|
115
|
+
*/
|
|
116
|
+
readonly ServerLocale: ServerLocale;
|
|
117
|
+
readonly MessageRenderer: MessageRenderer;
|
|
96
118
|
}
|
|
97
119
|
|
|
98
120
|
/** Optional configuration for {@link makeTestServices}. */
|
|
99
121
|
export interface MakeTestServicesOptions<
|
|
100
122
|
TAst extends AstNode = AstNode,
|
|
101
|
-
TDiagnostic extends
|
|
123
|
+
TDiagnostic extends AstDiagnostic = AstDiagnostic,
|
|
102
124
|
TTransfer extends TransferElement = TransferElement,
|
|
103
|
-
TProject extends Project = Project
|
|
125
|
+
TProject extends Project = Project,
|
|
126
|
+
TTransferDiagnostic extends TransferDiagnostic = TransferDiagnostic
|
|
104
127
|
> {
|
|
105
128
|
/**
|
|
106
129
|
* Serialiser used by the bundled `StubModelService`. The stub tree
|
|
@@ -112,6 +135,14 @@ export interface MakeTestServicesOptions<
|
|
|
112
135
|
* for tests that don't assert on the produced text.
|
|
113
136
|
*/
|
|
114
137
|
serialize?: (uri: string, root: TTransfer) => string;
|
|
138
|
+
/**
|
|
139
|
+
* Renderer bound on `MessageRenderer`. Default: the framework's own, which
|
|
140
|
+
* passes every sentence through unchanged. Supply one to install a catalogue
|
|
141
|
+
* or to drive the throwing path.
|
|
142
|
+
*/
|
|
143
|
+
messageRenderer?: (services: ServerSharedServices<TProject>) => MessageRenderer;
|
|
144
|
+
/** Locale handed to the bundle's {@link ServerLocale}. Default: none, i.e. the framework's English. */
|
|
145
|
+
locale?: Locale;
|
|
115
146
|
/**
|
|
116
147
|
* Languages to register on a {@link StubServiceRegistry} bound on the
|
|
117
148
|
* `ServiceRegistry` slot. This is how a test gets multi-language routing:
|
|
@@ -187,7 +218,7 @@ export interface MakeTestServicesOptions<
|
|
|
187
218
|
* Override the {@link TransferEncoder} factory. Default: framework
|
|
188
219
|
* {@link TransferEncoder} with no overrides.
|
|
189
220
|
*/
|
|
190
|
-
transferEncoder?: (services: ServerSharedServices<TProject>) => TransferEncoder<
|
|
221
|
+
transferEncoder?: (services: ServerSharedServices<TProject>) => TransferEncoder<TTransferDiagnostic>;
|
|
191
222
|
}
|
|
192
223
|
|
|
193
224
|
/**
|
|
@@ -205,9 +236,10 @@ export interface MakeTestServicesOptions<
|
|
|
205
236
|
*/
|
|
206
237
|
export interface TestServicesBundle<
|
|
207
238
|
TAst extends AstNode = AstNode,
|
|
208
|
-
TDiagnostic extends
|
|
239
|
+
TDiagnostic extends AstDiagnostic = AstDiagnostic,
|
|
209
240
|
TTransfer extends TransferElement = TransferElement,
|
|
210
|
-
TProject extends Project = Project
|
|
241
|
+
TProject extends Project = Project,
|
|
242
|
+
TTransferDiagnostic extends TransferDiagnostic = TransferDiagnostic
|
|
211
243
|
> extends Harness {
|
|
212
244
|
readonly services: ServerSharedServices<TProject>;
|
|
213
245
|
readonly documents: StubLangiumDocuments<TAst, TDiagnostic>;
|
|
@@ -229,10 +261,18 @@ export interface TestServicesBundle<
|
|
|
229
261
|
*/
|
|
230
262
|
readonly indexManager: StubIndexManager | undefined;
|
|
231
263
|
readonly modelService: ModelService<TAst, TDiagnostic, TTransfer>;
|
|
232
|
-
readonly transferEncoder: TransferEncoder<
|
|
264
|
+
readonly transferEncoder: TransferEncoder<TTransferDiagnostic>;
|
|
233
265
|
readonly logger: Logger;
|
|
234
266
|
/** The clock bound on the `Clock` slot — a `makeFakeClock()` if one was passed. */
|
|
235
267
|
readonly clock: Clock;
|
|
268
|
+
/**
|
|
269
|
+
* The service bound on `ServerLocale`, so a test can hand over a locale
|
|
270
|
+
* mid-run — which is also how it verifies the renderer reads the locale per
|
|
271
|
+
* render rather than caching it at construction.
|
|
272
|
+
*/
|
|
273
|
+
readonly serverLocale: ServerLocale;
|
|
274
|
+
/** The renderer bound on `MessageRenderer` — the framework's own unless one was supplied. */
|
|
275
|
+
readonly messageRenderer: MessageRenderer;
|
|
236
276
|
}
|
|
237
277
|
|
|
238
278
|
/**
|
|
@@ -247,12 +287,13 @@ export interface TestServicesBundle<
|
|
|
247
287
|
*/
|
|
248
288
|
export function makeTestServices<
|
|
249
289
|
TAst extends AstNode = AstNode,
|
|
250
|
-
TDiagnostic extends
|
|
290
|
+
TDiagnostic extends AstDiagnostic = AstDiagnostic,
|
|
251
291
|
TTransfer extends TransferElement = TransferElement,
|
|
252
|
-
TProject extends Project = Project
|
|
292
|
+
TProject extends Project = Project,
|
|
293
|
+
TTransferDiagnostic extends TransferDiagnostic = TransferDiagnostic
|
|
253
294
|
>(
|
|
254
|
-
options: MakeTestServicesOptions<TAst, TDiagnostic, TTransfer, TProject> = {}
|
|
255
|
-
): TestServicesBundle<TAst, TDiagnostic, TTransfer, TProject> {
|
|
295
|
+
options: MakeTestServicesOptions<TAst, TDiagnostic, TTransfer, TProject, TTransferDiagnostic> = {}
|
|
296
|
+
): TestServicesBundle<TAst, TDiagnostic, TTransfer, TProject, TTransferDiagnostic> {
|
|
256
297
|
const documents = makeStubLangiumDocuments<TAst, TDiagnostic>(options.seedDocuments);
|
|
257
298
|
const textDocuments = makeStubHydraniumTextDocuments();
|
|
258
299
|
const documentBuilder = makeStubDocumentBuilder();
|
|
@@ -289,7 +330,7 @@ export function makeTestServices<
|
|
|
289
330
|
// (after the factories run); the literal uses unsafe casts to
|
|
290
331
|
// partially-built objects to satisfy TestSharedServices, then patches
|
|
291
332
|
// them in.
|
|
292
|
-
const services: TestSharedServices<TAst, TDiagnostic, TTransfer, TProject> = {
|
|
333
|
+
const services: TestSharedServices<TAst, TDiagnostic, TTransfer, TProject, TTransferDiagnostic> = {
|
|
293
334
|
Clock: clock,
|
|
294
335
|
Logger: logger,
|
|
295
336
|
Tracer: tracer,
|
|
@@ -311,20 +352,33 @@ export function makeTestServices<
|
|
|
311
352
|
...(indexManager ? { IndexManager: indexManager } : {}),
|
|
312
353
|
WorkspaceLock: new HydraniumWorkspaceLock()
|
|
313
354
|
},
|
|
314
|
-
model: {} as TestSharedServices<TAst, TDiagnostic, TTransfer, TProject>['model']
|
|
355
|
+
model: {} as TestSharedServices<TAst, TDiagnostic, TTransfer, TProject, TTransferDiagnostic>['model'],
|
|
356
|
+
ServerLocale: {} as ServerLocale,
|
|
357
|
+
MessageRenderer: {} as DefaultMessageRenderer
|
|
315
358
|
};
|
|
316
359
|
const sharedServices = services as unknown as ServerSharedServices<TProject>;
|
|
317
360
|
|
|
361
|
+
// Patched in after the literal, like `model` below: both read the tree they
|
|
362
|
+
// belong to, and the renderer reads the locale service.
|
|
363
|
+
const mutableMessages = services as { ServerLocale: ServerLocale; MessageRenderer: MessageRenderer };
|
|
364
|
+
const serverLocale = new DefaultServerLocale(sharedServices);
|
|
365
|
+
if (options.locale) {
|
|
366
|
+
serverLocale.accept(options.locale);
|
|
367
|
+
}
|
|
368
|
+
mutableMessages.ServerLocale = serverLocale;
|
|
369
|
+
const messageRenderer = options.messageRenderer?.(sharedServices) ?? new DefaultMessageRenderer(sharedServices);
|
|
370
|
+
mutableMessages.MessageRenderer = messageRenderer;
|
|
371
|
+
|
|
318
372
|
const serialize = options.serialize ?? ((_uri: string, root: TTransfer) => JSON.stringify(root));
|
|
319
373
|
const transferEncoder = options.transferEncoder
|
|
320
374
|
? options.transferEncoder(sharedServices)
|
|
321
|
-
: new
|
|
375
|
+
: new DefaultTransferEncoder<unknown, TTransferDiagnostic>(sharedServices);
|
|
322
376
|
const modelService = options.modelService
|
|
323
377
|
? options.modelService(sharedServices)
|
|
324
378
|
: makeStubModelService<TAst, TDiagnostic, TTransfer>(sharedServices, serialize, options.modelServiceOptions);
|
|
325
379
|
|
|
326
380
|
const mutableModel = services.model as {
|
|
327
|
-
TransferEncoder: TransferEncoder<
|
|
381
|
+
TransferEncoder: TransferEncoder<TTransferDiagnostic>;
|
|
328
382
|
ModelService: ModelService<TAst, TDiagnostic, TTransfer>;
|
|
329
383
|
};
|
|
330
384
|
mutableModel.TransferEncoder = transferEncoder;
|
|
@@ -346,6 +400,8 @@ export function makeTestServices<
|
|
|
346
400
|
transferEncoder,
|
|
347
401
|
logger,
|
|
348
402
|
clock,
|
|
403
|
+
serverLocale,
|
|
404
|
+
messageRenderer,
|
|
349
405
|
dispose: () => {
|
|
350
406
|
// No-op: the bundled stubs hold only in-memory state (maps, arrays),
|
|
351
407
|
// released with the bundle when it goes out of scope. The hook exists
|
|
@@ -216,12 +216,14 @@ export function makeLspHarness(options: MakeLspHarnessOptions): LspHarness {
|
|
|
216
216
|
},
|
|
217
217
|
shutdown: transport.shutdown,
|
|
218
218
|
openDocument: transport.openDocument,
|
|
219
|
+
closeDocument: transport.closeDocument,
|
|
219
220
|
changeDocument: transport.changeDocument,
|
|
220
221
|
completion: transport.completion,
|
|
221
222
|
hover: transport.hover,
|
|
222
223
|
semanticTokens: transport.semanticTokens,
|
|
223
224
|
nextDiagnostics: transport.nextDiagnostics,
|
|
224
225
|
appliedEdits: transport.appliedEdits,
|
|
226
|
+
wireBytes: transport.wireBytes,
|
|
225
227
|
nextAppliedEdit: transport.nextAppliedEdit,
|
|
226
228
|
setApplyEditHandler: transport.setApplyEditHandler,
|
|
227
229
|
buildWorkspace: folders => buildWorkspaceProgrammatically(services, folders),
|
|
@@ -8,17 +8,16 @@
|
|
|
8
8
|
********************************************************************************/
|
|
9
9
|
|
|
10
10
|
import { type Harness } from '@hydranium/protocol/testing';
|
|
11
|
-
import {
|
|
11
|
+
import { PassThrough, type TransformCallback } from 'node:stream';
|
|
12
12
|
import { StreamMessageReader, StreamMessageWriter } from 'vscode-jsonrpc/node';
|
|
13
13
|
import { type Connection, ProposedFeatures } from 'vscode-languageserver/node';
|
|
14
|
+
import { withHydraniumLspFeatures } from '../../lsp/connection-features.js';
|
|
14
15
|
// The node `createConnection` from `vscode-languageserver/node` is built for a
|
|
15
16
|
// standalone server PROCESS: it wires `process.exit()` onto the input stream's
|
|
16
17
|
// `end`/`close` events, onto the `exit` notification (via its watchDog), and onto
|
|
17
|
-
// a parent-pid liveness timer
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
// stream (an uncatchable synchronous `ERR_STREAM_DESTROYED`) and/or exits the host
|
|
21
|
-
// test runner. The lower-level common `createConnection(connectionFactory,
|
|
18
|
+
// a parent-pid liveness timer. In-process every one of those is fatal —
|
|
19
|
+
// destroying the streams at teardown trips the `close` handler, which exits the
|
|
20
|
+
// host test runner. The lower-level common `createConnection(connectionFactory,
|
|
22
21
|
// watchDog, features)` form does none of that: it lets us inject a no-op-`exit`
|
|
23
22
|
// WatchDog and build the connection over the in-memory streams, so teardown is the
|
|
24
23
|
// primitive's responsibility alone.
|
|
@@ -30,6 +29,7 @@ import {
|
|
|
30
29
|
ApplyWorkspaceEditRequest,
|
|
31
30
|
CompletionRequest,
|
|
32
31
|
DidChangeTextDocumentNotification,
|
|
32
|
+
DidCloseTextDocumentNotification,
|
|
33
33
|
DidOpenTextDocumentNotification,
|
|
34
34
|
HoverRequest,
|
|
35
35
|
InitializeRequest,
|
|
@@ -170,8 +170,8 @@ function insertedText(edit: WorkspaceEdit): string {
|
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
/**
|
|
173
|
-
* The in-process LSP transport seam — a real `Connection` over
|
|
174
|
-
*
|
|
173
|
+
* The in-process LSP transport seam — a real `Connection` over a crossed pair
|
|
174
|
+
* of in-memory streams, plus the client side, the diagnostics capture,
|
|
175
175
|
* and the typed request facades — with NO services attached. It is the lower
|
|
176
176
|
* half of `makeLspHarness`, factored out so a caller can OWN the services
|
|
177
177
|
* tree: build the tree around {@link serverConnection} (`createXxxServices({
|
|
@@ -226,6 +226,12 @@ export interface LspServerConnection extends Harness {
|
|
|
226
226
|
* unhandled method.
|
|
227
227
|
*/
|
|
228
228
|
readonly appliedEdits: ReadonlyArray<AppliedEdit>;
|
|
229
|
+
/** Bytes written in each direction of the in-process JSON-RPC wire. */
|
|
230
|
+
readonly wireBytes: () => {
|
|
231
|
+
readonly clientToServer: number;
|
|
232
|
+
readonly serverToClient: number;
|
|
233
|
+
readonly total: number;
|
|
234
|
+
};
|
|
229
235
|
|
|
230
236
|
/**
|
|
231
237
|
* Drive the real LSP `initialize` → `initialized` handshake and return the
|
|
@@ -247,6 +253,8 @@ export interface LspServerConnection extends Harness {
|
|
|
247
253
|
* associates with a language (silent no-diagnostics). `version` defaults to 1.
|
|
248
254
|
*/
|
|
249
255
|
openDocument(uri: string, text: string, languageId: string, version?: number): void;
|
|
256
|
+
/** Send `textDocument/didClose` for a document opened through this harness. */
|
|
257
|
+
closeDocument(uri: string): Promise<void>;
|
|
250
258
|
/** Send `textDocument/didChange` for `uri` as a single full-text replacement at `version`. */
|
|
251
259
|
changeDocument(uri: string, text: string, version: number): void;
|
|
252
260
|
|
|
@@ -319,6 +327,39 @@ export interface LspServerConnection extends Harness {
|
|
|
319
327
|
dispose(): void;
|
|
320
328
|
}
|
|
321
329
|
|
|
330
|
+
/**
|
|
331
|
+
* A `PassThrough` that counts the bytes written through it. Counting here
|
|
332
|
+
* rather than in a `'data'` listener is what keeps the wire buffering: a
|
|
333
|
+
* listener switches the stream to flowing mode, and a message written before
|
|
334
|
+
* the server calls `listen()` is then delivered to the counter alone and lost.
|
|
335
|
+
*/
|
|
336
|
+
class CountingPassThrough extends PassThrough {
|
|
337
|
+
bytes = 0;
|
|
338
|
+
|
|
339
|
+
override _transform(chunk: Buffer, _encoding: BufferEncoding, callback: TransformCallback): void {
|
|
340
|
+
this.bytes += chunk.length;
|
|
341
|
+
callback(null, chunk);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/** A crossed pair of {@link CountingPassThrough}s, disposed as one. */
|
|
346
|
+
function makeCountingStreamPair(): {
|
|
347
|
+
readonly clientToServer: CountingPassThrough;
|
|
348
|
+
readonly serverToClient: CountingPassThrough;
|
|
349
|
+
dispose(): void;
|
|
350
|
+
} {
|
|
351
|
+
const clientToServer = new CountingPassThrough();
|
|
352
|
+
const serverToClient = new CountingPassThrough();
|
|
353
|
+
return {
|
|
354
|
+
clientToServer,
|
|
355
|
+
serverToClient,
|
|
356
|
+
dispose(): void {
|
|
357
|
+
clientToServer.destroy();
|
|
358
|
+
serverToClient.destroy();
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
|
|
322
363
|
/**
|
|
323
364
|
* Build the in-process LSP transport seam (server `Connection` + client + wire +
|
|
324
365
|
* diagnostics capture + typed facades) WITHOUT attaching a server. The caller
|
|
@@ -331,7 +372,7 @@ export interface LspServerConnection extends Harness {
|
|
|
331
372
|
* additional protocol heads (data-server, GLSP) onto the same `shared` services.
|
|
332
373
|
*/
|
|
333
374
|
export function makeLspServerConnection(): LspServerConnection {
|
|
334
|
-
const pair =
|
|
375
|
+
const pair = makeCountingStreamPair();
|
|
335
376
|
|
|
336
377
|
// No-op watchDog: in-process, no LSP lifecycle event (parent-pid liveness, the
|
|
337
378
|
// `exit` notification, …) may exit the host test runner — `dispose()` owns
|
|
@@ -347,7 +388,7 @@ export function makeLspServerConnection(): LspServerConnection {
|
|
|
347
388
|
logger =>
|
|
348
389
|
createProtocolConnection(new StreamMessageReader(pair.clientToServer), new StreamMessageWriter(pair.serverToClient), logger),
|
|
349
390
|
watchDog,
|
|
350
|
-
ProposedFeatures.all
|
|
391
|
+
withHydraniumLspFeatures(ProposedFeatures.all)
|
|
351
392
|
);
|
|
352
393
|
|
|
353
394
|
// Client side mirrors the directions: reads serverToClient, writes clientToServer.
|
|
@@ -415,6 +456,11 @@ export function makeLspServerConnection(): LspServerConnection {
|
|
|
415
456
|
client,
|
|
416
457
|
diagnostics,
|
|
417
458
|
appliedEdits,
|
|
459
|
+
wireBytes: () => ({
|
|
460
|
+
clientToServer: pair.clientToServer.bytes,
|
|
461
|
+
serverToClient: pair.serverToClient.bytes,
|
|
462
|
+
total: pair.clientToServer.bytes + pair.serverToClient.bytes
|
|
463
|
+
}),
|
|
418
464
|
|
|
419
465
|
async initialize(params?: Partial<InitializeParams>): Promise<InitializeResult> {
|
|
420
466
|
const initializeParams: InitializeParams = {
|
|
@@ -455,6 +501,10 @@ export function makeLspServerConnection(): LspServerConnection {
|
|
|
455
501
|
});
|
|
456
502
|
},
|
|
457
503
|
|
|
504
|
+
async closeDocument(uri: string): Promise<void> {
|
|
505
|
+
await client.sendNotification(DidCloseTextDocumentNotification.type, { textDocument: { uri } });
|
|
506
|
+
},
|
|
507
|
+
|
|
458
508
|
changeDocument(uri: string, text: string, version: number): void {
|
|
459
509
|
client.sendNotification(DidChangeTextDocumentNotification.type, {
|
|
460
510
|
textDocument: { uri, version },
|