linked-rolls 0.74.0 → 0.76.0

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 (42) hide show
  1. package/README.md +62 -26
  2. package/lib/collation/Collation.d.ts +12 -42
  3. package/lib/collation/Collation.js +15 -48
  4. package/lib/filiation/adoption.d.ts +23 -4
  5. package/lib/filiation/adoption.js +81 -23
  6. package/lib/filiation/edits.d.ts +35 -19
  7. package/lib/filiation/edits.js +68 -34
  8. package/lib/filiation/index.d.ts +2 -1
  9. package/lib/filiation/index.js +2 -1
  10. package/lib/filiation/record.d.ts +49 -0
  11. package/lib/filiation/record.js +49 -0
  12. package/lib/index.d.ts +1 -0
  13. package/lib/index.js +1 -0
  14. package/lib/io/asJsonLd.js +5 -1
  15. package/lib/io/importJsonLd.js +42 -4
  16. package/lib/io/migrate.d.ts +7 -0
  17. package/lib/io/migrate.js +196 -2
  18. package/lib/model/Agent.d.ts +3 -1
  19. package/lib/model/Assumption.d.ts +8 -1
  20. package/lib/model/Assumption.js +2 -1
  21. package/lib/model/Edit.d.ts +76 -17
  22. package/lib/model/Edit.js +52 -3
  23. package/lib/model/Edition.d.ts +32 -3
  24. package/lib/model/RollCopy.js +1 -1
  25. package/lib/model/Version.d.ts +3 -13
  26. package/lib/model/Version.js +7 -2
  27. package/lib/ops/collation.d.ts +8 -4
  28. package/lib/ops/collation.js +40 -23
  29. package/lib/ops/copies.js +1 -2
  30. package/lib/ops/draft.d.ts +1 -9
  31. package/lib/ops/draft.js +0 -12
  32. package/lib/ops/edits.d.ts +20 -3
  33. package/lib/ops/edits.js +36 -15
  34. package/lib/ops/index.d.ts +1 -1
  35. package/lib/ops/index.js +1 -1
  36. package/lib/ops/versions.d.ts +3 -2
  37. package/lib/ops/versions.js +4 -5
  38. package/lib/schema.json +60 -64
  39. package/lib/software.d.ts +12 -0
  40. package/lib/software.js +10 -0
  41. package/lib/spec/context.json +8 -5
  42. package/package.json +1 -1
@@ -1,14 +1,18 @@
1
1
  import { v4 } from "uuid";
2
2
  import { getAt, pathIn } from "../lookup/paths.js";
3
- import { collationsOf, defaultCollationTolerance, isCollationsOwn, unchecked } from "../collation/Collation.js";
3
+ import { collationsOf, defaultCollationTolerance, isCollationsOwn } from "../collation/Collation.js";
4
+ import { motivationProposedFor, technicalChange } from "../model/Edit.js";
4
5
  import { collationToleranceOf, derivesFrom, editsOf, insertedBy, principalDerivationOf } from "../model/Version.js";
5
6
  import { substitutionsBetween } from "../collation/substitution.js";
6
7
  import { trackerBarOf } from "../systems/index.js";
7
8
  import { assignReference, idOf } from "../model/Assumption.js";
8
- import { noChange, onVersion, insertion, deletion, asUnchecked, declaring, dropInsertions, reading } from "./draft.js";
9
+ import { noChange, onVersion, insertion, deletion, dropInsertions, reading } from "./draft.js";
9
10
  import { hypothesesBeside } from "./versions.js";
11
+ import { shapeOf } from "./edits.js";
12
+ import { predecessorOf } from "../analysis/stemma.js";
10
13
  import { placeOf, snapshotOf } from "../analysis/text.js";
11
14
  import { copyOfFeature, versionIn } from "../lookup/lookup.js";
15
+ import { motivationOfChanges, proposedMotivations } from "../filiation/edits.js";
12
16
  /** The carriers of each collated symbol pass to its counterpart. */
