@agentshouse/mdruntime 0.1.0-alpha.8 → 0.1.0-c009335e08279

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 (121) hide show
  1. package/AGENTS.md +208 -0
  2. package/README.md +44 -0
  3. package/dist/adapter.d.ts +215 -25
  4. package/dist/adapter.d.ts.map +1 -1
  5. package/dist/adapter.js +2 -3
  6. package/dist/attachment.d.ts +3 -0
  7. package/dist/attachment.d.ts.map +1 -0
  8. package/dist/attachment.js +8 -0
  9. package/dist/bootstrap.d.ts +6 -7
  10. package/dist/bootstrap.d.ts.map +1 -1
  11. package/dist/bootstrap.js +31 -28
  12. package/dist/change-set.d.ts +33 -0
  13. package/dist/change-set.d.ts.map +1 -0
  14. package/dist/change-set.js +83 -0
  15. package/dist/change.d.ts +9 -0
  16. package/dist/change.d.ts.map +1 -1
  17. package/dist/change.js +6 -5
  18. package/dist/client.d.ts +69 -0
  19. package/dist/client.d.ts.map +1 -0
  20. package/dist/client.js +165 -0
  21. package/dist/collection.d.ts +22 -15
  22. package/dist/collection.d.ts.map +1 -1
  23. package/dist/collection.js +60 -78
  24. package/dist/connection.d.ts +68 -40
  25. package/dist/connection.d.ts.map +1 -1
  26. package/dist/connection.js +1597 -961
  27. package/dist/conversation.d.ts +79 -0
  28. package/dist/conversation.d.ts.map +1 -0
  29. package/dist/conversation.js +557 -0
  30. package/dist/durability.d.ts +8 -3
  31. package/dist/durability.d.ts.map +1 -1
  32. package/dist/durability.js +7 -61
  33. package/dist/file.d.ts +20 -0
  34. package/dist/file.d.ts.map +1 -0
  35. package/dist/file.js +126 -0
  36. package/dist/host.d.ts +13 -0
  37. package/dist/host.d.ts.map +1 -0
  38. package/dist/host.js +175 -0
  39. package/dist/identity.d.ts +1 -0
  40. package/dist/identity.d.ts.map +1 -1
  41. package/dist/identity.js +10 -9
  42. package/dist/index.d.ts +14 -10
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +1 -3
  45. package/dist/log.js +5 -6
  46. package/dist/memory.d.ts +17 -2
  47. package/dist/memory.d.ts.map +1 -1
  48. package/dist/memory.js +268 -113
  49. package/dist/model.d.ts +10 -25
  50. package/dist/model.d.ts.map +1 -1
  51. package/dist/model.js +18 -21
  52. package/dist/observation.d.ts +25 -0
  53. package/dist/observation.d.ts.map +1 -0
  54. package/dist/observation.js +85 -0
  55. package/dist/outcome.d.ts +12 -24
  56. package/dist/outcome.d.ts.map +1 -1
  57. package/dist/outcome.js +1 -13
  58. package/dist/overlay.d.ts +9 -2
  59. package/dist/overlay.d.ts.map +1 -1
  60. package/dist/overlay.js +187 -43
  61. package/dist/paths.d.ts +0 -1
  62. package/dist/paths.d.ts.map +1 -1
  63. package/dist/paths.js +12 -19
  64. package/dist/query.d.ts +210 -9
  65. package/dist/query.d.ts.map +1 -1
  66. package/dist/query.js +420 -15
  67. package/dist/read-side.d.ts +14 -0
  68. package/dist/read-side.d.ts.map +1 -0
  69. package/dist/read-side.js +371 -0
  70. package/dist/refresh.d.ts +4 -5
  71. package/dist/refresh.d.ts.map +1 -1
  72. package/dist/refresh.js +45 -30
  73. package/dist/replica.d.ts +27 -6
  74. package/dist/replica.d.ts.map +1 -1
  75. package/dist/replica.js +233 -30
  76. package/dist/room-draft.d.ts +124 -0
  77. package/dist/room-draft.d.ts.map +1 -0
  78. package/dist/room-draft.js +327 -0
  79. package/dist/rows.d.ts +41 -0
  80. package/dist/rows.d.ts.map +1 -0
  81. package/dist/rows.js +100 -0
  82. package/dist/save.d.ts +10 -6
  83. package/dist/save.d.ts.map +1 -1
  84. package/dist/save.js +266 -333
  85. package/dist/search.d.ts +61 -0
  86. package/dist/search.d.ts.map +1 -0
  87. package/dist/search.js +125 -0
  88. package/dist/status.d.ts +9 -2
  89. package/dist/status.d.ts.map +1 -1
  90. package/dist/status.js +11 -14
  91. package/dist/store.d.ts +75 -18
  92. package/dist/store.d.ts.map +1 -1
  93. package/dist/store.js +358 -97
  94. package/dist/transfer.d.ts +5 -0
  95. package/dist/transfer.d.ts.map +1 -1
  96. package/dist/transfer.js +1 -5
  97. package/dist/wire.d.ts +64 -0
  98. package/dist/wire.d.ts.map +1 -0
  99. package/dist/wire.js +118 -0
  100. package/package.json +15 -13
  101. package/dist/adapter.js.map +0 -1
  102. package/dist/bootstrap.js.map +0 -1
  103. package/dist/change.js.map +0 -1
  104. package/dist/collection.js.map +0 -1
  105. package/dist/connection.js.map +0 -1
  106. package/dist/durability.js.map +0 -1
  107. package/dist/identity.js.map +0 -1
  108. package/dist/index.js.map +0 -1
  109. package/dist/log.js.map +0 -1
  110. package/dist/memory.js.map +0 -1
  111. package/dist/model.js.map +0 -1
  112. package/dist/outcome.js.map +0 -1
  113. package/dist/overlay.js.map +0 -1
  114. package/dist/paths.js.map +0 -1
  115. package/dist/query.js.map +0 -1
  116. package/dist/refresh.js.map +0 -1
  117. package/dist/replica.js.map +0 -1
  118. package/dist/save.js.map +0 -1
  119. package/dist/status.js.map +0 -1
  120. package/dist/store.js.map +0 -1
  121. package/dist/transfer.js.map +0 -1
