@hydranium/core 1.0.0-next.39 → 1.0.0-next.390
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 +78 -82
- package/lib/browser/host-heads-in-worker.d.ts +77 -0
- package/lib/browser/host-heads-in-worker.d.ts.map +1 -0
- package/lib/browser/host-heads-in-worker.js +169 -0
- package/lib/browser/host-heads-in-worker.js.map +1 -0
- package/lib/browser/index.d.ts +12 -0
- package/lib/browser/index.d.ts.map +1 -0
- package/lib/browser/index.js +17 -0
- package/lib/browser/index.js.map +1 -0
- package/lib/browser/indexeddb-file-system-store.d.ts +82 -0
- package/lib/browser/indexeddb-file-system-store.d.ts.map +1 -0
- package/lib/browser/indexeddb-file-system-store.js +181 -0
- package/lib/browser/indexeddb-file-system-store.js.map +1 -0
- package/lib/browser/start-language-server-in-worker.d.ts +32 -0
- package/lib/browser/start-language-server-in-worker.d.ts.map +1 -0
- package/lib/browser/start-language-server-in-worker.js +40 -0
- package/lib/browser/start-language-server-in-worker.js.map +1 -0
- package/lib/documents/ast-document-manager.d.ts +254 -140
- package/lib/documents/ast-document-manager.d.ts.map +1 -1
- package/lib/documents/ast-document-manager.js +311 -128
- 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 +101 -0
- package/lib/documents/dirty-state-tracker.d.ts.map +1 -0
- package/lib/documents/dirty-state-tracker.js +85 -0
- package/lib/documents/dirty-state-tracker.js.map +1 -0
- package/lib/documents/document-release-handler.d.ts +204 -0
- package/lib/documents/document-release-handler.d.ts.map +1 -0
- package/lib/documents/document-release-handler.js +317 -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 +52 -0
- package/lib/documents/file-system-task-queue.d.ts.map +1 -0
- package/lib/documents/file-system-task-queue.js +40 -0
- package/lib/documents/file-system-task-queue.js.map +1 -0
- package/lib/documents/hydranium-text-documents.d.ts +453 -282
- package/lib/documents/hydranium-text-documents.d.ts.map +1 -1
- package/lib/documents/hydranium-text-documents.js +918 -504
- 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 +234 -0
- package/lib/documents/language-client-shadow.d.ts.map +1 -0
- package/lib/documents/language-client-shadow.js +306 -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 +153 -0
- package/lib/documents/version-sync-service.d.ts.map +1 -0
- package/lib/documents/version-sync-service.js +186 -0
- package/lib/documents/version-sync-service.js.map +1 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -0
- package/lib/index.js.map +1 -1
- package/lib/langium/ast-extension/ast-extension-service.d.ts +42 -31
- package/lib/langium/ast-extension/ast-extension-service.d.ts.map +1 -1
- package/lib/langium/ast-extension/ast-extension-service.js +45 -19
- package/lib/langium/ast-extension/ast-extension-service.js.map +1 -1
- package/lib/langium/ast-extension/ast-node-builder.d.ts +12 -7
- package/lib/langium/ast-extension/ast-node-builder.d.ts.map +1 -1
- package/lib/langium/ast-extension/ast-node-builder.js +25 -9
- package/lib/langium/ast-extension/ast-node-builder.js.map +1 -1
- package/lib/langium/bootstrap.d.ts +49 -36
- package/lib/langium/bootstrap.d.ts.map +1 -1
- package/lib/langium/bootstrap.js +75 -36
- package/lib/langium/bootstrap.js.map +1 -1
- package/lib/langium/build-phase-pass/build-phase-pass-service.d.ts +9 -9
- 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 +25 -16
- package/lib/langium/build-phase-pass/build-phase-pass-service.js.map +1 -1
- package/lib/langium/build-phase-pass/build-phase-pass.d.ts +20 -8
- package/lib/langium/build-phase-pass/build-phase-pass.d.ts.map +1 -1
- package/lib/langium/build-phase-pass/build-phase-pass.js +20 -0
- package/lib/langium/build-phase-pass/build-phase-pass.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/console-tee.d.ts +27 -0
- package/lib/langium/diagnostics/console-tee.d.ts.map +1 -0
- package/lib/langium/diagnostics/console-tee.js +141 -0
- package/lib/langium/diagnostics/console-tee.js.map +1 -0
- package/lib/langium/diagnostics/hydranium-langium-profiler.d.ts +9 -20
- package/lib/langium/diagnostics/hydranium-langium-profiler.d.ts.map +1 -1
- package/lib/langium/diagnostics/hydranium-langium-profiler.js +15 -24
- package/lib/langium/diagnostics/hydranium-langium-profiler.js.map +1 -1
- package/lib/langium/diagnostics/log-preamble.js +1 -1
- package/lib/langium/diagnostics/log-preamble.js.map +1 -1
- package/lib/langium/diagnostics/logger.d.ts +25 -6
- package/lib/langium/diagnostics/logger.d.ts.map +1 -1
- package/lib/langium/diagnostics/logger.js +49 -17
- package/lib/langium/diagnostics/logger.js.map +1 -1
- package/lib/langium/diagnostics/lsp-logger.d.ts +25 -0
- package/lib/langium/diagnostics/lsp-logger.d.ts.map +1 -1
- package/lib/langium/diagnostics/lsp-logger.js +81 -46
- 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 +43 -30
- package/lib/langium/document-builder/build-pipeline-integration.js.map +1 -1
- package/lib/langium/document-builder/build-session.d.ts +6 -5
- package/lib/langium/document-builder/build-session.d.ts.map +1 -1
- package/lib/langium/document-builder/build-session.js +5 -5
- package/lib/langium/document-builder/build-session.js.map +1 -1
- package/lib/langium/document-builder/document-builder.d.ts +390 -40
- package/lib/langium/document-builder/document-builder.d.ts.map +1 -1
- package/lib/langium/document-builder/document-builder.js +635 -102
- 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 +20 -23
- package/lib/langium/integration-services.d.ts.map +1 -1
- package/lib/langium/integration-services.js.map +1 -1
- package/lib/langium/integrity/integrity-rule.d.ts +22 -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 +217 -29
- package/lib/langium/integrity/integrity-service.d.ts.map +1 -1
- package/lib/langium/integrity/integrity-service.js +588 -84
- package/lib/langium/integrity/integrity-service.js.map +1 -1
- package/lib/langium/keys/containment.d.ts +3 -2
- package/lib/langium/keys/containment.d.ts.map +1 -1
- package/lib/langium/keys/containment.js.map +1 -1
- package/lib/langium/keys/name-based-key-provider.d.ts +17 -10
- package/lib/langium/keys/name-based-key-provider.d.ts.map +1 -1
- package/lib/langium/keys/name-based-key-provider.js +24 -12
- 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 +30 -5
- package/lib/langium/language-module.d.ts.map +1 -1
- package/lib/langium/language-module.js +21 -5
- package/lib/langium/language-module.js.map +1 -1
- package/lib/langium/model-service/client-session.d.ts +405 -0
- package/lib/langium/model-service/client-session.d.ts.map +1 -0
- package/lib/langium/model-service/client-session.js +479 -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 +68 -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 +441 -323
- package/lib/langium/model-service/model-service.d.ts.map +1 -1
- package/lib/langium/model-service/model-service.js +602 -407
- package/lib/langium/model-service/model-service.js.map +1 -1
- package/lib/langium/module.d.ts +96 -37
- package/lib/langium/module.d.ts.map +1 -1
- package/lib/langium/module.js +41 -29
- package/lib/langium/module.js.map +1 -1
- package/lib/langium/naming/name-provider.d.ts +32 -7
- package/lib/langium/naming/name-provider.d.ts.map +1 -1
- package/lib/langium/naming/name-provider.js +10 -4
- package/lib/langium/naming/name-provider.js.map +1 -1
- package/lib/langium/naming/name-separator-validation.d.ts.map +1 -1
- package/lib/langium/project/abstract-project-manager.d.ts +184 -13
- package/lib/langium/project/abstract-project-manager.d.ts.map +1 -1
- package/lib/langium/project/abstract-project-manager.js +336 -16
- package/lib/langium/project/abstract-project-manager.js.map +1 -1
- package/lib/langium/project/project-change-event.d.ts +22 -3
- package/lib/langium/project/project-change-event.d.ts.map +1 -1
- package/lib/langium/project/project-manager.d.ts +28 -2
- package/lib/langium/project/project-manager.d.ts.map +1 -1
- package/lib/langium/project/single-project-manager.d.ts +7 -1
- package/lib/langium/project/single-project-manager.d.ts.map +1 -1
- package/lib/langium/project/single-project-manager.js +12 -0
- package/lib/langium/project/single-project-manager.js.map +1 -1
- package/lib/langium/residency/cst-residency-service.d.ts +92 -52
- package/lib/langium/residency/cst-residency-service.d.ts.map +1 -1
- package/lib/langium/residency/cst-residency-service.js +154 -58
- package/lib/langium/residency/cst-residency-service.js.map +1 -1
- package/lib/langium/scope/ast-node-description-provider.d.ts +46 -10
- package/lib/langium/scope/ast-node-description-provider.d.ts.map +1 -1
- package/lib/langium/scope/ast-node-description-provider.js +88 -15
- package/lib/langium/scope/ast-node-description-provider.js.map +1 -1
- package/lib/langium/scope/built-local-symbols.d.ts +12 -0
- package/lib/langium/scope/built-local-symbols.d.ts.map +1 -0
- package/lib/langium/scope/built-local-symbols.js +11 -0
- package/lib/langium/scope/built-local-symbols.js.map +1 -0
- package/lib/langium/scope/fallback-scope.d.ts +27 -0
- package/lib/langium/scope/fallback-scope.d.ts.map +1 -0
- package/lib/langium/scope/fallback-scope.js +35 -0
- package/lib/langium/scope/fallback-scope.js.map +1 -0
- package/lib/langium/scope/hydranium-scope-computation.d.ts +21 -18
- package/lib/langium/scope/hydranium-scope-computation.d.ts.map +1 -1
- package/lib/langium/scope/hydranium-scope-computation.js +38 -39
- package/lib/langium/scope/hydranium-scope-computation.js.map +1 -1
- package/lib/langium/scope/hydranium-scope-provider.d.ts +122 -32
- package/lib/langium/scope/hydranium-scope-provider.d.ts.map +1 -1
- package/lib/langium/scope/hydranium-scope-provider.js +217 -39
- package/lib/langium/scope/hydranium-scope-provider.js.map +1 -1
- package/lib/langium/scope/index.d.ts +1 -0
- package/lib/langium/scope/index.d.ts.map +1 -1
- package/lib/langium/scope/index.js +1 -0
- package/lib/langium/scope/index.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 +6 -5
- package/lib/langium/scope/reference-candidate-provider.d.ts.map +1 -1
- package/lib/langium/scope/reference-candidate-provider.js +3 -2
- package/lib/langium/scope/reference-candidate-provider.js.map +1 -1
- package/lib/langium/scope/scope-extension-service.d.ts +69 -37
- package/lib/langium/scope/scope-extension-service.d.ts.map +1 -1
- package/lib/langium/scope/scope-extension-service.js +102 -29
- package/lib/langium/scope/scope-extension-service.js.map +1 -1
- package/lib/langium/scope/scoped-ast-node-description.d.ts +1 -3
- package/lib/langium/scope/scoped-ast-node-description.d.ts.map +1 -1
- package/lib/langium/scope/scoped-ast-node-description.js +1 -3
- package/lib/langium/scope/scoped-ast-node-description.js.map +1 -1
- package/lib/langium/serialization/abstract-serializer.d.ts +38 -27
- package/lib/langium/serialization/abstract-serializer.d.ts.map +1 -1
- package/lib/langium/serialization/abstract-serializer.js +54 -30
- package/lib/langium/serialization/abstract-serializer.js.map +1 -1
- package/lib/langium/serialization/json-serializer.d.ts +8 -1
- package/lib/langium/serialization/json-serializer.d.ts.map +1 -1
- package/lib/langium/serialization/json-serializer.js +13 -3
- package/lib/langium/serialization/json-serializer.js.map +1 -1
- package/lib/langium/serialization/serializer.d.ts +1 -1
- package/lib/langium/serialization/yaml-serializer.d.ts +12 -0
- package/lib/langium/serialization/yaml-serializer.d.ts.map +1 -1
- package/lib/langium/serialization/yaml-serializer.js +24 -4
- 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 +10 -4
- 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 +60 -39
- package/lib/langium/transfer/transfer-encoder.d.ts.map +1 -1
- package/lib/langium/transfer/transfer-encoder.js +35 -24
- package/lib/langium/transfer/transfer-encoder.js.map +1 -1
- package/lib/langium/trivia/comment-preserver.d.ts +543 -0
- package/lib/langium/trivia/comment-preserver.d.ts.map +1 -0
- package/lib/langium/trivia/comment-preserver.js +1165 -0
- package/lib/langium/trivia/comment-preserver.js.map +1 -0
- package/lib/langium/trivia/document-ending-preserver.d.ts +51 -0
- package/lib/langium/trivia/document-ending-preserver.d.ts.map +1 -0
- package/lib/langium/trivia/document-ending-preserver.js +62 -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 +52 -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 +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 +168 -23
- package/lib/langium/validation/document-validator.d.ts.map +1 -1
- package/lib/langium/validation/document-validator.js +264 -26
- 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/ast-node-locator.d.ts +24 -0
- package/lib/langium/workspace/ast-node-locator.d.ts.map +1 -0
- package/lib/langium/workspace/ast-node-locator.js +32 -0
- package/lib/langium/workspace/ast-node-locator.js.map +1 -0
- package/lib/langium/workspace/document-uri-policy.d.ts +24 -15
- package/lib/langium/workspace/document-uri-policy.d.ts.map +1 -1
- package/lib/langium/workspace/document-uri-policy.js +22 -13
- 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 +167 -8
- package/lib/langium/workspace/file-system-provider.d.ts.map +1 -1
- package/lib/langium/workspace/file-system-provider.js +115 -13
- package/lib/langium/workspace/file-system-provider.js.map +1 -1
- package/lib/langium/workspace/hydranium-langium-document-factory.d.ts +78 -4
- package/lib/langium/workspace/hydranium-langium-document-factory.d.ts.map +1 -1
- package/lib/langium/workspace/hydranium-langium-document-factory.js +188 -5
- package/lib/langium/workspace/hydranium-langium-document-factory.js.map +1 -1
- package/lib/langium/workspace/hydranium-workspace-lock.d.ts +50 -1
- package/lib/langium/workspace/hydranium-workspace-lock.d.ts.map +1 -1
- package/lib/langium/workspace/hydranium-workspace-lock.js +73 -1
- package/lib/langium/workspace/hydranium-workspace-lock.js.map +1 -1
- package/lib/langium/workspace/hydranium-workspace-manager.d.ts +105 -21
- package/lib/langium/workspace/hydranium-workspace-manager.d.ts.map +1 -1
- package/lib/langium/workspace/hydranium-workspace-manager.js +186 -31
- package/lib/langium/workspace/hydranium-workspace-manager.js.map +1 -1
- package/lib/langium/workspace/in-memory-file-system-provider.d.ts +26 -9
- package/lib/langium/workspace/in-memory-file-system-provider.d.ts.map +1 -1
- package/lib/langium/workspace/in-memory-file-system-provider.js +45 -22
- 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 +3 -0
- package/lib/langium/workspace/index.d.ts.map +1 -1
- package/lib/langium/workspace/index.js +3 -0
- package/lib/langium/workspace/index.js.map +1 -1
- package/lib/langium/workspace/initialize-workspace.d.ts +40 -3
- package/lib/langium/workspace/initialize-workspace.d.ts.map +1 -1
- package/lib/langium/workspace/initialize-workspace.js +68 -3
- package/lib/langium/workspace/initialize-workspace.js.map +1 -1
- package/lib/langium/workspace/langium-documents.d.ts +7 -0
- package/lib/langium/workspace/langium-documents.d.ts.map +1 -1
- package/lib/langium/workspace/langium-documents.js +18 -1
- package/lib/langium/workspace/langium-documents.js.map +1 -1
- package/lib/langium/workspace/persistent-file-system-provider.d.ts +16 -10
- package/lib/langium/workspace/persistent-file-system-provider.d.ts.map +1 -1
- package/lib/langium/workspace/persistent-file-system-provider.js +25 -13
- package/lib/langium/workspace/persistent-file-system-provider.js.map +1 -1
- package/lib/{documents → langium/workspace}/self-save-registry.d.ts +7 -9
- package/lib/langium/workspace/self-save-registry.d.ts.map +1 -0
- package/lib/{documents → langium/workspace}/self-save-registry.js +9 -11
- package/lib/langium/workspace/self-save-registry.js.map +1 -0
- package/lib/langium/workspace/syntax-errors.d.ts +23 -0
- package/lib/langium/workspace/syntax-errors.d.ts.map +1 -0
- package/lib/langium/workspace/syntax-errors.js +29 -0
- package/lib/langium/workspace/syntax-errors.js.map +1 -0
- package/lib/langium/workspace/virtual-document.d.ts +55 -21
- package/lib/langium/workspace/virtual-document.d.ts.map +1 -1
- package/lib/langium/workspace/virtual-document.js +87 -24
- package/lib/langium/workspace/virtual-document.js.map +1 -1
- package/lib/langium/workspace/write-lock-scope.d.ts +22 -10
- package/lib/langium/workspace/write-lock-scope.d.ts.map +1 -1
- package/lib/langium/workspace/write-lock-scope.js +15 -5
- package/lib/langium/workspace/write-lock-scope.js.map +1 -1
- package/lib/launcher/integrated-server.d.ts +3 -1
- package/lib/launcher/integrated-server.d.ts.map +1 -1
- package/lib/locale/server-locale.d.ts +6 -6
- package/lib/locale/server-locale.d.ts.map +1 -1
- package/lib/locale/server-locale.js.map +1 -1
- 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/edit-requests-guard.d.ts +31 -0
- package/lib/lsp/edit-requests-guard.d.ts.map +1 -0
- package/lib/lsp/edit-requests-guard.js +125 -0
- package/lib/lsp/edit-requests-guard.js.map +1 -0
- package/lib/lsp/hydranium-document-update-handler.d.ts +126 -82
- package/lib/lsp/hydranium-document-update-handler.d.ts.map +1 -1
- package/lib/lsp/hydranium-document-update-handler.js +234 -101
- package/lib/lsp/hydranium-document-update-handler.js.map +1 -1
- package/lib/lsp/index.d.ts +6 -2
- package/lib/lsp/index.d.ts.map +1 -1
- package/lib/lsp/index.js +6 -2
- 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/save-text-document.d.ts +31 -0
- package/lib/lsp/save-text-document.d.ts.map +1 -0
- package/lib/lsp/save-text-document.js +52 -0
- package/lib/lsp/save-text-document.js.map +1 -0
- package/lib/lsp/semantic-token-provider.d.ts +58 -2
- package/lib/lsp/semantic-token-provider.d.ts.map +1 -1
- package/lib/lsp/semantic-token-provider.js +98 -9
- 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 +12 -7
- package/lib/lsp/start-language-server.d.ts.map +1 -1
- package/lib/lsp/start-language-server.js +21 -7
- package/lib/lsp/start-language-server.js.map +1 -1
- package/lib/messages/carriers.d.ts +4 -6
- package/lib/messages/carriers.d.ts.map +1 -1
- package/lib/messages/carriers.js +4 -6
- package/lib/messages/carriers.js.map +1 -1
- package/lib/messages/index.d.ts +2 -2
- package/lib/messages/index.d.ts.map +1 -1
- package/lib/messages/index.js +2 -2
- package/lib/messages/index.js.map +1 -1
- package/lib/messages/renderer.d.ts +10 -4
- package/lib/messages/renderer.d.ts.map +1 -1
- package/lib/messages/renderer.js +6 -0
- package/lib/messages/renderer.js.map +1 -1
- package/lib/node/event-loop-monitor.d.ts.map +1 -1
- package/lib/node/event-loop-monitor.js +3 -2
- 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 +5 -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/log-file-sink.d.ts +3 -2
- package/lib/node/log-file-sink.d.ts.map +1 -1
- package/lib/node/log-file-sink.js +6 -2
- package/lib/node/log-file-sink.js.map +1 -1
- package/lib/node/log-preamble-node.d.ts +5 -3
- package/lib/node/log-preamble-node.d.ts.map +1 -1
- package/lib/node/log-preamble-node.js +13 -10
- package/lib/node/log-preamble-node.js.map +1 -1
- package/lib/node/measure-memory.d.ts.map +1 -1
- package/lib/node/measure-memory.js +5 -4
- package/lib/node/measure-memory.js.map +1 -1
- package/lib/node/memory-monitor.d.ts +2 -2
- package/lib/node/memory-monitor.d.ts.map +1 -1
- package/lib/node/memory-monitor.js +9 -10
- package/lib/node/memory-monitor.js.map +1 -1
- package/lib/node/node-file-system-provider.d.ts +67 -9
- package/lib/node/node-file-system-provider.d.ts.map +1 -1
- package/lib/node/node-file-system-provider.js +198 -53
- package/lib/node/node-file-system-provider.js.map +1 -1
- package/lib/node/profile-capture.d.ts +12 -4
- package/lib/node/profile-capture.d.ts.map +1 -1
- package/lib/node/profile-capture.js +8 -6
- 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 +61 -0
- package/lib/node/rename-over-open-readers.d.ts.map +1 -0
- package/lib/node/rename-over-open-readers.js +80 -0
- package/lib/node/rename-over-open-readers.js.map +1 -0
- package/lib/node/server-diagnostics.js +1 -1
- package/lib/node/server-diagnostics.js.map +1 -1
- package/lib/node/server-state-snapshot.d.ts +6 -5
- package/lib/node/server-state-snapshot.d.ts.map +1 -1
- package/lib/node/server-state-snapshot.js +20 -17
- package/lib/node/server-state-snapshot.js.map +1 -1
- package/lib/node/socket-launcher.d.ts +43 -7
- package/lib/node/socket-launcher.d.ts.map +1 -1
- package/lib/node/socket-launcher.js +42 -7
- package/lib/node/socket-launcher.js.map +1 -1
- package/lib/node/startup-cpu-profile.d.ts +29 -0
- package/lib/node/startup-cpu-profile.d.ts.map +1 -0
- package/lib/node/startup-cpu-profile.js +91 -0
- package/lib/node/startup-cpu-profile.js.map +1 -0
- package/lib/node/stdio-launcher.d.ts +13 -13
- package/lib/node/stdio-launcher.d.ts.map +1 -1
- package/lib/node/stdio-launcher.js +21 -11
- package/lib/node/stdio-launcher.js.map +1 -1
- package/lib/node/validate-workspace.d.ts +1 -1
- package/lib/node/validate-workspace.d.ts.map +1 -1
- package/lib/node/validate-workspace.js +5 -1
- package/lib/node/validate-workspace.js.map +1 -1
- package/lib/testing/document-uri-policy-conformance.js +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 +2 -1
- package/lib/testing/fake-document.d.ts.map +1 -1
- 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.js.map +1 -1
- package/lib/testing/make-test-services.d.ts +45 -14
- package/lib/testing/make-test-services.d.ts.map +1 -1
- package/lib/testing/make-test-services.js +23 -7
- 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/applied-edit-capture.d.ts +29 -0
- package/lib/testing/node/applied-edit-capture.d.ts.map +1 -0
- package/lib/testing/node/applied-edit-capture.js +117 -0
- package/lib/testing/node/applied-edit-capture.js.map +1 -0
- package/lib/testing/node/golden-corpus.js.map +1 -1
- package/lib/testing/node/index.d.ts +4 -1
- package/lib/testing/node/index.d.ts.map +1 -1
- package/lib/testing/node/index.js +4 -1
- 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 +21 -6
- package/lib/testing/node/lsp-server-connection.d.ts.map +1 -1
- package/lib/testing/node/lsp-server-connection.js +49 -106
- package/lib/testing/node/lsp-server-connection.js.map +1 -1
- package/lib/testing/node/scratch-workspace.d.ts +2 -1
- package/lib/testing/node/scratch-workspace.d.ts.map +1 -1
- package/lib/testing/node/scratch-workspace.js +12 -6
- package/lib/testing/node/scratch-workspace.js.map +1 -1
- package/lib/testing/node/settle-server.d.ts +33 -0
- package/lib/testing/node/settle-server.d.ts.map +1 -0
- package/lib/testing/node/settle-server.js +84 -0
- package/lib/testing/node/settle-server.js.map +1 -0
- package/lib/testing/node/spawned-server.d.ts +30 -1
- package/lib/testing/node/spawned-server.d.ts.map +1 -1
- package/lib/testing/node/spawned-server.js +39 -2
- package/lib/testing/node/spawned-server.js.map +1 -1
- 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 +46 -16
- package/lib/testing/playwright/server-log-capture.d.ts.map +1 -1
- package/lib/testing/playwright/server-log-capture.js +111 -40
- package/lib/testing/playwright/server-log-capture.js.map +1 -1
- package/lib/testing/playwright/server-log-fixture.d.ts +16 -0
- package/lib/testing/playwright/server-log-fixture.d.ts.map +1 -1
- package/lib/testing/playwright/server-log-fixture.js +25 -6
- package/lib/testing/playwright/server-log-fixture.js.map +1 -1
- package/lib/testing/playwright/server-log-region.d.ts +15 -0
- package/lib/testing/playwright/server-log-region.d.ts.map +1 -0
- package/lib/testing/playwright/server-log-region.js +30 -0
- package/lib/testing/playwright/server-log-region.js.map +1 -0
- package/lib/testing/playwright/server-log-rename-reporter.d.ts.map +1 -1
- package/lib/testing/playwright/server-log-rename-reporter.js +4 -3
- package/lib/testing/playwright/server-log-rename-reporter.js.map +1 -1
- package/lib/testing/run-update-pipeline.d.ts +8 -5
- package/lib/testing/run-update-pipeline.d.ts.map +1 -1
- package/lib/testing/run-update-pipeline.js.map +1 -1
- package/lib/testing/stub-ast-document-manager.d.ts +11 -51
- package/lib/testing/stub-ast-document-manager.d.ts.map +1 -1
- package/lib/testing/stub-ast-document-manager.js +31 -59
- package/lib/testing/stub-ast-document-manager.js.map +1 -1
- package/lib/testing/stub-document-builder.d.ts +25 -11
- package/lib/testing/stub-document-builder.d.ts.map +1 -1
- package/lib/testing/stub-document-builder.js +91 -2
- 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 +132 -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 +8 -7
- 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.d.ts.map +1 -1
- package/lib/testing/stub-project-manager.js +10 -0
- 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/testing/stub-writable-file-system.js +2 -1
- package/lib/testing/stub-writable-file-system.js.map +1 -1
- package/lib/util/connection-liveness.d.ts +22 -6
- package/lib/util/connection-liveness.d.ts.map +1 -1
- package/lib/util/connection-liveness.js +75 -15
- package/lib/util/connection-liveness.js.map +1 -1
- package/lib/util/environment.d.ts +7 -0
- package/lib/util/environment.d.ts.map +1 -1
- package/lib/util/environment.js +15 -1
- package/lib/util/environment.js.map +1 -1
- package/lib/util/registry.d.ts.map +1 -1
- package/package.json +41 -60
- package/src/browser/host-heads-in-worker.ts +218 -0
- package/src/browser/index.ts +17 -0
- package/src/browser/indexeddb-file-system-store.ts +192 -0
- package/src/browser/start-language-server-in-worker.ts +56 -0
- package/src/documents/ast-document-manager.ts +477 -250
- package/src/documents/client-ids.ts +5 -22
- package/src/documents/client-session-errors.ts +26 -0
- package/src/documents/client-session-registry.ts +262 -0
- package/src/documents/dirty-state-tracker.ts +167 -0
- package/src/documents/document-release-handler.ts +404 -0
- package/src/documents/document-release-scheduler.ts +121 -0
- package/src/documents/file-system-task-queue.ts +77 -0
- package/src/documents/hydranium-text-documents.ts +1044 -615
- package/src/documents/index.ts +10 -2
- package/src/documents/language-client-shadow.ts +501 -0
- package/src/documents/model-ledger.ts +66 -0
- package/src/documents/text-ledger.ts +112 -0
- package/src/documents/version-sync-service.ts +304 -0
- package/src/index.ts +3 -0
- package/src/langium/ast-extension/ast-extension-service.ts +77 -41
- package/src/langium/ast-extension/ast-node-builder.ts +35 -13
- package/src/langium/bootstrap.ts +79 -43
- package/src/langium/build-phase-pass/build-phase-pass-service.ts +29 -19
- package/src/langium/build-phase-pass/build-phase-pass.ts +37 -8
- 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/console-tee.ts +150 -0
- package/src/langium/diagnostics/hydranium-langium-profiler.ts +15 -39
- package/src/langium/diagnostics/log-preamble.ts +1 -1
- package/src/langium/diagnostics/logger.ts +51 -17
- package/src/langium/diagnostics/lsp-logger.ts +83 -45
- package/src/langium/document-builder/build-pipeline-integration.ts +57 -32
- package/src/langium/document-builder/build-session.ts +4 -3
- package/src/langium/document-builder/document-builder.ts +773 -106
- package/src/langium/integration-services.ts +20 -23
- package/src/langium/integrity/integrity-rule.ts +22 -8
- package/src/langium/integrity/integrity-service.ts +656 -90
- package/src/langium/keys/containment.ts +3 -2
- package/src/langium/keys/name-based-key-provider.ts +24 -12
- package/src/langium/language-module.ts +52 -9
- package/src/langium/model-service/client-session.ts +769 -0
- package/src/langium/model-service/index.ts +2 -0
- package/src/langium/model-service/model-events.ts +82 -0
- package/src/langium/model-service/model-service.ts +885 -532
- package/src/langium/module.ts +141 -65
- package/src/langium/naming/name-provider.ts +34 -8
- package/src/langium/project/abstract-project-manager.ts +409 -20
- package/src/langium/project/project-change-event.ts +25 -3
- package/src/langium/project/project-manager.ts +31 -2
- package/src/langium/project/single-project-manager.ts +16 -1
- package/src/langium/residency/cst-residency-service.ts +210 -87
- package/src/langium/scope/ast-node-description-provider.ts +111 -16
- package/src/langium/scope/built-local-symbols.ts +13 -0
- package/src/langium/scope/fallback-scope.ts +38 -0
- package/src/langium/scope/hydranium-scope-computation.ts +45 -44
- package/src/langium/scope/hydranium-scope-provider.ts +245 -41
- package/src/langium/scope/index.ts +1 -0
- package/src/langium/scope/reference-candidate-provider.ts +6 -5
- package/src/langium/scope/scope-extension-service.ts +148 -56
- package/src/langium/scope/scoped-ast-node-description.ts +1 -3
- package/src/langium/serialization/abstract-serializer.ts +57 -41
- package/src/langium/serialization/json-serializer.ts +14 -3
- package/src/langium/serialization/serializer.ts +1 -1
- package/src/langium/serialization/yaml-serializer.ts +26 -4
- package/src/langium/service-registry.ts +41 -2
- package/src/langium/shared-services.ts +13 -4
- package/src/langium/single-langium-copy.ts +42 -0
- package/src/langium/transfer/transfer-encoder.ts +76 -50
- package/src/langium/trivia/comment-preserver.ts +1410 -0
- package/src/langium/trivia/document-ending-preserver.ts +71 -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 +56 -0
- package/src/langium/trivia/trivia-service.ts +99 -0
- package/src/langium/update-rewrite/update-rewrite-service.ts +1 -1
- package/src/langium/update-rewrite/update-rewrite.ts +1 -1
- package/src/langium/validation/document-validator.ts +312 -31
- package/src/langium/validation/validation-contribution-collector.ts +10 -1
- package/src/langium/workspace/ast-node-locator.ts +33 -0
- package/src/langium/workspace/document-uri-policy.ts +32 -18
- package/src/langium/workspace/file-not-found.ts +35 -0
- package/src/langium/workspace/file-system-provider.ts +258 -16
- package/src/langium/workspace/hydranium-langium-document-factory.ts +239 -4
- package/src/langium/workspace/hydranium-workspace-lock.ts +101 -2
- package/src/langium/workspace/hydranium-workspace-manager.ts +214 -35
- package/src/langium/workspace/in-memory-file-system-provider.ts +54 -23
- package/src/langium/workspace/index.ts +3 -0
- package/src/langium/workspace/initialize-workspace.ts +96 -4
- package/src/langium/workspace/langium-documents.ts +19 -1
- package/src/langium/workspace/persistent-file-system-provider.ts +27 -15
- package/src/{documents → langium/workspace}/self-save-registry.ts +12 -14
- package/src/langium/workspace/syntax-errors.ts +34 -0
- package/src/langium/workspace/virtual-document.ts +106 -25
- package/src/langium/workspace/write-lock-scope.ts +27 -12
- package/src/launcher/integrated-server.ts +3 -1
- package/src/locale/server-locale.ts +6 -6
- 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/edit-requests-guard.ts +152 -0
- package/src/lsp/hydranium-document-update-handler.ts +284 -110
- package/src/lsp/index.ts +6 -2
- package/src/lsp/lsp-latency.ts +62 -0
- package/src/lsp/save-text-document.ts +63 -0
- package/src/lsp/semantic-token-provider.ts +146 -8
- package/src/lsp/shared-module.ts +4 -8
- package/src/lsp/start-language-server.ts +21 -7
- package/src/messages/carriers.ts +4 -6
- package/src/messages/index.ts +11 -2
- package/src/messages/renderer.ts +11 -3
- package/src/node/event-loop-monitor.ts +3 -4
- package/src/node/heap-ceiling.ts +108 -0
- package/src/node/index.ts +5 -1
- package/src/node/latency-from-env.ts +1 -1
- package/src/node/log-file-sink.ts +6 -2
- package/src/node/log-preamble-node.ts +20 -10
- package/src/node/measure-memory.ts +5 -4
- package/src/node/memory-monitor.ts +10 -10
- package/src/node/node-file-system-provider.ts +214 -57
- package/src/node/profile-capture.ts +16 -15
- package/src/node/profiling-run.ts +30 -8
- package/src/node/rename-over-open-readers.ts +94 -0
- package/src/node/server-diagnostics.ts +1 -1
- package/src/node/server-state-snapshot.ts +28 -20
- package/src/node/socket-launcher.ts +78 -14
- package/src/node/startup-cpu-profile.ts +94 -0
- package/src/node/stdio-launcher.ts +29 -19
- package/src/node/validate-workspace.ts +8 -2
- package/src/testing/document-uri-policy-conformance.ts +1 -1
- package/src/testing/fake-document.ts +2 -1
- package/src/testing/index.ts +2 -1
- package/src/testing/langium-test-helpers.ts +1 -0
- package/src/testing/make-test-services.ts +83 -31
- package/src/testing/make-test-tracer.ts +26 -0
- package/src/testing/node/applied-edit-capture.ts +141 -0
- package/src/testing/node/index.ts +4 -1
- package/src/testing/node/lsp-harness.ts +2 -0
- package/src/testing/node/lsp-server-connection.ts +83 -119
- package/src/testing/node/scratch-workspace.ts +12 -6
- package/src/testing/node/settle-server.ts +89 -0
- package/src/testing/node/spawned-server.ts +57 -3
- 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 +137 -47
- package/src/testing/playwright/server-log-fixture.ts +46 -6
- package/src/testing/playwright/server-log-region.ts +32 -0
- package/src/testing/playwright/server-log-rename-reporter.ts +4 -3
- package/src/testing/run-update-pipeline.ts +8 -5
- package/src/testing/stub-ast-document-manager.ts +47 -123
- package/src/testing/stub-document-builder.ts +128 -15
- package/src/testing/stub-hydranium-text-documents.ts +184 -27
- package/src/testing/stub-langium-documents.ts +3 -2
- package/src/testing/stub-model-service.ts +9 -8
- package/src/testing/stub-project-manager.ts +10 -0
- 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 +3 -2
- package/src/util/connection-liveness.ts +81 -15
- package/src/util/environment.ts +24 -2
- package/lib/documents/language-client-text-shadow.d.ts +0 -124
- package/lib/documents/language-client-text-shadow.d.ts.map +0 -1
- package/lib/documents/language-client-text-shadow.js +0 -190
- 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 -211
- package/src/lsp/instrument-connection.ts +0 -66
- package/src/node/process-memory.ts +0 -299
|
@@ -6,9 +6,12 @@
|
|
|
6
6
|
*
|
|
7
7
|
* SPDX-License-Identifier: MIT
|
|
8
8
|
********************************************************************************/
|
|
9
|
-
import { isPromiseLike, Logger } from '@hydranium/protocol';
|
|
10
|
-
import { AstUtils, DocumentState, interruptAndCheck, UriUtils } from '@hydranium/langium';
|
|
9
|
+
import { describeErrorWithStack, isPromiseLike, Logger, textHash } from '@hydranium/protocol';
|
|
10
|
+
import { AstUtils, DocumentState, interruptAndCheck, isMultiReference, isOperationCancelled, UriUtils } from '@hydranium/langium';
|
|
11
|
+
import { CancellationToken } from 'vscode-languageserver';
|
|
11
12
|
import { Registry } from '../../util/registry.js';
|
|
13
|
+
import { hasSkippedText } from '../workspace/syntax-errors.js';
|
|
14
|
+
import { isVirtualUri } from '../workspace/virtual-document.js';
|
|
12
15
|
import { IntegrityPhase } from './integrity-rule.js';
|
|
13
16
|
export var IntegrityService;
|
|
14
17
|
(function (IntegrityService) {
|
|
@@ -23,11 +26,21 @@ export var IntegrityService;
|
|
|
23
26
|
* at `DocumentState.Validated` and delivered separately via `publishDiagnostics`
|
|
24
27
|
* or the `onModelUpdated` event.
|
|
25
28
|
*
|
|
29
|
+
* A document whose parse lacks some of its text reaches this state
|
|
30
|
+
* unrepaired: no rule runs on it until it parses.
|
|
31
|
+
*
|
|
26
32
|
* The AST is what this guarantees, not the text. For a closed document whose
|
|
27
33
|
* repair was STAGED rather than written (`'editor'` sync mode),
|
|
28
34
|
* `textDocument` still mirrors disk — read the repair off the AST, or from
|
|
29
35
|
* the staged content the next open consumes.
|
|
30
36
|
*
|
|
37
|
+
* A `Linked`-phase repair settles the documents that reference the repaired
|
|
38
|
+
* one in the same build against what the repair replaced. A build after it
|
|
39
|
+
* relinks them, and they settle again. Past `maxRelinkChain` such builds in
|
|
40
|
+
* a row they keep stale links. A closed `'editor'` document whose CST was
|
|
41
|
+
* shed re-reads its unrepaired text in that build and repeats the repair,
|
|
42
|
+
* so they resolve a renamed element by its old name until the next change.
|
|
43
|
+
*
|
|
31
44
|
* Invariant: integrity rules only register at Parsed or Linked, so the build
|
|
32
45
|
* is guaranteed post-integrity once it advances past `onBuildPhase(Linked)`
|
|
33
46
|
* into `IndexedReferences`. {@link IntegrityService.register} enforces this at
|
|
@@ -36,6 +49,15 @@ export var IntegrityService;
|
|
|
36
49
|
*/
|
|
37
50
|
IntegrityService.SettledState = DocumentState.IndexedReferences;
|
|
38
51
|
})(IntegrityService || (IntegrityService = {}));
|
|
52
|
+
/**
|
|
53
|
+
* The shared services of each server that has logged its first silent
|
|
54
|
+
* write-back. Every language of a server holds the same shared services, so
|
|
55
|
+
* keying on them makes {@link DefaultIntegrityService.noteSilentWrite} report once
|
|
56
|
+
* per server rather than once per language.
|
|
57
|
+
*/
|
|
58
|
+
const silentWriteReported = new WeakSet();
|
|
59
|
+
/** The running builds that relink dependents, per server, because a repair in one language can extend a chain in another. */
|
|
60
|
+
const runningRelinksByServer = new WeakMap();
|
|
39
61
|
/**
|
|
40
62
|
* Default {@link IntegrityService} implementation. Enforces rules,
|
|
41
63
|
* resyncs document text after mutations, and propagates corrections.
|
|
@@ -60,13 +82,14 @@ export class DefaultIntegrityService {
|
|
|
60
82
|
/** One logger per rule, created at registration and dropped on unregister. */
|
|
61
83
|
ruleLoggers = new Map();
|
|
62
84
|
/**
|
|
63
|
-
* Rules bucketed by the phase they target,
|
|
64
|
-
*
|
|
65
|
-
* `enforceIntegrity` call after a
|
|
66
|
-
* via reference identity of the
|
|
67
|
-
* {@link Registry.all}). Filtering the rule
|
|
68
|
-
* allocate one transient array per document per
|
|
69
|
-
* whose documents all settle at the same phase pays
|
|
85
|
+
* Rules bucketed by the phase they target, then by each `$type` from
|
|
86
|
+
* {@link nodeTypesFor}, preserving the registry's priority order within
|
|
87
|
+
* each bucket. Rebuilt lazily on the first `enforceIntegrity` call after a
|
|
88
|
+
* registry mutation — staleness is detected via reference identity of the
|
|
89
|
+
* registry's cached array (see {@link Registry.all}). Filtering the rule
|
|
90
|
+
* list per call would instead allocate one transient array per document per
|
|
91
|
+
* phase, which a workspace whose documents all settle at the same phase pays
|
|
92
|
+
* on every build.
|
|
70
93
|
*/
|
|
71
94
|
phaseBuckets = new Map();
|
|
72
95
|
phaseBucketsFor;
|
|
@@ -77,11 +100,28 @@ export class DefaultIntegrityService {
|
|
|
77
100
|
tracer;
|
|
78
101
|
/**
|
|
79
102
|
* The framework document builder, used to re-parse + re-link a document in place after a
|
|
80
|
-
* Linked-phase correction (see {@link resyncDocument}).
|
|
81
|
-
* `shared.workspace.DocumentBuilder` to {@link HydraniumDocumentBuilder}; the narrowing
|
|
82
|
-
* cast surfaces its single-document phase runner.
|
|
103
|
+
* Linked-phase correction (see {@link resyncDocument}).
|
|
83
104
|
*/
|
|
84
105
|
documentBuilder;
|
|
106
|
+
/** Each document's {@link DependentRelink}, from its request until it settles. See {@link relinkDependents}. */
|
|
107
|
+
relinkBuilds = new WeakMap();
|
|
108
|
+
/** The {@link replayKey} of the latest repair of each document that {@link stagesRepairs}, with the hash of the text it came from. */
|
|
109
|
+
replayKeys = new WeakMap();
|
|
110
|
+
/** The relinks the check inside the lock found needed, until their build starts. */
|
|
111
|
+
scheduledRelinks = new WeakSet();
|
|
112
|
+
/** The relinks of every language whose build runs, from its start until it settles or the next build starts. */
|
|
113
|
+
runningRelinks;
|
|
114
|
+
/** The rules of a repair while a relink's build waited or ran. Only one while it ran gets the next build in the chain. */
|
|
115
|
+
repairedAgain = new WeakMap();
|
|
116
|
+
/**
|
|
117
|
+
* Marks {@link scheduledRelinks} running as their builds start. Set on the
|
|
118
|
+
* first request only so it subscribes once, and never disposed.
|
|
119
|
+
*/
|
|
120
|
+
relinkStarts;
|
|
121
|
+
/** See {@link IntegrityServiceOptions.maxRelinkChain}. */
|
|
122
|
+
maxRelinkChain;
|
|
123
|
+
/** The rules that mutated each document in its latest `Linked`-phase {@link enforceIntegrity} pass, so a warning can name them. */
|
|
124
|
+
mutatingRules = new WeakMap();
|
|
85
125
|
constructor(services, options = {}) {
|
|
86
126
|
this.services = services;
|
|
87
127
|
this.textDocuments = services.shared.workspace.TextDocuments;
|
|
@@ -89,6 +129,12 @@ export class DefaultIntegrityService {
|
|
|
89
129
|
this.tracer = services.shared.Tracer.for(options.logName ?? 'Integrity').trace('instantiated');
|
|
90
130
|
this.documentBuilder = services.shared.workspace.DocumentBuilder;
|
|
91
131
|
this.syncMode = options.syncMode ?? 'silent';
|
|
132
|
+
this.maxRelinkChain = options.maxRelinkChain ?? 3;
|
|
133
|
+
if (!Number.isInteger(this.maxRelinkChain) || this.maxRelinkChain < 1) {
|
|
134
|
+
throw new RangeError(`The integrity service's maxRelinkChain option must be an integer of at least 1, not ${this.maxRelinkChain}.`);
|
|
135
|
+
}
|
|
136
|
+
this.runningRelinks = runningRelinksByServer.get(services.shared) ?? new Set();
|
|
137
|
+
runningRelinksByServer.set(services.shared, this.runningRelinks);
|
|
92
138
|
// Read the language's IntegrityRuleContribution group and let each
|
|
93
139
|
// contribution register one or many rules through this service (the
|
|
94
140
|
// declarative path; equivalent to imperative `register(rule)` calls).
|
|
@@ -114,24 +160,35 @@ export class DefaultIntegrityService {
|
|
|
114
160
|
* rule set to completion against a doomed build.
|
|
115
161
|
*/
|
|
116
162
|
async enforceBatch(documents, phase, cancelToken) {
|
|
117
|
-
const
|
|
163
|
+
const sincePhaseStart = this.services.shared.Clock.stopwatch();
|
|
118
164
|
let mutatedCount = 0;
|
|
119
165
|
// Per-rule self-time profiling is opt-in: only spin up a session when the
|
|
120
166
|
// debug threshold is active, so the production `info` path allocates
|
|
121
167
|
// nothing and the hot rule loop stays a single const-branch off `session`.
|
|
122
168
|
const session = Logger.isLevelEnabled('debug') ? this.tracer.profile(`integrity ${DocumentState[phase]}`) : undefined;
|
|
169
|
+
// Before any skip or cancel, so text with parse errors also ends a replay.
|
|
170
|
+
for (const document of documents) {
|
|
171
|
+
this.forgetReplayOfOtherText(document);
|
|
172
|
+
}
|
|
123
173
|
for (const document of documents) {
|
|
124
|
-
|
|
125
|
-
|
|
174
|
+
if (this.isStructurallyBroken(document)) {
|
|
175
|
+
this.tracer.with(document.uri.toString()).debug('Parse errors: rules skipped until the document parses');
|
|
176
|
+
}
|
|
177
|
+
else if (await this.enforceIntegrity(document, phase, cancelToken, session)) {
|
|
126
178
|
mutatedCount++;
|
|
127
|
-
|
|
179
|
+
// Not cancellable: see `resyncDocument`.
|
|
180
|
+
await this.resyncDocument(document, CancellationToken.None);
|
|
128
181
|
}
|
|
129
182
|
await interruptAndCheck(cancelToken);
|
|
130
183
|
}
|
|
131
|
-
const totalMs = Math.round(
|
|
132
|
-
|
|
184
|
+
const totalMs = Math.round(sincePhaseStart.elapsedMs);
|
|
185
|
+
// A repair is the operator's to know of; the timing alone is diagnosis.
|
|
186
|
+
if (mutatedCount > 0) {
|
|
133
187
|
this.tracer.info(`enforce ${DocumentState[phase]}: docs=${documents.length}, mutated=${mutatedCount} [${totalMs}ms]`);
|
|
134
188
|
}
|
|
189
|
+
else if (totalMs >= 25) {
|
|
190
|
+
this.tracer.debug(`enforce ${DocumentState[phase]}: docs=${documents.length}, mutated=${mutatedCount} [${totalMs}ms]`);
|
|
191
|
+
}
|
|
135
192
|
// One line per rule (count + self-% + self-ms), sorted by cost — only when profiling.
|
|
136
193
|
session?.report('debug');
|
|
137
194
|
}
|
|
@@ -146,6 +203,12 @@ export class DefaultIntegrityService {
|
|
|
146
203
|
'Allowed phases are Parsed and Linked.');
|
|
147
204
|
}
|
|
148
205
|
const disposable = this.rules.register(rule);
|
|
206
|
+
// No parsed node carries a type the reflection does not know, so such a
|
|
207
|
+
// rule never runs. A warning, not a throw: a test reflection may omit the type.
|
|
208
|
+
if (!this.services.shared.AstReflection.getAllTypes().includes(rule.nodeType)) {
|
|
209
|
+
this.tracer.warn(`Integrity rule '${this.formatRule(rule)}' is keyed on node type '${rule.nodeType}', ` +
|
|
210
|
+
'which the AST reflection does not know, so no parsed node matches it.');
|
|
211
|
+
}
|
|
149
212
|
this.ruleLoggers.set(rule.id, this.tracer.sub(IntegrityPhase.toString(rule.phase)).sub(rule.label ?? rule.id));
|
|
150
213
|
return {
|
|
151
214
|
dispose: () => {
|
|
@@ -162,6 +225,14 @@ export class DefaultIntegrityService {
|
|
|
162
225
|
}
|
|
163
226
|
return removed;
|
|
164
227
|
}
|
|
228
|
+
/**
|
|
229
|
+
* Seam: does the parse of `document` lack some of its text? {@link enforceBatch}
|
|
230
|
+
* runs no rule on such a document, because a repair is written back by
|
|
231
|
+
* serializing the AST, and a recovered AST lacks what the parser skipped.
|
|
232
|
+
*/
|
|
233
|
+
isStructurallyBroken(document) {
|
|
234
|
+
return hasSkippedText(document);
|
|
235
|
+
}
|
|
165
236
|
/**
|
|
166
237
|
* Run all rules for the given phase against matching AST nodes. Returns
|
|
167
238
|
* `true` if any rule mutated the AST.
|
|
@@ -180,37 +251,58 @@ export class DefaultIntegrityService {
|
|
|
180
251
|
* full rule sweep) — coarser than per (node × rule) to avoid a microtask
|
|
181
252
|
* per inner iteration, finer than per-document so a long-running rule set
|
|
182
253
|
* on a large file can still interrupt mid-stream. Throws
|
|
183
|
-
* `OperationCancelled` when the token is cancelled
|
|
184
|
-
* pipeline absorbs the throw at the lock-holder.
|
|
254
|
+
* `OperationCancelled` when the token is cancelled before any rule mutated
|
|
255
|
+
* the AST; Langium's build pipeline absorbs the throw at the lock-holder.
|
|
256
|
+
* After a mutation it stops the sweep and returns `true` instead, so the
|
|
257
|
+
* caller can resync what was mutated before the cancellation unwinds.
|
|
185
258
|
*/
|
|
186
259
|
async enforceIntegrity(document, phase, cancelToken, session) {
|
|
187
260
|
if (cancelToken?.isCancellationRequested) {
|
|
188
261
|
return false;
|
|
189
262
|
}
|
|
190
263
|
let changed = false;
|
|
191
|
-
const
|
|
192
|
-
if (
|
|
264
|
+
const rulesByType = this.getPhaseBucket(phase);
|
|
265
|
+
if (rulesByType.size === 0) {
|
|
193
266
|
return false;
|
|
194
267
|
}
|
|
268
|
+
// Read only after a Linked-phase repair. Cleared when such a pass starts, so
|
|
269
|
+
// one that records nothing leaves no older record to be named in its place.
|
|
270
|
+
const recorded = phase > DocumentState.Parsed;
|
|
271
|
+
if (recorded) {
|
|
272
|
+
this.mutatingRules.delete(document);
|
|
273
|
+
}
|
|
274
|
+
let mutating;
|
|
195
275
|
const relativeUri = this.services.shared.workspace.WorkspaceManager.wsRelativePath(document.uri);
|
|
196
276
|
for (const node of AstUtils.streamAst(document.parseResult.value)) {
|
|
197
|
-
for (const rule of
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if (
|
|
207
|
-
|
|
277
|
+
for (const rule of rulesByType.get(node.$type) ?? NO_RULES) {
|
|
278
|
+
const ruleLogger = this.ruleLoggers.get(rule.id).with(relativeUri);
|
|
279
|
+
// Scope per rule so the session aggregates self-time by rule id across all
|
|
280
|
+
// nodes; off the profiling path `session` is undefined and we call directly.
|
|
281
|
+
const enforced = session
|
|
282
|
+
? session.scope(rule.id, () => rule.enforce(node, document, ruleLogger))
|
|
283
|
+
: rule.enforce(node, document, ruleLogger);
|
|
284
|
+
const mutated = isPromiseLike(enforced) ? await enforced : enforced;
|
|
285
|
+
if (mutated) {
|
|
286
|
+
if (recorded && mutating === undefined) {
|
|
287
|
+
// Only a mutating pass leads to a read, so a pass that mutates nothing allocates nothing.
|
|
288
|
+
mutating = new Set();
|
|
289
|
+
this.mutatingRules.set(document, mutating);
|
|
208
290
|
}
|
|
209
|
-
|
|
291
|
+
mutating?.add(rule);
|
|
292
|
+
ruleLogger.trace(`[${relativeUri}] Mutated ${this.formatNode(node)}`);
|
|
210
293
|
}
|
|
294
|
+
changed = mutated || changed;
|
|
211
295
|
}
|
|
212
296
|
if (cancelToken !== undefined) {
|
|
213
|
-
|
|
297
|
+
try {
|
|
298
|
+
await interruptAndCheck(cancelToken);
|
|
299
|
+
}
|
|
300
|
+
catch (err) {
|
|
301
|
+
if (changed && isOperationCancelled(err)) {
|
|
302
|
+
return true;
|
|
303
|
+
}
|
|
304
|
+
throw err;
|
|
305
|
+
}
|
|
214
306
|
}
|
|
215
307
|
}
|
|
216
308
|
return changed;
|
|
@@ -219,27 +311,112 @@ export class DefaultIntegrityService {
|
|
|
219
311
|
* Re-serialise the document text after AST mutations, propagate corrections,
|
|
220
312
|
* and re-parse at Parsed phase (safe because linking hasn't occurred yet).
|
|
221
313
|
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
* a natural interruption point.
|
|
314
|
+
* Runs to the end whatever `cancelToken` says: the AST is already mutated,
|
|
315
|
+
* and skipping the resync leaves it against unchanged text that the next
|
|
316
|
+
* build does not re-parse. `cancelToken` reaches only the re-parse.
|
|
226
317
|
*/
|
|
227
318
|
async resyncDocument(document, cancelToken) {
|
|
228
|
-
if (cancelToken?.isCancellationRequested) {
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
319
|
const root = document.parseResult.value;
|
|
232
|
-
|
|
320
|
+
// Extracted while `document` still holds the text being replaced — the
|
|
321
|
+
// resync that follows overwrites it with `newText`. Absent on a test
|
|
322
|
+
// stub that binds no trivia group; `createServerLanguageModule` always
|
|
323
|
+
// provides it, and an empty registry is already the no-op.
|
|
324
|
+
const trivia = this.services.trivia?.TriviaService;
|
|
325
|
+
const extracted = trivia?.extract(document);
|
|
326
|
+
const serialized = await this.services.serializer.Serializer.serializeAst(root);
|
|
327
|
+
const newText = extracted === undefined ? serialized : trivia.apply(serialized, extracted, UriUtils.toUri(document.textDocument.uri));
|
|
233
328
|
const oldText = document.textDocument.getText();
|
|
234
329
|
if (oldText === newText) {
|
|
235
330
|
return;
|
|
236
331
|
}
|
|
237
332
|
const version = document.textDocument.version;
|
|
238
|
-
//
|
|
239
|
-
//
|
|
240
|
-
//
|
|
241
|
-
|
|
242
|
-
|
|
333
|
+
// Commit into the store's own document when the URI is open there, rather
|
|
334
|
+
// than into whichever text-document object this build is holding. The two
|
|
335
|
+
// are the same on the LSP path and are NOT when the document was built for
|
|
336
|
+
// an already-open URI through `fromString`: repairing only the build's copy
|
|
337
|
+
// leaves the store — the server's authority on what an open document says —
|
|
338
|
+
// on the unrepaired text, and the reconciling re-parse then redefines
|
|
339
|
+
// `textDocument` onto the store's object and discards the repair with it.
|
|
340
|
+
//
|
|
341
|
+
// Compared against the CST's own text, not against `document.textDocument`.
|
|
342
|
+
// That object IS the store's on the LSP path, so asking it whether the
|
|
343
|
+
// store still agrees compares the store with itself and can only ever say
|
|
344
|
+
// yes — the guard would be vacuous exactly where an editor race can happen.
|
|
345
|
+
// The CST's `fullText` is the text that actually produced this AST, which
|
|
346
|
+
// is the only thing a repair derived from it is valid against. A document
|
|
347
|
+
// with no CST (built from a model rather than parsed) has no better answer
|
|
348
|
+
// than the text it is carrying.
|
|
349
|
+
const parsedFrom = document.parseResult.value.$cstNode?.root.fullText ?? oldText;
|
|
350
|
+
const commit = this.textDocuments.commitRepair(document.textDocument.uri, parsedFrom, newText);
|
|
351
|
+
if (commit.status === 'stale') {
|
|
352
|
+
// An edit landed after the parse this repair came from, so the repair
|
|
353
|
+
// describes text the store has already replaced. Abandon it rather than
|
|
354
|
+
// hand it to `syncCorrections`: an override that persists from there
|
|
355
|
+
// would write a correction over the edit that superseded it. That edit
|
|
356
|
+
// drives a build of its own, which re-runs these rules against what the
|
|
357
|
+
// document actually says.
|
|
358
|
+
//
|
|
359
|
+
// Abandoning the WRITE is only half of it. The build carries on to its
|
|
360
|
+
// settled phase with whatever AST is registered, and every settled
|
|
361
|
+
// consumer reads that AST rather than the store — so leaving the rule's
|
|
362
|
+
// mutation in place would answer questions about this document from a
|
|
363
|
+
// parse of text nobody has. Reconciling discards it by re-reading the
|
|
364
|
+
// store, which is what the document now has to agree with.
|
|
365
|
+
//
|
|
366
|
+
// No dependents are relinked, because the edit's build relinks them.
|
|
367
|
+
await this.reconcileDocument(document, cancelToken);
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
// A committed repair is a new version; a document no client has open keeps
|
|
371
|
+
// its number here, and the re-versioning below moves it once the build
|
|
372
|
+
// has reconciled. Through the store's `update`, so the `instanceof
|
|
373
|
+
// FullTextDocument` gate in the bare `TextDocument.update` does not trip
|
|
374
|
+
// on adopter-custom text-document types.
|
|
375
|
+
const textDocument = commit.status === 'committed' ? commit.document : this.textDocuments.update(document.textDocument, [{ text: newText }], version);
|
|
376
|
+
await this.syncCorrections(textDocument, parsedFrom);
|
|
377
|
+
if (document.state > DocumentState.Parsed) {
|
|
378
|
+
// Requested before the in-place relink, and an error logged, so neither skips the other.
|
|
379
|
+
try {
|
|
380
|
+
this.relinkDependents(document, { from: parsedFrom, to: newText });
|
|
381
|
+
}
|
|
382
|
+
catch (error) {
|
|
383
|
+
this.tracer
|
|
384
|
+
.with(document.uri.toString())
|
|
385
|
+
.error(`Relinking the dependents of a repaired document failed. ${describeErrorWithStack(error)}`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
await this.reconcileDocument(document, cancelToken);
|
|
389
|
+
// Re-version against the REPAIRED text, after either branch. The repair is
|
|
390
|
+
// a content change the store has not seen: whatever reconciliation ran
|
|
391
|
+
// during the re-parse saw the text on disk, which in `'editor'` sync mode
|
|
392
|
+
// is the PRE-repair text. Leave the sequence describing that and the next
|
|
393
|
+
// open hashes the repair, finds a mismatch and steps the version again, so
|
|
394
|
+
// every base version taken from this build is stale before it is used.
|
|
395
|
+
// An open document keeps the store's own version, which is not this
|
|
396
|
+
// method's to move.
|
|
397
|
+
//
|
|
398
|
+
// Deliberately NOT gated on cancellation, unlike the entry to this method:
|
|
399
|
+
// `syncCorrections` has already written or staged the repair by now, so a
|
|
400
|
+
// preempted build that skipped this would leave the sequence describing
|
|
401
|
+
// text that is no longer there.
|
|
402
|
+
if (!this.textDocuments.isOpen(document.textDocument.uri)) {
|
|
403
|
+
// The root describes the repair too; left at the re-parse's number, a
|
|
404
|
+
// syncing read waits for a build nothing requests. The CST is still
|
|
405
|
+
// the unrepaired text, so the repair is reported as the parsed text.
|
|
406
|
+
this.services.shared.workspace.VersionSyncService.modelProduced(document, { text: newText });
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Bring `document` back into agreement with the text it is supposed to
|
|
411
|
+
* describe, after a rule has mutated its AST.
|
|
412
|
+
*
|
|
413
|
+
* Used for a correction that was applied and for one that was abandoned,
|
|
414
|
+
* because the document is left inconsistent either way: applied, the text
|
|
415
|
+
* moved under the CST; abandoned, the AST carries a mutation the text never
|
|
416
|
+
* had. Both are the same question — re-read and re-derive — and the phase is
|
|
417
|
+
* what decides how far that has to go.
|
|
418
|
+
*/
|
|
419
|
+
async reconcileDocument(document, cancelToken) {
|
|
243
420
|
if (document.state <= DocumentState.Parsed) {
|
|
244
421
|
// Parsed-phase correction: re-parse only. The build pipeline still runs
|
|
245
422
|
// IndexedContent → ComputedScopes → Linked → … on the fresh AST afterwards,
|
|
@@ -265,24 +442,216 @@ export class DefaultIntegrityService {
|
|
|
265
442
|
// stays in the builder, its proper home, rather than being duplicated here.
|
|
266
443
|
await this.documentBuilder.reparseAndRelink(document, cancelToken);
|
|
267
444
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Relink the documents that reference `document` in a build after this
|
|
448
|
+
* one, where it counts as changed. They were linked before the repair, so
|
|
449
|
+
* they hold nodes a re-parse replaced, or names the repair changed.
|
|
450
|
+
*
|
|
451
|
+
* Each document has at most one such build, its {@link DependentRelink},
|
|
452
|
+
* which goes through four steps.
|
|
453
|
+
*
|
|
454
|
+
* 1. Requested here, and kept in {@link relinkBuilds}. A repair while it
|
|
455
|
+
* waits is relinked by it.
|
|
456
|
+
* 2. Checked inside the lock, which skips it unless {@link isRelinkNeeded}.
|
|
457
|
+
* A needed one joins {@link scheduledRelinks}. While a build outside the
|
|
458
|
+
* lock runs, it is requested again once that build ends.
|
|
459
|
+
* 3. Started, when `onUpdate` reports its build. An explicit `build` starts
|
|
460
|
+
* none. It is in {@link runningRelinks} until it settles or the next
|
|
461
|
+
* build starts that overlaps no other. A repair while it runs is kept in
|
|
462
|
+
* {@link repairedAgain} and gets the next build.
|
|
463
|
+
* 4. Settled, when its request resolves, which drops it from every record.
|
|
464
|
+
*
|
|
465
|
+
* A repair of a document that a running build relinked continues that
|
|
466
|
+
* build's chain, which {@link maxRelinkChain} bounds. A repair with the
|
|
467
|
+
* {@link replayKey} of the one before requests none.
|
|
468
|
+
*/
|
|
469
|
+
relinkDependents(document, repair) {
|
|
470
|
+
const key = this.replayKey(document, repair);
|
|
471
|
+
if (key !== undefined && this.replayKeys.get(document)?.key === key) {
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
const rules = [...(this.mutatingRules.get(document) ?? [])];
|
|
475
|
+
const pending = this.relinkBuilds.get(document);
|
|
476
|
+
let requested = true;
|
|
477
|
+
if (pending !== undefined) {
|
|
478
|
+
this.repairedAgain.set(pending, rules);
|
|
479
|
+
}
|
|
480
|
+
else {
|
|
481
|
+
const causes = [...this.runningRelinks].filter(relink => this.isRelinkedBy(document, relink.document));
|
|
482
|
+
requested = this.relinkInChain(document, Math.max(0, ...causes.map(relink => relink.chain)) + 1, rules);
|
|
483
|
+
}
|
|
484
|
+
// Recorded after the request, so one that throws or is past the bound leaves no key that skips the next repair.
|
|
485
|
+
if (key !== undefined && requested) {
|
|
486
|
+
this.replayKeys.set(document, { key, fromHash: textHash(repair.from) });
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Whether a build where `changed` counts as changed relinks `document`, as
|
|
491
|
+
* Langium's `shouldRelink` decides. Read from the document's links, because
|
|
492
|
+
* its build has dropped its indexed references until it indexes again.
|
|
493
|
+
*/
|
|
494
|
+
isRelinkedBy(document, changed) {
|
|
495
|
+
const target = changed.uri.toString();
|
|
496
|
+
return document.references.some(reference => {
|
|
497
|
+
const descriptions = isMultiReference(reference)
|
|
498
|
+
? reference.items.map(item => item.$nodeDescription)
|
|
499
|
+
: [reference.$nodeDescription];
|
|
500
|
+
return reference.error !== undefined || descriptions.some(description => description?.documentUri.toString() === target);
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Request the build at `chain`, or warn naming `rules` past
|
|
505
|
+
* {@link maxRelinkChain} and drop the {@link replayKey} of `document`.
|
|
506
|
+
* Returns whether it requested the build.
|
|
507
|
+
*/
|
|
508
|
+
relinkInChain(document, chain, rules) {
|
|
509
|
+
if (chain > this.maxRelinkChain) {
|
|
510
|
+
this.replayKeys.delete(document);
|
|
511
|
+
const builds = this.maxRelinkChain === 1 ? '1 build in a row that relinks' : `${this.maxRelinkChain} builds in a row that relink`;
|
|
512
|
+
this.tracer
|
|
513
|
+
.with(document.uri.toString())
|
|
514
|
+
.warn(`${this.formatRules(rules)} repaired documents in ${builds} their dependents, ` +
|
|
515
|
+
'which keep stale links until the next change. A rule that does not settle causes this, ' +
|
|
516
|
+
'or documents with linking errors that rules repair one after another.');
|
|
517
|
+
return false;
|
|
518
|
+
}
|
|
519
|
+
this.requestRelink(document, chain);
|
|
520
|
+
return true;
|
|
521
|
+
}
|
|
522
|
+
/** Request the build {@link relinkInChain} decided on, skipped unless {@link isRelinkNeeded}. */
|
|
523
|
+
requestRelink(document, chain) {
|
|
524
|
+
const uri = document.uri;
|
|
525
|
+
this.relinkStarts ??= this.documentBuilder.onUpdate(changed => this.startRelinks(changed));
|
|
526
|
+
const relink = { document, chain };
|
|
527
|
+
let unlockedBuild;
|
|
528
|
+
const stillNeeded = () => {
|
|
529
|
+
// No locked build runs during the lock read, so one seen here runs outside the lock.
|
|
530
|
+
unlockedBuild = this.documentBuilder.activeBuild;
|
|
531
|
+
if (unlockedBuild !== undefined) {
|
|
532
|
+
return false;
|
|
533
|
+
}
|
|
534
|
+
// Marked before the deferral check, so a deferred relink stays scheduled until it settles.
|
|
535
|
+
const needed = this.isRelinkNeeded(document);
|
|
536
|
+
if (needed) {
|
|
537
|
+
this.scheduledRelinks.add(relink);
|
|
538
|
+
}
|
|
539
|
+
return needed;
|
|
540
|
+
};
|
|
541
|
+
const settled = () => {
|
|
542
|
+
this.relinkBuilds.delete(document);
|
|
543
|
+
this.scheduledRelinks.delete(relink);
|
|
544
|
+
this.runningRelinks.delete(relink);
|
|
545
|
+
};
|
|
546
|
+
const requestFailed = (error) => {
|
|
547
|
+
// No build relinks the dependents, so the same repair again needs one.
|
|
548
|
+
this.replayKeys.delete(document);
|
|
549
|
+
this.tracer
|
|
550
|
+
.with(uri.toString())
|
|
551
|
+
.error(`Requesting the next build that relinks the dependents of a repaired document failed. ${describeErrorWithStack(error)}`);
|
|
552
|
+
};
|
|
553
|
+
const request = this.services.shared.workspace.VersionSyncService.requestRecoveryBuild(uri, { stillNeeded });
|
|
554
|
+
// Recorded after the request, so one that throws leaves no relink that never settles.
|
|
555
|
+
this.relinkBuilds.set(document, relink);
|
|
556
|
+
request
|
|
557
|
+
.then(() => {
|
|
558
|
+
if (unlockedBuild !== undefined) {
|
|
559
|
+
// Requested again once that build ends, so the two never overlap. A repair meanwhile waits for it.
|
|
560
|
+
unlockedBuild
|
|
561
|
+
.then(() => {
|
|
562
|
+
settled();
|
|
563
|
+
this.requestRelink(document, chain);
|
|
564
|
+
})
|
|
565
|
+
.catch(requestFailed);
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
// A build that never started, or was cancelled and not run again,
|
|
569
|
+
// leaves the repair to the build that held it back. Read before the
|
|
570
|
+
// next build's `onUpdate` clears it, which the lock's queue orders later.
|
|
571
|
+
const ran = this.runningRelinks.has(relink);
|
|
572
|
+
settled();
|
|
573
|
+
const again = this.repairedAgain.get(relink);
|
|
574
|
+
if (ran && again !== undefined) {
|
|
575
|
+
this.relinkInChain(document, chain + 1, again);
|
|
576
|
+
}
|
|
577
|
+
}, (error) => {
|
|
578
|
+
settled();
|
|
579
|
+
// The dependents were not relinked, so the same repair again needs its build.
|
|
580
|
+
this.replayKeys.delete(document);
|
|
581
|
+
this.tracer
|
|
582
|
+
.with(uri.toString())
|
|
583
|
+
.error(`The build that relinks the dependents of a repaired document failed. ${describeErrorWithStack(error)}`);
|
|
584
|
+
})
|
|
585
|
+
.catch(requestFailed);
|
|
586
|
+
}
|
|
587
|
+
/** Mark the {@link scheduledRelinks} of the `changed` documents running, as the build that carries them starts. */
|
|
588
|
+
startRelinks(changed) {
|
|
589
|
+
// An explicit build relinks no dependents and ends no build it overlaps.
|
|
590
|
+
if (this.documentBuilder.isInsideBuildUpdate()) {
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
// The build before this one ended, done or cancelled, so its relinks run no more,
|
|
594
|
+
// unless this one overlaps it, as a reentrant build does.
|
|
595
|
+
// The set is shared by every language. Each service clears only its own,
|
|
596
|
+
// because another's listener may already have marked this build's relinks running.
|
|
597
|
+
if (!this.documentBuilder.overlapsRunningBuild()) {
|
|
598
|
+
for (const relink of this.runningRelinks) {
|
|
599
|
+
if (this.relinkBuilds.get(relink.document) === relink) {
|
|
600
|
+
this.runningRelinks.delete(relink);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
const documents = this.services.shared.workspace.LangiumDocuments;
|
|
605
|
+
for (const uri of changed) {
|
|
606
|
+
const document = documents.getDocument(uri);
|
|
607
|
+
const relink = document === undefined ? undefined : this.relinkBuilds.get(document);
|
|
608
|
+
if (relink !== undefined && this.scheduledRelinks.delete(relink)) {
|
|
609
|
+
// The starting build relinks any repair while it waited.
|
|
610
|
+
this.repairedAgain.delete(relink);
|
|
611
|
+
this.runningRelinks.add(relink);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Whether a build where `document` counts as changed relinks another
|
|
617
|
+
* document, by the builder's own test, which counts a document a cancelled
|
|
618
|
+
* build left unindexed as relinked.
|
|
619
|
+
*/
|
|
620
|
+
isRelinkNeeded(document) {
|
|
621
|
+
const documents = this.services.shared.workspace.LangiumDocuments;
|
|
622
|
+
const changed = new Set([document.uri.toString()]);
|
|
623
|
+
return (documents.getDocument(document.uri) === document &&
|
|
624
|
+
documents.all.some(other => other !== document && this.documentBuilder.shouldRelink(other, changed)));
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Whether `document` stages its repairs rather than writing them, as a
|
|
628
|
+
* closed document does in `'editor'` mode, so its source keeps the
|
|
629
|
+
* unrepaired text.
|
|
630
|
+
*/
|
|
631
|
+
stagesRepairs(document) {
|
|
632
|
+
return this.syncMode === 'editor' && !this.textDocuments.isOpen(document.textDocument.uri);
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* What tells `repair` made again from the same text apart from a new one,
|
|
636
|
+
* for a document that {@link stagesRepairs}, which reads the unrepaired
|
|
637
|
+
* text again in every build that re-parses it after its CST was shed. Such
|
|
638
|
+
* a repair requests no build, because the build that re-parsed the
|
|
639
|
+
* document relinked its dependents, and another would replay it again.
|
|
640
|
+
* Hashes, so the record keeps no text the shed freed.
|
|
641
|
+
*/
|
|
642
|
+
replayKey(document, repair) {
|
|
643
|
+
return this.stagesRepairs(document) ? textHash(repair.from) + textHash(repair.to) : undefined;
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* Drop the {@link replayKey} of `document` once it was parsed from other
|
|
647
|
+
* text than its repair came from, such as a save and a revert. A repair of
|
|
648
|
+
* that text again is a new one, whose dependents need their build.
|
|
649
|
+
*/
|
|
650
|
+
forgetReplayOfOtherText(document) {
|
|
651
|
+
const recorded = this.replayKeys.get(document);
|
|
652
|
+
const parsedFrom = document.parseResult.value.$cstNode?.root.fullText;
|
|
653
|
+
if (recorded !== undefined && parsedFrom !== undefined && recorded.fromHash !== textHash(parsedFrom)) {
|
|
654
|
+
this.replayKeys.delete(document);
|
|
286
655
|
}
|
|
287
656
|
}
|
|
288
657
|
/**
|
|
@@ -290,40 +659,155 @@ export class DefaultIntegrityService {
|
|
|
290
659
|
* already in the synced store (in-place in {@link resyncDocument}); this
|
|
291
660
|
* method routes the out-of-band part by document registration:
|
|
292
661
|
*
|
|
293
|
-
* - **Open in the language client** → nothing to push here. The AST
|
|
294
|
-
* rode the current build, so
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
662
|
+
* - **Open in the language client** → nothing to push here. The AST
|
|
663
|
+
* mutation rode the current build, so
|
|
664
|
+
* `DefaultModelService.syncToLanguageClient` (the persistent
|
|
665
|
+
* integrity-settled listener) mirrors it to the client by
|
|
666
|
+
* *content* (shadow diff), and the editor shows it as an unsaved change.
|
|
667
|
+
* - **Held only through the data or GLSP head**, or waiting out the release
|
|
668
|
+
* grace after its last client's connection was lost → the store is the
|
|
669
|
+
* authority, and those heads read the correction from the settled build.
|
|
670
|
+
* In silent mode it is also written to disk when the text it was computed
|
|
671
|
+
* from is what disk holds, since the repair is then the only difference;
|
|
672
|
+
* otherwise it waits for the next save. Editor mode always waits, and the
|
|
673
|
+
* repair leaves the document dirty until a save.
|
|
298
674
|
* - **Closed, silent mode** → write to disk directly (disk is authoritative).
|
|
299
|
-
* - **Closed, editor mode** → stage so the next open
|
|
675
|
+
* - **Closed, editor mode** → stage, so the next open takes the correction
|
|
676
|
+
* over the disk text.
|
|
677
|
+
*
|
|
678
|
+
* A held URI is not closed. Writing it as one persists the holder's unsaved
|
|
679
|
+
* edits with the repair, and staging it leaves text no open reads, because
|
|
680
|
+
* only a first open consumes the stage.
|
|
681
|
+
*
|
|
682
|
+
* `parsedFrom` is the text the repaired AST was parsed from. Without it a
|
|
683
|
+
* held URI's repair is left to the next save.
|
|
300
684
|
*/
|
|
301
|
-
async syncCorrections(document) {
|
|
302
|
-
//
|
|
303
|
-
//
|
|
304
|
-
//
|
|
305
|
-
// open under a symlinked path still answers `true`.
|
|
685
|
+
async syncCorrections(document, parsedFrom) {
|
|
686
|
+
// Only the open/closed question is asked, so no reverse address
|
|
687
|
+
// resolution is needed: a file open under a symlinked path still answers
|
|
688
|
+
// `true`.
|
|
306
689
|
if (this.textDocuments.isOpenInLanguageClient(document.uri)) {
|
|
307
690
|
return;
|
|
308
691
|
}
|
|
692
|
+
// A virtual document has no disk backing, so neither persisting nor
|
|
693
|
+
// staging applies: there is no file to write and no editor that could open
|
|
694
|
+
// one. `URI.fsPath` yields a path for any scheme, so handing this to the
|
|
695
|
+
// provider would address `<cwd>/<contributor>/<name>` — an unrelated
|
|
696
|
+
// location a disk-backed provider refuses outright, turning a repair that
|
|
697
|
+
// was never persistable into a build failure. The correction is already on
|
|
698
|
+
// the AST and in the text store, which is the whole of where a virtual
|
|
699
|
+
// document lives, so there is nothing further to propagate.
|
|
700
|
+
if (isVirtualUri(document.uri)) {
|
|
701
|
+
this.tracer.with(document.uri).debug('Virtual document: correction kept in memory, nothing to persist');
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
// A document waiting out the release grace still holds its lost client's
|
|
705
|
+
// unsaved text, so writing it as a closed file would persist that text.
|
|
706
|
+
if (this.textDocuments.isOpenInAnyClient(document.uri) || this.textDocuments.isReleaseDeferred(document.uri)) {
|
|
707
|
+
if (this.syncMode === 'silent' && parsedFrom !== undefined) {
|
|
708
|
+
await this.persistIfDiskMatches(document, parsedFrom);
|
|
709
|
+
}
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
309
712
|
// Closed files, silent mode: write to disk directly.
|
|
310
713
|
if (this.syncMode === 'silent') {
|
|
714
|
+
const repaired = document.getText();
|
|
311
715
|
// Async write so the integrity pass does not block the event loop on a slow filesystem.
|
|
312
|
-
|
|
716
|
+
// In the file's task queue, behind any save already queued: written
|
|
717
|
+
// beside one, the older repair can land last and stay on disk.
|
|
718
|
+
await this.services.shared.workspace.FileSystemTaskQueue.enqueue(document.uri, () => this.fileSystemProvider.writeFile(UriUtils.toUri(document.uri), repaired));
|
|
719
|
+
this.noteSilentWrite(document.uri);
|
|
313
720
|
return;
|
|
314
721
|
}
|
|
315
|
-
// Closed files, editor mode: stage content
|
|
722
|
+
// Closed files, editor mode: stage content for the next open.
|
|
316
723
|
this.textDocuments.stagePendingContent(document.uri, document.getText());
|
|
317
724
|
}
|
|
725
|
+
/**
|
|
726
|
+
* Write the repair in `document` to disk when disk still holds `parsedFrom`,
|
|
727
|
+
* the text the repair was computed from — so the write carries the repair
|
|
728
|
+
* and nothing a holder could still discard.
|
|
729
|
+
*
|
|
730
|
+
* The read, the compare and the write run as one task in the file's task
|
|
731
|
+
* queue, so no save of the file lands between them. The store is compared
|
|
732
|
+
* again once the read returns, and the write is skipped if it no longer
|
|
733
|
+
* holds the repair: an edit does not wait for the queue, and writing the
|
|
734
|
+
* older repair then puts text on disk that no participant holds. The
|
|
735
|
+
* skipped repair loses nothing: the edit drives a build of its own, and a
|
|
736
|
+
* save writes the store's text. A file that cannot be read is left alone
|
|
737
|
+
* too: there is no evidence it matches. So is a file an editor opened in the
|
|
738
|
+
* meantime: the editor receives the repair as an unsaved change, and writing
|
|
739
|
+
* it would change the file under the editor.
|
|
740
|
+
*/
|
|
741
|
+
async persistIfDiskMatches(document, parsedFrom) {
|
|
742
|
+
const uri = UriUtils.toUri(document.uri);
|
|
743
|
+
const repaired = document.getText();
|
|
744
|
+
await this.services.shared.workspace.FileSystemTaskQueue.enqueue(document.uri, async () => {
|
|
745
|
+
let onDisk;
|
|
746
|
+
try {
|
|
747
|
+
onDisk = await this.fileSystemProvider.readFile(uri);
|
|
748
|
+
}
|
|
749
|
+
catch (error) {
|
|
750
|
+
this.tracer.with(document.uri).debug(`Held document unreadable on disk, repair left to the next save: ${String(error)}`);
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
// The file itself, not the store's disk baseline: the baseline moves
|
|
754
|
+
// only when the server hears of a change, so it can still hold the
|
|
755
|
+
// parsed text after another process rewrote the file and before the
|
|
756
|
+
// watcher reports it, and this write would then replace that change.
|
|
757
|
+
if (onDisk !== parsedFrom) {
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
if (this.textDocuments.get(document.uri)?.getText() !== repaired) {
|
|
761
|
+
this.tracer.with(document.uri).debug('Held document changed while disk was read, repair left to that change');
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
if (this.textDocuments.isOpenInLanguageClient(document.uri)) {
|
|
765
|
+
this.tracer.with(document.uri).debug('Editor attached while disk was read, repair left to its save');
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
await this.fileSystemProvider.writeFile(uri, repaired);
|
|
769
|
+
this.textDocuments.setDiskBaseline(document.uri, repaired);
|
|
770
|
+
this.noteSilentWrite(document.uri);
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
/**
|
|
774
|
+
* Hand the first repair written to disk in `'silent'` sync mode to
|
|
775
|
+
* {@link reportSilentWrite}. Once per server, whichever language writes,
|
|
776
|
+
* rather than per file: a workspace-wide repair pass would otherwise log a
|
|
777
|
+
* line per document.
|
|
778
|
+
*/
|
|
779
|
+
noteSilentWrite(uri) {
|
|
780
|
+
if (silentWriteReported.has(this.services.shared)) {
|
|
781
|
+
return;
|
|
782
|
+
}
|
|
783
|
+
silentWriteReported.add(this.services.shared);
|
|
784
|
+
this.reportSilentWrite(uri);
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* Log a server's first silent write-back, so an adopter learns that
|
|
788
|
+
* integrity rules edit their files and which setting controls it.
|
|
789
|
+
*/
|
|
790
|
+
reportSilentWrite(uri) {
|
|
791
|
+
this.tracer.info(`Wrote an integrity repair to ${uri}. The integrity service's syncMode option is 'silent', ` +
|
|
792
|
+
"which writes repairs to disk; 'editor' leaves disk alone. Later repairs are written without this line.");
|
|
793
|
+
}
|
|
318
794
|
/**
|
|
319
795
|
* Format a rule's name for inclusion in user-facing diagnostic strings
|
|
320
|
-
* (error messages thrown during registration). Defaults to
|
|
796
|
+
* (error messages thrown during registration, and log lines). Defaults to
|
|
321
797
|
* `label ?? id`. Adopters override when their error reporting needs
|
|
322
798
|
* richer rule context.
|
|
323
799
|
*/
|
|
324
800
|
formatRule(rule) {
|
|
325
801
|
return rule.label ?? rule.id;
|
|
326
802
|
}
|
|
803
|
+
/** `rules` as the subject of a log line, or a rule left unnamed when an override recorded none. */
|
|
804
|
+
formatRules(rules) {
|
|
805
|
+
if (rules.length === 0) {
|
|
806
|
+
return 'An integrity rule';
|
|
807
|
+
}
|
|
808
|
+
const names = rules.map(rule => `'${this.formatRule(rule)}'`).join(', ');
|
|
809
|
+
return rules.length === 1 ? `Integrity rule ${names}` : `Integrity rules ${names}`;
|
|
810
|
+
}
|
|
327
811
|
/**
|
|
328
812
|
* Format an AST node for the per-mutation `trace` log line. Returns
|
|
329
813
|
* `'TypeName'` or `"TypeName('label')"` when the node carries a string
|
|
@@ -338,6 +822,17 @@ export class DefaultIntegrityService {
|
|
|
338
822
|
const label = fromName ?? fromId;
|
|
339
823
|
return label ? `${node.$type}('${label}')` : node.$type;
|
|
340
824
|
}
|
|
825
|
+
/**
|
|
826
|
+
* The `$type`s `rule` runs on. Defaults to its `nodeType` and every subtype,
|
|
827
|
+
* as Langium's validation registry does: no node carries an abstract or union
|
|
828
|
+
* type as its `$type`, so an exact match never runs a rule keyed on one.
|
|
829
|
+
* Read only when the phase buckets rebuild after a registration change, so an
|
|
830
|
+
* override must not depend on anything else.
|
|
831
|
+
*/
|
|
832
|
+
nodeTypesFor(rule) {
|
|
833
|
+
// A type the reflection does not know still matches itself.
|
|
834
|
+
return [rule.nodeType, ...this.services.shared.AstReflection.getAllSubTypes(rule.nodeType)];
|
|
835
|
+
}
|
|
341
836
|
getPhaseBucket(phase) {
|
|
342
837
|
const current = this.rules.all();
|
|
343
838
|
if (this.phaseBucketsFor !== current) {
|
|
@@ -345,10 +840,18 @@ export class DefaultIntegrityService {
|
|
|
345
840
|
for (const rule of current) {
|
|
346
841
|
let bucket = next.get(rule.phase);
|
|
347
842
|
if (!bucket) {
|
|
348
|
-
bucket =
|
|
843
|
+
bucket = new Map();
|
|
349
844
|
next.set(rule.phase, bucket);
|
|
350
845
|
}
|
|
351
|
-
|
|
846
|
+
// Deduplicated, or a rule runs twice on a node of its own type.
|
|
847
|
+
for (const nodeType of new Set(this.nodeTypesFor(rule))) {
|
|
848
|
+
let rules = bucket.get(nodeType);
|
|
849
|
+
if (!rules) {
|
|
850
|
+
rules = [];
|
|
851
|
+
bucket.set(nodeType, rules);
|
|
852
|
+
}
|
|
853
|
+
rules.push(rule);
|
|
854
|
+
}
|
|
352
855
|
}
|
|
353
856
|
this.phaseBuckets = next;
|
|
354
857
|
this.phaseBucketsFor = current;
|
|
@@ -356,6 +859,7 @@ export class DefaultIntegrityService {
|
|
|
356
859
|
return this.phaseBuckets.get(phase) ?? EMPTY_PHASE_BUCKET;
|
|
357
860
|
}
|
|
358
861
|
}
|
|
359
|
-
|
|
360
|
-
const EMPTY_PHASE_BUCKET =
|
|
862
|
+
// Shared empty results so neither the cold path nor a node no rule matches allocates.
|
|
863
|
+
const EMPTY_PHASE_BUCKET = new Map();
|
|
864
|
+
const NO_RULES = Object.freeze([]);
|
|
361
865
|
//# sourceMappingURL=integrity-service.js.map
|