@hydranium/protocol 1.0.0-next.123 → 1.0.0-next.127

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.
Files changed (94) hide show
  1. package/lib/client/data-connection.d.ts +35 -4
  2. package/lib/client/data-connection.d.ts.map +1 -1
  3. package/lib/client/data-connection.js +67 -5
  4. package/lib/client/data-connection.js.map +1 -1
  5. package/lib/client/data-events.d.ts +5 -1
  6. package/lib/client/data-events.d.ts.map +1 -1
  7. package/lib/client/data-events.js +7 -0
  8. package/lib/client/data-events.js.map +1 -1
  9. package/lib/client/data-session.d.ts +76 -8
  10. package/lib/client/data-session.d.ts.map +1 -1
  11. package/lib/client/data-session.js +108 -19
  12. package/lib/client/data-session.js.map +1 -1
  13. package/lib/client/index.d.ts +3 -1
  14. package/lib/client/index.d.ts.map +1 -1
  15. package/lib/client/index.js +3 -1
  16. package/lib/client/index.js.map +1 -1
  17. package/lib/client/message-relay.d.ts +1 -1
  18. package/lib/client/message-relay.js +1 -1
  19. package/lib/client/post-message-transport.d.ts +64 -3
  20. package/lib/client/post-message-transport.d.ts.map +1 -1
  21. package/lib/client/post-message-transport.js +175 -1
  22. package/lib/client/post-message-transport.js.map +1 -1
  23. package/lib/client/rpc-connection.d.ts +6 -0
  24. package/lib/client/rpc-connection.d.ts.map +1 -1
  25. package/lib/client/rpc-connection.js +9 -1
  26. package/lib/client/rpc-connection.js.map +1 -1
  27. package/lib/clock.d.ts +38 -0
  28. package/lib/clock.d.ts.map +1 -1
  29. package/lib/clock.js +36 -1
  30. package/lib/clock.js.map +1 -1
  31. package/lib/data/data-protocol-methods.d.ts +2 -2
  32. package/lib/data/data-protocol-methods.d.ts.map +1 -1
  33. package/lib/data/data-protocol-methods.js +1 -0
  34. package/lib/data/data-protocol-methods.js.map +1 -1
  35. package/lib/data/data-server-protocol.d.ts +11 -1
  36. package/lib/data/data-server-protocol.d.ts.map +1 -1
  37. package/lib/data/events.d.ts +14 -0
  38. package/lib/data/events.d.ts.map +1 -1
  39. package/lib/errors.d.ts +20 -9
  40. package/lib/errors.d.ts.map +1 -1
  41. package/lib/errors.js +18 -9
  42. package/lib/errors.js.map +1 -1
  43. package/lib/glsp-save-model-actions.d.ts +50 -0
  44. package/lib/glsp-save-model-actions.d.ts.map +1 -0
  45. package/lib/glsp-save-model-actions.js +28 -0
  46. package/lib/glsp-save-model-actions.js.map +1 -0
  47. package/lib/index.d.ts +1 -0
  48. package/lib/index.d.ts.map +1 -1
  49. package/lib/index.js +1 -0
  50. package/lib/index.js.map +1 -1
  51. package/lib/messages/index.d.ts +1 -1
  52. package/lib/messages/index.d.ts.map +1 -1
  53. package/lib/messages/index.js +2 -1
  54. package/lib/messages/index.js.map +1 -1
  55. package/lib/testing/data-doubles.d.ts +3 -1
  56. package/lib/testing/data-doubles.d.ts.map +1 -1
  57. package/lib/testing/data-doubles.js +6 -1
  58. package/lib/testing/data-doubles.js.map +1 -1
  59. package/lib/testing/fake-clock.d.ts +9 -1
  60. package/lib/testing/fake-clock.d.ts.map +1 -1
  61. package/lib/testing/fake-clock.js +54 -45
  62. package/lib/testing/fake-clock.js.map +1 -1
  63. package/lib/testing/node/index.d.ts +1 -0
  64. package/lib/testing/node/index.d.ts.map +1 -1
  65. package/lib/testing/node/index.js +2 -2
  66. package/lib/testing/node/index.js.map +1 -1
  67. package/lib/testing/node/message-port-pair.d.ts +25 -0
  68. package/lib/testing/node/message-port-pair.d.ts.map +1 -0
  69. package/lib/testing/node/message-port-pair.js +26 -0
  70. package/lib/testing/node/message-port-pair.js.map +1 -0
  71. package/lib/transfer-document.d.ts +8 -0
  72. package/lib/transfer-document.d.ts.map +1 -1
  73. package/lib/transfer-document.js.map +1 -1
  74. package/package.json +1 -1
  75. package/src/client/data-connection.ts +72 -6
  76. package/src/client/data-events.ts +9 -0
  77. package/src/client/data-session.ts +125 -21
  78. package/src/client/index.ts +3 -1
  79. package/src/client/message-relay.ts +1 -1
  80. package/src/client/post-message-transport.ts +219 -4
  81. package/src/client/rpc-connection.ts +10 -1
  82. package/src/clock.ts +56 -0
  83. package/src/data/data-protocol-methods.ts +1 -0
  84. package/src/data/data-server-protocol.ts +12 -0
  85. package/src/data/events.ts +16 -0
  86. package/src/errors.ts +24 -9
  87. package/src/glsp-save-model-actions.ts +59 -0
  88. package/src/index.ts +1 -0
  89. package/src/messages/index.ts +1 -1
  90. package/src/testing/data-doubles.ts +10 -1
  91. package/src/testing/fake-clock.ts +62 -47
  92. package/src/testing/node/index.ts +2 -2
  93. package/src/testing/node/message-port-pair.ts +40 -0
  94. package/src/transfer-document.ts +8 -0
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/messages/index.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;;;;;;;;;;;;AAElF;;;;;;;;;;;;;;GAcG;AAEH,+CAA6B;AAE7B,oCAA+C;AAAtC,4GAAA,kBAAkB,OAAA;AAC3B,2DAA6F;AAApF,4HAAA,0BAA0B,OAAA;AAAE,uHAAA,qBAAqB,OAAA;AAC1D,uDAAgG;AAAvF,2HAAA,2BAA2B,OAAA;AAAE,yHAAA,yBAAyB,OAAA;AAC/D,yDAKiC;AAJ9B,oHAAA,mBAAmB,OAAA;AACnB,4HAAA,2BAA2B,OAAA;AAC3B,4HAAA,2BAA2B,OAAA;AAC3B,6HAAA,4BAA4B,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/messages/index.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;;;;;;;;;;;;AAElF;;;;;;;;;;;;;;GAcG;AAEH,+CAA6B;AAE7B,oCAA+D;AAAtD,wGAAA,cAAc,OAAA;AAAE,4GAAA,kBAAkB,OAAA;AAC3C,2DAA6F;AAApF,4HAAA,0BAA0B,OAAA;AAAE,uHAAA,qBAAqB,OAAA;AAC1D,uDAAgG;AAAvF,2HAAA,2BAA2B,OAAA;AAAE,yHAAA,yBAAyB,OAAA;AAC/D,yDAKiC;AAJ9B,oHAAA,mBAAmB,OAAA;AACnB,4HAAA,2BAA2B,OAAA;AAC3B,4HAAA,2BAA2B,OAAA;AAC3B,6HAAA,4BAA4B,OAAA"}
@@ -32,7 +32,7 @@
32
32
  import { type MessageConnection } from 'vscode-jsonrpc';