@@ -0,0 +1,85 @@
1
+ export function rowsOf(result) {
2
+ return 'groups' in result ? result.groups : result.documents;
3
+ }
4
+ function keyedResult(first) {
5
+ const grouped = 'groups' in first.result;
6
+ const rows = rowsOf(first.result);
7
+ const byKey = new Map(first.keys.map((key, index) => [key, rows[index]]));
8
+ let keys = first.keys;
9
+ return {
10
+ value: first.result,
11
+ next(message) {
12
+ const change = message;
13
+ for (const key of change.removed)
14
+ byKey.delete(key);
15
+ for (const [key, row] of change.changed)
16
+ byKey.set(key, row);
17
+ keys = change.order ?? keys.filter((key) => byKey.has(key));
18
+ const next = keys.map((key) => byKey.get(key));
19
+ return grouped
20
+ ? { groups: next }
21
+ : { documents: next };
22
+ },
23
+ };
24
+ }
25
+ function whole(first) {
26
+ return { value: first, next: (message) => message };
27
+ }
28
+ export function observed(first, stop, keyed) {
29
+ const reducer = keyed ? keyedResult(first) : whole(first);
30
+ let value = reducer.value;
31
+ let open = true;
32
+ const listeners = new Set();
33
+ const end = () => {
34
+ open = false;
35
+ listeners.clear();
36
+ };
37
+ return {
38
+ observation: {
39
+ current: () => value,
40
+ subscribe(listener) {
41
+ const entry = { hear: listener };
42
+ if (open)
43
+ listeners.add(entry);
44
+ return () => {
45
+ listeners.delete(entry);
46
+ };
47
+ },
48
+ close() {
49
+ if (!open)
50
+ return;
51
+ end();
52
+ stop();
53
+ },
54
+ },
55
+ receive(message) {
56
+ if (!open)
57
+ return;
58
+ value = reducer.next(message);
59
+ for (const entry of [...listeners]) {
60
+ if (listeners.has(entry))
61
+ entry.hear(value);
62
+ }
63
+ },
64
+ end,
65
+ };
66
+ }
67
+ export function opened(watch, keyed) {
68
+ return new Promise((resolve, reject) => {
69
+ let handle;
70
+ let stop = () => { };
71
+ try {
72
+ stop = watch((message) => {
73
+ if (handle !== undefined) {
74
+ handle.receive(message);
75
+ return;
76
+ }
77
+ handle = observed(message, () => stop(), keyed);
78
+ resolve(handle.observation);
79
+ });
80
+ }
81
+ catch (error) {
82
+ reject(error);
83
+ }
84
+ });
85
+ }
package/dist/outcome.d.ts CHANGED
@@ -1,30 +1,18 @@
1
+ import type { ActionResult } from './adapter.js';
1
2
  import type { ChangeBatch } from './change.js';
