@hydranium/core 1.0.0-next.24 → 1.0.0-next.241
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/README.md +22 -17
- package/lib/documents/ast-document-manager.d.ts +219 -122
- package/lib/documents/ast-document-manager.d.ts.map +1 -1
- package/lib/documents/ast-document-manager.js +241 -130
- 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/client-session-errors.d.ts +15 -0
- package/lib/documents/client-session-errors.d.ts.map +1 -0
- package/lib/documents/client-session-errors.js +15 -0
- package/lib/documents/client-session-errors.js.map +1 -0
- package/lib/documents/client-session-registry.d.ts +146 -0
- package/lib/documents/client-session-registry.d.ts.map +1 -0
- package/lib/documents/client-session-registry.js +207 -0
- package/lib/documents/client-session-registry.js.map +1 -0
- package/lib/documents/dirty-state-tracker.d.ts +79 -0
- package/lib/documents/dirty-state-tracker.d.ts.map +1 -0
- package/lib/documents/dirty-state-tracker.js +69 -0
- package/lib/documents/dirty-state-tracker.js.map +1 -0
- package/lib/documents/document-release-handler.d.ts +179 -0
- package/lib/documents/document-release-handler.d.ts.map +1 -0
- package/lib/documents/document-release-handler.js +283 -0
- package/lib/documents/document-release-handler.js.map +1 -0
- package/lib/documents/document-release-scheduler.d.ts +67 -0
- package/lib/documents/document-release-scheduler.d.ts.map +1 -0
- package/lib/documents/document-release-scheduler.js +80 -0
- package/lib/documents/document-release-scheduler.js.map +1 -0
- package/lib/documents/file-system-task-queue.d.ts +49 -0
- package/lib/documents/file-system-task-queue.d.ts.map +1 -0
- package/lib/documents/file-system-task-queue.js +34 -0
- package/lib/documents/file-system-task-queue.js.map +1 -0
- package/lib/documents/hydranium-text-documents.d.ts +399 -282
- package/lib/documents/hydranium-text-documents.d.ts.map +1 -1
- package/lib/documents/hydranium-text-documents.js +816 -483
- package/lib/documents/hydranium-text-documents.js.map +1 -1
- package/lib/documents/index.d.ts +10 -2
- package/lib/documents/index.d.ts.map +1 -1
- package/lib/documents/index.js +10 -2
- package/lib/documents/index.js.map +1 -1
- package/lib/documents/language-client-shadow.d.ts +218 -0
- package/lib/documents/language-client-shadow.d.ts.map +1 -0
- package/lib/documents/language-client-shadow.js +283 -0
- package/lib/documents/language-client-shadow.js.map +1 -0
- package/lib/documents/model-ledger.d.ts +47 -0
- package/lib/documents/model-ledger.d.ts.map +1 -0
- package/lib/documents/model-ledger.js +30 -0
- package/lib/documents/model-ledger.js.map +1 -0
- package/lib/documents/text-ledger.d.ts +64 -0
- package/lib/documents/text-ledger.d.ts.map +1 -0
- package/lib/documents/text-ledger.js +63 -0
- package/lib/documents/text-ledger.js.map +1 -0
- package/lib/documents/version-sync-service.d.ts +134 -0
- package/lib/documents/version-sync-service.d.ts.map +1 -0
- package/lib/documents/version-sync-service.js +171 -0
- package/lib/documents/version-sync-service.js.map +1 -0
- package/lib/index.d.ts +5 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +8 -0
- package/lib/index.js.map +1 -1
- package/lib/langium/ast-extension/ast-extension-service.d.ts.map +1 -1
- package/lib/langium/ast-extension/ast-extension-service.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 +23 -16
- package/lib/langium/bootstrap.d.ts.map +1 -1
- package/lib/langium/bootstrap.js +66 -28
- package/lib/langium/bootstrap.js.map +1 -1
- package/lib/langium/build-phase-pass/build-phase-pass-service.d.ts.map +1 -1
- package/lib/langium/build-phase-pass/build-phase-pass-service.js.map +1 -1
- package/lib/langium/composite-ast-reflection.d.ts +46 -0
- package/lib/langium/composite-ast-reflection.d.ts.map +1 -0
- package/lib/langium/composite-ast-reflection.js +97 -0
- package/lib/langium/composite-ast-reflection.js.map +1 -0
- 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/config/settings.js.map +1 -1
- package/lib/langium/diagnostics/hydranium-langium-profiler.d.ts.map +1 -1
- package/lib/langium/diagnostics/hydranium-langium-profiler.js.map +1 -1
- package/lib/langium/diagnostics/logger.d.ts +10 -3
- package/lib/langium/diagnostics/logger.d.ts.map +1 -1
- package/lib/langium/diagnostics/logger.js +12 -5
- package/lib/langium/diagnostics/logger.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 +57 -16
- package/lib/langium/diagnostics/lsp-logger.js.map +1 -1
- package/lib/langium/diagnostics/server-tracer.d.ts.map +1 -1
- package/lib/langium/diagnostics/server-tracer.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.map +1 -1
- package/lib/langium/document-builder/build-session.js.map +1 -1
- package/lib/langium/document-builder/document-builder.d.ts +294 -33
- package/lib/langium/document-builder/document-builder.d.ts.map +1 -1
- package/lib/langium/document-builder/document-builder.js +477 -61
- package/lib/langium/document-builder/document-builder.js.map +1 -1
- package/lib/langium/documentation/comment-provider.d.ts.map +1 -1
- package/lib/langium/documentation/comment-provider.js.map +1 -1
- package/lib/langium/integration-services.d.ts +61 -19
- 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-rule.d.ts +16 -8
- package/lib/langium/integrity/integrity-rule.d.ts.map +1 -1
- package/lib/langium/integrity/integrity-rule.js.map +1 -1
- package/lib/langium/integrity/integrity-service.d.ts +81 -24
- package/lib/langium/integrity/integrity-service.d.ts.map +1 -1
- package/lib/langium/integrity/integrity-service.js +264 -57
- 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/keys/positional-key-provider.d.ts.map +1 -1
- package/lib/langium/keys/positional-key-provider.js.map +1 -1
- package/lib/langium/labeling/label-provider.d.ts.map +1 -1
- package/lib/langium/labeling/label-provider.js.map +1 -1
- package/lib/langium/language-module.d.ts +29 -4
- package/lib/langium/language-module.d.ts.map +1 -1
- package/lib/langium/language-module.js +18 -4
- package/lib/langium/language-module.js.map +1 -1
- package/lib/langium/model-service/client-session.d.ts +343 -0
- package/lib/langium/model-service/client-session.d.ts.map +1 -0
- package/lib/langium/model-service/client-session.js +411 -0
- package/lib/langium/model-service/client-session.js.map +1 -0
- package/lib/langium/model-service/index.d.ts +2 -0
- package/lib/langium/model-service/index.d.ts.map +1 -1
- package/lib/langium/model-service/index.js +2 -0
- package/lib/langium/model-service/index.js.map +1 -1
- package/lib/langium/model-service/model-events.d.ts +61 -0
- package/lib/langium/model-service/model-events.d.ts.map +1 -0
- package/lib/langium/model-service/model-events.js +10 -0
- package/lib/langium/model-service/model-events.js.map +1 -0
- package/lib/langium/model-service/model-service.d.ts +432 -282
- package/lib/langium/model-service/model-service.d.ts.map +1 -1
- package/lib/langium/model-service/model-service.js +504 -438
- package/lib/langium/model-service/model-service.js.map +1 -1
- package/lib/langium/module.d.ts +150 -35
- package/lib/langium/module.d.ts.map +1 -1
- package/lib/langium/module.js +47 -35
- 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/project/abstract-project-manager.d.ts.map +1 -1
- package/lib/langium/project/abstract-project-manager.js +9 -2
- package/lib/langium/project/abstract-project-manager.js.map +1 -1
- package/lib/langium/project/project-change-event.d.ts +2 -2
- package/lib/langium/project/single-project-manager.d.ts.map +1 -1
- package/lib/langium/project/single-project-manager.js.map +1 -1
- package/lib/langium/residency/cst-residency-service.d.ts +30 -10
- package/lib/langium/residency/cst-residency-service.d.ts.map +1 -1
- package/lib/langium/residency/cst-residency-service.js +23 -57
- package/lib/langium/residency/cst-residency-service.js.map +1 -1
- package/lib/langium/scope/ast-node-description-provider.d.ts.map +1 -1
- package/lib/langium/scope/ast-node-description-provider.js.map +1 -1
- package/lib/langium/scope/hydranium-scope-computation.d.ts.map +1 -1
- package/lib/langium/scope/hydranium-scope-computation.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/scope/reference-builder.d.ts.map +1 -1
- package/lib/langium/scope/reference-builder.js.map +1 -1
- package/lib/langium/scope/reference-candidate-provider.d.ts.map +1 -1
- package/lib/langium/scope/reference-candidate-provider.js.map +1 -1
- package/lib/langium/scope/scope-extension-service.d.ts.map +1 -1
- package/lib/langium/scope/scope-extension-service.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/serialization/json-serializer.d.ts +1 -1
- package/lib/langium/serialization/json-serializer.d.ts.map +1 -1
- package/lib/langium/serialization/json-serializer.js.map +1 -1
- package/lib/langium/serialization/yaml-serializer.d.ts.map +1 -1
- package/lib/langium/serialization/yaml-serializer.js.map +1 -1
- package/lib/langium/service-registry.d.ts +29 -1
- package/lib/langium/service-registry.d.ts.map +1 -1
- package/lib/langium/service-registry.js +37 -0
- package/lib/langium/service-registry.js.map +1 -1
- package/lib/langium/shared-services.d.ts +21 -6
- package/lib/langium/shared-services.d.ts.map +1 -1
- package/lib/langium/shared-services.js.map +1 -1
- package/lib/langium/single-langium-copy.d.ts +22 -0
- package/lib/langium/single-langium-copy.d.ts.map +1 -0
- package/lib/langium/single-langium-copy.js +36 -0
- package/lib/langium/single-langium-copy.js.map +1 -0
- package/lib/langium/transfer/transfer-encoder.d.ts +77 -26
- package/lib/langium/transfer/transfer-encoder.d.ts.map +1 -1
- package/lib/langium/transfer/transfer-encoder.js +46 -24
- 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/update-rewrite/normalize-empty-strings.d.ts.map +1 -1
- package/lib/langium/update-rewrite/update-rewrite-service.d.ts.map +1 -1
- package/lib/langium/update-rewrite/update-rewrite-service.js.map +1 -1
- package/lib/langium/update-rewrite/update-rewrite.d.ts +1 -1
- package/lib/langium/validation/document-validator.d.ts +280 -9
- 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/validation/validation-contribution-collector.d.ts +9 -1
- package/lib/langium/validation/validation-contribution-collector.d.ts.map +1 -1
- package/lib/langium/validation/validation-contribution-collector.js +1 -1
- package/lib/langium/validation/validation-contribution-collector.js.map +1 -1
- package/lib/langium/workspace/document-uri-policy.d.ts +15 -10
- package/lib/langium/workspace/document-uri-policy.d.ts.map +1 -1
- package/lib/langium/workspace/document-uri-policy.js +7 -5
- package/lib/langium/workspace/document-uri-policy.js.map +1 -1
- package/lib/langium/workspace/file-not-found.d.ts +23 -0
- package/lib/langium/workspace/file-not-found.d.ts.map +1 -0
- package/lib/langium/workspace/file-not-found.js +31 -0
- package/lib/langium/workspace/file-not-found.js.map +1 -0
- package/lib/langium/workspace/file-system-provider.d.ts +135 -9
- package/lib/langium/workspace/file-system-provider.d.ts.map +1 -1
- package/lib/langium/workspace/file-system-provider.js +93 -14
- package/lib/langium/workspace/file-system-provider.js.map +1 -1
- package/lib/langium/workspace/hydranium-langium-document-factory.d.ts +56 -1
- package/lib/langium/workspace/hydranium-langium-document-factory.d.ts.map +1 -1
- package/lib/langium/workspace/hydranium-langium-document-factory.js +79 -0
- package/lib/langium/workspace/hydranium-langium-document-factory.js.map +1 -1
- package/lib/langium/workspace/hydranium-workspace-lock.d.ts +43 -1
- package/lib/langium/workspace/hydranium-workspace-lock.d.ts.map +1 -1
- package/lib/langium/workspace/hydranium-workspace-lock.js +58 -1
- package/lib/langium/workspace/hydranium-workspace-lock.js.map +1 -1
- package/lib/langium/workspace/hydranium-workspace-manager.d.ts +82 -9
- package/lib/langium/workspace/hydranium-workspace-manager.d.ts.map +1 -1
- package/lib/langium/workspace/hydranium-workspace-manager.js +128 -10
- package/lib/langium/workspace/hydranium-workspace-manager.js.map +1 -1
- package/lib/langium/workspace/in-memory-file-system-provider.d.ts +26 -3
- package/lib/langium/workspace/in-memory-file-system-provider.d.ts.map +1 -1
- package/lib/langium/workspace/in-memory-file-system-provider.js +41 -15
- package/lib/langium/workspace/in-memory-file-system-provider.js.map +1 -1
- package/lib/langium/workspace/index-manager.d.ts.map +1 -1
- package/lib/langium/workspace/index-manager.js.map +1 -1
- package/lib/langium/workspace/index.d.ts +1 -0
- package/lib/langium/workspace/index.d.ts.map +1 -1
- package/lib/langium/workspace/index.js +1 -0
- package/lib/langium/workspace/index.js.map +1 -1
- package/lib/langium/workspace/initialize-workspace.d.ts +31 -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 +46 -4
- package/lib/langium/workspace/langium-documents.d.ts.map +1 -1
- package/lib/langium/workspace/langium-documents.js +60 -5
- package/lib/langium/workspace/langium-documents.js.map +1 -1
- package/lib/langium/workspace/persistent-file-system-provider.d.ts +1 -8
- package/lib/langium/workspace/persistent-file-system-provider.d.ts.map +1 -1
- package/lib/langium/workspace/persistent-file-system-provider.js +0 -7
- package/lib/langium/workspace/persistent-file-system-provider.js.map +1 -1
- package/lib/{documents → langium/workspace}/self-save-registry.d.ts +38 -7
- package/lib/langium/workspace/self-save-registry.d.ts.map +1 -0
- package/lib/{documents → langium/workspace}/self-save-registry.js +29 -16
- package/lib/langium/workspace/self-save-registry.js.map +1 -0
- package/lib/langium/workspace/virtual-document.d.ts +48 -15
- package/lib/langium/workspace/virtual-document.d.ts.map +1 -1
- package/lib/langium/workspace/virtual-document.js +78 -18
- package/lib/langium/workspace/virtual-document.js.map +1 -1
- package/lib/langium/workspace/write-lock-scope.d.ts +20 -10
- package/lib/langium/workspace/write-lock-scope.d.ts.map +1 -1
- package/lib/langium/workspace/write-lock-scope.js +12 -4
- package/lib/langium/workspace/write-lock-scope.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 +92 -81
- package/lib/lsp/hydranium-document-update-handler.d.ts.map +1 -1
- package/lib/lsp/hydranium-document-update-handler.js +153 -99
- 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/shared-module.d.ts +4 -8
- package/lib/lsp/shared-module.d.ts.map +1 -1
- package/lib/lsp/shared-module.js.map +1 -1
- package/lib/lsp/start-language-server.d.ts +8 -7
- package/lib/lsp/start-language-server.d.ts.map +1 -1
- package/lib/lsp/start-language-server.js +13 -7
- 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 +142 -0
- package/lib/messages/renderer.d.ts.map +1 -0
- package/lib/messages/renderer.js +165 -0
- package/lib/messages/renderer.js.map +1 -0
- package/lib/node/event-loop-monitor.js.map +1 -1
- 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 -1
- package/lib/node/index.d.ts.map +1 -1
- package/lib/node/index.js +1 -1
- 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/lint-grammar.js.map +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/memory-monitor.js.map +1 -1
- package/lib/node/node-file-system-provider.d.ts +41 -6
- package/lib/node/node-file-system-provider.d.ts.map +1 -1
- package/lib/node/node-file-system-provider.js +109 -49
- 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 +1 -1
- package/lib/node/profile-capture.js.map +1 -1
- package/lib/node/profile-digest.js.map +1 -1
- package/lib/node/profiling-run.d.ts +13 -3
- package/lib/node/profiling-run.d.ts.map +1 -1
- package/lib/node/profiling-run.js +17 -8
- 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 +20 -4
- package/lib/node/socket-launcher.d.ts.map +1 -1
- package/lib/node/socket-launcher.js +5 -4
- package/lib/node/socket-launcher.js.map +1 -1
- package/lib/node/stdio-launcher.d.ts +6 -5
- package/lib/node/stdio-launcher.d.ts.map +1 -1
- package/lib/node/stdio-launcher.js +2 -2
- package/lib/node/stdio-launcher.js.map +1 -1
- package/lib/testing/document-uri-policy-conformance.js.map +1 -1
- package/lib/testing/fake-description.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/index.d.ts +1 -1
- package/lib/testing/index.d.ts.map +1 -1
- package/lib/testing/index.js +2 -1
- package/lib/testing/index.js.map +1 -1
- package/lib/testing/langium-test-helpers.d.ts.map +1 -1
- package/lib/testing/langium-test-helpers.js +1 -0
- package/lib/testing/langium-test-helpers.js.map +1 -1
- package/lib/testing/make-noop-language-services.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 +72 -14
- package/lib/testing/make-test-services.d.ts.map +1 -1
- package/lib/testing/make-test-services.js +42 -10
- package/lib/testing/make-test-services.js.map +1 -1
- package/lib/testing/make-test-tracer.d.ts +12 -0
- package/lib/testing/make-test-tracer.d.ts.map +1 -1
- package/lib/testing/make-test-tracer.js +13 -0
- package/lib/testing/make-test-tracer.js.map +1 -1
- package/lib/testing/node/golden-corpus.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 +11 -3
- package/lib/testing/node/lsp-server-connection.d.ts.map +1 -1
- package/lib/testing/node/lsp-server-connection.js +43 -10
- 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 +10 -5
- 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 +34 -2
- 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/browser-capture-bridge.js.map +1 -1
- package/lib/testing/playwright/e2e-profiling.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 +24 -8
- package/lib/testing/playwright/server-log-capture.d.ts.map +1 -1
- package/lib/testing/playwright/server-log-capture.js +27 -6
- 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/run-update-pipeline.d.ts +4 -4
- package/lib/testing/run-update-pipeline.d.ts.map +1 -1
- package/lib/testing/stub-ast-document-manager.d.ts +11 -52
- package/lib/testing/stub-ast-document-manager.d.ts.map +1 -1
- package/lib/testing/stub-ast-document-manager.js +24 -65
- package/lib/testing/stub-ast-document-manager.js.map +1 -1
- package/lib/testing/stub-document-builder.d.ts +26 -11
- package/lib/testing/stub-document-builder.d.ts.map +1 -1
- package/lib/testing/stub-document-builder.js +78 -5
- package/lib/testing/stub-document-builder.js.map +1 -1
- package/lib/testing/stub-hydranium-text-documents.d.ts +33 -10
- package/lib/testing/stub-hydranium-text-documents.d.ts.map +1 -1
- package/lib/testing/stub-hydranium-text-documents.js +115 -16
- package/lib/testing/stub-hydranium-text-documents.js.map +1 -1
- package/lib/testing/stub-index-manager.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 +7 -6
- package/lib/testing/stub-model-service.d.ts.map +1 -1
- package/lib/testing/stub-model-service.js +4 -4
- package/lib/testing/stub-model-service.js.map +1 -1
- package/lib/testing/stub-project-manager.js.map +1 -1
- package/lib/testing/stub-self-save-registry.d.ts +1 -1
- package/lib/testing/stub-self-save-registry.d.ts.map +1 -1
- package/lib/testing/stub-service-registry.d.ts +1 -1
- package/lib/testing/stub-service-registry.js.map +1 -1
- package/lib/testing/stub-writable-file-system.d.ts +1 -1
- package/lib/testing/stub-writable-file-system.d.ts.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/lib/util/environment.d.ts.map +1 -1
- package/lib/util/environment.js.map +1 -1
- package/lib/util/registry.d.ts.map +1 -1
- package/package.json +32 -48
- package/src/documents/ast-document-manager.ts +379 -231
- package/src/documents/client-ids.ts +5 -22
- package/src/documents/client-session-errors.ts +24 -0
- package/src/documents/client-session-registry.ts +262 -0
- package/src/documents/dirty-state-tracker.ts +130 -0
- package/src/documents/document-release-handler.ts +365 -0
- package/src/documents/document-release-scheduler.ts +121 -0
- package/src/documents/file-system-task-queue.ts +68 -0
- package/src/documents/hydranium-text-documents.ts +931 -595
- package/src/documents/index.ts +10 -2
- package/src/documents/language-client-shadow.ts +451 -0
- package/src/documents/model-ledger.ts +66 -0
- package/src/documents/text-ledger.ts +112 -0
- package/src/documents/version-sync-service.ts +267 -0
- package/src/index.ts +8 -0
- package/src/langium/ast-extension/ast-node-builder.ts +66 -22
- package/src/langium/bootstrap.ts +66 -28
- package/src/langium/composite-ast-reflection.ts +112 -0
- package/src/langium/config/configuration-provider.ts +119 -0
- package/src/langium/config/index.ts +1 -0
- package/src/langium/diagnostics/logger.ts +12 -5
- package/src/langium/diagnostics/lsp-logger.ts +59 -15
- package/src/langium/document-builder/build-pipeline-integration.ts +50 -5
- package/src/langium/document-builder/document-builder.ts +565 -59
- package/src/langium/integration-services.ts +83 -24
- package/src/langium/integrity/integrity-rule.ts +16 -8
- package/src/langium/integrity/integrity-service.ts +287 -62
- 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 +48 -7
- package/src/langium/model-service/client-session.ts +644 -0
- package/src/langium/model-service/index.ts +2 -0
- package/src/langium/model-service/model-events.ts +75 -0
- package/src/langium/model-service/model-service.ts +790 -468
- package/src/langium/module.ts +199 -64
- package/src/langium/naming/name-provider.ts +27 -5
- package/src/langium/naming/name-separator-validation.ts +34 -5
- package/src/langium/project/abstract-project-manager.ts +9 -1
- package/src/langium/project/project-change-event.ts +2 -2
- package/src/langium/residency/cst-residency-service.ts +45 -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 +41 -2
- package/src/langium/shared-services.ts +21 -6
- package/src/langium/single-langium-copy.ts +42 -0
- package/src/langium/transfer/transfer-encoder.ts +104 -37
- 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/update-rewrite/update-rewrite.ts +1 -1
- package/src/langium/validation/document-validator.ts +523 -10
- package/src/langium/validation/validation-contribution-collector.ts +10 -1
- package/src/langium/workspace/document-uri-policy.ts +15 -10
- package/src/langium/workspace/file-not-found.ts +35 -0
- package/src/langium/workspace/file-system-provider.ts +205 -17
- package/src/langium/workspace/hydranium-langium-document-factory.ts +117 -0
- package/src/langium/workspace/hydranium-workspace-lock.ts +86 -2
- package/src/langium/workspace/hydranium-workspace-manager.ts +154 -14
- package/src/langium/workspace/in-memory-file-system-provider.ts +48 -17
- package/src/langium/workspace/index.ts +1 -0
- package/src/langium/workspace/initialize-workspace.ts +43 -5
- package/src/langium/workspace/langium-documents.ts +75 -6
- package/src/langium/workspace/persistent-file-system-provider.ts +1 -8
- package/src/{documents → langium/workspace}/self-save-registry.ts +54 -15
- package/src/langium/workspace/virtual-document.ts +96 -19
- package/src/langium/workspace/write-lock-scope.ts +24 -11
- 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 +187 -108
- 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/shared-module.ts +4 -8
- package/src/lsp/start-language-server.ts +13 -7
- package/src/messages/carriers.ts +78 -0
- package/src/messages/index.ts +36 -0
- package/src/messages/renderer.ts +212 -0
- package/src/node/heap-ceiling.ts +108 -0
- package/src/node/index.ts +1 -1
- 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 +124 -53
- package/src/node/profile-capture.ts +9 -3
- package/src/node/profiling-run.ts +30 -8
- package/src/node/rename-over-open-readers.ts +78 -0
- package/src/node/socket-launcher.ts +24 -8
- package/src/node/stdio-launcher.ts +8 -7
- package/src/testing/fake-document.ts +24 -5
- package/src/testing/index.ts +2 -1
- package/src/testing/langium-test-helpers.ts +1 -0
- package/src/testing/make-noop-shared-services.ts +50 -2
- package/src/testing/make-test-services.ts +125 -31
- package/src/testing/make-test-tracer.ts +26 -0
- 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 +66 -12
- package/src/testing/node/scratch-workspace.ts +10 -5
- package/src/testing/node/spawned-server.ts +36 -2
- package/src/testing/node/unhandled-rejections.ts +31 -0
- package/src/testing/parse-semantic-root.ts +1 -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 +45 -11
- package/src/testing/playwright/server-log-rename-reporter.ts +12 -1
- package/src/testing/run-update-pipeline.ts +4 -4
- package/src/testing/stub-ast-document-manager.ts +36 -138
- package/src/testing/stub-document-builder.ts +102 -18
- package/src/testing/stub-hydranium-text-documents.ts +165 -27
- package/src/testing/stub-langium-documents.ts +3 -2
- package/src/testing/stub-model-service.ts +9 -8
- package/src/testing/stub-self-save-registry.ts +1 -1
- package/src/testing/stub-service-registry.ts +1 -1
- package/src/testing/stub-writable-file-system.ts +1 -1
- package/src/util/connection-liveness.ts +37 -14
- package/src/util/environment.ts +9 -1
- package/lib/documents/language-client-text-shadow.d.ts +0 -101
- package/lib/documents/language-client-text-shadow.d.ts.map +0 -1
- package/lib/documents/language-client-text-shadow.js +0 -156
- package/lib/documents/language-client-text-shadow.js.map +0 -1
- package/lib/documents/self-save-registry.d.ts.map +0 -1
- package/lib/documents/self-save-registry.js.map +0 -1
- 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/lib/node/process-memory.d.ts +0 -66
- package/lib/node/process-memory.d.ts.map +0 -1
- package/lib/node/process-memory.js +0 -252
- package/lib/node/process-memory.js.map +0 -1
- package/src/documents/language-client-text-shadow.ts +0 -175
- package/src/lsp/instrument-connection.ts +0 -66
- package/src/node/process-memory.ts +0 -299
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
|
|
10
|
+
import { type URI, UriUtils } from '@hydranium/langium';
|
|
11
|
+
import { type CanonicalUri, type Tracer } from '@hydranium/protocol';
|
|
12
|
+
import { type CancellationToken, type Disposable } from 'vscode-languageserver';
|
|
13
|
+
import { type LogNameOptions } from '../langium/diagnostics/logger.js';
|
|
14
|
+
import { HYDRANIUM_BUILD_REASONS } from '../langium/document-builder/document-builder.js';
|
|
15
|
+
import { type ServerSharedServices } from '../langium/module.js';
|
|
16
|
+
import { isFileNotFound } from '../langium/workspace/file-not-found.js';
|
|
17
|
+
import { isConnectionGoneError } from '../util/connection-liveness.js';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A document the store has released: no client holds its text any more. Its
|
|
21
|
+
* queries read the store live, not a snapshot taken at the release.
|
|
22
|
+
*/
|
|
23
|
+
export interface ReleasedDocument {
|
|
24
|
+
readonly uri: CanonicalUri;
|
|
25
|
+
/** Whether `uri` names this document, under the store's own keying. */
|
|
26
|
+
isFor(uri: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Whether a client took the document back: it holds it again, or it waits
|
|
29
|
+
* out a new grace. Either way it is that client's, and the build keeps its text.
|
|
30
|
+
*/
|
|
31
|
+
isReclaimed(): boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The rejection of a release skipped because the connection or the workspace
|
|
36
|
+
* went away, with the error that showed it as `cause`. The store logs it at
|
|
37
|
+
* debug, as routine at teardown, and any other rejection as an error.
|
|
38
|
+
*/
|
|
39
|
+
export class DocumentReleaseSkippedError extends Error {
|
|
40
|
+
constructor(cause: unknown) {
|
|
41
|
+
super(`Release skipped: the connection or the workspace went away. ${cause instanceof Error ? cause.message : String(cause)}`, {
|
|
42
|
+
cause
|
|
43
|
+
});
|
|
44
|
+
this.name = 'DocumentReleaseSkippedError';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Whether `error` is a {@link DocumentReleaseSkippedError}, by name, so one
|
|
50
|
+
* thrown by another installed copy of this package counts too.
|
|
51
|
+
*/
|
|
52
|
+
export function isDocumentReleaseSkippedError(error: unknown): error is DocumentReleaseSkippedError {
|
|
53
|
+
return error instanceof Error && error.name === 'DocumentReleaseSkippedError';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Decides what the build keeps for a document the store has released. Called
|
|
58
|
+
* by the store at each release, for every head, after its release event.
|
|
59
|
+
*
|
|
60
|
+
* The returned promise settles the release: it resolves once the build holds
|
|
61
|
+
* what it keeps for the document, and rejects when that build failed and may
|
|
62
|
+
* still hold the released text. Until then, watchers keep a document released
|
|
63
|
+
* dirty marked dirty. On a resolve the store announces it clean, naming the
|
|
64
|
+
* store's last text while the build still has the document, and no text once
|
|
65
|
+
* it has none; on a rejection, no text. The store logs a throw or rejection; reject with a
|
|
66
|
+
* {@link DocumentReleaseSkippedError} for a release skipped at teardown.
|
|
67
|
+
*
|
|
68
|
+
* The data server announces the first build of a released document as the
|
|
69
|
+
* release, so a handler that builds nothing leaves that to whichever build
|
|
70
|
+
* comes next; one that carries a client's write keeps that client's name.
|
|
71
|
+
*
|
|
72
|
+
* Extend {@link DefaultDocumentReleaseHandler} to change only the policy: it
|
|
73
|
+
* keeps the locking and the wait for the build. An implementation written
|
|
74
|
+
* from scratch has to wait for that build itself before it resolves.
|
|
75
|
+
*/
|
|
76
|
+
export interface DocumentReleaseHandler {
|
|
77
|
+
didReleaseDocument(released: ReleasedDocument): Promise<void>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** What the build does with a released document: rebuild it from its file, or remove it. */
|
|
81
|
+
export type DocumentReleaseDecision = 'rebuild' | 'remove';
|
|
82
|
+
|
|
83
|
+
/** How {@link DefaultDocumentReleaseHandler.runRelease} went. */
|
|
84
|
+
export type DocumentReleaseOutcome =
|
|
85
|
+
/** A client took the document back: what the build keeps is that client's. */
|
|
86
|
+
| { readonly kind: 'reclaimed' }
|
|
87
|
+
/**
|
|
88
|
+
* The lock resolved the write without running it, and the write that
|
|
89
|
+
* cancelled it does not build this document. The framework's lock always
|
|
90
|
+
* runs a cancelled write; a rebound `WorkspaceLock` may not.
|
|
91
|
+
*/
|
|
92
|
+
| { readonly kind: 'discarded'; readonly decision: DocumentReleaseDecision }
|
|
93
|
+
/** The build started and was cancelled; `parsed` when it parsed the document first. */
|
|
94
|
+
| { readonly kind: 'cancelled'; readonly decision: DocumentReleaseDecision; readonly parsed: boolean }
|
|
95
|
+
/** The decision was carried out. */
|
|
96
|
+
| { readonly kind: 'completed'; readonly decision: DocumentReleaseDecision; readonly parsed: boolean }
|
|
97
|
+
/** The decision or the build threw; `decision` is unset when deciding did. */
|
|
98
|
+
| { readonly kind: 'failed'; readonly decision: DocumentReleaseDecision | undefined; readonly parsed: boolean; readonly error: unknown }
|
|
99
|
+
/** The connection or the workspace went away: nothing more is built. `parsed` when the build parsed the document first. */
|
|
100
|
+
| { readonly kind: 'skipped'; readonly parsed: boolean; readonly error: unknown };
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Rebuilds a released document from the file system provider, so the build
|
|
104
|
+
* stops carrying the unsaved text of its last client. Override
|
|
105
|
+
* `decideRelease` or `applyReleaseDecision` to change the policy and keep the
|
|
106
|
+
* locking and the wait for the build.
|
|
107
|
+
*
|
|
108
|
+
* The provider decides, for every scheme, by `exists`: a document it can
|
|
109
|
+
* serve is rebuilt from its text, and any other — an editor's `untitled:`
|
|
110
|
+
* buffer, a file never saved, or one deleted meanwhile — is removed
|
|
111
|
+
* from the workspace. A `virtual:` document survives, since the framework's
|
|
112
|
+
* provider for that scheme serves it from the index, whatever provider the
|
|
113
|
+
* host passes as `context.fileSystemProvider`; an edited one therefore keeps
|
|
114
|
+
* its last client's text, and keeping it read-only is the client's job.
|
|
115
|
+
*
|
|
116
|
+
* The answer is read in the document's disk queue, so the rebuild follows
|
|
117
|
+
* any save still queued rather than reverting past it; a file that goes
|
|
118
|
+
* after that read is removed when its rebuild finds none.
|
|
119
|
+
*
|
|
120
|
+
* Whether the document is still released is checked again inside the write
|
|
121
|
+
* lock, as its holder: checked only before waiting for the lock, a client that
|
|
122
|
+
* opens or re-creates the document meanwhile would have its text rebuilt over,
|
|
123
|
+
* or the document removed. A document some client has open again, or that
|
|
124
|
+
* waits out a new grace, is left to that client.
|
|
125
|
+
*
|
|
126
|
+
* The promise resolves once the revert has parsed the file, even if it is
|
|
127
|
+
* then cancelled, or else once the build it requests in its place has parsed
|
|
128
|
+
* it or removed the document. It rejects when that build fails, and when the
|
|
129
|
+
* revert is skipped because the connection or the workspace went away before
|
|
130
|
+
* it parsed the file, with a {@link DocumentReleaseSkippedError}.
|
|
131
|
+
*/
|
|
132
|
+
export class DefaultDocumentReleaseHandler implements DocumentReleaseHandler {
|
|
133
|
+
protected readonly tracer: Tracer;
|
|
134
|
+
|
|
135
|
+
constructor(
|
|
136
|
+
protected readonly services: ServerSharedServices,
|
|
137
|
+
options: LogNameOptions = {}
|
|
138
|
+
) {
|
|
139
|
+
this.tracer = services.Tracer.for(options.logName ?? this.constructor.name).trace('instantiated');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async didReleaseDocument(released: ReleasedDocument): Promise<void> {
|
|
143
|
+
const target = UriUtils.toUri(released.uri);
|
|
144
|
+
const outcome = await this.runRelease(released, target);
|
|
145
|
+
this.tracer.with(released.uri).debug(`Release outcome: ${this.formatReleaseOutcome(outcome)}`);
|
|
146
|
+
if (outcome.kind === 'skipped') {
|
|
147
|
+
if (!outcome.parsed) {
|
|
148
|
+
throw new DocumentReleaseSkippedError(outcome.error);
|
|
149
|
+
}
|
|
150
|
+
// The build holds the file's text: only what followed its parse, such as the diagnostics publish, was lost.
|
|
151
|
+
const { error } = outcome;
|
|
152
|
+
this.tracer
|
|
153
|
+
.with(released.uri)
|
|
154
|
+
.debug(`Revert on release skipped after its parse: ${error instanceof Error ? error.message : String(error)}`);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (outcome.kind === 'failed') {
|
|
158
|
+
const { error } = outcome;
|
|
159
|
+
this.tracer
|
|
160
|
+
.with(released.uri)
|
|
161
|
+
.error(`Revert on release dropped. ${error instanceof Error ? (error.stack ?? error.message) : String(error)}`);
|
|
162
|
+
}
|
|
163
|
+
const parsed = 'parsed' in outcome && outcome.parsed;
|
|
164
|
+
// Without it, a revert stopped short, or an override that built nothing,
|
|
165
|
+
// leaves the root on the released text. A failed one also lost the change
|
|
166
|
+
// the update handler held back at the release; a document known to have
|
|
167
|
+
// no file is removed, as the revert would have.
|
|
168
|
+
const stoppedShort =
|
|
169
|
+
((outcome.kind === 'discarded' || outcome.kind === 'cancelled' || outcome.kind === 'completed') &&
|
|
170
|
+
!parsed &&
|
|
171
|
+
this.services.workspace.LangiumDocuments.getDocument(target) !== undefined) ||
|
|
172
|
+
outcome.kind === 'failed';
|
|
173
|
+
const recover = async (): Promise<void> => {
|
|
174
|
+
const failure = 'Build after a revert that stopped short failed; the build keeps the released text';
|
|
175
|
+
let built: boolean;
|
|
176
|
+
try {
|
|
177
|
+
built = await this.requestRecoveryBuild(released, target, 'decision' in outcome && outcome.decision === 'remove');
|
|
178
|
+
} catch (err: unknown) {
|
|
179
|
+
throw new Error(`${failure}. ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
180
|
+
}
|
|
181
|
+
if (!built) {
|
|
182
|
+
throw new Error(failure);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
await this.waitForReleaseBuild(released, target, parsed, stoppedShort && !released.isReclaimed() ? recover : undefined);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Decide, then carry the decision out under the write lock unless a client
|
|
190
|
+
* holds the document again. Answers how that went; a parse of the document
|
|
191
|
+
* seen meanwhile counts even when the build was cancelled after it, since
|
|
192
|
+
* the build it yields to does not parse again.
|
|
193
|
+
*/
|
|
194
|
+
protected async runRelease(released: ReleasedDocument, target: URI): Promise<DocumentReleaseOutcome> {
|
|
195
|
+
const workspace = this.services.workspace;
|
|
196
|
+
let decision: DocumentReleaseDecision | undefined;
|
|
197
|
+
let parsed = false;
|
|
198
|
+
let parses: Disposable | undefined;
|
|
199
|
+
// Typed by assertion: the write's callback moves it, which narrowing does not see.
|
|
200
|
+
let progress = 'queued' as 'queued' | 'reclaimed' | 'building' | 'built';
|
|
201
|
+
try {
|
|
202
|
+
// Decided before the lock: every build and read waits while the lock
|
|
203
|
+
// is held, and the default decision waits on the file's save I/O.
|
|
204
|
+
const decided = await this.decideRelease(released, target);
|
|
205
|
+
decision = decided;
|
|
206
|
+
await workspace.WorkspaceManager?.ready;
|
|
207
|
+
// Queuing the write cancels the running build, even when it then reverts nothing.
|
|
208
|
+
if (released.isReclaimed()) {
|
|
209
|
+
return { kind: 'reclaimed' };
|
|
210
|
+
}
|
|
211
|
+
await workspace.WorkspaceLock.write(async token => {
|
|
212
|
+
if (released.isReclaimed()) {
|
|
213
|
+
progress = 'reclaimed';
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
parses = workspace.VersionSyncService.onDidRecordModel(document => {
|
|
217
|
+
parsed ||= released.isFor(document.uri.toString());
|
|
218
|
+
});
|
|
219
|
+
progress = 'building';
|
|
220
|
+
await this.applyReleaseDecision(target, decided, token);
|
|
221
|
+
progress = 'built';
|
|
222
|
+
});
|
|
223
|
+
// A cancelled build throws inside the write, and the lock resolves.
|
|
224
|
+
if (progress === 'reclaimed') {
|
|
225
|
+
return { kind: 'reclaimed' };
|
|
226
|
+
}
|
|
227
|
+
if (progress === 'queued') {
|
|
228
|
+
return { kind: 'discarded', decision: decided };
|
|
229
|
+
}
|
|
230
|
+
if (progress === 'building') {
|
|
231
|
+
return { kind: 'cancelled', decision: decided, parsed };
|
|
232
|
+
}
|
|
233
|
+
return { kind: 'completed', decision: decided, parsed };
|
|
234
|
+
} catch (error: unknown) {
|
|
235
|
+
// A revert that finishes after the LSP peer went away fails its
|
|
236
|
+
// diagnostics publish, and one that runs after its workspace was torn
|
|
237
|
+
// down finds no file: teardown races, not failed reverts.
|
|
238
|
+
if (isConnectionGoneError(error) || isFileNotFound(error, target)) {
|
|
239
|
+
return { kind: 'skipped', parsed, error };
|
|
240
|
+
}
|
|
241
|
+
return { kind: 'failed', decision, parsed, error };
|
|
242
|
+
} finally {
|
|
243
|
+
parses?.dispose();
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* `outcome` for the line each release logs at debug: its kind, the
|
|
249
|
+
* decision and whether the document was parsed.
|
|
250
|
+
*/
|
|
251
|
+
protected formatReleaseOutcome(outcome: DocumentReleaseOutcome): string {
|
|
252
|
+
if (outcome.kind === 'reclaimed') {
|
|
253
|
+
return 'reclaimed by a client, built nothing';
|
|
254
|
+
}
|
|
255
|
+
const decision = 'decision' in outcome && outcome.decision !== undefined ? ` ${outcome.decision}` : '';
|
|
256
|
+
const parsed = 'parsed' in outcome ? (outcome.parsed ? ', parsed' : ', not parsed') : '';
|
|
257
|
+
return `${outcome.kind}${decision}${parsed}`;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* The policy: rebuild a document the file system provider can serve, and
|
|
262
|
+
* remove any other. Read in the document's disk queue, so it follows any
|
|
263
|
+
* save still queued rather than deciding past it.
|
|
264
|
+
*/
|
|
265
|
+
protected decideRelease(released: ReleasedDocument, target: URI): Promise<DocumentReleaseDecision> {
|
|
266
|
+
const workspace = this.services.workspace;
|
|
267
|
+
return workspace.FileSystemTaskQueue.enqueue(released.uri, async () =>
|
|
268
|
+
(await workspace.FileSystemProvider.exists(target)) ? 'rebuild' : 'remove'
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Carry `decision` out under the write lock; a file gone since the decision
|
|
274
|
+
* is removed instead. An override must rebuild or remove the document:
|
|
275
|
+
* release settlement waits for its parse or removal, and one that does
|
|
276
|
+
* neither is followed by a recovery build that rebuilds it.
|
|
277
|
+
*/
|
|
278
|
+
protected async applyReleaseDecision(target: URI, decision: DocumentReleaseDecision, token: CancellationToken): Promise<void> {
|
|
279
|
+
const builder = this.services.workspace.DocumentBuilder;
|
|
280
|
+
builder.markNextReason(HYDRANIUM_BUILD_REASONS.didRelease);
|
|
281
|
+
try {
|
|
282
|
+
await (decision === 'rebuild' ? builder.update([target], [], token) : builder.update([], [target], token));
|
|
283
|
+
} catch (err: unknown) {
|
|
284
|
+
if (decision !== 'rebuild' || !isFileNotFound(err, target)) {
|
|
285
|
+
throw err;
|
|
286
|
+
}
|
|
287
|
+
this.tracer.with(target.toString()).debug('Revert found no file; removing the document instead');
|
|
288
|
+
builder.markNextReason(HYDRANIUM_BUILD_REASONS.didRelease);
|
|
289
|
+
await builder.update([], [target], token);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/** The build in place of a release that stopped short; answers whether it ran. */
|
|
294
|
+
protected requestRecoveryBuild(released: ReleasedDocument, target: URI, deleted: boolean): Promise<boolean> {
|
|
295
|
+
return this.services.workspace.VersionSyncService.requestRecoveryBuild(target, {
|
|
296
|
+
deleted,
|
|
297
|
+
reason: HYDRANIUM_BUILD_REASONS.didRelease,
|
|
298
|
+
// The update handler dropped the change it held back at the release.
|
|
299
|
+
ignoreDeferred: true,
|
|
300
|
+
stillNeeded: () => !released.isReclaimed()
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Resolve now when the build holds the file's text of `target` or no longer
|
|
306
|
+
* has it, else once a parse or removal of `target` reaches the store:
|
|
307
|
+
* settled with the released text still in the build, the release would name
|
|
308
|
+
* that text. `startRecovery` requests the build in place of a revert that
|
|
309
|
+
* stopped short, started only once the parse and removal are watched, so a
|
|
310
|
+
* build that records the document at once is not missed. Rejects when that
|
|
311
|
+
* build fails, since no parse or removal is coming then.
|
|
312
|
+
*/
|
|
313
|
+
protected waitForReleaseBuild(
|
|
314
|
+
released: ReleasedDocument,
|
|
315
|
+
target: URI,
|
|
316
|
+
parsed: boolean,
|
|
317
|
+
startRecovery: (() => Promise<void>) | undefined
|
|
318
|
+
): Promise<void> {
|
|
319
|
+
const workspace = this.services.workspace;
|
|
320
|
+
// A client holding the document again keeps what the build holds for it.
|
|
321
|
+
if (parsed || workspace.LangiumDocuments.getDocument(target) === undefined || released.isReclaimed()) {
|
|
322
|
+
// Settled now, so a failed recovery build is only logged.
|
|
323
|
+
startRecovery?.().catch((err: unknown) => this.tracer.with(released.uri).error(err instanceof Error ? err.message : String(err)));
|
|
324
|
+
return Promise.resolve();
|
|
325
|
+
}
|
|
326
|
+
return new Promise<void>((resolve, reject) => {
|
|
327
|
+
let ended = false;
|
|
328
|
+
const finish = (end: () => void): void => {
|
|
329
|
+
if (ended) {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
ended = true;
|
|
333
|
+
parses.dispose();
|
|
334
|
+
removals.dispose();
|
|
335
|
+
end();
|
|
336
|
+
};
|
|
337
|
+
const parses = workspace.VersionSyncService.onDidRecordModel(document => {
|
|
338
|
+
if (released.isFor(document.uri.toString())) {
|
|
339
|
+
finish(resolve);
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
const removals = workspace.DocumentBuilder.onUpdate((_changed, deleted) => {
|
|
343
|
+
if (deleted.some(uri => released.isFor(uri.toString()))) {
|
|
344
|
+
finish(resolve);
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
startRecovery?.().then(
|
|
348
|
+
// A recovery build no longer needed, for a reclaimed document, builds nothing.
|
|
349
|
+
() => {
|
|
350
|
+
if (released.isReclaimed()) {
|
|
351
|
+
finish(resolve);
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
(err: unknown) => {
|
|
355
|
+
// Settled by a parse that came first, so only logged.
|
|
356
|
+
if (ended) {
|
|
357
|
+
this.tracer.with(released.uri).error(err instanceof Error ? err.message : String(err));
|
|
358
|
+
} else {
|
|
359
|
+
finish(() => reject(err));
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
);
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
|
|
10
|
+
import { type CanonicalUri, type Clock, type Stopwatch } from '@hydranium/protocol';
|
|
11
|
+
import { type Disposable } from 'vscode-languageserver';
|
|
12
|
+
|
|
13
|
+
/** What an open of a document whose release is deferred means for it, as {@link DocumentReleaseScheduler.resolveOpen} decides. */
|
|
14
|
+
export type DeferredReleaseOpenDecision =
|
|
15
|
+
/** The opener was lost from the document within its grace: it keeps the unsaved text. */
|
|
16
|
+
| 'keep'
|
|
17
|
+
/** Any other opener: the document is released first, and opens as a first open does. */
|
|
18
|
+
| 'release'
|
|
19
|
+
/** No release was deferred. */
|
|
20
|
+
| 'none';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Decides when the store releases a document no client holds: at once, or,
|
|
24
|
+
* when its last client's connection was lost, once a grace has passed, so a
|
|
25
|
+
* client that reconnects in time finds its unsaved text.
|
|
26
|
+
*/
|
|
27
|
+
export interface DocumentReleaseScheduler {
|
|
28
|
+
/** How long a deferred release waits; `0` releases at once. */
|
|
29
|
+
readonly graceMs: number;
|
|
30
|
+
/** `clientId` closed `key` because its connection was lost. */
|
|
31
|
+
recordLoss(key: CanonicalUri, clientId: string): void;
|
|
32
|
+
/** No client holds `key` after a loss: run `release` once the grace has passed, or now when there is none. */
|
|
33
|
+
defer(key: CanonicalUri, release: () => void): void;
|
|
34
|
+
isDeferred(key: CanonicalUri): boolean;
|
|
35
|
+
/** `clientId` opens `key`; a deferred release ends either way. */
|
|
36
|
+
resolveOpen(key: CanonicalUri, clientId: string): DeferredReleaseOpenDecision;
|
|
37
|
+
/** End a deferred release of `key` without running it. */
|
|
38
|
+
cancel(key: CanonicalUri): void;
|
|
39
|
+
/** `key` was released: drop the losses recorded for it. */
|
|
40
|
+
clearLosses(key: CanonicalUri): void;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export class DefaultDocumentReleaseScheduler implements DocumentReleaseScheduler {
|
|
44
|
+
protected readonly deferred = new Map<CanonicalUri, Disposable>();
|
|
45
|
+
/**
|
|
46
|
+
* Per document, the clients whose close of it was caused by a lost
|
|
47
|
+
* connection and that have not opened it again, each with a stopwatch
|
|
48
|
+
* started at its loss. Every such client counts, not only the last to
|
|
49
|
+
* close: one connection's sessions all end lost together, and any of them
|
|
50
|
+
* may reopen first. A stopwatch rather than a `now()` reading, because a
|
|
51
|
+
* wall-clock step would otherwise expire a claim early or revive one past
|
|
52
|
+
* its grace, against a grace timer that the step leaves alone.
|
|
53
|
+
*/
|
|
54
|
+
protected readonly lostClients = new Map<CanonicalUri, Map<string, Stopwatch>>();
|
|
55
|
+
|
|
56
|
+
constructor(
|
|
57
|
+
protected readonly clock: Clock,
|
|
58
|
+
readonly graceMs: number
|
|
59
|
+
) {}
|
|
60
|
+
|
|
61
|
+
recordLoss(key: CanonicalUri, clientId: string): void {
|
|
62
|
+
let lost = this.lostClients.get(key);
|
|
63
|
+
if (!lost) {
|
|
64
|
+
lost = new Map();
|
|
65
|
+
this.lostClients.set(key, lost);
|
|
66
|
+
}
|
|
67
|
+
lost.set(clientId, this.clock.stopwatch());
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
defer(key: CanonicalUri, release: () => void): void {
|
|
71
|
+
this.cancel(key);
|
|
72
|
+
if (this.graceMs <= 0) {
|
|
73
|
+
release();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
this.deferred.set(
|
|
77
|
+
key,
|
|
78
|
+
this.clock.setTimer(() => {
|
|
79
|
+
this.deferred.delete(key);
|
|
80
|
+
release();
|
|
81
|
+
}, this.graceMs)
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
isDeferred(key: CanonicalUri): boolean {
|
|
86
|
+
return this.deferred.has(key);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* A claim past its grace counts as any other client's: without the limit,
|
|
91
|
+
* a client that returns late inherits the unsaved text of a holder lost
|
|
92
|
+
* after it. Cancelling for every open instead hands a lost client's unsaved
|
|
93
|
+
* text to whoever opens next, with nothing marking it unsaved.
|
|
94
|
+
*/
|
|
95
|
+
resolveOpen(key: CanonicalUri, clientId: string): DeferredReleaseOpenDecision {
|
|
96
|
+
const lost = this.lostClients.get(key);
|
|
97
|
+
for (const [lostId, sinceLoss] of lost ?? []) {
|
|
98
|
+
if (sinceLoss.elapsedMs >= this.graceMs) {
|
|
99
|
+
lost?.delete(lostId);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const returning = lost?.delete(clientId) ?? false;
|
|
103
|
+
if (lost?.size === 0) {
|
|
104
|
+
this.lostClients.delete(key);
|
|
105
|
+
}
|
|
106
|
+
if (!this.deferred.has(key)) {
|
|
107
|
+
return 'none';
|
|
108
|
+
}
|
|
109
|
+
this.cancel(key);
|
|
110
|
+
return returning ? 'keep' : 'release';
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
cancel(key: CanonicalUri): void {
|
|
114
|
+
this.deferred.get(key)?.dispose();
|
|
115
|
+
this.deferred.delete(key);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
clearLosses(key: CanonicalUri): void {
|
|
119
|
+
this.lostClients.delete(key);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
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 { type CanonicalUri } from '@hydranium/protocol';
|
|
11
|
+
import { type ServerSharedServices } from '../langium/module.js';
|
|
12
|
+
import { type DocumentUriPolicy } from '../langium/workspace/document-uri-policy.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* One queue of file-system tasks per file, shared by every server-side reader
|
|
16
|
+
* and writer of a file whose accesses must not interleave with its saves.
|
|
17
|
+
*
|
|
18
|
+
* Two writes of one file that bypass the queue can land in either order, and
|
|
19
|
+
* the older text then stays on disk. Tasks of different files run in
|
|
20
|
+
* parallel.
|
|
21
|
+
*/
|
|
22
|
+
export interface FileSystemTaskQueue {
|
|
23
|
+
/**
|
|
24
|
+
* Run `task` once every task already enqueued for `uri` has settled, and
|
|
25
|
+
* before any enqueued after it. `uri` is keyed by its canonical identity, so
|
|
26
|
+
* every spelling of one file shares a queue. A task that has nothing to do
|
|
27
|
+
* still resolves once the tasks before it have settled.
|
|
28
|
+
*
|
|
29
|
+
* A task must not await a build, nor a save, another task or an open of a
|
|
30
|
+
* document no client has open, all of the same file: a build's integrity
|
|
31
|
+
* repair enqueues its own write and the build waits for it, and such an
|
|
32
|
+
* open reads the file here, so a task waiting on either never resolves,
|
|
33
|
+
* which wedges the file's queue for good.
|
|
34
|
+
*/
|
|
35
|
+
enqueue<T>(uri: string, task: () => Promise<T>): Promise<T>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export class DefaultFileSystemTaskQueue implements FileSystemTaskQueue {
|
|
39
|
+
/**
|
|
40
|
+
* Per canonical URI, the settling of the last task enqueued for it; the next
|
|
41
|
+
* task chains behind it. An entry leaves once its file's queue is idle. Kept
|
|
42
|
+
* outside the workspace lock, whose `write` cancels the write before it: a
|
|
43
|
+
* save cancelled that way reports success for text it never wrote.
|
|
44
|
+
*/
|
|
45
|
+
protected readonly queues = new Map<CanonicalUri, Promise<void>>();
|
|
46
|
+
|
|
47
|
+
protected readonly uriPolicy: DocumentUriPolicy;
|
|
48
|
+
|
|
49
|
+
constructor(services: { readonly workspace: Pick<ServerSharedServices['workspace'], 'DocumentUriPolicy'> }) {
|
|
50
|
+
this.uriPolicy = services.workspace.DocumentUriPolicy;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
enqueue<T>(uri: string, task: () => Promise<T>): Promise<T> {
|
|
54
|
+
const key = this.uriPolicy.canonicalUri(uri);
|
|
55
|
+
const result = (this.queues.get(key) ?? Promise.resolve()).then(task);
|
|
56
|
+
const settled = result.then(
|
|
57
|
+
() => undefined,
|
|
58
|
+
() => undefined
|
|
59
|
+
);
|
|
60
|
+
this.queues.set(key, settled);
|
|
61
|
+
void settled.then(() => {
|
|
62
|
+
if (this.queues.get(key) === settled) {
|
|
63
|
+
this.queues.delete(key);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
}
|