33
33
  import type { DataPort } from '../client/data-port';
34
34
  import type { DataClientProtocol } from '../data/data-server-protocol';
35
- import type { ProjectsChangedEvent, TransferDocumentDeletedEvent, TransferDocumentSavedEvent, TransferDocumentsBuiltEvent, TransferDocumentUpdatedEvent } from '../data/events';
35
+ import type { ProjectsChangedEvent, TransferDocumentDeletedEvent, TransferDocumentDirtyChangedEvent, TransferDocumentSavedEvent, TransferDocumentsBuiltEvent, TransferDocumentUpdatedEvent } from '../data/events';
36
36
  import type { ResolvedMessage } from '../messages/primitives';
37
37
  import type { Project } from '../project';
38
38
  import type { TransferDiagnostic } from '../transfer-diagnostic';
@@ -96,6 +96,8 @@ export interface CapturingDataClient<TTransfer extends TransferElement, TDiagnos
96
96
  readonly updates: TransferDocumentUpdatedEvent<TTransfer, TDiagnostic>[];
97
97
  /** Every `onDocumentSaved` event, in arrival order. */
98
98
  readonly saves: TransferDocumentSavedEvent<TTransfer, TDiagnostic>[];
99
+ /** Every `onDocumentDirtyChanged` event, in arrival order. */
100
+ readonly dirtyChanges: TransferDocumentDirtyChangedEvent[];
99
101
  /** Every `onDocumentDeleted` event, in arrival order. */
100
102
  readonly deletions: TransferDocumentDeletedEvent[];
101
103
  /** Every `onDocumentsBuilt` event, in arrival order. */