2
- export type AffectedState = Readonly<Record<string, string>>;
3
- export type QueueOutcome = {
4
- kind: 'pending';
5
- } | {
6
- kind: 'conflicted';
7
- roomVersion: string;
8
- affected: AffectedState;
9
- text: string;
10
- } | {
11
- kind: 'rejected';
12
- affected: AffectedState;
13
- text: string;
14
- } | {
15
- kind: 'expired';
3
+ export type CallResult = ActionResult | {
4
+ kind: 'undeclared';
16
5
  };
17
- export type AcceptedOutcome = {
18
- kind: 'accepted';
19
- roomVersion: string;
20
- author: string;
21
- time: string;
6
+ export type Submission = {
7
+ readonly state: 'waiting' | 'submitted';
8
+ } | {
9
+ readonly state: 'reset';
10
+ readonly reset: string;
22
11
  };
23
- export type SubmissionOutcome = QueueOutcome | AcceptedOutcome;
24
12
  export type QueueEntry = {
25
13
  readonly batch: ChangeBatch;
26
- readonly outcome: QueueOutcome;
27
- };
28
- export declare function refused(outcome: SubmissionOutcome | undefined): boolean;
29
- export declare function queuedOutcome(outcome: SubmissionOutcome | undefined): QueueOutcome;
14
+ } & (Submission | {
15
+ readonly state: 'accepted';
16
+ readonly roomVersion: string;
17
+ });
30
18
  //# sourceMappingURL=outcome.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"outcome.d.ts","sourceRoot":"","sources":["../src/outcome.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE7D,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IACE,IAAI,EAAE,YAAY,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,aAAa,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;CACd,GACD;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,aAAa,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;CACd,GACD;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC;AAExB,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,UAAU,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,eAAe,CAAC;AAE/D,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;CAChC,CAAC;AAEF,wBAAgB,OAAO,CAAC,OAAO,EAAE,iBAAiB,GAAG,SAAS,GAAG,OAAO,CAIvE;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,SAAS,GAAG,YAAY,CAKlF"}
1
+ {"version":3,"file":"outcome.d.ts","sourceRoot":"","sources":["../src/outcome.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC;AAE/D,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,WAAW,CAAA;CAAE,GAC3C;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAExD,MAAM,MAAM,UAAU,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;CAAE,GAAG,CACvD,UAAU,GACV;IAAE,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAC/D,CAAC"}
package/dist/outcome.js CHANGED
@@ -1,13 +1 @@
1
- export function refused(outcome) {
2
- return outcome?.kind === 'conflicted' || outcome?.kind === 'rejected' || outcome?.kind === 'expired';
3
- }
4
- export function queuedOutcome(outcome) {
5
- if (outcome === undefined || outcome.kind === 'accepted' || outcome.kind === 'pending') {
6
- return {
7
- kind: 'pending'
8
- };
9
- }
10
- return outcome;
11
- }
12
-
13
- //# sourceMappingURL=outcome.js.map
1
+ export {};
package/dist/overlay.d.ts CHANGED
@@ -1,8 +1,15 @@
1
+ import type { HeadChange } from './adapter.js';
1
2
  import type { ChangeBatch } from './change.js';
2
- export type Layer = {
3
+ export type Heads = {
4
+ revisions: Readonly<Record<string, string>>;
5
+ changes: Readonly<Record<string, HeadChange>>;
6
+ };
7
+ export type Layer = Heads & {
3
8
  documents: Readonly<Record<string, string>>;
4
9
  binaryTargets: readonly string[];
5
- revisions: Readonly<Record<string, string>>;
6
10
  };
11
+ export declare function sameChange(left: HeadChange | undefined, right: HeadChange | undefined): boolean;
7
12
  export declare function overlay(base: Layer, queue: readonly ChangeBatch[]): Layer;
13
+ export declare function sameLayerText(left: Layer, right: Layer): boolean;
14
+ export declare function overlayChanged(base: Layer, queue: readonly ChangeBatch[], previousBase: Layer, previousQueue: readonly ChangeBatch[], previousVisible: Layer): Layer;
8
15
  //# sourceMappingURL=overlay.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../src/overlay.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAU,WAAW,EAAgB,MAAM,aAAa,CAAC;AAErE,MAAM,MAAM,KAAK,GAAG;IAClB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5C,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC7C,CAAC;AAyIF,wBAAgB,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,WAAW,EAAE,GAAG,KAAK,CAezE"}
1
+ {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../src/overlay.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAU,WAAW,EAAgB,MAAM,aAAa,CAAC;AAErE,MAAM,MAAM,KAAK,GAAG;IAClB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5C,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG,KAAK,GAAG;IAC1B,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5C,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC,CAAC;AAEF,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS,EAAE,KAAK,EAAE,UAAU,GAAG,SAAS,GAAG,OAAO,CAQ/F;AAoJD,wBAAgB,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,WAAW,EAAE,GAAG,KAAK,CAiBzE;AAQD,wBAAgB,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAQhE;AAmBD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,KAAK,EACX,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,YAAY,EAAE,KAAK,EACnB,aAAa,EAAE,SAAS,WAAW,EAAE,EACrC,eAAe,EAAE,KAAK,GACrB,KAAK,CA4FP"}
package/dist/overlay.js CHANGED
@@ -1,4 +1,12 @@
1
1
  import { apply, parse, serialize } from '@agentshouse/mdmodel';
2
+ export function sameChange(left, right) {
3
+ if (left === undefined || right === undefined)
4
+ return left === right;
5
+ return (left.time === right.time &&
6
+ left.author?.kind === right.author?.kind &&
7
+ left.author?.id === right.author?.id &&
8
+ left.author?.name === right.author?.name);
9
+ }
2
10
  const EMPTY_FRONTMATTER = '---\n---\n';
3
11
  function at(path, name) {
4
12
  return `${path} ${name}`;
@@ -7,7 +15,7 @@ function priorsOf(preconditions) {
7
15
  const fields = new Map();
8
16
  const sections = new Map();
9
17
  const preambles = new Map();
10
- for (const precondition of preconditions){
18
+ for (const precondition of preconditions) {
11
19
  if (precondition.kind === 'field') {
12
20
  fields.set(at(precondition.path, precondition.name), precondition.value);
13
21
  }
@@ -19,25 +27,24 @@ function priorsOf(preconditions) {
19
27
  }
20
28
  }
21
29
  return {
22
- field: (path, name)=>fields.get(at(path, name)),
23
- section: (path, name)=>sections.get(at(path, name)) ?? '',
24
- preamble: (path)=>preambles.get(path) ?? ''
30
+ field: (path, name) => fields.get(at(path, name)),
31
+ section: (path, name) => sections.get(at(path, name)) ?? '',
32
+ preamble: (path) => preambles.get(path) ?? '',
25
33
  };
26
34
  }
27
35
  function compose(fields, sections) {
28
- const body = Object.entries(sections).map(([name, value])=>`\n## ${name}\n${value}`).join('');
36
+ const body = Object.entries(sections)
37
+ .map(([name, value]) => `\n## ${name}\n${value}`)
38
+ .join('');
29
39
  const skeleton = `${EMPTY_FRONTMATTER}${body}`;
30
40
  const opened = parse(skeleton);
31
- if (!opened.ok) return skeleton;
41
+ if (!opened.ok)
42
+ return skeleton;
32
43
  let document = opened.document;
33
- for (const [name, value] of Object.entries(fields)){
34
- const next = apply(document, {
35
- kind: 'field',
36
- name,
37
- value,
38
- prior: undefined
39
- });
40
- if (next.outcome === 'applied') document = next.document;
44
+ for (const [name, value] of Object.entries(fields)) {
45
+ const next = apply(document, { kind: 'field', name, value, prior: undefined });
46
+ if (next.outcome === 'applied')
47
+ document = next.document;
41
48
  }
42
49
  return serialize(document);
43
50
  }
@@ -47,50 +54,65 @@ function edited(document, change, priors) {
47
54
  kind: 'field',
48
55
  name: change.name,
49
56
  value: change.value,
50
- prior: priors.field(change.path, change.name)
57
+ prior: priors.field(change.path, change.name),
51
58
  });
52
59
  }
53
60
  if (change.kind === 'preamble') {
54
61
  return apply(document, {
55
62
  kind: 'preamble',
56
63
  value: change.value,
57
- prior: priors.preamble(change.path)
64
+ prior: priors.preamble(change.path),
58
65
  });
59
66
  }
60
- if (change.kind !== 'section') return null;
67
+ if (change.kind !== 'section')
68
+ return null;
61
69
  return apply(document, {
62
70
  kind: 'section',
63
71
  name: change.name,
64
72
  value: change.value,
65
- prior: priors.section(change.path, change.name)
73
+ prior: priors.section(change.path, change.name),
66
74
  });
67
75
  }
68
76
  function edit(staged, change, priors) {
69
77
  const text = staged.documents[change.path];
70
- if (text === undefined) return;
78
+ if (text === undefined)
79
+ return;
71
80
  const parsed = parse(text, change.path);
72
- if (!parsed.ok) return;
81
+ if (!parsed.ok)
82
+ return;
73
83
  const next = edited(parsed.document, change, priors);
74
- if (next?.outcome === 'applied') staged.documents[change.path] = serialize(next.document);
84
+ if (next?.outcome === 'applied')
85
+ staged.documents[change.path] = serialize(next.document);
75
86
  }
76
87
  function relocate(staged, from, to) {
77
88
  const text = staged.documents[from];
78
89
  if (text !== undefined) {
79
90
  delete staged.documents[from];
80
91
  staged.documents[to] = text;
81
- } else if (staged.binaryTargets.delete(from)) {
92
+ }
93
+ else if (staged.binaryTargets.delete(from)) {
82
94
  staged.binaryTargets.add(to);
83
- } else {
95
+ }
96
+ else {
84
97
  return;
85
98
  }
86
- const revision = staged.revisions[from];
87
- if (revision === undefined) return;
88
- delete staged.revisions[from];
89
- staged.revisions[to] = revision;
99
+ moveHead(staged, from, to);
100
+ }
101
+ function moveHead(heads, from, to) {
102
+ const revision = heads.revisions[from];
103
+ const change = heads.changes[from];
104
+ delete heads.revisions[from];
105
+ delete heads.changes[from];
106
+ delete heads.changes[to];
107
+ if (revision !== undefined)
108
+ heads.revisions[to] = revision;
109
+ if (change !== undefined)
110
+ heads.changes[to] = change;
90
111
  }
91
112
  function erase(staged, path) {
92
113
  delete staged.documents[path];
93
114
  delete staged.revisions[path];
115
+ delete staged.changes[path];
94
116
  staged.binaryTargets.delete(path);
95
117
  }
96
118
  function stage(staged, change, priors) {
@@ -99,11 +121,14 @@ function stage(staged, change, priors) {
99
121
  return;
100
122
  }
101
123
  if (change.kind === 'create') {
102
- staged.documents[change.path] = compose(change.fields, change.sections);
124
+ staged.documents[change.path] =
125
+ 'content' in change ? change.content : compose(change.fields, change.sections);
126
+ delete staged.changes[change.path];
103
127
  return;
104
128
  }
105
129
  if (change.kind === 'replace') {
106
- if (staged.documents[change.path] === undefined) return;
130
+ if (staged.documents[change.path] === undefined)
131
+ return;
107
132
  staged.documents[change.path] = change.content;
108
133
  return;
109
134
  }
@@ -115,25 +140,144 @@ function stage(staged, change, priors) {
115
140
  }
116
141
  export function overlay(base, queue) {
117
142
  const staged = {
118
- documents: {
119
- ...base.documents
120
- },
143
+ documents: { ...base.documents },
121
144
  binaryTargets: new Set(base.binaryTargets),
122
- revisions: {
123
- ...base.revisions
124
- }
145
+ revisions: { ...base.revisions },
146
+ changes: { ...base.changes },
125
147
  };
126
- for (const batch of queue){
148
+ for (const batch of queue) {
127
149
  const priors = priorsOf(batch.preconditions);
128
- for (const change of batch.changes)stage(staged, change, priors);
150
+ for (const change of batch.changes)
151
+ stage(staged, change, priors);
129
152
  }
130
153
  return {
131
154
  documents: staged.documents,
132
- binaryTargets: [
133
- ...staged.binaryTargets
134
- ].sort(),
135
- revisions: staged.revisions
155
+ binaryTargets: [...staged.binaryTargets].sort(),
156
+ revisions: staged.revisions,
157
+ changes: staged.changes,
158
+ };
159
+ }
160
+ function pathsOf(batch) {
161
+ return batch.changes.flatMap((change) => change.kind === 'move' ? [change.path, change.to] : [change.path]);
162
+ }
163
+ export function sameLayerText(left, right) {
164
+ const paths = Object.keys(left.documents);
165
+ return (paths.length === Object.keys(right.documents).length &&
166
+ paths.every((path) => left.documents[path] === right.documents[path]) &&
167
+ left.binaryTargets.length === right.binaryTargets.length &&
168
+ left.binaryTargets.every((path) => right.binaryTargets.includes(path)));
169
+ }
170
+ function replayHeads(base, queue) {
171
+ const heads = { revisions: { ...base.revisions }, changes: { ...base.changes } };
172
+ for (const batch of queue) {
173
+ for (const change of batch.changes) {
174
+ if (change.kind === 'remove') {
175
+ delete heads.revisions[change.path];
176
+ delete heads.changes[change.path];
177
+ }
178
+ else if (change.kind === 'create') {
179
+ delete heads.changes[change.path];
180
+ }
181
+ else if (change.kind === 'move') {
182
+ moveHead(heads, change.path, change.to);
183
+ }
184
+ }
185
+ }
186
+ return heads;
187
+ }
188
+ export function overlayChanged(base, queue, previousBase, previousQueue, previousVisible) {
189
+ const before = previousQueue.map((batch) => JSON.stringify(batch));
190
+ const after = queue.map((batch) => JSON.stringify(batch));
191
+ if (before.length === after.length &&
192
+ before.every((id, index) => id === after[index]) &&
193
+ sameLayerText(base, previousBase)) {
194
+ return {
195
+ documents: previousVisible.documents,
196
+ binaryTargets: previousVisible.binaryTargets,
197
+ ...replayHeads(base, queue),
198
+ };
199
+ }
200
+ const affected = new Set();
201
+ const paths = new Set([
202
+ ...Object.keys(base.documents),
203
+ ...Object.keys(previousBase.documents),
204
+ ...Object.keys(base.revisions),
205
+ ...Object.keys(previousBase.revisions),
206
+ ...Object.keys(base.changes),
207
+ ...Object.keys(previousBase.changes),
208
+ ...base.binaryTargets,
209
+ ...previousBase.binaryTargets,
210
+ ]);
211
+ for (const path of paths) {
212
+ if (base.documents[path] !== previousBase.documents[path] ||
213
+ base.revisions[path] !== previousBase.revisions[path] ||
214
+ !sameChange(base.changes[path], previousBase.changes[path]) ||
215
+ base.binaryTargets.includes(path) !== previousBase.binaryTargets.includes(path))
216
+ affected.add(path);
217
+ }
218
+ const oldIds = new Set(before);
219
+ const newIds = new Set(after);
220
+ for (const batch of previousQueue) {
221
+ if (!newIds.has(JSON.stringify(batch)))
222
+ for (const path of pathsOf(batch))
223
+ affected.add(path);
224
+ }
225
+ for (const batch of queue) {
226
+ if (!oldIds.has(JSON.stringify(batch)))
227
+ for (const path of pathsOf(batch))
228
+ affected.add(path);
229
+ }
230
+ let expanded = true;
231
+ while (expanded) {
232
+ expanded = false;
233
+ for (const batch of queue) {
234
+ const touched = pathsOf(batch);
235
+ if (!touched.some((path) => affected.has(path)))
236
+ continue;
237
+ for (const path of touched) {
238
+ if (affected.has(path))
239
+ continue;
240
+ affected.add(path);
241
+ expanded = true;
242
+ }
243
+ }
244
+ }
245
+ const documents = {};
246
+ const revisions = {};
247
+ const changes = {};
248
+ for (const path of affected) {
249
+ if (base.documents[path] !== undefined)
250
+ documents[path] = base.documents[path];
251
+ if (base.revisions[path] !== undefined)
252
+ revisions[path] = base.revisions[path];
253
+ if (base.changes[path] !== undefined)
254
+ changes[path] = base.changes[path];
255
+ }
256
+ const staged = overlay({
257
+ documents,
258
+ revisions,
259
+ changes,
260
+ binaryTargets: base.binaryTargets.filter((path) => affected.has(path)),
261
+ }, queue.filter((batch) => pathsOf(batch).some((path) => affected.has(path))));
262
+ const mergedDocuments = { ...previousVisible.documents };
263
+ const mergedRevisions = { ...previousVisible.revisions };
264
+ const mergedChanges = { ...previousVisible.changes };
265
+ const mergedTargets = new Set(previousVisible.binaryTargets);
266
+ for (const path of affected) {
267
+ delete mergedDocuments[path];
268
+ delete mergedRevisions[path];
269
+ delete mergedChanges[path];
270
+ mergedTargets.delete(path);
271
+ }
272
+ Object.assign(mergedDocuments, staged.documents);
273
+ Object.assign(mergedRevisions, staged.revisions);
274
+ Object.assign(mergedChanges, staged.changes);
275
+ for (const path of staged.binaryTargets)
276
+ mergedTargets.add(path);
277
+ return {
278
+ documents: mergedDocuments,
279
+ revisions: mergedRevisions,
280
+ changes: mergedChanges,
281
+ binaryTargets: [...mergedTargets].sort(),
136
282
  };
137
283
  }
138
-
139
- //# sourceMappingURL=overlay.js.map
package/dist/paths.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  export declare function normalize(path: string): string | null;
2
- export declare function resolve(from: string, reference: string): string | null;
3
2
  export declare function relative(from: string, target: string): string;
4
3
  export declare function beneath(prefix: string, path: string): boolean;
5
4
  export declare function covered(prefixes: readonly string[], path: string): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAKA,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYrD;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGtE;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAW7D;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED,wBAAgB,OAAO,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAK1E"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAKA,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYrD;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAW7D;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED,wBAAgB,OAAO,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAK1E"}
package/dist/paths.js CHANGED
@@ -4,10 +4,12 @@ function dirname(path) {
4
4
  }
5
5
  export function normalize(path) {
6
6
  const parts = [];
7
- for (const part of path.split('/')){
8
- if (part === '' || part === '.') continue;
7
+ for (const part of path.split('/')) {
8
+ if (part === '' || part === '.')
9
+ continue;
9
10
  if (part === '..') {
10
- if (parts.length === 0) return null;
11
+ if (parts.length === 0)
12
+ return null;
11
13
  parts.pop();
12
14
  continue;
13
15
  }
@@ -15,33 +17,24 @@ export function normalize(path) {
15
17
  }
16
18
  return parts.join('/');
17
19
  }
18
- export function resolve(from, reference) {
19
- const base = dirname(from);
20
- return normalize(base === '' ? reference : `${base}/${reference}`);
21
- }
22
20
  export function relative(from, target) {
23
- const base = dirname(from).split('/').filter((part)=>part !== '');
21
+ const base = dirname(from)
22
+ .split('/')
23
+ .filter((part) => part !== '');
24
24
  const parts = target.split('/');
25
25
  let shared = 0;
26
- while(shared < base.length && shared + 1 < parts.length && base[shared] === parts[shared]){
26
+ while (shared < base.length && shared + 1 < parts.length && base[shared] === parts[shared]) {
27
27
  shared += 1;
28
28
  }
29
- const up = Array.from({
30
- length: base.length - shared
31
- }, ()=>'..');
32
- return [
33
- ...up,
34
- ...parts.slice(shared)
35
- ].join('/');
29
+ const up = Array.from({ length: base.length - shared }, () => '..');
30
+ return [...up, ...parts.slice(shared)].join('/');
36
31
  }
37
32
  export function beneath(prefix, path) {
38
33
  return path === prefix || path.startsWith(`${prefix}/`);
39
34
  }
40
35
  export function covered(prefixes, path) {
41
- return prefixes.some((prefix)=>{
36
+ return prefixes.some((prefix) => {
42
37
  const normalized = normalize(prefix);
43
38
  return normalized !== null && (normalized === '' || beneath(normalized, path));
44
39
  });
45
40
  }
46
-
47
- //# sourceMappingURL=paths.js.map