linked-rolls 0.47.0 → 0.48.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.
@@ -85,6 +85,27 @@ export type Collation = {
85
85
  };
86
86
  /** Each of the own symbols with every inherited symbol it collates with, both in the order given. */
87
87
  export declare const collationsOf: (own: readonly Readonly<AnySymbol>[], inherited: readonly Readonly<AnySymbol>[], locate: Locate, tolerance?: CollationTolerance) => Collation[];
88
+ /**
89
+ * The motivation a collation writes on what it makes, saying that
90
+ * nobody has read it yet.
91
+ *
92
+ * A collation produces its edits by a rule, and an edition that
93
+ * publishes them unmarked would present a machine's output as an
94
+ * editor's reading. Stating that they are unchecked is the honest
95
+ * middle: the readings are there to be seen and argued with, and a
96
+ * reader can tell which of them anybody has weighed.
97
+ *
98
+ * It does not make an edit the editor's. `isCollationsOwn` passes over
99
+ * this motivation exactly, so a collation rewrites what it marked
100
+ * before, and only what somebody has actually written stays.
101
+ */
102
+ export declare const unchecked = "unchecked";
103
+ /** The version's statement of what the unchecked motivation means, to stand in its `motivations`. */
104
+ export declare const uncheckedMotivation: {
105
+ readonly type: 'motivation';
106
+ readonly id: "unchecked";
107
+ readonly note: 'Made by collating the two texts and not yet read by an editor.';
108
+ };
88
109
  /**
89
110
  * Whether the edit is one a collation writes by itself: a bare
90
111
  * insertion or a bare deletion saying nothing further, or an
package/lib/Collation.js CHANGED
@@ -89,6 +89,27 @@ export const collationsOf = (own, inherited, locate, tolerance = defaultCollatio
89
89
  };
90
90
  /** The edit type a collation draws by itself, from the two systems' vocabularies rather than off the paper. */
91
91
  const drawnByCollation = 'replace-with-equivalent';
92
+ /**
93
+ * The motivation a collation writes on what it makes, saying that
94
+ * nobody has read it yet.
95
+ *
96
+ * A collation produces its edits by a rule, and an edition that
97
+ * publishes them unmarked would present a machine's output as an
98
+ * editor's reading. Stating that they are unchecked is the honest
99
+ * middle: the readings are there to be seen and argued with, and a
100
+ * reader can tell which of them anybody has weighed.
101
+ *
102
+ * It does not make an edit the editor's. `isCollationsOwn` passes over
103
+ * this motivation exactly, so a collation rewrites what it marked
104
+ * before, and only what somebody has actually written stays.
105
+ */
106
+ export const unchecked = 'unchecked';
107
+ /** The version's statement of what the unchecked motivation means, to stand in its `motivations`. */
108
+ export const uncheckedMotivation = {
109
+ type: 'motivation',
110
+ id: unchecked,
111
+ note: 'Made by collating the two texts and not yet read by an editor.'
112
+ };
92
113
  /**
93
114
  * Whether the edit is one a collation writes by itself: a bare
94
115
  * insertion or a bare deletion saying nothing further, or an
@@ -107,4 +128,6 @@ const drawnByCollation = 'replace-with-equivalent';
107
128
  * draws a second time over the very same symbols.
108
129
  */
109
130
  export const isCollationsOwn = (edit) => edit.editType === drawnByCollation
110
- || (edit.editType === undefined && edit.motivation === undefined && edit['@annotation'] === undefined);
131
+ || (edit.editType === undefined
132
+ && (edit.motivation === undefined || edit.motivation === unchecked)
133
+ && edit['@annotation'] === undefined);
@@ -32,6 +32,19 @@ export declare const revertScale: (copy: RollCopy) => void;
32
32
  *
33
33
  * Only holes are touched. What a writing or a mark spans is no valve.
34
34
  */
35
+ /**
36
+ * The holes the extension cannot be taken off, being no longer than it
37
+ * is: the reader reported them open for less time than it holds a valve
38
+ * on beyond the perforation, so the constant over-corrects them and
39
+ * would leave them ending before they begin.
40
+ *
41
+ * They are where the constant shows its limit rather than where the
42
+ * copy is wrong, the extension varying by about half a millimetre with
43
+ * the port. What to do with them is an editorial question — a condition
44
+ * on the feature, a reading of the hole, a smaller extension — and
45
+ * `shortenHoles` throws rather than answer it.
46
+ */
47
+ export declare const tooShortToShorten: (extension: Millimeters, copy: RollCopy) => Readonly<FeatureOrPatch>[];
35
48
  export declare const shortenHoles: (extension: Millimeters, copy: RollCopy) => void;
36
49
  /** Puts the reader's extension back on the copy's holes, as far as one was taken off. */
37
50
  export declare const revertShortening: (copy: RollCopy) => void;