@@ -1 +1 @@
1
- {"version":3,"file":"data-doubles.d.ts","sourceRoot":"","sources":["../../src/testing/data-doubles.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAW,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,KAAK,EACT,oBAAoB,EACpB,4BAA4B,EAC5B,0BAA0B,EAC1B,2BAA2B,EAC3B,4BAA4B,EAC9B,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,0CAA0C;AAC1C,MAAM,WAAW,mBAAmB;IACjC;;;;;;;;OAQG;IACH,OAAO,IAAI,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAC5D;AAED,8DAA8D;AAC9D,MAAM,WAAW,YAAa,SAAQ,QAAQ;IAC3C;;;;;;OAMG;IACH,QAAQ,CAAC,WAAW,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACnD;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS;QAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;KAAE,EAAE,CAAC;IAC7F;;;;OAIG;IACH,WAAW,IAAI,IAAI,CAAC;IACpB,4FAA4F;IAC5F,OAAO,IAAI,IAAI,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAuB3E;AAED,oEAAoE;AACpE,MAAM,WAAW,mBAAmB,CACjC,SAAS,SAAS,eAAe,EACjC,WAAW,SAAS,kBAAkB,GAAG,kBAAkB,EAC3D,QAAQ,SAAS,OAAO,GAAG,OAAO;IAElC,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;IACtE,yDAAyD;IACzD,QAAQ,CAAC,OAAO,EAAE,4BAA4B,CAAC,SAAS,EAAE,WAAW,CAAC,EAAE,CAAC;IACzE,uDAAuD;IACvD,QAAQ,CAAC,KAAK,EAAE,0BAA0B,CAAC,SAAS,EAAE,WAAW,CAAC,EAAE,CAAC;IACrE,yDAAyD;IACzD,QAAQ,CAAC,SAAS,EAAE,4BAA4B,EAAE,CAAC;IACnD,wDAAwD;IACxD,QAAQ,CAAC,MAAM,EAAE,2BAA2B,EAAE,CAAC;IAC/C,yDAAyD;IACzD,QAAQ,CAAC,eAAe,EAAE,oBAAoB,CAAC,QAAQ,CAAC,EAAE,CAAC;CAC7D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACpC,SAAS,SAAS,eAAe,EACjC,WAAW,SAAS,kBAAkB,GAAG,kBAAkB,EAC3D,QAAQ,SAAS,OAAO,GAAG,OAAO,EACnC,SAAS,GAAE,OAAO,CAAC,kBAAkB,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAM,GAAG,mBAAmB,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAC,CAkCtI"}
1
+ {"version":3,"file":"data-doubles.d.ts","sourceRoot":"","sources":["../../src/testing/data-doubles.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAW,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,KAAK,EACT,oBAAoB,EACpB,4BAA4B,EAC5B,iCAAiC,EACjC,0BAA0B,EAC1B,2BAA2B,EAC3B,4BAA4B,EAC9B,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,0CAA0C;AAC1C,MAAM,WAAW,mBAAmB;IACjC;;;;;;;;OAQG;IACH,OAAO,IAAI,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAC5D;AAED,8DAA8D;AAC9D,MAAM,WAAW,YAAa,SAAQ,QAAQ;IAC3C;;;;;;OAMG;IACH,QAAQ,CAAC,WAAW,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACnD;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS;QAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;KAAE,EAAE,CAAC;IAC7F;;;;OAIG;IACH,WAAW,IAAI,IAAI,CAAC;IACpB,4FAA4F;IAC5F,OAAO,IAAI,IAAI,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAuB3E;AAED,oEAAoE;AACpE,MAAM,WAAW,mBAAmB,CACjC,SAAS,SAAS,eAAe,EACjC,WAAW,SAAS,kBAAkB,GAAG,kBAAkB,EAC3D,QAAQ,SAAS,OAAO,GAAG,OAAO;IAElC,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;IACtE,yDAAyD;IACzD,QAAQ,CAAC,OAAO,EAAE,4BAA4B,CAAC,SAAS,EAAE,WAAW,CAAC,EAAE,CAAC;IACzE,uDAAuD;IACvD,QAAQ,CAAC,KAAK,EAAE,0BAA0B,CAAC,SAAS,EAAE,WAAW,CAAC,EAAE,CAAC;IACrE,8DAA8D;IAC9D,QAAQ,CAAC,YAAY,EAAE,iCAAiC,EAAE,CAAC;IAC3D,yDAAyD;IACzD,QAAQ,CAAC,SAAS,EAAE,4BAA4B,EAAE,CAAC;IACnD,wDAAwD;IACxD,QAAQ,CAAC,MAAM,EAAE,2BAA2B,EAAE,CAAC;IAC/C,yDAAyD;IACzD,QAAQ,CAAC,eAAe,EAAE,oBAAoB,CAAC,QAAQ,CAAC,EAAE,CAAC;CAC7D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACpC,SAAS,SAAS,eAAe,EACjC,WAAW,SAAS,kBAAkB,GAAG,kBAAkB,EAC3D,QAAQ,SAAS,OAAO,GAAG,OAAO,EACnC,SAAS,GAAE,OAAO,CAAC,kBAAkB,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAM,GAAG,mBAAmB,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAC,CAwCtI"}
@@ -81,6 +81,7 @@ function makeFakeDataPort(options) {
81
81
  function makeCapturingDataClient(overrides = {}) {
82
82
  const updates = [];
83
83
  const saves = [];
84
+ const dirtyChanges = [];
84
85
  const deletions = [];
85
86
  const builds = [];
86
87
  const projectsChanges = [];
@@ -93,6 +94,10 @@ function makeCapturingDataClient(overrides = {}) {
93
94
  (event => {
94
95
  saves.push(event);
95
96
  }),
97
+ onDocumentDirtyChanged: overrides.onDocumentDirtyChanged ??
98
+ (event => {
99
+ dirtyChanges.push(event);
100
+ }),
96
101
  onDocumentDeleted: overrides.onDocumentDeleted ??
97
102
  (event => {
98
103
  deletions.push(event);
@@ -106,6 +111,6 @@ function makeCapturingDataClient(overrides = {}) {
106
111
  projectsChanges.push(event);
107
112
  })
108
113
  };
109
- return { client, updates, saves, deletions, builds, projectsChanges };
114
+ return { client, updates, saves, dirtyChanges, deletions, builds, projectsChanges };
110
115
  }
111
116
  //# sourceMappingURL=data-doubles.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"data-doubles.js","sourceRoot":"","sources":["../../src/testing/data-doubles.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;AA0FlF,4CAuBC;AAmCD,0DAsCC;AAxLD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,mDAAiE;AAyDjE;;;;;;GAMG;AACH,SAAgB,gBAAgB,CAAC,OAA4B;IAC1D,MAAM,WAAW,GAAwB,EAAE,CAAC;IAC5C,MAAM,QAAQ,GAAmD,EAAE,CAAC;IACpE,MAAM,cAAc,GAAG,IAAI,wBAAO,EAAQ,CAAC;IAC3C,OAAO;QACJ,WAAW;QACX,QAAQ;QACR,SAAS,EAAE,cAAc,CAAC,KAAK;QAC/B,KAAK,CAAC,OAAO;YACV,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;YAC3C,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC7B,OAAO,UAAU,CAAC;QACrB,CAAC;QACD,WAAW,CAAC,KAAc,EAAE,OAAwB;YACjD,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QACrC,CAAC;QACD,WAAW;YACR,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAClC,CAAC;QACD,OAAO;YACJ,cAAc,CAAC,OAAO,EAAE,CAAC;QAC5B,CAAC;KACH,CAAC;AACL,CAAC;AAsBD;;;;;;;;;;;;GAYG;AACH,SAAgB,uBAAuB,CAIrC,YAA2E,EAAE;IAC5E,MAAM,OAAO,GAA2D,EAAE,CAAC;IAC3E,MAAM,KAAK,GAAyD,EAAE,CAAC;IACvE,MAAM,SAAS,GAAmC,EAAE,CAAC;IACrD,MAAM,MAAM,GAAkC,EAAE,CAAC;IACjD,MAAM,eAAe,GAAqC,EAAE,CAAC;IAC7D,MAAM,MAAM,GAAyD;QAClE,iBAAiB,EACd,SAAS,CAAC,iBAAiB;YAC3B,CAAC,KAAK,CAAC,EAAE;gBACN,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACvB,CAAC,CAAC;QACL,eAAe,EACZ,SAAS,CAAC,eAAe;YACzB,CAAC,KAAK,CAAC,EAAE;gBACN,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACrB,CAAC,CAAC;QACL,iBAAiB,EACd,SAAS,CAAC,iBAAiB;YAC3B,CAAC,KAAK,CAAC,EAAE;gBACN,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACzB,CAAC,CAAC;QACL,gBAAgB,EACb,SAAS,CAAC,gBAAgB;YAC1B,CAAC,KAAK,CAAC,EAAE;gBACN,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACtB,CAAC,CAAC;QACL,iBAAiB,EACd,SAAS,CAAC,iBAAiB;YAC3B,CAAC,KAAK,CAAC,EAAE;gBACN,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC/B,CAAC,CAAC;KACP,CAAC;IACF,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;AACzE,CAAC"}
1
+ {"version":3,"file":"data-doubles.js","sourceRoot":"","sources":["../../src/testing/data-doubles.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;AA2FlF,4CAuBC;AAqCD,0DA4CC;AAjMD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,mDAAiE;AA0DjE;;;;;;GAMG;AACH,SAAgB,gBAAgB,CAAC,OAA4B;IAC1D,MAAM,WAAW,GAAwB,EAAE,CAAC;IAC5C,MAAM,QAAQ,GAAmD,EAAE,CAAC;IACpE,MAAM,cAAc,GAAG,IAAI,wBAAO,EAAQ,CAAC;IAC3C,OAAO;QACJ,WAAW;QACX,QAAQ;QACR,SAAS,EAAE,cAAc,CAAC,KAAK;QAC/B,KAAK,CAAC,OAAO;YACV,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;YAC3C,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC7B,OAAO,UAAU,CAAC;QACrB,CAAC;QACD,WAAW,CAAC,KAAc,EAAE,OAAwB;YACjD,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QACrC,CAAC;QACD,WAAW;YACR,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAClC,CAAC;QACD,OAAO;YACJ,cAAc,CAAC,OAAO,EAAE,CAAC;QAC5B,CAAC;KACH,CAAC;AACL,CAAC;AAwBD;;;;;;;;;;;;GAYG;AACH,SAAgB,uBAAuB,CAIrC,YAA2E,EAAE;IAC5E,MAAM,OAAO,GAA2D,EAAE,CAAC;IAC3E,MAAM,KAAK,GAAyD,EAAE,CAAC;IACvE,MAAM,YAAY,GAAwC,EAAE,CAAC;IAC7D,MAAM,SAAS,GAAmC,EAAE,CAAC;IACrD,MAAM,MAAM,GAAkC,EAAE,CAAC;IACjD,MAAM,eAAe,GAAqC,EAAE,CAAC;IAC7D,MAAM,MAAM,GAAyD;QAClE,iBAAiB,EACd,SAAS,CAAC,iBAAiB;YAC3B,CAAC,KAAK,CAAC,EAAE;gBACN,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACvB,CAAC,CAAC;QACL,eAAe,EACZ,SAAS,CAAC,eAAe;YACzB,CAAC,KAAK,CAAC,EAAE;gBACN,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACrB,CAAC,CAAC;QACL,sBAAsB,EACnB,SAAS,CAAC,sBAAsB;YAChC,CAAC,KAAK,CAAC,EAAE;gBACN,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC5B,CAAC,CAAC;QACL,iBAAiB,EACd,SAAS,CAAC,iBAAiB;YAC3B,CAAC,KAAK,CAAC,EAAE;gBACN,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACzB,CAAC,CAAC;QACL,gBAAgB,EACb,SAAS,CAAC,gBAAgB;YAC1B,CAAC,KAAK,CAAC,EAAE;gBACN,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACtB,CAAC,CAAC;QACL,iBAAiB,EACd,SAAS,CAAC,iBAAiB;YAC3B,CAAC,KAAK,CAAC,EAAE;gBACN,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC/B,CAAC,CAAC;KACP,CAAC;IACF,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;AACvF,CAAC"}
@@ -14,9 +14,13 @@ export interface FakeClock extends Clock {
14
14
  * whose deadline falls within the window — in chronological order, each at
15
15
  * its own deadline (so `now()` inside a callback reads the fire instant, not
16
16
  * the advance target). Timers scheduled by a callback fire too if they fall
17
- * within the same window.
17
+ * within the same window. A {@link Clock.raceTimer} over a promise that
18
+ * settles through a chain still pending loses to the timer, so let that
19
+ * chain settle before advancing.
18
20
  */
19
21
  advance(ms: number): void;
22
+ /** How many {@link Clock.setTimer} timers have neither fired nor been disposed. */
23
+ pendingTimers(): number;
20
24
  }
21
25
  /**
22
26
  * In-process {@link Clock} double for deterministic time. The real
@@ -28,6 +32,10 @@ export interface FakeClock extends Clock {
28
32
  *
29
33
  * Server-free and DI-free — lives in `@hydranium/protocol/testing` so every
30
34
  * head can bind it without pulling in a server package.
35
+ *
36
+ * The clock is a `SystemClock` with its time replaced, so its methods live on
37
+ * its prototype and a spread of it carries none of them. Replace one by
38
+ * assigning it onto the clock, or layer over the clock with `Object.create`.
31
39
  */
32
40
  export declare function makeFakeClock(options?: {
33
41
  now?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"fake-clock.d.ts","sourceRoot":"","sources":["../../src/testing/fake-clock.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,KAAK,EAA8B,MAAM,UAAU,CAAC;AAGlE,2FAA2F;AAC3F,MAAM,WAAW,SAAU,SAAQ,KAAK;IACrC;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AASD;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,SAAS,CA+DvE"}
1
+ {"version":3,"file":"fake-clock.d.ts","sourceRoot":"","sources":["../../src/testing/fake-clock.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,KAAK,EAA+B,MAAM,UAAU,CAAC;AAGnE,2FAA2F;AAC3F,MAAM,WAAW,SAAU,SAAQ,KAAK;IACrC;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,mFAAmF;IACnF,aAAa,IAAI,MAAM,CAAC;CAC1B;AASD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,SAAS,CAEvE"}
@@ -9,6 +9,7 @@
9
9
  ********************************************************************************/
10
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
11
  exports.makeFakeClock = makeFakeClock;
12
+ const clock_1 = require("../clock");
12
13
  const util_1 = require("../util");
13
14
  /**
14
15
  * In-process {@link Clock} double for deterministic time. The real
@@ -20,67 +21,75 @@ const util_1 = require("../util");
20
21
  *
21
22
  * Server-free and DI-free — lives in `@hydranium/protocol/testing` so every
22
23
  * head can bind it without pulling in a server package.
24
+ *
25
+ * The clock is a `SystemClock` with its time replaced, so its methods live on
26
+ * its prototype and a spread of it carries none of them. Replace one by
27
+ * assigning it onto the clock, or layer over the clock with `Object.create`.
23
28
  */
24
29
  function makeFakeClock(options = {}) {
25
- let current = options.now ?? 0;
26
- const timers = [];
27
- const makeStopwatch = () => {
28
- const start = current;
29
- let lastLap = current;
30
+ return new VirtualClock(options.now ?? 0);
31
+ }
32
+ /**
33
+ * A `SystemClock` whose time, stopwatches and timers read one virtual axis, so
34
+ * the `measure` and `raceTimer` it inherits run on that axis too.
35
+ */
36
+ class VirtualClock extends clock_1.SystemClock {
37
+ current;
38
+ timers = [];
39
+ constructor(current) {
40
+ super();
41
+ this.current = current;
42
+ }
43
+ now() {
44
+ return this.current;
45
+ }
46
+ setTimer(callback, ms) {
47
+ const timer = { at: this.current + ms, callback, disposed: false, fired: false };
48
+ this.timers.push(timer);
49
+ return util_1.Disposable.create(() => {
50
+ timer.disposed = true;
51
+ });
52
+ }
53
+ stopwatch() {
54
+ const read = () => this.current;
55
+ const start = read();
56
+ let lastLap = start;
30
57
  let stopped;
31
58
  return {
32
59
  get elapsedMs() {
33
- return (stopped ?? current) - start;
60
+ return (stopped ?? read()) - start;
34
61
  },
35
62
  lap() {
36
- const at = stopped ?? current;
63
+ const at = stopped ?? read();
37
64
  const split = at - lastLap;
38
65
  lastLap = at;
39
66
  return split;
40
67
  },
41
68
  stop() {
42
- if (stopped === undefined) {
43
- stopped = current;
44
- }
69
+ stopped ??= read();
45
70
  return stopped - start;
46
71
  }
47
72
  };
48
- };
49
- return {
50
- now: () => current,
51
- setTimer(callback, ms) {
52
- const timer = { at: current + ms, callback, disposed: false, fired: false };
53
- timers.push(timer);
54
- return util_1.Disposable.create(() => {
55
- timer.disposed = true;
56
- });
57
- },
58
- stopwatch: makeStopwatch,
59
- measure: ((callback) => {
60
- const stopwatch = makeStopwatch();
61
- const result = callback();
62
- if (result instanceof Promise) {
63
- return result.then(value => ({ result: value, elapsedMs: stopwatch.elapsedMs }));
64
- }
65
- return { result: result, elapsedMs: stopwatch.elapsedMs };
66
- }),
67
- advance(ms) {
68
- const target = current + ms;
69
- // Fire due timers one at a time, re-scanning after each so a callback
70
- // that schedules a nearer timer still fires within this window.
71
- for (;;) {
72
- const next = timers
73
- .filter(timer => !timer.disposed && !timer.fired && timer.at <= target)
74
- .sort((left, right) => left.at - right.at)[0];
75
- if (!next) {
76
- break;
77
- }
78
- current = next.at;
79
- next.fired = true;
80
- next.callback();
73
+ }
74
+ pendingTimers() {
75
+ return this.timers.filter(timer => !timer.disposed && !timer.fired).length;
76
+ }
77
+ advance(ms) {
78
+ const target = this.current + ms;
79
+ // Fire due timers one at a time, re-scanning after each so a callback
80
+ // that schedules a nearer timer still fires within this window.
81
+ for (;;) {
82
+ const next = this.timers
83
+ .filter(timer => !timer.disposed && !timer.fired && timer.at <= target)
84
+ .sort((left, right) => left.at - right.at)[0];
85
+ if (!next) {
86
+ break;
81
87
  }
82
- current = target;
88
+ this.current = next.at;
89
+ next.fired = true;
90
+ next.callback();
83
91
  }
84
- };
92
+ this.current = target;
93
+ }
85
94
  }
86
95
  //# sourceMappingURL=fake-clock.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fake-clock.js","sourceRoot":"","sources":["../../src/testing/fake-clock.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fake-clock.js","sourceRoot":"","sources":["../../src/testing/fake-clock.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;AA2ClF,sCAEC;AA3CD,oCAAmE;AACnE,kCAAqC;AAyBrC;;;;;;;;;;;;;;GAcG;AACH,SAAgB,aAAa,CAAC,UAA4B,EAAE;IACzD,OAAO,IAAI,YAAY,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED;;;GAGG;AACH,MAAM,YAAa,SAAQ,mBAAW;IAGb;IAFH,MAAM,GAAgB,EAAE,CAAC;IAE5C,YAAsB,OAAe;QAClC,KAAK,EAAE,CAAC;QADW,YAAO,GAAP,OAAO,CAAQ;IAErC,CAAC;IAEQ,GAAG;QACT,OAAO,IAAI,CAAC,OAAO,CAAC;IACvB,CAAC;IAEQ,QAAQ,CAAC,QAAoB,EAAE,EAAU;QAC/C,MAAM,KAAK,GAAc,EAAE,EAAE,EAAE,IAAI,CAAC,OAAO,GAAG,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;QAC5F,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,OAAO,iBAAU,CAAC,MAAM,CAAC,GAAG,EAAE;YAC3B,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;QACzB,CAAC,CAAC,CAAC;IACN,CAAC;IAEQ,SAAS;QACf,MAAM,IAAI,GAAG,GAAW,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC;QACxC,MAAM,KAAK,GAAG,IAAI,EAAE,CAAC;QACrB,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,OAA2B,CAAC;QAChC,OAAO;YACJ,IAAI,SAAS;gBACV,OAAO,CAAC,OAAO,IAAI,IAAI,EAAE,CAAC,GAAG,KAAK,CAAC;YACtC,CAAC;YACD,GAAG;gBACA,MAAM,EAAE,GAAG,OAAO,IAAI,IAAI,EAAE,CAAC;gBAC7B,MAAM,KAAK,GAAG,EAAE,GAAG,OAAO,CAAC;gBAC3B,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,KAAK,CAAC;YAChB,CAAC;YACD,IAAI;gBACD,OAAO,KAAK,IAAI,EAAE,CAAC;gBACnB,OAAO,OAAO,GAAG,KAAK,CAAC;YAC1B,CAAC;SACH,CAAC;IACL,CAAC;IAED,aAAa;QACV,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;IAC9E,CAAC;IAED,OAAO,CAAC,EAAU;QACf,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;QACjC,sEAAsE;QACtE,gEAAgE;QAChE,SAAS,CAAC;YACP,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM;iBACpB,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,EAAE,IAAI,MAAM,CAAC;iBACtE,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YACjD,IAAI,CAAC,IAAI,EAAE,CAAC;gBACT,MAAM;YACT,CAAC;YACD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC;YACvB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;YAClB,IAAI,CAAC,QAAQ,EAAE,CAAC;QACnB,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IACzB,CAAC;CACH"}
@@ -8,4 +8,5 @@
8
8
  ********************************************************************************/
9
9
  export * from './duplex-connection';
10
10
  export * from './duplex-stream';
11
+ export * from './message-port-pair';
11
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/testing/node/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAalF,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/testing/node/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAYlF,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC"}
@@ -23,8 +23,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
23
23
  };
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  // Subpath barrel for `@hydranium/protocol/testing/node` — the test transports
26
- // that need a Node runtime: a crossed `PassThrough` pair and the in-process
27
- // `MessageConnection` bridge over it.
26
+ // that need a Node runtime.
28
27
  //
29
28
  // Separate from `./testing` because a `PassThrough` is in `DuplexStreamPair`'s
30
29
  // exported type and `StreamMessageReader` comes from `vscode-jsonrpc/node`, so
@@ -34,4 +33,5 @@ Object.defineProperty(exports, "__esModule", { value: true });
34
33
  // their own.
35
34
  __exportStar(require("./duplex-connection"), exports);
36
35
  __exportStar(require("./duplex-stream"), exports);
36
+ __exportStar(require("./message-port-pair"), exports);
37
37
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/testing/node/index.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;;;;;;;;;;;AAElF,8EAA8E;AAC9E,4EAA4E;AAC5E,sCAAsC;AACtC,EAAE;AACF,+EAA+E;AAC/E,+EAA+E;AAC/E,+EAA+E;AAC/E,4EAA4E;AAC5E,8EAA8E;AAC9E,aAAa;AAEb,sDAAoC;AACpC,kDAAgC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/testing/node/index.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;;;;;;;;;;;AAElF,8EAA8E;AAC9E,4BAA4B;AAC5B,EAAE;AACF,+EAA+E;AAC/E,+EAA+E;AAC/E,+EAA+E;AAC/E,4EAA4E;AAC5E,8EAA8E;AAC9E,aAAa;AAEb,sDAAoC;AACpC,kDAAgC;AAChC,sDAAoC"}
@@ -0,0 +1,25 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+ import type { TransferredMessagePort } from '../../client/post-message-transport';
10
+ /**
11
+ * The two ends of a `worker_threads` `MessageChannel`, typed as the transferred
12
+ * browser ports `createMessagePortTransport` takes. Node's port clones and keeps
13
+ * order as a browser's does, which is what lets a headless test stand in for a
14
+ * worker.
15
+ *
16
+ * `dispose` closes both ports. Node reports that as a close and a browser port
17
+ * reports nothing, so a test that asserts on a close does so before teardown.
18
+ */
19
+ export interface MessagePortPair {
20
+ readonly port1: TransferredMessagePort;
21
+ readonly port2: TransferredMessagePort;
22
+ dispose(): void;
23
+ }
24
+ export declare function makeMessagePortPair(): MessagePortPair;
25
+ //# sourceMappingURL=message-port-pair.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-port-pair.d.ts","sourceRoot":"","sources":["../../../src/testing/node/message-port-pair.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAGlF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAElF;;;;;;;;GAQG;AACH,MAAM,WAAW,eAAe;IAC7B,QAAQ,CAAC,KAAK,EAAE,sBAAsB,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,sBAAsB,CAAC;IACvC,OAAO,IAAI,IAAI,CAAC;CAClB;AAED,wBAAgB,mBAAmB,IAAI,eAAe,CAYrD"}
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ /********************************************************************************
3
+ * Copyright (c) 2026 EclipseSource and others.
4
+ *
5
+ * This program and the accompanying materials are made available under the
6
+ * terms of the MIT License which is available in the project root.
7
+ *
8
+ * SPDX-License-Identifier: MIT
9
+ ********************************************************************************/
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.makeMessagePortPair = makeMessagePortPair;
12
+ const node_worker_threads_1 = require("node:worker_threads");
13
+ function makeMessagePortPair() {
14
+ const channel = new node_worker_threads_1.MessageChannel();
15
+ return {
16
+ // Node's port satisfies the structural type at runtime; the cast records
17
+ // one platform's port standing in for the other's.
18
+ port1: channel.port1,
19
+ port2: channel.port2,
20
+ dispose() {
21
+ channel.port1.close();
22
+ channel.port2.close();
23
+ }
24
+ };
25
+ }
26
+ //# sourceMappingURL=message-port-pair.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-port-pair.js","sourceRoot":"","sources":["../../../src/testing/node/message-port-pair.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;AAoBlF,kDAYC;AA9BD,6DAAqD;AAkBrD,SAAgB,mBAAmB;IAChC,MAAM,OAAO,GAAG,IAAI,oCAAc,EAAE,CAAC;IACrC,OAAO;QACJ,yEAAyE;QACzE,mDAAmD;QACnD,KAAK,EAAE,OAAO,CAAC,KAA0C;QACzD,KAAK,EAAE,OAAO,CAAC,KAA0C;QACzD,OAAO;YACJ,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACzB,CAAC;KACH,CAAC;AACL,CAAC"}
@@ -41,6 +41,14 @@ export interface TransferDocument<TTransfer extends TransferElement, TDiagnostic
41
41
  */
42
42
  root?: TTransfer;
43
43
  diagnostics: TDiagnostic[];
44
+ /**
45
+ * Whether the server holds text for this document that its file does not,
46
+ * as the server last knew the file: set on every document a data server
47
+ * answers or sends that the server holds, and absent otherwise. A change
48
+ * after this snapshot arrives as `onDocumentDirtyChanged` to a client
49
+ * watching the document.
50
+ */
51
+ dirty?: boolean;
44
52
  }
45
53
  /**
46
54
  * A {@link TransferDocument} the server actually had, so `root` is present.
@@ -1 +1 @@
1
- {"version":3,"file":"transfer-document.d.ts","sourceRoot":"","sources":["../src/transfer-document.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEnF;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,gBAAgB,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB;IAClG,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;OAOG;IACH,OAAO,EAAE,eAAe,CAAC;IACzB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,WAAW,EAAE,WAAW,EAAE,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,MAAM,sBAAsB,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB,IAAI,gBAAgB,CACvH,SAAS,EACT,WAAW,CACb,GAAG;IACD,IAAI,EAAE,SAAS,CAAC;CAClB,CAAC;AAEF,yBAAiB,gBAAgB,CAAC;IAC/B;;;OAGG;IACH,SAAgB,QAAQ,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB,EACzF,QAAQ,EAAE,gBAAgB,CAAC,SAAS,EAAE,WAAW,CAAC,GAClD,QAAQ,IAAI,sBAAsB,CAAC,SAAS,EAAE,WAAW,CAAC,CAE5D;IAED;;;;;OAKG;IACH,SAAgB,YAAY,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB,EAC7F,QAAQ,EAAE,gBAAgB,CAAC,SAAS,EAAE,WAAW,CAAC,GAClD,sBAAsB,CAAC,SAAS,EAAE,WAAW,CAAC,CAKhD;IAED;;;;;;;OAOG;IACH,SAAgB,MAAM,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB,EACvF,GAAG,EAAE,MAAM,EACX,WAAW,GAAE,WAAW,EAAO,GAC/B,gBAAgB,CAAC,SAAS,EAAE,WAAW,CAAC,CAE1C;IAED;;;;;OAKG;IACH,SAAgB,MAAM,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB,EACvF,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,EACf,WAAW,GAAE,WAAW,EAAO,GAC/B,gBAAgB,CAAC,SAAS,EAAE,WAAW,CAAC,CAE1C;CACH"}
1
+ {"version":3,"file":"transfer-document.d.ts","sourceRoot":"","sources":["../src/transfer-document.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEnF;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,gBAAgB,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB;IAClG,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;OAOG;IACH,OAAO,EAAE,eAAe,CAAC;IACzB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,WAAW,EAAE,WAAW,EAAE,CAAC;IAC3B;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,MAAM,sBAAsB,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB,IAAI,gBAAgB,CACvH,SAAS,EACT,WAAW,CACb,GAAG;IACD,IAAI,EAAE,SAAS,CAAC;CAClB,CAAC;AAEF,yBAAiB,gBAAgB,CAAC;IAC/B;;;OAGG;IACH,SAAgB,QAAQ,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB,EACzF,QAAQ,EAAE,gBAAgB,CAAC,SAAS,EAAE,WAAW,CAAC,GAClD,QAAQ,IAAI,sBAAsB,CAAC,SAAS,EAAE,WAAW,CAAC,CAE5D;IAED;;;;;OAKG;IACH,SAAgB,YAAY,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB,EAC7F,QAAQ,EAAE,gBAAgB,CAAC,SAAS,EAAE,WAAW,CAAC,GAClD,sBAAsB,CAAC,SAAS,EAAE,WAAW,CAAC,CAKhD;IAED;;;;;;;OAOG;IACH,SAAgB,MAAM,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB,EACvF,GAAG,EAAE,MAAM,EACX,WAAW,GAAE,WAAW,EAAO,GAC/B,gBAAgB,CAAC,SAAS,EAAE,WAAW,CAAC,CAE1C;IAED;;;;;OAKG;IACH,SAAgB,MAAM,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB,EACvF,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,EACf,WAAW,GAAE,WAAW,EAAO,GAC/B,gBAAgB,CAAC,SAAS,EAAE,WAAW,CAAC,CAE1C;CACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"transfer-document.js","sourceRoot":"","sources":["../src/transfer-document.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;AAIlF,uDAAmF;AA+CnF,IAAiB,gBAAgB,CAuDhC;AAvDD,WAAiB,gBAAgB;IAC9B;;;OAGG;IACH,SAAgB,QAAQ,CACrB,QAAkD;QAElD,OAAO,QAAQ,CAAC,IAAI,KAAK,SAAS,CAAC;IACtC,CAAC;IAJe,yBAAQ,WAIvB,CAAA;IAED;;;;;OAKG;IACH,SAAgB,YAAY,CACzB,QAAkD;QAElD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;QACrD,CAAC;QACD,OAAO,QAAQ,CAAC;IACnB,CAAC;IAPe,6BAAY,eAO3B,CAAA;IAED;;;;;;;OAOG;IACH,SAAgB,MAAM,CACnB,GAAW,EACX,cAA6B,EAAE;QAE/B,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAA,4BAAiB,EAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;IAC/E,CAAC;IALe,uBAAM,SAKrB,CAAA;IAED;;;;;OAKG;IACH,SAAgB,MAAM,CACnB,GAAW,EACX,OAAe,EACf,IAAe,EACf,cAA6B,EAAE;QAE/B,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAA,4BAAiB,EAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IAC1E,CAAC;IAPe,uBAAM,SAOrB,CAAA;AACJ,CAAC,EAvDgB,gBAAgB,gCAAhB,gBAAgB,QAuDhC"}
1
+ {"version":3,"file":"transfer-document.js","sourceRoot":"","sources":["../src/transfer-document.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;AAIlF,uDAAmF;AAuDnF,IAAiB,gBAAgB,CAuDhC;AAvDD,WAAiB,gBAAgB;IAC9B;;;OAGG;IACH,SAAgB,QAAQ,CACrB,QAAkD;QAElD,OAAO,QAAQ,CAAC,IAAI,KAAK,SAAS,CAAC;IACtC,CAAC;IAJe,yBAAQ,WAIvB,CAAA;IAED;;;;;OAKG;IACH,SAAgB,YAAY,CACzB,QAAkD;QAElD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;QACrD,CAAC;QACD,OAAO,QAAQ,CAAC;IACnB,CAAC;IAPe,6BAAY,eAO3B,CAAA;IAED;;;;;;;OAOG;IACH,SAAgB,MAAM,CACnB,GAAW,EACX,cAA6B,EAAE;QAE/B,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAA,4BAAiB,EAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;IAC/E,CAAC;IALe,uBAAM,SAKrB,CAAA;IAED;;;;;OAKG;IACH,SAAgB,MAAM,CACnB,GAAW,EACX,OAAe,EACf,IAAe,EACf,cAA6B,EAAE;QAE/B,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAA,4BAAiB,EAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IAC1E,CAAC;IAPe,uBAAM,SAOrB,CAAA;AACJ,CAAC,EAvDgB,gBAAgB,gCAAhB,gBAAgB,QAuDhC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hydranium/protocol",
3
- "version": "1.0.0-next.123",
3
+ "version": "1.0.0-next.127",
4
4
  "description": "Generic, language-agnostic types, constants, and pure utilities for the hydranium framework.",
5
5
  "keywords": [
6
6
  "hydranium",
@@ -7,6 +7,7 @@
7
7
  * SPDX-License-Identifier: MIT
8
8
  ********************************************************************************/
9
9
 
10
+ import { Emitter, type Event } from 'vscode-jsonrpc';
10
11
  import { FRAMEWORK_CLIENT_IDS } from '../client-ids';
11
12
  import {
12
13
  DATA_CLIENT_PROTOCOL_METHODS,
@@ -14,7 +15,8 @@ import {
14
15
  type DataClientProtocol,
15
16
  type DataServerProtocol,
16
17
  type DiagnosticOf,
17
- type ProjectOf
18
+ type ProjectOf,
19
+ type TransferDocumentDirtyChangedEvent
18
20
  } from '../data';
19
21
  import type { TransferElement } from '../transfer-element';
20
22
  import { DataEvents } from './data-events';
@@ -90,6 +92,20 @@ export class DataConnection<
90
92
  > extends RpcConnection<TServer, TClient> {
91
93
  protected readonly sessions = new Set<DataSession<TTransfer, TServer>>();
92
94
  protected readonly sessionFactory: DataSessionFactory<TTransfer, TServer>;
95
+ protected readonly createSessionEmitter = new Emitter<DataSession<TTransfer, TServer>>();
96
+ /**
97
+ * Fires with each session {@link createSession} starts, before it returns,
98
+ * so a listener sees every session a caller can. A session started before
99
+ * the listener subscribed is in {@link liveSessions}.
100
+ */
101
+ readonly onDidCreateSession: Event<DataSession<TTransfer, TServer>> = this.createSessionEmitter.event;
102
+ /**
103
+ * Per URI, the `dirty` the client was last told since a session of this
104
+ * connection last opened the URI. A restore tells the client its answer
105
+ * only where it differs, so the client hears changes and nothing else; see
106
+ * {@link DataSessionHost.restoreDirty}.
107
+ */
108
+ protected readonly dirtyStates = new Map<string, boolean>();
93
109
 
94
110
  constructor(port: DataPort, client: TClient, ...rest: DataConnectionArgs<TTransfer, TClient, TServer>) {
95
111
  const [options = {}] = rest as [
@@ -107,12 +123,22 @@ export class DataConnection<
107
123
  options.sessionFactory ?? ((clientId, host, label) => new DataSession<TTransfer, TServer>(clientId, host, label));
108
124
  }
109
125
 
126
+ /**
127
+ * The sessions of this connection that have not ended, in the order they
128
+ * started. A session is listed until its `onDidDispose` fires, or until
129
+ * {@link dispose} clears the list.
130
+ */
131
+ get liveSessions(): readonly DataSession<TTransfer, TServer>[] {
132
+ return [...this.sessions];
133
+ }
134
+
110
135
  /**
111
136
  * Start a participant on this connection, registered with the server under a
112
137
  * fresh id, `label` plus `#` plus a random UUID, or under `clientId` when
113
- * given. Synchronous: the registration is sent at once, and the session's
114
- * calls wait for it. The server refuses an id live anywhere in its process,
115
- * and every call of that session then rejects with a
138
+ * given. Pass a `label` naming the participant; without one it is
139
+ * `session`. Synchronous: the registration is sent at once, and the
140
+ * session's calls wait for it. The server refuses an id live anywhere in
141
+ * its process, and every call of that session then rejects with a
116
142
  * `DuplicateClientIdError` code.
117
143
  *
118
144
  * Throws for an id in {@link FRAMEWORK_CLIENT_IDS} — those are authors the
@@ -133,18 +159,56 @@ export class DataConnection<
133
159
  id,
134
160
  {
135
161
  connected: () => this.connected(),
136
- releaseSession: released => this.sessions.delete(released),
137
- reportError: (error, reported) => this.reportError(error, reported)
162
+ reportError: (error, reported) => this.reportError(error, reported),
163
+ restoreDirty: event => {
164
+ if (this.dirtyStates.get(event.uri) !== event.dirty) {
165
+ this.deliverDirty(event);
166
+ }
167
+ },
168
+ forgetDirty: uri => this.dirtyStates.delete(uri)
138
169
  },
139
170
  label
140
171
  );
141
172
  this.sessions.add(session);
173
+ // Subscribed before the session is handed out, so the id is free again
174
+ // on this connection by the time any caller's listener runs.
175
+ session.onDidDispose(() => this.sessions.delete(session));
142
176
  // A failure reaches the session's own calls, which wait for the same
143
177
  // registration; caught here only so it is not also reported unhandled.
144
178
  session.connected().catch(() => undefined);
179
+ this.createSessionEmitter.fire(session);
145
180
  return session;
146
181
  }
147
182
 
183
+ /**
184
+ * The client, with its `onDocumentDirtyChanged` passing through
185
+ * {@link deliverDirty} first, so {@link dirtyStates} holds what the server
186
+ * told it. Every other bound method forwards to the client unchanged, and
187
+ * one the client lacks stays absent, so the binding still refuses it.
188
+ */
189
+ protected override localTarget(): TClient {
190
+ const client = this.client as unknown as Record<string, unknown>;
191
+ if (typeof client.onDocumentDirtyChanged !== 'function') {
192
+ return this.client;
193
+ }
194
+ const target: Record<string, unknown> = {};
195
+ for (const name of this.clientMethods) {
196
+ const method: unknown = client[name];
197
+ if (typeof method === 'function') {
198
+ target[name] = (params: unknown): unknown => (method as (params: unknown) => unknown).call(client, params);
199
+ }
200
+ }
201
+ target.onDocumentDirtyChanged = (event: TransferDocumentDirtyChangedEvent): void => this.deliverDirty(event);
202
+ return target as unknown as TClient;
203
+ }
204
+
205
+ /** Record `event` in {@link dirtyStates} and hand it to the client. */
206
+ protected deliverDirty(event: TransferDocumentDirtyChangedEvent): void {
207
+ this.dirtyStates.set(event.uri, event.dirty);
208
+ const client = this.client as unknown as Partial<Pick<DataClientProtocol<TTransfer>, 'onDocumentDirtyChanged'>>;
209
+ client.onDocumentDirtyChanged?.(event);
210
+ }
211
+
148
212
  /**
149
213
  * After the transport dropped, reconnect on the next macrotask for the
150
214
  * sessions with documents open, so they re-watch and follow their documents
@@ -173,7 +237,9 @@ export class DataConnection<
173
237
  for (const session of [...this.sessions]) {
174
238
  session.detach();
175
239
  }
240
+ // For a factory's session whose `detach` does not fire.
176
241
  this.sessions.clear();
242
+ this.createSessionEmitter.dispose();
177
243
  super.dispose();
178
244
  }
179
245
  }
@@ -12,6 +12,7 @@ import type {
12
12
  DataClientProtocol,
13
13
  ProjectsChangedEvent,
14
14
  TransferDocumentDeletedEvent,
15
+ TransferDocumentDirtyChangedEvent,
15
16
  TransferDocumentSavedEvent,
16
17
  TransferDocumentsBuiltEvent,
17
18
  TransferDocumentUpdatedEvent
@@ -47,6 +48,7 @@ export class DataEvents<
47
48
  > implements DataClientProtocol<TTransfer, TDiagnostic, TProject> {
48
49
  protected readonly documentUpdatedEmitter = new Emitter<TransferDocumentUpdatedEvent<TTransfer, TDiagnostic>>();
49
50
  protected readonly documentSavedEmitter = new Emitter<TransferDocumentSavedEvent<TTransfer, TDiagnostic>>();
51
+ protected readonly documentDirtyChangedEmitter = new Emitter<TransferDocumentDirtyChangedEvent>();
50
52
  protected readonly documentDeletedEmitter = new Emitter<TransferDocumentDeletedEvent>();
51
53
  protected readonly documentsBuiltEmitter = new Emitter<TransferDocumentsBuiltEvent>();
52
54
  protected readonly projectsChangedEmitter = new Emitter<ProjectsChangedEvent<TProject>>();
@@ -55,6 +57,8 @@ export class DataEvents<
55
57
  readonly onDidUpdateDocument: Event<TransferDocumentUpdatedEvent<TTransfer, TDiagnostic>> = this.documentUpdatedEmitter.event;
56
58
  /** A watched document was persisted to disk. */
57
59
  readonly onDidSaveDocument: Event<TransferDocumentSavedEvent<TTransfer, TDiagnostic>> = this.documentSavedEmitter.event;
60
+ /** A watched document's text started or stopped differing from its file. */
61
+ readonly onDidChangeDocumentDirty: Event<TransferDocumentDirtyChangedEvent> = this.documentDirtyChangedEmitter.event;
58
62
  /** A document's backing file was removed, watched or not. Any watch survives. */
59
63
  readonly onDidDeleteDocument: Event<TransferDocumentDeletedEvent> = this.documentDeletedEmitter.event;
60
64
  /** Documents built that nobody watches — re-read anything derived from them. */
@@ -72,6 +76,10 @@ export class DataEvents<
72
76
  this.documentSavedEmitter.fire(event);
73
77
  }
74
78
 
79
+ onDocumentDirtyChanged(event: TransferDocumentDirtyChangedEvent): void {
80
+ this.documentDirtyChangedEmitter.fire(event);
81
+ }
82
+
75
83
  onDocumentDeleted(event: TransferDocumentDeletedEvent): void {
76
84
  this.documentDeletedEmitter.fire(event);
77
85
  }
@@ -87,6 +95,7 @@ export class DataEvents<
87
95
  dispose(): void {
88
96
  this.documentUpdatedEmitter.dispose();
89
97
  this.documentSavedEmitter.dispose();
98
+ this.documentDirtyChangedEmitter.dispose();
90
99
  this.documentDeletedEmitter.dispose();
91
100
  this.documentsBuiltEmitter.dispose();
92
101
  this.projectsChangedEmitter.dispose();