13
17
  const handOverCarriers = (edition, draft, collations) => collations.forEach(({ symbol, counterpart }) => {
14
18
  const path = pathIn(edition, counterpart.id);
@@ -43,15 +47,18 @@ const byExchange = (edits) => new Map(edits.map(edit => [exchangeKey((edit.inser
43
47
  * tolerance it was collated at and becomes the principal one; the
44
48
  * hypotheses the child stated beside its former one stay.
45
49
  *
46
- * The edits the child already stated are rewritten only as far as a
47
- * collation wrote them (`isCollationsOwn`). An editor's reading of the
50
+ * The edits the child already stated are rewritten only as far as they
51
+ * are the program's (`isCollationsOwn`). An editor's reading of the
48
52
  * difference between the two texts stays, and the symbols it speaks for
49
53
  * are left out of the collation, so that connecting the two again
50
54
  * neither doubles them nor silently drops what somebody established by
51
55
  * hand. An equivalence is the collation's own, since it is drawn from
52
56
  * the two systems' vocabularies rather than read off the paper, but one
53
57
  * drawn again over the very same symbols is kept as it stands, with its
54
- * identifier and whatever was written on it.
58
+ * identifier and whatever was written on it. An insertion or deletion
59
+ * drawn anew has the motivation its shape calls for
60
+ * (`motivationProposedFor`): the generic musical one, or the technical
61
+ * one, which an equivalence drawn anew always has.
55
62
  *
56
63
  * The child's own text is what it shows less what the parent hands
57
64
  * down, so that connecting two versions already connected collates the
@@ -101,31 +108,36 @@ export const connectVersions = (childId, parentId, tolerance = defaultCollationT
101
108
  return alreadyStated.get(exchangeKey(inserted, deleted)) ?? {
102
109
  type: 'edit',
103
110
  id: v4(),
104
- editType: 'recoding',
105
- motivation: unchecked,
111
+ motivation: technicalChange,
106
112
  insert: [...by],
107
113
  delete: deleted
108
114
  };
109
115
  };
110
- const edits = [
111
- ...established,
112
- ...substituted.map(equivalence),
113
- ...own.filter(symbol => !collated.has(symbol.id) && !paired.has(symbol.id)).map(insertion).map(asUnchecked),
116
+ const bare = [
117
+ ...own.filter(symbol => !collated.has(symbol.id) && !paired.has(symbol.id)).map(insertion),
114
118
  ...inherited
115
119
  .filter(symbol => !matched.has(symbol.id) && !paired.has(symbol.id))
116
- .map(symbol => asUnchecked(deletion(symbol.id)))
120
+ .map(symbol => deletion(symbol.id))
117
121
  ];
122
+ const drawn = [...established, ...substituted.map(equivalence), ...bare];
118
123
  // Read off the child as it stands, since once its edits are written a
119
124
  // reading of it would copy them all.
120
- const motivations = declaring(child?.motivations ?? [], edits);
121
125
  const basedOn = [
122
126
  { ...assignReference(parentId), collationTolerance: tolerance },
123
127
  ...(child ? hypothesesBeside(child, parentId) : [])
124
128
  ];
129
+ // What kind of change an insertion or a deletion is depends on what it stands among.
130
+ const connected = { ...edition, versions: edition.versions.map(version => version.id === childId ? { ...version, edits: drawn, basedOn } : version) };
131
+ const motivations = proposedMotivations(connected, childId);
132
+ const anew = new Set(bare.map(edit => edit.id));
133
+ const edits = drawn.map(edit => {
134
+ if (!anew.has(edit.id))
135
+ return edit;
136
+ return { ...edit, motivation: motivationOfChanges(motivations, [...(edit.insert ?? []).map(symbol => symbol.id), ...(edit.delete ?? [])]) };
137
+ });
125
138
  return onVersion(childId, (version, draft) => {
126
139
  handOverCarriers(edition, draft, collations);
127
140
  version.edits = edits;
128
- version.motivations = motivations;
129
141
  version.basedOn = basedOn;
130
142
  });
131
143
  });
@@ -184,7 +196,8 @@ const sharedWith = (edition, symbol, copies) => {
184
196
  * Takes the named copies' reading of a symbol back out of the symbol it
185
197
  * was collated into: their carriers pass to a new symbol of the
186
198
  * version's own, the remaining copies keep the symbol they had, and the
187
- * version states the exchange.
199
+ * version states the exchange, with the motivation its shape calls for
200
+ * (`motivationProposedFor`) where the version derives from another.
188
201
  *
189
202
  * This is the inverse of the hand-over a collation makes, and it is
190
203
  * what lets a derivation be collated a second time. A collated symbol
@@ -217,14 +230,18 @@ export const separateReadings = (versionId, copies, symbolIds) => reading(editio
217
230
  return noChange;
218
231
  const inserted = new Set(insertedBy(version).map(symbol => symbol.id));
219
232
  const stated = editsOf(version);
220
- const separations = shared.map(({ symbol, mine }) => ({
221
- type: 'edit',
222
- id: v4(),
223
- insert: [readingOf(symbol, [...mine])],
224
- // A symbol the version inserts itself stays where it is, minus
225
- // the carriers that leave it. Only one it inherits is exchanged.
226
- ...(inserted.has(symbol.id) ? {} : { delete: [symbol.id] })
227
- }));
233
+ const derived = predecessorOf(edition, versionId) !== undefined;
234
+ const separations = shared.map(({ symbol, mine }) => {
235
+ const separation = {
236
+ type: 'edit',
237
+ id: v4(),
238
+ insert: [readingOf(symbol, [...mine])],
239
+ // A symbol the version inserts itself stays where it is, minus
240
+ // the carriers that leave it. Only one it inherits is exchanged.
241
+ ...(inserted.has(symbol.id) ? {} : { delete: [symbol.id] })
242
+ };
243
+ return derived ? { ...separation, motivation: motivationProposedFor(shapeOf(edition, versionId, separation)) } : separation;
244
+ });
228
245
  return onVersion(versionId, (version, draft) => {
229
246
  shared.forEach(({ symbol, theirs }) => {
230
247
  const path = pathIn(edition, symbol.id);
package/lib/ops/copies.js CHANGED
@@ -21,8 +21,7 @@ export const createVersion = (copy) => draft => {
21
21
  draft.versions.push({
22
22
  id: v4(),
23
23
  system: systemOf(bar),
24
- edits: asSymbols(featuresOf(copy), bar).map(insertion),
25
- motivations: []
24
+ edits: asSymbols(featuresOf(copy), bar).map(insertion)
26
25
  });
27
26
  };
28
27
  /**
@@ -3,7 +3,7 @@ import { Draft } from "immer";
3
3
  import { Edition } from "../model/Edition.js";
4
4
  import { AnySymbol } from "../model/Symbol.js";
5
5
  import { Edit } from "../model/Edit.js";
6
- import { Motivation, Version } from "../model/Version.js";
6
+ import { Version } from "../model/Version.js";
7
7
  import { RollCopy } from "../model/RollCopy.js";
8
8
  import { Belief, ReferenceAssumption } from "../model/Assumption.js";
9
9
  import { FeatureOrPatch } from "../model/Feature.js";
@@ -42,14 +42,6 @@ export declare const droppedIds: (before: readonly WithId[], after: readonly Wit
42
42
  export type Ids = ReadonlySet<string>;
43
43
  export declare const insertion: (symbol: AnySymbol) => Edit;
44
44
  export declare const deletion: (symbolId: string) => Edit;
45
- /** The edit as a collation leaves it: made by rule, and not yet read by anybody. */
46
- export declare const asUnchecked: (edit: Edit) => Edit;
47
- /**
48
- * The motivations with the unchecked one declared, where any edit
49
- * names it and the version does not state it yet. An edit naming a
50
- * motivation the version leaves undeclared points at nothing.
51
- */
52
- export declare const declaring: (motivations: Motivation[], edits: readonly Edit[]) => Motivation[];
53
45
  export declare const insertedIn: (versions: readonly Version[]) => AnySymbol[];
54
46
  /** The edits with the change applied, less those it emptied; the very same array where it changed none. */
55
47
  export declare const edited: (edits: Edit[], change: (edit: Edit) => Edit) => Edit[];
package/lib/ops/draft.js CHANGED
@@ -1,7 +1,6 @@
1
1
  /** What the operations are built from: the type of an operation, how one finds what it writes to on the draft, and the edits it writes. */
2
2
  import { isDraft } from "immer";
3
3
  import { v4 } from "uuid";
4
- import { unchecked, uncheckedMotivation } from "../collation/Collation.js";
5
4
  import { insertedBy } from "../model/Version.js";
6
5
  import { featuresOf } from "../model/RollCopy.js";
7
6
  import { assignReference } from "../model/Assumption.js";
@@ -45,17 +44,6 @@ export const droppedIds = (before, after) => {
45
44
  };
46
45
  export const insertion = (symbol) => ({ type: 'edit', id: v4(), insert: [symbol] });
47
46
  export const deletion = (symbolId) => ({ type: 'edit', id: v4(), delete: [symbolId] });
48
- /** The edit as a collation leaves it: made by rule, and not yet read by anybody. */
49
- export const asUnchecked = (edit) => ({ ...edit, motivation: unchecked });
50
- /**
51
- * The motivations with the unchecked one declared, where any edit
52
- * names it and the version does not state it yet. An edit naming a
53
- * motivation the version leaves undeclared points at nothing.
54
- */
55
- export const declaring = (motivations, edits) => edits.some(edit => edit.motivation === unchecked)
56
- && !motivations.some(motivation => motivation.id === unchecked)
57
- ? [...motivations, uncheckedMotivation]
58
- : motivations;
59
47
  const isEmpty = (edit) => !edit.insert?.length && !edit.delete?.length;
60
48
  export const insertedIn = (versions) => versions.flatMap(insertedBy);
61
49
  /** The edits with the change applied, less those it emptied; the very same array where it changed none. */
@@ -1,13 +1,30 @@
1
- import { Edit } from "../model/Edit.js";
1
+ import { Edit, EditShape } from "../model/Edit.js";
2
2
  import { EditionOp } from "./draft.js";
3
+ import { Edition } from "../model/Edition.js";
4
+ /**
5
+ * A guess at the shape of an edit, from the symbols it exchanges and
6
+ * from the systems the version and the one it is based on are coded
7
+ * for, or nothing where it takes no shape the guess knows. It looks at
8
+ * the edit alone: a single expression deleted is taken for a redundancy
9
+ * removed, which `proposeEdits` checks against the text.
10
+ * @category Lookups
11
+ */
12
+ export declare const shapeOf: (edition: Edition, versionId: string, edit: Readonly<Edit>) => EditShape | undefined;
3
13
  /**
4
14
  * Replaces the edits with a single one carrying all their insertions
5
- * and deletions, classified by a guess at what the exchange does.
15
+ * and deletions. It keeps the first motivation of the editor's that any
16
+ * of them states, and where none does, it has the one its shape calls
17
+ * for (`motivationProposedFor`), so that a merge says it is a musical
18
+ * or a technical change, unless the version derives from none. A
19
+ * grouping that says no more is the program's by rule
20
+ * (`isCollationsOwn`), until the editor says why it was made.
6
21
  * @category Operations
7
22
  */
8
23
  export declare const mergeEdits: (versionId: string, toMerge: readonly Edit[]) => EditionOp;
9
24
  /**
10
- * Replaces the edit with one edit per inserted and one per deleted symbol.
25
+ * Replaces the edit with one edit per inserted and one per deleted
26
+ * symbol. Each part keeps the motivation of the edit, since splitting
27
+ * an edit does not change why it was made.
11
28
  * @category Operations
12
29
  */
13
30
  export declare const splitEdit: (versionId: string, toSplit: Edit) => EditionOp;
package/lib/ops/edits.js CHANGED
@@ -1,6 +1,8 @@
1
1
  /** Merging and splitting the edits of a version. */
2
2
  import { v4 } from "uuid";
3
+ import { motivationProposedFor, musicalChange, technicalChange } from "../model/Edit.js";
3
4
  import { editsOf } from "../model/Version.js";
5
+ import { keyOf } from "../systems/TrackerBar.js";
4
6
  import { trackerBarOf } from "../systems/index.js";
5
7
  import { distance, mm, subtract } from "../model/Quantity.js";
6
8
  import { noChange, onVersion, insertion, deletion, reading } from "./draft.js";
@@ -15,18 +17,24 @@ const lengthOf = (span) => subtract(span.to, span.from);
15
17
  /** How far apart two onsets may lie for the one symbol to count as a replacement of the other. */
16
18
  const REPLACEMENT_TOLERANCE = mm(5);
17
19
  /** Shorten or prolong, where the inserted symbol starts about where the deleted one did. */
18
- const replacementType = (edition, inserted, deleted) => {
20
+ const replacementShape = (edition, inserted, deleted) => {
19
21
  const after = placeOf(edition, inserted);
20
22
  const before = placeOf(edition, deleted);
21
23
  if (!after || !before || distance(after.from, before.from) >= REPLACEMENT_TOLERANCE)
22
24
  return undefined;
23
25
  return lengthOf(after) < lengthOf(before) ? 'shorten' : 'prolong';
24
26
  };
27
+ /** Whether the two symbols say the same thing, as a perforation put elsewhere does. */
28
+ const sameKind = (a, b) => a.type !== 'text' && b.type !== 'text' && keyOf(a) === keyOf(b);
25
29
  /**
26
- * A guess at what an edit does, from the symbols it exchanges and from
27
- * the systems the version and the one it is based on are coded for.
30
+ * A guess at the shape of an edit, from the symbols it exchanges and
31
+ * from the systems the version and the one it is based on are coded
32
+ * for, or nothing where it takes no shape the guess knows. It looks at
33
+ * the edit alone: a single expression deleted is taken for a redundancy
34
+ * removed, which `proposeEdits` checks against the text.
35
+ * @category Lookups
28
36
  */
29
- const guessEditType = (edition, versionId, edit) => {
37
+ export const shapeOf = (edition, versionId, edit) => {
30
38
  const inserts = edit.insert ?? [];
31
39
  const deletes = symbolsIn(edition, edit.delete ?? []);
32
40
  const inserted = expressionTypesOf(inserts);
@@ -40,8 +48,7 @@ const guessEditType = (edition, versionId, edit) => {
40
48
  * SforzandoForte says the same thing in the other system's words, and
41
49
  * a red command the green bar cannot read struck, or a green hold put
42
50
  * in where the red had no word for it, belongs to the same act. That
43
- * is a recoding. Calling it a corrected error would say the editor
44
- * made a mistake. Only an insertion spelling the bar's own accent
51
+ * is a recoding. Only an insertion spelling the bar's own accent
45
52
  * reads more narrowly, as the accent it spells.
46
53
  */
47
54
  const transferred = bar && parentBar && bar.id !== parentBar.id;
@@ -56,38 +63,52 @@ const guessEditType = (edition, versionId, edit) => {
56
63
  return 'shift';
57
64
  if (inserted.length === 0 && deleted.length === 1)
58
65
  return 'remove-redundancy';
59
- if (inserts.length === 1 && deletes.length === 1)
60
- return replacementType(edition, inserts[0], deletes[0]) ?? 'correct-error';
61
- return 'correct-error';
66
+ if (inserts.length === 1 && deletes.length === 1) {
67
+ return replacementShape(edition, inserts[0], deletes[0]) ?? (sameKind(inserts[0], deletes[0]) ? 'shift' : undefined);
68
+ }
69
+ return undefined;
62
70
  };
63
71
  /**
64
72
  * Replaces the edits with a single one carrying all their insertions
65
- * and deletions, classified by a guess at what the exchange does.
73
+ * and deletions. It keeps the first motivation of the editor's that any
74
+ * of them states, and where none does, it has the one its shape calls
75
+ * for (`motivationProposedFor`), so that a merge says it is a musical
76
+ * or a technical change, unless the version derives from none. A
77
+ * grouping that says no more is the program's by rule
78
+ * (`isCollationsOwn`), until the editor says why it was made.
66
79
  * @category Operations
67
80
  */
68
81
  export const mergeEdits = (versionId, toMerge) => reading(edition => {
69
82
  if (toMerge.length === 0)
70
83
  return noChange;
84
+ const { motivation: _first, ...first } = toMerge[0];
71
85
  const merged = {
72
- ...toMerge[0],
86
+ ...first,
73
87
  id: v4(),
74
88
  insert: toMerge.flatMap(edit => edit.insert ?? []),
75
89
  delete: toMerge.flatMap(edit => edit.delete ?? [])
76
90
  };
77
- merged.editType = guessEditType(edition, versionId, merged);
91
+ const editors = toMerge.find(edit => edit.motivation !== undefined && edit.motivation !== musicalChange && edit.motivation !== technicalChange);
92
+ if (editors)
93
+ merged.motivation = editors.motivation;
94
+ else if (predecessorOf(edition, versionId))
95
+ merged.motivation = motivationProposedFor(shapeOf(edition, versionId, merged));
78
96
  const mergedIds = new Set(toMerge.map(edit => edit.id));
79
97
  return onVersion(versionId, version => {
80
98
  version.edits = [...editsOf(version).filter(edit => !mergedIds.has(edit.id)), merged];
81
99
  });
82
100
  });
83
101
  /**
84
- * Replaces the edit with one edit per inserted and one per deleted symbol.
102
+ * Replaces the edit with one edit per inserted and one per deleted
103
+ * symbol. Each part keeps the motivation of the edit, since splitting
104
+ * an edit does not change why it was made.
85
105
  * @category Operations
86
106
  */
87
107
  export const splitEdit = (versionId, toSplit) => {
108
+ const kept = toSplit.motivation === undefined ? {} : { motivation: toSplit.motivation };
88
109
  const parts = [
89
- ...(toSplit.insert ?? []).map(insertion),
90
- ...(toSplit.delete ?? []).map(deletion)
110
+ ...(toSplit.insert ?? []).map(symbol => ({ ...insertion(symbol), ...kept })),
111
+ ...(toSplit.delete ?? []).map(id => ({ ...deletion(id), ...kept }))
91
112
  ];
92
113
  return onVersion(versionId, version => {
93
114
  version.edits = [...editsOf(version).filter(edit => edit.id !== toSplit.id), ...parts];
@@ -8,6 +8,6 @@ export { createVersion, addCopy, alignmentFor, alignCopy, alignCopies, chooseRef
8
8
  export { stateFeatureCondition, addFeature, addBorneFeature, removeFeatures, mergeObstacle, mergeObstacleIn, mergeFeatures, type FeatureAct, type MergeObstacle } from "./features.js";
9
9
  export { detachVersion, removeVersion, removeSymbols, deriveVersion, stateDerivation, clearDerivation } from "./versions.js";
10
10
  export { connectVersions, collateSymbols, separateReadings } from "./collation.js";
11
- export { mergeEdits, splitEdit } from "./edits.js";
11
+ export { mergeEdits, splitEdit, shapeOf } from "./edits.js";
12
12
  export { placeCommand, unplaceCommand, pairCommands, unpairCommand } from "./commands.js";
13
13
  export { createBelief, clearBelief, setCertainty, addReason, removeReason } from "./beliefs.js";
package/lib/ops/index.js CHANGED
@@ -8,6 +8,6 @@ export { createVersion, addCopy, alignmentFor, alignCopy, alignCopies, chooseRef
8
8
  export { stateFeatureCondition, addFeature, addBorneFeature, removeFeatures, mergeObstacle, mergeObstacleIn, mergeFeatures } from "./features.js";
9
9
  export { detachVersion, removeVersion, removeSymbols, deriveVersion, stateDerivation, clearDerivation } from "./versions.js";
10
10
  export { connectVersions, collateSymbols, separateReadings } from "./collation.js";
11
- export { mergeEdits, splitEdit } from "./edits.js";
11
+ export { mergeEdits, splitEdit, shapeOf } from "./edits.js";
12
12
  export { placeCommand, unplaceCommand, pairCommands, unpairCommand } from "./commands.js";
13
13
  export { createBelief, clearBelief, setCertainty, addReason, removeReason } from "./beliefs.js";
@@ -5,8 +5,9 @@ import { EditionOp } from "./draft.js";
5
5
  export declare const hypothesesBeside: (version: Readonly<Version>, parentId: string) => Derivation[];
6
6
  /**
7
7
  * Makes the version stand on its own: what it inherited becomes its
8
- * own insertions, and its derivations go, the hypotheses among them,
9
- * with the motivations that belonged to them.
8
+ * own insertions, and its derivations go, the hypotheses among them.
9
+ * Its edits now state its text rather than a change, and say nothing of
10
+ * why they were made.
10
11
  * @category Operations
11
12
  */
12
13
  export declare const detachVersion: (versionId: string) => EditionOp;
@@ -28,8 +28,9 @@ const dropDerivations = (version, matches) => {
28
28
  };
29
29
  /**
30
30
  * Makes the version stand on its own: what it inherited becomes its
31
- * own insertions, and its derivations go, the hypotheses among them,
32
- * with the motivations that belonged to them.
31
+ * own insertions, and its derivations go, the hypotheses among them.
32
+ * Its edits now state its text rather than a change, and say nothing of
33
+ * why they were made.
33
34
  * @category Operations
34
35
  */
35
36
  export const detachVersion = (versionId) => reading(edition => {
@@ -37,7 +38,6 @@ export const detachVersion = (versionId) => reading(edition => {
37
38
  return onVersion(versionId, version => {
38
39
  version.edits = edits;
39
40
  delete version.basedOn;
40
- version.motivations = [];
41
41
  });
42
42
  });
43
43
  /**
@@ -76,8 +76,7 @@ export const deriveVersion = (versionId, editIds) => onVersion(versionId, (versi
76
76
  id: v4(),
77
77
  system: stateOf(version).system,
78
78
  basedOn: [assignReference(versionId)],
79
- edits: moved,
80
- motivations: []
79
+ edits: moved
81
80
  });
82
81
  });
83
82
  /**