package/lib/alignment.js CHANGED
@@ -78,9 +78,28 @@ const holesOf = (copy) => featuresOf(copy).filter(feature => feature.type === 'H
78
78
  *
79
79
  * Only holes are touched. What a writing or a mark spans is no valve.
80
80
  */
81
+ /**
82
+ * The holes the extension cannot be taken off, being no longer than it
83
+ * is: the reader reported them open for less time than it holds a valve
84
+ * on beyond the perforation, so the constant over-corrects them and
85
+ * would leave them ending before they begin.
86
+ *
87
+ * They are where the constant shows its limit rather than where the
88
+ * copy is wrong, the extension varying by about half a millimetre with
89
+ * the port. What to do with them is an editorial question — a condition
90
+ * on the feature, a reading of the hole, a smaller extension — and
91
+ * `shortenHoles` throws rather than answer it.
92
+ */
93
+ export const tooShortToShorten = (extension, copy) => holesOf(copy).filter(hole => hole.horizontal.to - hole.horizontal.from <= extension);
81
94
  export const shortenHoles = (extension, copy) => {
82
95
  if (copy.ops.includes('shortened'))
83
96
  return;
97
+ const tooShort = tooShortToShorten(extension, copy);
98
+ if (tooShort.length > 0) {
99
+ throw new Error(`The extension of ${extension} mm cannot be taken off ${tooShort.length} `
100
+ + `hole(s) of copy ${copy.id}, which are no longer than it: `
101
+ + `${tooShort.map(hole => hole.id).join(', ')}`);
102
+ }
84
103
  holesOf(copy).forEach(hole => { hole.horizontal.to = subtract(hole.horizontal.to, extension); });
85
104
  copy.ops = [...copy.ops, 'shortened'];
86
105
  copy.measurements.readerExtension = extension;
package/lib/editionOps.js CHANGED
@@ -2,7 +2,7 @@ import { current, isDraft } from "immer";
2
2
  import { v4 } from "uuid";
3
3
  import { getAt } from "./EditionView.js";
4
4
  import { isCommand, placementRelations } from "./Symbol.js";
5
- import { collationsOf, defaultCollationTolerance, isCollationsOwn } from "./Collation.js";
5
+ import { collationsOf, defaultCollationTolerance, isCollationsOwn, unchecked, uncheckedMotivation } from "./Collation.js";
6
6
  import { collationToleranceOf, editsOf, insertedBy, principalDerivationOf } from "./Version.js";
7
7
  import { asSymbols, barOf, featuresByAct, featuresOf, isPaperStretch, statesNothing } from "./RollCopy.js";
8
8
  import { systemOf } from "./TrackerBar.js";
@@ -54,6 +54,17 @@ const droppedIds = (before, after) => {
54
54
  };
55
55
  const insertion = (symbol) => ({ type: 'edit', id: v4(), insert: [symbol] });
56
56
  const deletion = (symbolId) => ({ type: 'edit', id: v4(), delete: [symbolId] });
57
+ /** The edit as a collation leaves it: made by rule, and not yet read by anybody. */
58
+ const asUnchecked = (edit) => ({ ...edit, motivation: unchecked });
59
+ /**
60
+ * The motivations with the unchecked one declared, where any edit
61
+ * names it and the version does not state it yet. An edit naming a
62
+ * motivation the version leaves undeclared points at nothing.
63
+ */
64
+ const declaring = (motivations, edits) => edits.some(edit => edit.motivation === unchecked)
65
+ && !motivations.some(motivation => motivation.id === unchecked)
66
+ ? [...motivations, uncheckedMotivation]
67
+ : motivations;
57
68
  const isEmpty = (edit) => !edit.insert?.length && !edit.delete?.length;
58
69
  const insertedIn = (versions) => versions.flatMap(insertedBy);
59
70
  /** The edits with the change applied, less those it emptied; the very same array where it changed none. */
@@ -733,6 +744,7 @@ export const connectVersions = (view, childId, parentId, tolerance = defaultColl
733
744
  type: 'edit',
734
745
  id: v4(),
735
746
  editType: 'replace-with-equivalent',
747
+ motivation: unchecked,
736
748
  insert: [...by],
737
749
  delete: deleted
738
750
  };
@@ -740,14 +752,15 @@ export const connectVersions = (view, childId, parentId, tolerance = defaultColl
740
752
  const edits = [
741
753
  ...established,
742
754
  ...substituted.map(equivalence),
743
- ...own.filter(symbol => !collated.has(symbol.id) && !paired.has(symbol.id)).map(insertion),
755
+ ...own.filter(symbol => !collated.has(symbol.id) && !paired.has(symbol.id)).map(insertion).map(asUnchecked),
744
756
  ...inherited
745
757
  .filter(symbol => !matched.has(symbol.id) && !paired.has(symbol.id))
746
- .map(symbol => deletion(symbol.id))
758
+ .map(symbol => asUnchecked(deletion(symbol.id)))
747
759
  ];
748
760
  return onVersion(childId, (child, draft) => {
749
761
  handOverCarriers(view, draft, collations);
750
762
  child.edits = edits;
763
+ child.motivations = declaring(stateOf(child).motivations, edits);
751
764
  child.basedOn = [
752
765
  { ...assignReference(parentId), collationTolerance: tolerance },
753
766
  ...hypothesesBeside(stateOf(child), parentId)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linked-rolls",
3
- "version": "0.47.0",
3
+ "version": "0.48.0",
4
4
  "description": "Digital editions of piano rolls: import, collation, editorial assumptions, JSON-LD export, and emulation through a reproducing system",
5
5
  "license": "MIT",
6
6
  "repository": {