linked-rolls 0.57.0 → 0.59.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.
- package/README.md +54 -367
- package/lib/{constraints.d.ts → analysis/constraints.d.ts} +1 -1
- package/lib/{constraints.js → analysis/constraints.js} +8 -7
- package/lib/analysis/ownPaper.d.ts +26 -0
- package/lib/analysis/ownPaper.js +41 -0
- package/lib/{reservations.d.ts → analysis/reservations.d.ts} +3 -3
- package/lib/{reservations.js → analysis/reservations.js} +3 -3
- package/lib/{sigla.d.ts → analysis/sigla.d.ts} +2 -2
- package/lib/{sigla.js → analysis/sigla.js} +4 -4
- package/lib/{witnesses.d.ts → analysis/witnesses.d.ts} +2 -2
- package/lib/{witnesses.js → analysis/witnesses.js} +2 -2
- package/lib/{Collation.d.ts → collation/Collation.d.ts} +4 -4
- package/lib/{Collation.js → collation/Collation.js} +4 -4
- package/lib/{alignment.d.ts → collation/alignment.d.ts} +4 -4
- package/lib/{alignment.js → collation/alignment.js} +10 -16
- package/lib/{scatter.d.ts → collation/scatter.d.ts} +4 -4
- package/lib/{scatter.js → collation/scatter.js} +3 -3
- package/lib/{statistics.d.ts → collation/statistics.d.ts} +1 -1
- package/lib/{statistics.js → collation/statistics.js} +2 -2
- package/lib/{substitution.d.ts → collation/substitution.d.ts} +9 -24
- package/lib/{substitution.js → collation/substitution.js} +13 -37
- package/lib/emulation/Emulation.d.ts +64 -0
- package/lib/emulation/Emulation.js +282 -0
- package/lib/emulation/negotiation.d.ts +14 -0
- package/lib/emulation/negotiation.js +20 -0
- package/lib/index.d.ts +43 -35
- package/lib/index.js +36 -35
- package/lib/{asJsonLd.d.ts → io/asJsonLd.d.ts} +1 -1
- package/lib/{asJsonLd.js → io/asJsonLd.js} +3 -3
- package/lib/{context.d.ts → io/context.d.ts} +4 -4
- package/lib/{context.js → io/context.js} +4 -4
- package/lib/{importJsonLd.d.ts → io/importJsonLd.d.ts} +1 -1
- package/lib/io/importJsonLd.js +128 -0
- package/lib/{migrate.js → io/migrate.js} +59 -55
- package/lib/{Agent.d.ts → model/Agent.d.ts} +1 -1
- package/lib/{Assumption.d.ts → model/Assumption.d.ts} +1 -1
- package/lib/{Edit.d.ts → model/Edit.d.ts} +1 -1
- package/lib/{Edition.d.ts → model/Edition.d.ts} +2 -2
- package/lib/{Feature.d.ts → model/Feature.d.ts} +1 -1
- package/lib/{FeatureSource.d.ts → model/FeatureSource.d.ts} +1 -1
- package/lib/{Perforator.d.ts → model/Perforator.d.ts} +1 -1
- package/lib/{RollCopy.d.ts → model/RollCopy.d.ts} +3 -10
- package/lib/{RollCopy.js → model/RollCopy.js} +3 -5
- package/lib/{Symbol.d.ts → model/Symbol.d.ts} +1 -1
- package/lib/{Version.d.ts → model/Version.d.ts} +10 -2
- package/lib/{Version.js → model/Version.js} +24 -1
- package/lib/{vocabulary.js → model/vocabulary.js} +2 -2
- package/lib/ops/beliefs.d.ts +9 -0
- package/lib/ops/beliefs.js +31 -0
- package/lib/ops/collation.d.ts +62 -0
- package/lib/ops/collation.js +228 -0
- package/lib/ops/commands.d.ts +9 -0
- package/lib/ops/commands.js +29 -0
- package/lib/ops/copies.d.ts +74 -0
- package/lib/ops/copies.js +135 -0
- package/lib/ops/draft.d.ts +59 -0
- package/lib/ops/draft.js +81 -0
- package/lib/ops/edits.d.ts +10 -0
- package/lib/ops/edits.js +82 -0
- package/lib/ops/features.d.ts +84 -0
- package/lib/ops/features.js +296 -0
- package/lib/ops/forget.d.ts +31 -0
- package/lib/ops/forget.js +110 -0
- package/lib/ops/immutable.d.ts +16 -0
- package/lib/ops/immutable.js +46 -0
- package/lib/ops/index.d.ts +13 -0
- package/lib/ops/index.js +7 -0
- package/lib/ops/versions.d.ts +33 -0
- package/lib/ops/versions.js +95 -0
- package/lib/readers/AtonParser.js +5 -7
- package/lib/readers/phillipsEroll.d.ts +3 -3
- package/lib/readers/phillipsEroll.js +4 -5
- package/lib/readers/spencerBar.d.ts +2 -2
- package/lib/readers/spencerBar.js +2 -3
- package/lib/readers/stanfordAton.d.ts +3 -3
- package/lib/readers/stanfordAton.js +2 -3
- package/lib/schema.json +0 -13
- package/lib/{ReproducingSystem.d.ts → systems/ReproducingSystem.d.ts} +3 -3
- package/lib/{TrackerBar.d.ts → systems/TrackerBar.d.ts} +48 -8
- package/lib/{TrackerBar.js → systems/TrackerBar.js} +11 -2
- package/lib/systems/index.d.ts +8 -2
- package/lib/systems/index.js +7 -1
- package/lib/systems/welte.d.ts +100 -0
- package/lib/systems/welte.js +119 -0
- package/lib/systems/welteLicensee/bar.d.ts +1 -1
- package/lib/systems/welteLicensee/bar.js +5 -2
- package/lib/systems/welteLicensee/system.d.ts +1 -1
- package/lib/systems/welteLicensee/system.js +1 -1
- package/lib/systems/welteT100/bar.d.ts +27 -1
- package/lib/systems/welteT100/bar.js +44 -2
- package/lib/systems/welteT100/system.d.ts +6 -39
- package/lib/systems/welteT100/system.js +19 -128
- package/lib/systems/welteT98/bar.d.ts +1 -1
- package/lib/systems/welteT98/bar.js +18 -2
- package/lib/systems/welteT98/system.d.ts +20 -38
- package/lib/systems/welteT98/system.js +20 -121
- package/lib/validate.d.ts +1 -1
- package/lib/{EditionView.d.ts → view/EditionView.d.ts} +17 -41
- package/lib/{EditionView.js → view/EditionView.js} +26 -75
- package/package.json +7 -2
- package/lib/Emulation.d.ts +0 -36
- package/lib/Emulation.js +0 -250
- package/lib/editionOps.d.ts +0 -260
- package/lib/editionOps.js +0 -1079
- package/lib/importJsonLd.js +0 -57
- /package/lib/{migrate.d.ts → io/migrate.d.ts} +0 -0
- /package/lib/{Agent.js → model/Agent.js} +0 -0
- /package/lib/{Assumption.js → model/Assumption.js} +0 -0
- /package/lib/{ConditionState.d.ts → model/ConditionState.d.ts} +0 -0
- /package/lib/{ConditionState.js → model/ConditionState.js} +0 -0
- /package/lib/{Edit.js → model/Edit.js} +0 -0
- /package/lib/{Edition.js → model/Edition.js} +0 -0
- /package/lib/{Feature.js → model/Feature.js} +0 -0
- /package/lib/{FeatureSource.js → model/FeatureSource.js} +0 -0
- /package/lib/{Perforator.js → model/Perforator.js} +0 -0
- /package/lib/{Quantity.d.ts → model/Quantity.d.ts} +0 -0
- /package/lib/{Quantity.js → model/Quantity.js} +0 -0
- /package/lib/{Symbol.js → model/Symbol.js} +0 -0
- /package/lib/{TrackCalibration.d.ts → model/TrackCalibration.d.ts} +0 -0
- /package/lib/{TrackCalibration.js → model/TrackCalibration.js} +0 -0
- /package/lib/{notes.d.ts → model/notes.d.ts} +0 -0
- /package/lib/{notes.js → model/notes.js} +0 -0
- /package/lib/{procedures.d.ts → model/procedures.d.ts} +0 -0
- /package/lib/{procedures.js → model/procedures.js} +0 -0
- /package/lib/{vocabulary.d.ts → model/vocabulary.d.ts} +0 -0
- /package/lib/{sorted.d.ts → shared/sorted.d.ts} +0 -0
- /package/lib/{sorted.js → shared/sorted.js} +0 -0
- /package/lib/{utils.d.ts → shared/utils.d.ts} +0 -0
- /package/lib/{utils.js → shared/utils.js} +0 -0
- /package/lib/{ReproducingSystem.js → systems/ReproducingSystem.js} +0 -0
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { v4 } from "uuid";
|
|
2
|
-
import {
|
|
3
|
-
import { trackerBarOf } from "./systems/index.js";
|
|
2
|
+
import { defaultTrackerBar, trackerBarOf } from "../systems/index.js";
|
|
4
3
|
import { assignReference, certaintyOf, isAsserted } from "./Assumption.js";
|
|
5
4
|
import { px, track } from "./Quantity.js";
|
|
6
5
|
export const rollConditions = [
|
|
@@ -43,10 +42,9 @@ export const featuresOf = (copy) => featuresByAct(copy).flat();
|
|
|
43
42
|
export const isPaperStretch = (condition) => condition.conditionType === 'paper-stretch';
|
|
44
43
|
/**
|
|
45
44
|
* The bar a copy is read by, which is the one it was cut for. A copy
|
|
46
|
-
* that names no system falls back to
|
|
47
|
-
* before the systems were told apart; `reservationsAbout` says so.
|
|
45
|
+
* that names no system falls back to `defaultTrackerBar`.
|
|
48
46
|
*/
|
|
49
|
-
export const barOf = (copy) => trackerBarOf(copy.production?.system) ??
|
|
47
|
+
export const barOf = (copy) => trackerBarOf(copy.production?.system) ?? defaultTrackerBar;
|
|
50
48
|
/** The diameter of the punch the copy was cut with, where the edition holds it true or likely. */
|
|
51
49
|
export const punchDiameterOf = (copy) => {
|
|
52
50
|
const diameter = copy.production?.perforator?.condition?.punchDiameter;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReferenceAssumption } from "./Assumption.js";
|
|
2
|
-
import { WithId } from "
|
|
2
|
+
import { WithId } from "../shared/utils.js";
|
|
3
3
|
/**
|
|
4
4
|
* A symbol is an abstract musical or textual entity carried by one or more
|
|
5
5
|
* physical features on the roll. Symbols are the result of interpreting
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Edit } from "./Edit.js";
|
|
2
2
|
import { Concept } from "./Agent.js";
|
|
3
3
|
import { ActorAssignment, Belief, Certainty, DateAssignment, ObjectAssumption, ReferenceAssumption } from "./Assumption.js";
|
|
4
|
-
import { CollationTolerance } from "
|
|
4
|
+
import { CollationTolerance } from "../collation/Collation.js";
|
|
5
5
|
import { AnySymbol } from "./Symbol.js";
|
|
6
|
-
import { WithId, WithNote, WithType } from "
|
|
6
|
+
import { WithId, WithNote, WithType } from "../shared/utils.js";
|
|
7
7
|
/**
|
|
8
8
|
* A motivation provides a reason or rationale for an editorial change.
|
|
9
9
|
* Motivations are defined at the version level and referenced by edits.
|
|
@@ -131,3 +131,11 @@ export declare const derivationsOf: (version: Readonly<Version>) => {
|
|
|
131
131
|
* below another's reads the version's edits against another parent.
|
|
132
132
|
*/
|
|
133
133
|
export declare const principalDerivationOf: (version: Readonly<Version>) => Readonly<Derivation> | undefined;
|
|
134
|
+
/**
|
|
135
|
+
* Whether the version derives from the other, directly or through the
|
|
136
|
+
* versions between them, by any derivation it states, a hypothesis
|
|
137
|
+
* among them: a hypothesis held more certain becomes the principal one.
|
|
138
|
+
* A version derives from itself in no statement, and a stemma that
|
|
139
|
+
* loops is walked once round.
|
|
140
|
+
*/
|
|
141
|
+
export declare const derivesFrom: (versions: readonly Readonly<Version>[], versionId: string, ancestorId: string) => boolean;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { certainties, certaintyOf, idOf } from "./Assumption.js";
|
|
2
|
-
import { defaultCollationTolerance } from "
|
|
2
|
+
import { defaultCollationTolerance } from "../collation/Collation.js";
|
|
3
3
|
/** The tolerance the derivation was collated at, or the default where it states none. */
|
|
4
4
|
export const collationToleranceOf = (derivation) => derivation.collationTolerance ?? defaultCollationTolerance;
|
|
5
5
|
/** The edits the version states, none where it leaves its text unstated. */
|
|
@@ -26,3 +26,26 @@ const rankOf = (derivation) => certainties.indexOf(certaintyOf(derivation));
|
|
|
26
26
|
export const principalDerivationOf = (version) => (version.basedOn ?? [])
|
|
27
27
|
.filter(derivation => rankOf(derivation) <= certainties.indexOf('possible'))
|
|
28
28
|
.reduce((principal, derivation) => principal === undefined || rankOf(derivation) < rankOf(principal) ? derivation : principal, undefined);
|
|
29
|
+
/**
|
|
30
|
+
* Whether the version derives from the other, directly or through the
|
|
31
|
+
* versions between them, by any derivation it states, a hypothesis
|
|
32
|
+
* among them: a hypothesis held more certain becomes the principal one.
|
|
33
|
+
* A version derives from itself in no statement, and a stemma that
|
|
34
|
+
* loops is walked once round.
|
|
35
|
+
*/
|
|
36
|
+
export const derivesFrom = (versions, versionId, ancestorId) => {
|
|
37
|
+
const byId = new Map(versions.map(version => [version.id, version]));
|
|
38
|
+
const seen = new Set();
|
|
39
|
+
const pending = [versionId];
|
|
40
|
+
while (pending.length > 0) {
|
|
41
|
+
const id = pending.pop();
|
|
42
|
+
if (seen.has(id))
|
|
43
|
+
continue;
|
|
44
|
+
seen.add(id);
|
|
45
|
+
const parents = (byId.get(id)?.basedOn ?? []).map(idOf);
|
|
46
|
+
if (parents.includes(ancestorId))
|
|
47
|
+
return true;
|
|
48
|
+
pending.push(...parents);
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { drives } from "./Perforator.js";
|
|
2
2
|
import { procedures } from "./procedures.js";
|
|
3
|
-
import { systemOf } from "
|
|
4
|
-
import { trackerBars } from "
|
|
3
|
+
import { systemOf } from "../systems/TrackerBar.js";
|
|
4
|
+
import { trackerBars } from "../systems/index.js";
|
|
5
5
|
/**
|
|
6
6
|
* The concepts the type vocabulary declares, whatever kind they are:
|
|
7
7
|
* the reproducing systems, the procedures and the drives of a
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Path } from "../view/EditionView.js";
|
|
2
|
+
import { AnyArgumentation, Certainty } from "../model/Assumption.js";
|
|
3
|
+
import { EditionOp } from "./draft.js";
|
|
4
|
+
/** Annotates the assumption at the path with a belief held true, for reasons to be added. */
|
|
5
|
+
export declare const createBelief: (path: Path) => EditionOp;
|
|
6
|
+
export declare const clearBelief: (path: Path) => EditionOp;
|
|
7
|
+
export declare const setCertainty: (path: Path, certainty: Certainty) => EditionOp;
|
|
8
|
+
export declare const addReason: (path: Path, reason: AnyArgumentation) => EditionOp;
|
|
9
|
+
export declare const removeReason: (path: Path, index: number) => EditionOp;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { v4 } from "uuid";
|
|
2
|
+
import { getAt } from "../view/EditionView.js";
|
|
3
|
+
const onAssumptionAt = (path, op) => draft => {
|
|
4
|
+
const assumption = getAt(path, draft);
|
|
5
|
+
if (assumption)
|
|
6
|
+
op(assumption);
|
|
7
|
+
};
|
|
8
|
+
const onBeliefAt = (path, op) => onAssumptionAt(path, assumption => {
|
|
9
|
+
const belief = assumption['@annotation']?.belief;
|
|
10
|
+
if (belief)
|
|
11
|
+
op(belief);
|
|
12
|
+
});
|
|
13
|
+
/** Annotates the assumption at the path with a belief held true, for reasons to be added. */
|
|
14
|
+
export const createBelief = (path) => onAssumptionAt(path, assumption => {
|
|
15
|
+
assumption['@annotation'] = {
|
|
16
|
+
id: v4(),
|
|
17
|
+
belief: { type: 'belief', id: v4(), certainty: 'true', reasons: [] }
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
export const clearBelief = (path) => onAssumptionAt(path, assumption => {
|
|
21
|
+
delete assumption['@annotation'];
|
|
22
|
+
});
|
|
23
|
+
export const setCertainty = (path, certainty) => onBeliefAt(path, belief => {
|
|
24
|
+
belief.certainty = certainty;
|
|
25
|
+
});
|
|
26
|
+
export const addReason = (path, reason) => onBeliefAt(path, belief => {
|
|
27
|
+
belief.reasons.push(reason);
|
|
28
|
+
});
|
|
29
|
+
export const removeReason = (path, index) => onBeliefAt(path, belief => {
|
|
30
|
+
belief.reasons.splice(index, 1);
|
|
31
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { EditionView } from "../view/EditionView.js";
|
|
2
|
+
import { CollationTolerance } from "../collation/Collation.js";
|
|
3
|
+
import { ObjectAssumption } from "../model/Assumption.js";
|
|
4
|
+
import { EditionOp } from "./draft.js";
|
|
5
|
+
/**
|
|
6
|
+
* Bases the child on the parent. A symbol of the child that collates
|
|
7
|
+
* with one the parent hands down adds its carriers to that symbol; the
|
|
8
|
+
* rest become the child's insertions, and what the parent hands down
|
|
9
|
+
* and the child lacks becomes its deletions. The derivation states the
|
|
10
|
+
* tolerance it was collated at and becomes the principal one; the
|
|
11
|
+
* hypotheses the child stated beside its former one stay.
|
|
12
|
+
*
|
|
13
|
+
* The edits the child already stated are rewritten only as far as a
|
|
14
|
+
* collation wrote them (`isCollationsOwn`). An editor's reading of the
|
|
15
|
+
* difference between the two texts stays, and the symbols it speaks for
|
|
16
|
+
* are left out of the collation, so that connecting the two again
|
|
17
|
+
* neither doubles them nor silently drops what somebody established by
|
|
18
|
+
* hand. An equivalence is the collation's own, since it is drawn from
|
|
19
|
+
* the two systems' vocabularies rather than read off the paper, but one
|
|
20
|
+
* drawn again over the very same symbols is kept as it stands, with its
|
|
21
|
+
* identifier and whatever was written on it.
|
|
22
|
+
*
|
|
23
|
+
* The child's own text is what it shows less what the parent hands
|
|
24
|
+
* down, so that connecting two versions already connected collates the
|
|
25
|
+
* child's symbols and not the parent's with themselves.
|
|
26
|
+
*
|
|
27
|
+
* A version is based on itself or on one of its own descendants in no
|
|
28
|
+
* statement, since the stemma would loop; asked for that, nothing
|
|
29
|
+
* changes.
|
|
30
|
+
*/
|
|
31
|
+
export declare const connectVersions: (given: EditionView, childId: string, parentId: string, tolerance?: ObjectAssumption<CollationTolerance>) => EditionOp;
|
|
32
|
+
/**
|
|
33
|
+
* Folds the version's own symbols into those it inherits and collates
|
|
34
|
+
* with: the carriers pass over, and the insertions go. Collates at the
|
|
35
|
+
* tolerance of the derivation, where the caller names none.
|
|
36
|
+
*/
|
|
37
|
+
export declare const collateSymbols: (given: EditionView, versionId: string, symbolIds: readonly string[], tolerance?: CollationTolerance) => EditionOp;
|
|
38
|
+
/**
|
|
39
|
+
* Takes the named copies' reading of a symbol back out of the symbol it
|
|
40
|
+
* was collated into: their carriers pass to a new symbol of the
|
|
41
|
+
* version's own, the remaining copies keep the symbol they had, and the
|
|
42
|
+
* version states the exchange.
|
|
43
|
+
*
|
|
44
|
+
* This is the inverse of the hand-over a collation makes, and it is
|
|
45
|
+
* what lets a derivation be collated a second time. A collated symbol
|
|
46
|
+
* is one symbol carrying every copy that reads it, so nothing else
|
|
47
|
+
* takes the two readings apart again, and without that a tolerance
|
|
48
|
+
* arrived at after the fact could never be applied.
|
|
49
|
+
*
|
|
50
|
+
* The copies named are one **side** of the derivation, the same side a
|
|
51
|
+
* window is measured over, and `sidesOf` is what says which they are.
|
|
52
|
+
* Naming one copy of a side that has several does not separate that
|
|
53
|
+
* side: what stays behind is the rest of it, mixed with the other
|
|
54
|
+
* side's copies, and a collation then compares one copy against that
|
|
55
|
+
* mixture rather than the two texts against each other.
|
|
56
|
+
*
|
|
57
|
+
* Symbols the named copies alone carry are already the version's own
|
|
58
|
+
* and are passed over, so a reading somebody has separated by hand
|
|
59
|
+
* keeps its identifier and the edit that speaks for it. Named symbols
|
|
60
|
+
* narrow the act to those; naming none separates the whole reading.
|
|
61
|
+
*/
|
|
62
|
+
export declare const separateReadings: (given: EditionView, versionId: string, copies: ReadonlySet<string>, symbolIds?: readonly string[]) => EditionOp;
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { v4 } from "uuid";
|
|
2
|
+
import { getAt } from "../view/EditionView.js";
|
|
3
|
+
import { collationsOf, defaultCollationTolerance, isCollationsOwn, unchecked } from "../collation/Collation.js";
|
|
4
|
+
import { collationToleranceOf, derivesFrom, editsOf, insertedBy, principalDerivationOf } from "../model/Version.js";
|
|
5
|
+
import { substitutionsBetween } from "../collation/substitution.js";
|
|
6
|
+
import { trackerBarOf } from "../systems/index.js";
|
|
7
|
+
import { assignReference, idOf } from "../model/Assumption.js";
|
|
8
|
+
import { noChange, onVersion, stateOf, insertion, deletion, asUnchecked, declaring, insertedIn, dropInsertions, reading } from "./draft.js";
|
|
9
|
+
import { hypothesesBeside } from "./versions.js";
|
|
10
|
+
/** The carriers of each collated symbol pass to its counterpart. */
|
|
11
|
+
const handOverCarriers = (view, draft, collations) => collations.forEach(({ symbol, counterpart }) => {
|
|
12
|
+
const path = view.getPath(counterpart.id);
|
|
13
|
+
const target = path && getAt(path, draft);
|
|
14
|
+
target?.carriers.push(...symbol.carriers);
|
|
15
|
+
});
|
|
16
|
+
/** Whether the two versions are coded for different reproducing systems. */
|
|
17
|
+
const differ = (child, parent) => {
|
|
18
|
+
const one = trackerBarOf(child?.system);
|
|
19
|
+
const other = trackerBarOf(parent?.system);
|
|
20
|
+
return one !== undefined && other !== undefined && one.id !== other.id;
|
|
21
|
+
};
|
|
22
|
+
/** The symbols a set of edits speaks for, whether by inserting or by deleting them. */
|
|
23
|
+
const spokenForBy = (edits) => new Set(edits.flatMap(edit => [
|
|
24
|
+
...(edit.insert ?? []).map(symbol => symbol.id),
|
|
25
|
+
...(edit.delete ?? [])
|
|
26
|
+
]));
|
|
27
|
+
/** An exchange of symbols, as a key: what it puts in against what it takes out. */
|
|
28
|
+
const exchangeKey = (inserted, deleted) => `${[...inserted].sort().join(',')}/${[...deleted].sort().join(',')}`;
|
|
29
|
+
/**
|
|
30
|
+
* The edits already stated, by the exchange each of them makes. An
|
|
31
|
+
* equivalence the collation draws a second time is the one already
|
|
32
|
+
* stated, and drawing it again is no reason to mint a new identifier or
|
|
33
|
+
* to drop the motivation somebody wrote on it.
|
|
34
|
+
*/
|
|
35
|
+
const byExchange = (edits) => new Map(edits.map(edit => [exchangeKey((edit.insert ?? []).map(symbol => symbol.id), edit.delete ?? []), edit]));
|
|
36
|
+
/**
|
|
37
|
+
* Bases the child on the parent. A symbol of the child that collates
|
|
38
|
+
* with one the parent hands down adds its carriers to that symbol; the
|
|
39
|
+
* rest become the child's insertions, and what the parent hands down
|
|
40
|
+
* and the child lacks becomes its deletions. The derivation states the
|
|
41
|
+
* tolerance it was collated at and becomes the principal one; the
|
|
42
|
+
* hypotheses the child stated beside its former one stay.
|
|
43
|
+
*
|
|
44
|
+
* The edits the child already stated are rewritten only as far as a
|
|
45
|
+
* collation wrote them (`isCollationsOwn`). An editor's reading of the
|
|
46
|
+
* difference between the two texts stays, and the symbols it speaks for
|
|
47
|
+
* are left out of the collation, so that connecting the two again
|
|
48
|
+
* neither doubles them nor silently drops what somebody established by
|
|
49
|
+
* hand. An equivalence is the collation's own, since it is drawn from
|
|
50
|
+
* the two systems' vocabularies rather than read off the paper, but one
|
|
51
|
+
* drawn again over the very same symbols is kept as it stands, with its
|
|
52
|
+
* identifier and whatever was written on it.
|
|
53
|
+
*
|
|
54
|
+
* The child's own text is what it shows less what the parent hands
|
|
55
|
+
* down, so that connecting two versions already connected collates the
|
|
56
|
+
* child's symbols and not the parent's with themselves.
|
|
57
|
+
*
|
|
58
|
+
* A version is based on itself or on one of its own descendants in no
|
|
59
|
+
* statement, since the stemma would loop; asked for that, nothing
|
|
60
|
+
* changes.
|
|
61
|
+
*/
|
|
62
|
+
export const connectVersions = (given, childId, parentId, tolerance = defaultCollationTolerance) => reading(given, view => {
|
|
63
|
+
if (childId === parentId || derivesFrom(view.edition.versions, parentId, childId))
|
|
64
|
+
return noChange;
|
|
65
|
+
const child = view.version(childId);
|
|
66
|
+
const stated = child ? editsOf(child) : [];
|
|
67
|
+
const established = stated.filter(edit => !isCollationsOwn(edit));
|
|
68
|
+
const spokenFor = spokenForBy(established);
|
|
69
|
+
const unspoken = (symbol) => !spokenFor.has(symbol.id);
|
|
70
|
+
// What the parent hands down and the child still shows passes
|
|
71
|
+
// through: it is neither the child's own symbol nor one it lacks.
|
|
72
|
+
// Without that, connecting a pair already connected would collate
|
|
73
|
+
// the inherited symbols with themselves and double their carriers.
|
|
74
|
+
const handedDown = view.snapshot(parentId).filter(unspoken);
|
|
75
|
+
const shown = new Set(view.snapshot(childId).map(symbol => symbol.id));
|
|
76
|
+
const inheritedIds = new Set(handedDown.map(symbol => symbol.id));
|
|
77
|
+
const inherited = handedDown.filter(symbol => !shown.has(symbol.id));
|
|
78
|
+
const own = view.snapshot(childId).filter(symbol => unspoken(symbol) && !inheritedIds.has(symbol.id));
|
|
79
|
+
const locate = (symbol) => view.placeOf(symbol);
|
|
80
|
+
const collations = collationsOf(own, inherited, locate, tolerance);
|
|
81
|
+
const collated = new Set(collations.map(({ symbol }) => symbol.id));
|
|
82
|
+
const matched = new Set(collations.map(({ counterpart }) => counterpart.id));
|
|
83
|
+
/**
|
|
84
|
+
* Where the child is coded for another system, a held command of
|
|
85
|
+
* its own often stands for a latched pair of the parent's. Saying so
|
|
86
|
+
* as one edit is the transfer being carried out, and leaving the two
|
|
87
|
+
* apart would make the apparatus a list of unexplained losses beside
|
|
88
|
+
* a list of unexplained gains.
|
|
89
|
+
*/
|
|
90
|
+
const substituted = differ(child, view.version(parentId))
|
|
91
|
+
? substitutionsBetween(own.filter(symbol => !collated.has(symbol.id)), inherited.filter(symbol => !matched.has(symbol.id)), locate, tolerance)
|
|
92
|
+
: [];
|
|
93
|
+
const paired = new Set(substituted.flatMap(({ replaced, by }) => [...by, ...replaced].map(symbol => symbol.id)));
|
|
94
|
+
const alreadyStated = byExchange(stated);
|
|
95
|
+
const equivalence = ({ replaced, by }) => {
|
|
96
|
+
const inserted = by.map(symbol => symbol.id);
|
|
97
|
+
const deleted = replaced.map(symbol => symbol.id);
|
|
98
|
+
return alreadyStated.get(exchangeKey(inserted, deleted)) ?? {
|
|
99
|
+
type: 'edit',
|
|
100
|
+
id: v4(),
|
|
101
|
+
editType: 'replace-with-equivalent',
|
|
102
|
+
motivation: unchecked,
|
|
103
|
+
insert: [...by],
|
|
104
|
+
delete: deleted
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
const edits = [
|
|
108
|
+
...established,
|
|
109
|
+
...substituted.map(equivalence),
|
|
110
|
+
...own.filter(symbol => !collated.has(symbol.id) && !paired.has(symbol.id)).map(insertion).map(asUnchecked),
|
|
111
|
+
...inherited
|
|
112
|
+
.filter(symbol => !matched.has(symbol.id) && !paired.has(symbol.id))
|
|
113
|
+
.map(symbol => asUnchecked(deletion(symbol.id)))
|
|
114
|
+
];
|
|
115
|
+
return onVersion(childId, (child, draft) => {
|
|
116
|
+
handOverCarriers(view, draft, collations);
|
|
117
|
+
child.edits = edits;
|
|
118
|
+
child.motivations = declaring(stateOf(child).motivations, edits);
|
|
119
|
+
child.basedOn = [
|
|
120
|
+
{ ...assignReference(parentId), collationTolerance: tolerance },
|
|
121
|
+
...hypothesesBeside(stateOf(child), parentId)
|
|
122
|
+
];
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
/**
|
|
126
|
+
* Folds the version's own symbols into those it inherits and collates
|
|
127
|
+
* with: the carriers pass over, and the insertions go. Collates at the
|
|
128
|
+
* tolerance of the derivation, where the caller names none.
|
|
129
|
+
*/
|
|
130
|
+
export const collateSymbols = (given, versionId, symbolIds, tolerance) => reading(given, view => {
|
|
131
|
+
const version = view.version(versionId);
|
|
132
|
+
const principal = version && principalDerivationOf(version);
|
|
133
|
+
if (!version || !principal)
|
|
134
|
+
return noChange;
|
|
135
|
+
const chosen = new Set(symbolIds);
|
|
136
|
+
const own = insertedIn([version]).filter(symbol => chosen.has(symbol.id));
|
|
137
|
+
const collations = collationsOf(own, view.snapshot(idOf(principal)), symbol => view.placeOf(symbol), tolerance ?? collationToleranceOf(principal));
|
|
138
|
+
const collated = new Set(collations.map(({ symbol }) => symbol.id));
|
|
139
|
+
return onVersion(versionId, (version, draft) => {
|
|
140
|
+
handOverCarriers(view, draft, collations);
|
|
141
|
+
dropInsertions(version, collated);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
/** The symbol as one copy reads it: what it says, on the given carriers, standing in no relation of its own. */
|
|
145
|
+
const readingOf = (symbol, carriers) => {
|
|
146
|
+
const identity = { id: v4(), carriers };
|
|
147
|
+
switch (symbol.type) {
|
|
148
|
+
case 'note':
|
|
149
|
+
return { type: 'note', pitch: symbol.pitch, ...identity };
|
|
150
|
+
case 'expression':
|
|
151
|
+
return { type: 'expression', expressionType: symbol.expressionType, scope: symbol.scope, ...identity };
|
|
152
|
+
case 'text':
|
|
153
|
+
return { type: 'text', text: symbol.text, ...identity };
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* The symbol where the named copies and at least one other carry it,
|
|
158
|
+
* with the carriers of each side.
|
|
159
|
+
*
|
|
160
|
+
* A symbol the named copies alone carry has no other side to be
|
|
161
|
+
* separated from and is passed over. That covers the insertions, and it
|
|
162
|
+
* covers a symbol an ancestor holds on one branch's witness alone,
|
|
163
|
+
* where the two versions do not disagree and there is nothing to take
|
|
164
|
+
* apart.
|
|
165
|
+
*/
|
|
166
|
+
const sharedWith = (view, symbol, copies) => {
|
|
167
|
+
const onNamedCopy = (carrier) => {
|
|
168
|
+
const copy = view.copyOf(idOf(carrier));
|
|
169
|
+
return copy !== undefined && copies.has(copy.id);
|
|
170
|
+
};
|
|
171
|
+
const mine = symbol.carriers.filter(onNamedCopy);
|
|
172
|
+
const theirs = symbol.carriers.filter(carrier => !onNamedCopy(carrier));
|
|
173
|
+
return mine.length > 0 && theirs.length > 0 ? [{ symbol, mine, theirs }] : [];
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Takes the named copies' reading of a symbol back out of the symbol it
|
|
177
|
+
* was collated into: their carriers pass to a new symbol of the
|
|
178
|
+
* version's own, the remaining copies keep the symbol they had, and the
|
|
179
|
+
* version states the exchange.
|
|
180
|
+
*
|
|
181
|
+
* This is the inverse of the hand-over a collation makes, and it is
|
|
182
|
+
* what lets a derivation be collated a second time. A collated symbol
|
|
183
|
+
* is one symbol carrying every copy that reads it, so nothing else
|
|
184
|
+
* takes the two readings apart again, and without that a tolerance
|
|
185
|
+
* arrived at after the fact could never be applied.
|
|
186
|
+
*
|
|
187
|
+
* The copies named are one **side** of the derivation, the same side a
|
|
188
|
+
* window is measured over, and `sidesOf` is what says which they are.
|
|
189
|
+
* Naming one copy of a side that has several does not separate that
|
|
190
|
+
* side: what stays behind is the rest of it, mixed with the other
|
|
191
|
+
* side's copies, and a collation then compares one copy against that
|
|
192
|
+
* mixture rather than the two texts against each other.
|
|
193
|
+
*
|
|
194
|
+
* Symbols the named copies alone carry are already the version's own
|
|
195
|
+
* and are passed over, so a reading somebody has separated by hand
|
|
196
|
+
* keeps its identifier and the edit that speaks for it. Named symbols
|
|
197
|
+
* narrow the act to those; naming none separates the whole reading.
|
|
198
|
+
*/
|
|
199
|
+
export const separateReadings = (given, versionId, copies, symbolIds) => reading(given, view => {
|
|
200
|
+
const version = view.version(versionId);
|
|
201
|
+
if (!version)
|
|
202
|
+
return noChange;
|
|
203
|
+
const chosen = symbolIds && new Set(symbolIds);
|
|
204
|
+
const shared = view.snapshot(versionId)
|
|
205
|
+
.filter(symbol => chosen === undefined || chosen.has(symbol.id))
|
|
206
|
+
.flatMap(symbol => sharedWith(view, symbol, copies));
|
|
207
|
+
if (shared.length === 0)
|
|
208
|
+
return noChange;
|
|
209
|
+
const inserted = new Set(insertedBy(version).map(symbol => symbol.id));
|
|
210
|
+
const stated = editsOf(version);
|
|
211
|
+
const separations = shared.map(({ symbol, mine }) => ({
|
|
212
|
+
type: 'edit',
|
|
213
|
+
id: v4(),
|
|
214
|
+
insert: [readingOf(symbol, [...mine])],
|
|
215
|
+
// A symbol the version inserts itself stays where it is, minus
|
|
216
|
+
// the carriers that leave it. Only one it inherits is exchanged.
|
|
217
|
+
...(inserted.has(symbol.id) ? {} : { delete: [symbol.id] })
|
|
218
|
+
}));
|
|
219
|
+
return onVersion(versionId, (version, draft) => {
|
|
220
|
+
shared.forEach(({ symbol, theirs }) => {
|
|
221
|
+
const path = view.getPath(symbol.id);
|
|
222
|
+
const target = path && getAt(path, draft);
|
|
223
|
+
if (target)
|
|
224
|
+
target.carriers = theirs;
|
|
225
|
+
});
|
|
226
|
+
version.edits = [...stated, ...separations];
|
|
227
|
+
});
|
|
228
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { EditionView } from "../view/EditionView.js";
|
|
2
|
+
import { PlacementRelation } from "../model/Symbol.js";
|
|
3
|
+
import { EditionOp } from "./draft.js";
|
|
4
|
+
/** States how the follower is placed relative to the reference, in place of any earlier statement. */
|
|
5
|
+
export declare const placeCommand: (view: EditionView, followerId: string, referenceId: string, relation: PlacementRelation) => EditionOp;
|
|
6
|
+
export declare const unplaceCommand: (view: EditionView, followerId: string) => EditionOp;
|
|
7
|
+
/** The pair is stated on `statingId` only, as the format asks. */
|
|
8
|
+
export declare const pairCommands: (view: EditionView, statingId: string, partnerId: string) => EditionOp;
|
|
9
|
+
export declare const unpairCommand: (view: EditionView, statingId: string) => EditionOp;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { getAt } from "../view/EditionView.js";
|
|
2
|
+
import { isCommand, placementRelations } from "../model/Symbol.js";
|
|
3
|
+
import { assignReference } from "../model/Assumption.js";
|
|
4
|
+
import { reading } from "./draft.js";
|
|
5
|
+
/**
|
|
6
|
+
* Runs the change on the command the view locates by id, in whichever
|
|
7
|
+
* version inserted it. A statement made there holds in every version
|
|
8
|
+
* that carries the command.
|
|
9
|
+
*/
|
|
10
|
+
const onCommand = (view, id, op) => reading(view, fresh => draft => {
|
|
11
|
+
const path = fresh.getPath(id);
|
|
12
|
+
const symbol = path && getAt(path, draft);
|
|
13
|
+
if (isCommand(symbol))
|
|
14
|
+
op(symbol);
|
|
15
|
+
});
|
|
16
|
+
const clearPlacement = (command) => placementRelations.forEach(relation => { delete command[relation]; });
|
|
17
|
+
/** States how the follower is placed relative to the reference, in place of any earlier statement. */
|
|
18
|
+
export const placeCommand = (view, followerId, referenceId, relation) => onCommand(view, followerId, command => {
|
|
19
|
+
clearPlacement(command);
|
|
20
|
+
command[relation] = assignReference(referenceId);
|
|
21
|
+
});
|
|
22
|
+
export const unplaceCommand = (view, followerId) => onCommand(view, followerId, clearPlacement);
|
|
23
|
+
/** The pair is stated on `statingId` only, as the format asks. */
|
|
24
|
+
export const pairCommands = (view, statingId, partnerId) => onCommand(view, statingId, command => {
|
|
25
|
+
command.pairedWith = assignReference(partnerId);
|
|
26
|
+
});
|
|
27
|
+
export const unpairCommand = (view, statingId) => onCommand(view, statingId, command => {
|
|
28
|
+
delete command.pairedWith;
|
|
29
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/** Operations on the copies: adding and aligning them, and what they state of their source, their carriage and their condition. */
|
|
2
|
+
import { Draft } from "immer";
|
|
3
|
+
import { Edition } from "../model/Edition.js";
|
|
4
|
+
import { AnySymbol } from "../model/Symbol.js";
|
|
5
|
+
import { GeneralRollCondition, RollCopy, ScaleReading, Shift } from "../model/RollCopy.js";
|
|
6
|
+
import { FeatureSource } from "../model/FeatureSource.js";
|
|
7
|
+
import { Belief, ObjectAssumption, ReferenceAssumption } from "../model/Assumption.js";
|
|
8
|
+
import { Millimeters } from "../model/Quantity.js";
|
|
9
|
+
import { EditionOp } from "./draft.js";
|
|
10
|
+
/**
|
|
11
|
+
* Puts the copy into the edition with a version of its own, which
|
|
12
|
+
* inserts every symbol the copy's own tracker bar reads on it. The
|
|
13
|
+
* version is a reading in that system's words, so it is coded for the
|
|
14
|
+
* system the copy was cut for.
|
|
15
|
+
*/
|
|
16
|
+
export declare const createVersion: (copy: RollCopy) => EditionOp;
|
|
17
|
+
/**
|
|
18
|
+
* Puts the copy into the edition without a version of its own, as for a
|
|
19
|
+
* copy whose features are not read into symbols: one known only from a
|
|
20
|
+
* recording states instead which versions it carries.
|
|
21
|
+
*/
|
|
22
|
+
export declare const addCopy: (copy: RollCopy) => EditionOp;
|
|
23
|
+
/**
|
|
24
|
+
* Shifts and then scales the copy's features into line with another
|
|
25
|
+
* copy's, and puts the scale down to what the reading says: the paper,
|
|
26
|
+
* or the speed the copy was cut for.
|
|
27
|
+
*/
|
|
28
|
+
export declare const alignCopy: (copyId: string, shift: Shift, scale: number, reading?: ScaleReading) => EditionOp;
|
|
29
|
+
/**
|
|
30
|
+
* Puts the copy's features back where they were measured. A paper
|
|
31
|
+
* stretch read off the alignment goes with it; a speed stated stays,
|
|
32
|
+
* being a fact about the copy.
|
|
33
|
+
*/
|
|
34
|
+
export declare const unalignCopy: (copyId: string) => EditionOp;
|
|
35
|
+
/**
|
|
36
|
+
* Takes the extension a pneumatic reader adds off the ends of the
|
|
37
|
+
* copy's chains of holes, and records how much was taken, so that their lengths
|
|
38
|
+
* can be compared with a scanned copy's at all.
|
|
39
|
+
*/
|
|
40
|
+
export declare const shortenCopy: (copyId: string, extension: Millimeters, leaving?: ReadonlySet<string>) => EditionOp;
|
|
41
|
+
/** Puts the reader's extension back on the copy's chains of holes. */
|
|
42
|
+
export declare const unshortenCopy: (copyId: string) => EditionOp;
|
|
43
|
+
/** States what the copy's features were read from, in place of any earlier statement. */
|
|
44
|
+
export declare const stateSource: (copyId: string, source: FeatureSource) => EditionOp;
|
|
45
|
+
/** Takes back the statement, leaving the copy silent about its source again. */
|
|
46
|
+
export declare const clearSource: (copyId: string) => EditionOp;
|
|
47
|
+
/** Gives the copy the siglum it is referred to by, or takes it away where the siglum given is blank. */
|
|
48
|
+
export declare const nameCopy: (copyId: string, siglum: string) => EditionOp;
|
|
49
|
+
/** Takes out the copy's statements that match, and the list itself where none is left. */
|
|
50
|
+
export declare const dropStatements: (copy: Draft<RollCopy>, matches: (statement: Readonly<ReferenceAssumption>) => boolean) => void;
|
|
51
|
+
/**
|
|
52
|
+
* States that the copy carries the version, under the belief given. It
|
|
53
|
+
* is meant for a copy whose features are not read into symbols, such as
|
|
54
|
+
* one known only from a recording, and `carriageProblems` reports it
|
|
55
|
+
* where features carry symbols already. A second statement about one
|
|
56
|
+
* version is none.
|
|
57
|
+
*/
|
|
58
|
+
export declare const stateCarriage: (copyId: string, versionId: string, belief?: Belief) => EditionOp;
|
|
59
|
+
/** Takes back the copy's statement that it carries the version. */
|
|
60
|
+
export declare const clearCarriage: (copyId: string, versionId: string) => EditionOp;
|
|
61
|
+
/**
|
|
62
|
+
* Adds a general condition to the copy, beside whatever is stated of it
|
|
63
|
+
* already. The other condition a copy may be in, a paper stretch, is
|
|
64
|
+
* read off an alignment and stated by `alignCopy`.
|
|
65
|
+
*/
|
|
66
|
+
export declare const addGeneralCondition: (copyId: string, condition: ObjectAssumption<GeneralRollCondition>) => EditionOp;
|
|
67
|
+
/** The symbols of the versions that no other copy carries. */
|
|
68
|
+
export declare const symbolsCarriedOnlyBy: (edition: Edition, copyId: string) => AnySymbol[];
|
|
69
|
+
/**
|
|
70
|
+
* Takes the copy out of the edition together with the symbols only it
|
|
71
|
+
* carries, and with every reference the versions and the argumentations
|
|
72
|
+
* made to those symbols.
|
|
73
|
+
*/
|
|
74
|
+
export declare const removeCopy: (copyId: string) => EditionOp;
|