linked-rolls 0.25.1 → 0.27.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 +35 -9
- package/lib/Assumption.d.ts +10 -1
- package/lib/Assumption.js +2 -0
- package/lib/EditionView.d.ts +1 -0
- package/lib/EditionView.js +10 -8
- package/lib/FeatureSource.d.ts +52 -12
- package/lib/FeatureSource.js +11 -8
- package/lib/RollCopy.d.ts +11 -3
- package/lib/Version.d.ts +28 -7
- package/lib/Version.js +17 -2
- package/lib/asJsonLd.js +2 -2
- package/lib/editionOps.d.ts +36 -5
- package/lib/editionOps.js +119 -19
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/migrate.js +22 -2
- package/lib/readers/phillipsEroll.js +1 -2
- package/lib/readers/spencerBar.js +0 -1
- package/lib/readers/stanfordAton.js +0 -1
- package/lib/reservations.d.ts +16 -9
- package/lib/reservations.js +57 -7
- package/lib/schema.json +155 -11
- package/lib/spec/context.json +13 -1
- package/lib/witnesses.d.ts +33 -0
- package/lib/witnesses.js +48 -0
- package/package.json +1 -1
package/lib/editionOps.js
CHANGED
|
@@ -3,7 +3,7 @@ import { v4 } from "uuid";
|
|
|
3
3
|
import { getAt } from "./EditionView";
|
|
4
4
|
import { isPerforation, placementRelations } from "./Symbol";
|
|
5
5
|
import { collationsOf, defaultCollationTolerance } from "./Collation";
|
|
6
|
-
import { collationToleranceOf, insertedBy } from "./Version";
|
|
6
|
+
import { collationToleranceOf, editsOf, insertedBy, principalDerivationOf } from "./Version";
|
|
7
7
|
import { asSymbols, barOf, isPaperStretch } from "./RollCopy";
|
|
8
8
|
import { systemOf } from "./TrackerBar";
|
|
9
9
|
import { substitutionsBetween } from "./substitution";
|
|
@@ -65,7 +65,9 @@ const droppingInsertions = (symbolIds) => (edit) => {
|
|
|
65
65
|
};
|
|
66
66
|
/** Takes the symbols out of the version's own insertions, and the edits that had nothing else. */
|
|
67
67
|
const dropInsertions = (version, symbolIds) => {
|
|
68
|
-
|
|
68
|
+
const edits = stateOf(version).edits;
|
|
69
|
+
if (edits)
|
|
70
|
+
version.edits = edited(edits, droppingInsertions(symbolIds));
|
|
69
71
|
};
|
|
70
72
|
/**
|
|
71
73
|
* Puts the copy into the edition with a version of its own, which
|
|
@@ -86,6 +88,14 @@ export const createVersion = (siglum, copy) => draft => {
|
|
|
86
88
|
motivations: []
|
|
87
89
|
});
|
|
88
90
|
};
|
|
91
|
+
/**
|
|
92
|
+
* Puts the copy into the edition without a version of its own, as for a
|
|
93
|
+
* copy whose features are not read into symbols: one known only from a
|
|
94
|
+
* recording states instead which versions it carries.
|
|
95
|
+
*/
|
|
96
|
+
export const addCopy = (copy) => draft => {
|
|
97
|
+
draft.copies.push(copy);
|
|
98
|
+
};
|
|
89
99
|
/** States what the scale is put down to, in place of an earlier reading. */
|
|
90
100
|
const readScale = (copy, reading) => {
|
|
91
101
|
if (reading.cause === 'paper') {
|
|
@@ -125,6 +135,39 @@ export const stateSource = (copyId, source) => onCopy(copyId, copy => {
|
|
|
125
135
|
export const clearSource = (copyId) => onCopy(copyId, copy => {
|
|
126
136
|
copy.readFrom = undefined;
|
|
127
137
|
});
|
|
138
|
+
/** A reference under the belief given, where one is given. */
|
|
139
|
+
const referenceHeld = (id, belief) => ({ ...assignReference(id), ...(belief && { '@annotation': { id: v4(), belief } }) });
|
|
140
|
+
/** The references less those that match, or nothing where none is left. */
|
|
141
|
+
const withoutReferences = (references, matches) => {
|
|
142
|
+
const kept = references.filter(reference => !matches(reference));
|
|
143
|
+
return kept.length > 0 ? kept : undefined;
|
|
144
|
+
};
|
|
145
|
+
/** Takes out the copy's statements that match, and the list itself where none is left. */
|
|
146
|
+
const dropStatements = (copy, matches) => {
|
|
147
|
+
const statements = stateOf(copy).carries;
|
|
148
|
+
if (!statements?.some(matches))
|
|
149
|
+
return;
|
|
150
|
+
const kept = withoutReferences(statements, matches);
|
|
151
|
+
if (kept)
|
|
152
|
+
copy.carries = kept;
|
|
153
|
+
else
|
|
154
|
+
delete copy.carries;
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* States that the copy carries the version, under the belief given. It
|
|
158
|
+
* is meant for a copy whose features are not read into symbols, such as
|
|
159
|
+
* one known only from a recording, and `carriageProblems` reports it
|
|
160
|
+
* where features carry symbols already. A second statement about one
|
|
161
|
+
* version is none.
|
|
162
|
+
*/
|
|
163
|
+
export const stateCarriage = (copyId, versionId, belief) => onCopy(copyId, copy => {
|
|
164
|
+
const statements = stateOf(copy).carries ?? [];
|
|
165
|
+
if (statements.some(statement => idOf(statement) === versionId))
|
|
166
|
+
return;
|
|
167
|
+
copy.carries = [...statements, referenceHeld(versionId, belief)];
|
|
168
|
+
});
|
|
169
|
+
/** Takes back the copy's statement that it carries the version. */
|
|
170
|
+
export const clearCarriage = (copyId, versionId) => onCopy(copyId, copy => dropStatements(copy, statement => idOf(statement) === versionId));
|
|
128
171
|
/**
|
|
129
172
|
* Adds a general condition to the copy, beside whatever is stated of it
|
|
130
173
|
* already. The other condition a copy may be in, a paper stretch, is
|
|
@@ -278,15 +321,17 @@ const forgetFeatures = (draft, features) => {
|
|
|
278
321
|
const versions = stateOf(draft.versions);
|
|
279
322
|
const dropped = new Set(insertedIn(versions).filter(carriedOnlyOn(features)).map(symbol => symbol.id));
|
|
280
323
|
const forget = forgettingFeatures(features, dropped);
|
|
281
|
-
const edits = versions.map(version => edited(version.edits, forget));
|
|
324
|
+
const edits = versions.map(version => version.edits && edited(version.edits, forget));
|
|
282
325
|
const gone = new Set([
|
|
283
326
|
...features,
|
|
284
327
|
...dropped,
|
|
285
|
-
...versions.flatMap((version, i) => droppedIds(version
|
|
328
|
+
...versions.flatMap((version, i) => droppedIds(editsOf(version), edits[i] ?? []))
|
|
286
329
|
]);
|
|
287
330
|
renameReferences(draft, ids => without(ids, id => gone.has(id)));
|
|
288
331
|
draft.versions.forEach((version, i) => {
|
|
289
|
-
|
|
332
|
+
const stated = edits[i];
|
|
333
|
+
if (stated)
|
|
334
|
+
version.edits = stated;
|
|
290
335
|
});
|
|
291
336
|
};
|
|
292
337
|
/**
|
|
@@ -417,7 +462,9 @@ const carryOver = (draft, replaced, mergedId) => {
|
|
|
417
462
|
};
|
|
418
463
|
const versions = stateOf(draft.versions);
|
|
419
464
|
draft.versions.forEach((version, i) => {
|
|
420
|
-
|
|
465
|
+
const edits = versions[i].edits;
|
|
466
|
+
if (edits)
|
|
467
|
+
version.edits = mapped(edits, recarrying);
|
|
421
468
|
});
|
|
422
469
|
};
|
|
423
470
|
/**
|
|
@@ -463,12 +510,34 @@ const differ = (child, parent) => {
|
|
|
463
510
|
const other = trackerBarOf(parent?.system);
|
|
464
511
|
return one !== undefined && other !== undefined && one.id !== other.id;
|
|
465
512
|
};
|
|
513
|
+
/** Whether the version's text is read against the parent, its principal derivation naming it. */
|
|
514
|
+
const readsAgainst = (version, parentId) => {
|
|
515
|
+
const principal = principalDerivationOf(version);
|
|
516
|
+
return principal !== undefined && idOf(principal) === parentId;
|
|
517
|
+
};
|
|
518
|
+
/** The derivations the version states beside its principal one, less any naming the parent. */
|
|
519
|
+
const hypothesesBeside = (version, parentId) => {
|
|
520
|
+
const principal = principalDerivationOf(version);
|
|
521
|
+
return (version.basedOn ?? []).filter(derivation => derivation !== principal && idOf(derivation) !== parentId);
|
|
522
|
+
};
|
|
523
|
+
/** Takes out the derivations that match, and the list itself where none is left. */
|
|
524
|
+
const dropDerivations = (version, matches) => {
|
|
525
|
+
const derivations = stateOf(version).basedOn;
|
|
526
|
+
if (!derivations?.some(matches))
|
|
527
|
+
return;
|
|
528
|
+
const kept = withoutReferences(derivations, matches);
|
|
529
|
+
if (kept)
|
|
530
|
+
version.basedOn = kept;
|
|
531
|
+
else
|
|
532
|
+
delete version.basedOn;
|
|
533
|
+
};
|
|
466
534
|
/**
|
|
467
535
|
* Bases the child on the parent. A symbol of the child that collates
|
|
468
536
|
* with one the parent hands down adds its carriers to that symbol; the
|
|
469
537
|
* rest become the child's insertions, and what the parent hands down
|
|
470
538
|
* and the child lacks becomes its deletions. The derivation states the
|
|
471
|
-
* tolerance it was collated at
|
|
539
|
+
* tolerance it was collated at and becomes the principal one; the
|
|
540
|
+
* hypotheses the child stated beside its former one stay.
|
|
472
541
|
*/
|
|
473
542
|
export const connectVersions = (view, childId, parentId, tolerance = defaultCollationTolerance) => {
|
|
474
543
|
const inherited = view.snapshot(parentId);
|
|
@@ -504,7 +573,10 @@ export const connectVersions = (view, childId, parentId, tolerance = defaultColl
|
|
|
504
573
|
return onVersion(childId, (child, draft) => {
|
|
505
574
|
handOverCarriers(view, draft, collations);
|
|
506
575
|
child.edits = edits;
|
|
507
|
-
child.basedOn =
|
|
576
|
+
child.basedOn = [
|
|
577
|
+
{ ...assignReference(parentId), collationTolerance: tolerance },
|
|
578
|
+
...hypothesesBeside(stateOf(child), parentId)
|
|
579
|
+
];
|
|
508
580
|
});
|
|
509
581
|
};
|
|
510
582
|
/**
|
|
@@ -514,11 +586,12 @@ export const connectVersions = (view, childId, parentId, tolerance = defaultColl
|
|
|
514
586
|
*/
|
|
515
587
|
export const collateSymbols = (view, versionId, symbolIds, tolerance) => {
|
|
516
588
|
const version = view.get(versionId);
|
|
517
|
-
|
|
589
|
+
const principal = version && principalDerivationOf(version);
|
|
590
|
+
if (!version || !principal)
|
|
518
591
|
return noChange;
|
|
519
592
|
const chosen = new Set(symbolIds);
|
|
520
593
|
const own = insertedIn([version]).filter(symbol => chosen.has(symbol.id));
|
|
521
|
-
const collations = collationsOf(own, view.snapshot(idOf(
|
|
594
|
+
const collations = collationsOf(own, view.snapshot(idOf(principal)), symbol => view.placeOf(symbol), tolerance ?? collationToleranceOf(principal));
|
|
522
595
|
const collated = new Set(collations.map(({ symbol }) => symbol.id));
|
|
523
596
|
return onVersion(versionId, (version, draft) => {
|
|
524
597
|
handOverCarriers(view, draft, collations);
|
|
@@ -527,8 +600,8 @@ export const collateSymbols = (view, versionId, symbolIds, tolerance) => {
|
|
|
527
600
|
};
|
|
528
601
|
/**
|
|
529
602
|
* Makes the version stand on its own: what it inherited becomes its
|
|
530
|
-
* own insertions, and
|
|
531
|
-
* with the motivations that belonged to
|
|
603
|
+
* own insertions, and its derivations go, the hypotheses among them,
|
|
604
|
+
* with the motivations that belonged to them.
|
|
532
605
|
*/
|
|
533
606
|
export const detachVersion = (view, versionId) => {
|
|
534
607
|
const edits = view.snapshot(versionId).map(insertion);
|
|
@@ -538,13 +611,20 @@ export const detachVersion = (view, versionId) => {
|
|
|
538
611
|
version.motivations = [];
|
|
539
612
|
});
|
|
540
613
|
};
|
|
541
|
-
/**
|
|
614
|
+
/**
|
|
615
|
+
* Takes the version out. Whatever read its text against it comes to
|
|
616
|
+
* stand on its own, a hypothesis that something derives from it goes,
|
|
617
|
+
* and so does a copy's statement that it carries the version.
|
|
618
|
+
*/
|
|
542
619
|
export const removeVersion = (view, versionId) => {
|
|
543
620
|
const detachments = view.edition.versions
|
|
544
|
-
.filter(version =>
|
|
621
|
+
.filter(version => readsAgainst(version, versionId))
|
|
545
622
|
.map(version => detachVersion(view, version.id));
|
|
623
|
+
const namesIt = (reference) => idOf(reference) === versionId;
|
|
546
624
|
return draft => {
|
|
547
625
|
detachments.forEach(detach => detach(draft));
|
|
626
|
+
draft.versions.forEach(version => dropDerivations(version, namesIt));
|
|
627
|
+
draft.copies.forEach(copy => dropStatements(copy, namesIt));
|
|
548
628
|
draft.versions = without(draft.versions, version => version.id === versionId);
|
|
549
629
|
};
|
|
550
630
|
};
|
|
@@ -553,19 +633,39 @@ export const removeSymbols = (versionId, symbolIds) => onVersion(versionId, vers
|
|
|
553
633
|
/** Moves the edits into a new version based on this one. */
|
|
554
634
|
export const deriveVersion = (versionId, editIds) => onVersion(versionId, (version, draft) => {
|
|
555
635
|
const chosen = new Set(editIds);
|
|
556
|
-
const moved = version.
|
|
557
|
-
|
|
636
|
+
const moved = editsOf(version).filter(edit => chosen.has(edit.id));
|
|
637
|
+
if (version.edits)
|
|
638
|
+
version.edits = without(version.edits, edit => chosen.has(edit.id));
|
|
558
639
|
draft.versions.push({
|
|
559
640
|
type: 'Version',
|
|
560
641
|
id: v4(),
|
|
561
642
|
siglum: `${version.siglum}_derived`,
|
|
562
643
|
system: stateOf(version).system,
|
|
563
644
|
versionType: 'unicum',
|
|
564
|
-
basedOn: assignReference(versionId),
|
|
645
|
+
basedOn: [assignReference(versionId)],
|
|
565
646
|
edits: moved,
|
|
566
647
|
motivations: []
|
|
567
648
|
});
|
|
568
649
|
});
|
|
650
|
+
/**
|
|
651
|
+
* States that the version may also derive from the parent, beside what
|
|
652
|
+
* it derives from already: a hypothesis, such as a contamination, under
|
|
653
|
+
* the belief given. The text stays read against the principal derivation
|
|
654
|
+
* unless the belief holds this one more certain. A version derives from
|
|
655
|
+
* itself, or twice from one parent, in no statement.
|
|
656
|
+
*/
|
|
657
|
+
export const stateDerivation = (versionId, parentId, belief) => onVersion(versionId, version => {
|
|
658
|
+
const derivations = stateOf(version).basedOn ?? [];
|
|
659
|
+
if (parentId === versionId || derivations.some(derivation => idOf(derivation) === parentId))
|
|
660
|
+
return;
|
|
661
|
+
version.basedOn = [...derivations, referenceHeld(parentId, belief)];
|
|
662
|
+
});
|
|
663
|
+
/** Takes back the hypothesis that the version derives from the parent; the principal derivation goes with `detachVersion`. */
|
|
664
|
+
export const clearDerivation = (versionId, parentId) => onVersion(versionId, version => {
|
|
665
|
+
if (readsAgainst(stateOf(version), parentId))
|
|
666
|
+
return;
|
|
667
|
+
dropDerivations(version, derivation => idOf(derivation) === parentId);
|
|
668
|
+
});
|
|
569
669
|
const sameSequence = (a, b) => a.length === b.length && a.every((value, i) => value === b[i]);
|
|
570
670
|
const expressionTypesOf = (symbols) => symbols.filter((symbol) => symbol.type === 'expression').map(symbol => symbol.expressionType);
|
|
571
671
|
/**
|
|
@@ -640,7 +740,7 @@ export const mergeEdits = (view, versionId, toMerge) => {
|
|
|
640
740
|
merged.editType = guessEditType(view, versionId, merged);
|
|
641
741
|
const mergedIds = new Set(toMerge.map(edit => edit.id));
|
|
642
742
|
return onVersion(versionId, version => {
|
|
643
|
-
version.edits = [...version.
|
|
743
|
+
version.edits = [...editsOf(version).filter(edit => !mergedIds.has(edit.id)), merged];
|
|
644
744
|
});
|
|
645
745
|
};
|
|
646
746
|
/** Replaces the edit with one edit per inserted and one per deleted symbol. */
|
|
@@ -650,7 +750,7 @@ export const splitEdit = (versionId, toSplit) => {
|
|
|
650
750
|
...(toSplit.delete ?? []).map(deletion)
|
|
651
751
|
];
|
|
652
752
|
return onVersion(versionId, version => {
|
|
653
|
-
version.edits = [...version.
|
|
753
|
+
version.edits = [...editsOf(version).filter(edit => edit.id !== toSplit.id), ...parts];
|
|
654
754
|
});
|
|
655
755
|
};
|
|
656
756
|
/**
|
package/lib/index.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export * from './ReproducingSystem';
|
|
|
18
18
|
export * from './FeatureSource';
|
|
19
19
|
export * from './RollCopy';
|
|
20
20
|
export * from './reservations';
|
|
21
|
+
export * from './witnesses';
|
|
21
22
|
export * from './alignment';
|
|
22
23
|
export * from './Edition';
|
|
23
24
|
export * from './EditionView';
|
package/lib/index.js
CHANGED
|
@@ -18,6 +18,7 @@ export * from './ReproducingSystem';
|
|
|
18
18
|
export * from './FeatureSource';
|
|
19
19
|
export * from './RollCopy';
|
|
20
20
|
export * from './reservations';
|
|
21
|
+
export * from './witnesses';
|
|
21
22
|
export * from './alignment';
|
|
22
23
|
export * from './Edition';
|
|
23
24
|
export * from './EditionView';
|
package/lib/migrate.js
CHANGED
|
@@ -69,7 +69,27 @@ const withScale = (node) => {
|
|
|
69
69
|
const factor = (node.conditions ?? []).find(isPaperStretch)?.factor;
|
|
70
70
|
return factor === undefined ? node : { ...node, measurements: { ...node.measurements, scale: factor } };
|
|
71
71
|
};
|
|
72
|
-
|
|
72
|
+
/** A derivation written as a single one, before a version could name several. */
|
|
73
|
+
const isSingleDerivation = (basedOn) => basedOn !== null && typeof basedOn === 'object' && !Array.isArray(basedOn);
|
|
74
|
+
const withDerivationList = (node) => isSingleDerivation(node.basedOn) ? { ...node, basedOn: [node.basedOn] } : node;
|
|
75
|
+
/**
|
|
76
|
+
* A copy read on a roll reader was stated as a recording before a sound
|
|
77
|
+
* recording could be one. A sound recording gives no holes, so a recording
|
|
78
|
+
* with holes is a reading.
|
|
79
|
+
*/
|
|
80
|
+
const withReadingKind = (node) => node.readFrom?.kind === 'recording' && Array.isArray(node.features)
|
|
81
|
+
&& node.features.some((feature) => feature?.['@type'] === 'Hole')
|
|
82
|
+
? { ...node, readFrom: { ...node.readFrom, kind: 'reading' } }
|
|
83
|
+
: node;
|
|
84
|
+
/** A keeper nobody could name was written as an empty one before a copy could leave it out. */
|
|
85
|
+
const withoutEmptyKeeper = (node) => {
|
|
86
|
+
if (node.keeper?.name !== '' || node.keeper.sameAs?.length)
|
|
87
|
+
return node;
|
|
88
|
+
const { keeper: _unnamed, ...rest } = node;
|
|
89
|
+
return rest;
|
|
90
|
+
};
|
|
91
|
+
const migrateNode = (node) => [withRenamedKeys, withTypology, withReferences, withKeeper, withoutEmptyKeeper, withProductionNodes, withScale,
|
|
92
|
+
withDerivationList, withReadingKind]
|
|
73
93
|
.reduce((result, step) => step(result), node);
|
|
74
94
|
/** The items each walked, or the very same list where the walk changed none. */
|
|
75
95
|
const walked = (items) => {
|
|
@@ -181,7 +201,7 @@ const withSystems = (edition) => {
|
|
|
181
201
|
const withEditors = (edition) => !edition.creation || edition.creation.editors
|
|
182
202
|
? edition
|
|
183
203
|
: { ...edition, creation: { ...edition.creation, editors: [] } };
|
|
184
|
-
const statesNoTolerance = (version) => version.basedOn && !version.basedOn.collationTolerance;
|
|
204
|
+
const statesNoTolerance = (version) => isSingleDerivation(version.basedOn) && !version.basedOn.collationTolerance;
|
|
185
205
|
/**
|
|
186
206
|
* The collation tolerance was the edition's before it was stated on
|
|
187
207
|
* each derivation. An edition written then collated every version at
|
|
@@ -147,13 +147,12 @@ export function readFromPhillipsEroll(buffer, { system = welteT100, controlOffse
|
|
|
147
147
|
id: v4(),
|
|
148
148
|
ops: [],
|
|
149
149
|
conditions: [],
|
|
150
|
-
keeper: { name: '', sameAs: [] },
|
|
151
150
|
measurements: {},
|
|
152
151
|
production: { system: systemOf(system) },
|
|
153
152
|
modifications: [],
|
|
154
153
|
features,
|
|
155
154
|
readFrom: {
|
|
156
|
-
kind: '
|
|
155
|
+
kind: 'reading',
|
|
157
156
|
actor: assignObject({ name: 'Phillips, Peter', sameAs: [] }),
|
|
158
157
|
note: 'Read on Phillips’s pneumatic roll reader. The places are elapsed time put back onto the paper, and a hole runs as long as its switch stayed open, which is longer than the perforation.'
|
|
159
158
|
}
|
|
@@ -113,7 +113,6 @@ export function readFromSpencerBar(buffer, { rowsPerInch = SPENCER_ROWS_PER_INCH
|
|
|
113
113
|
id: v4(),
|
|
114
114
|
ops: [],
|
|
115
115
|
conditions: [],
|
|
116
|
-
keeper: { name: '', sameAs: [] },
|
|
117
116
|
measurements: {},
|
|
118
117
|
production: { system: systemOf(system) },
|
|
119
118
|
modifications: [],
|
|
@@ -157,7 +157,6 @@ export function readFromStanfordAton(atonString, { trackShift, system = welteT10
|
|
|
157
157
|
id: v4(),
|
|
158
158
|
ops: [],
|
|
159
159
|
conditions: [],
|
|
160
|
-
keeper: { name: '', sameAs: [] },
|
|
161
160
|
production: { system: systemOf(system) },
|
|
162
161
|
modifications: [],
|
|
163
162
|
...((scan ?? stanford) && { scan: scan ?? stanford?.scan }),
|
package/lib/reservations.d.ts
CHANGED
|
@@ -1,23 +1,30 @@
|
|
|
1
1
|
import { RollCopy } from "./RollCopy";
|
|
2
|
-
|
|
2
|
+
import { Version } from "./Version";
|
|
3
|
+
import { EditionView } from "./EditionView";
|
|
4
|
+
export declare const reservationTypes: readonly ['source-not-stated', 'source-undocumented', 'software-not-named', 'instrument-not-named', 'features-interpreted', 'no-physical-evidence', 'measurement-undocumented', 'not-calibrated', 'system-unknown', 'keeper-unknown'];
|
|
3
5
|
export type ReservationType = typeof reservationTypes[number];
|
|
4
6
|
/**
|
|
5
|
-
* Something an edition cannot vouch for in one of its copies
|
|
7
|
+
* Something an edition cannot vouch for in one of its copies or
|
|
8
|
+
* versions.
|
|
6
9
|
*
|
|
7
|
-
* A reservation is worked out from what the copy
|
|
8
|
-
* and is never written into the edition: it says that
|
|
9
|
-
*
|
|
10
|
-
* away. Nothing here describes the state of the paper, which is a
|
|
10
|
+
* A reservation is worked out from what the copy or version states
|
|
11
|
+
* about itself and is never written into the edition: it says that
|
|
12
|
+
* knowledge of it is incomplete, so filling in what is missing makes it
|
|
13
|
+
* go away. Nothing here describes the state of the paper, which is a
|
|
11
14
|
* condition of the copy.
|
|
12
15
|
*/
|
|
13
|
-
export interface Reservation {
|
|
14
|
-
type:
|
|
16
|
+
export interface Reservation<T extends string = ReservationType> {
|
|
17
|
+
type: T;
|
|
15
18
|
/** What the reservation means for a reader, in one sentence. */
|
|
16
19
|
note: string;
|
|
17
20
|
}
|
|
18
21
|
/**
|
|
19
22
|
* What the edition cannot vouch for in a copy, in the order the
|
|
20
23
|
* checks are listed: where its features came from first, then what
|
|
21
|
-
* the measurement leaves open.
|
|
24
|
+
* the measurement leaves open, then who holds it.
|
|
22
25
|
*/
|
|
23
26
|
export declare const reservationsAbout: (copy: RollCopy) => Reservation[];
|
|
27
|
+
export declare const versionReservationTypes: readonly ['text-not-stated', 'type-not-stated', 'witnessed-by-statement-only'];
|
|
28
|
+
export type VersionReservationType = typeof versionReservationTypes[number];
|
|
29
|
+
/** What the edition cannot vouch for in a version, in the order the checks are listed. */
|
|
30
|
+
export declare const reservationsAboutVersion: (view: EditionView, version: Readonly<Version>) => Reservation<VersionReservationType>[];
|
package/lib/reservations.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { bearsPhysicalEvidence, isMeasured, sourceLabels } from "./FeatureSource";
|
|
2
2
|
import { calibrationOf } from "./RollCopy";
|
|
3
3
|
import { trackerBarOf } from "./systems";
|
|
4
|
+
import { witnessesOf } from "./witnesses";
|
|
4
5
|
export const reservationTypes = [
|
|
5
6
|
'source-not-stated',
|
|
6
7
|
'source-undocumented',
|
|
8
|
+
'software-not-named',
|
|
9
|
+
'instrument-not-named',
|
|
7
10
|
'features-interpreted',
|
|
8
11
|
'no-physical-evidence',
|
|
9
12
|
'measurement-undocumented',
|
|
10
13
|
'not-calibrated',
|
|
11
|
-
'system-unknown'
|
|
14
|
+
'system-unknown',
|
|
15
|
+
'keeper-unknown'
|
|
12
16
|
];
|
|
13
17
|
const sourceStated = copy => copy.readFrom ? undefined : {
|
|
14
18
|
type: 'source-not-stated',
|
|
@@ -23,6 +27,20 @@ const sourceDocumented = copy => {
|
|
|
23
27
|
note: `The copy names ${sourceLabels[source.kind]} as its source, but records nobody who made it, no device and no date.`
|
|
24
28
|
};
|
|
25
29
|
};
|
|
30
|
+
/** An emulation and a recording are turned into notes by software, which says how far to trust them. */
|
|
31
|
+
const softwareNamed = copy => {
|
|
32
|
+
const source = copy.readFrom;
|
|
33
|
+
if (!source || isMeasured(source.kind) || source.software?.length)
|
|
34
|
+
return undefined;
|
|
35
|
+
return {
|
|
36
|
+
type: 'software-not-named',
|
|
37
|
+
note: `The copy names ${sourceLabels[source.kind]} as its source, but not the software that turned it into notes.`
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
const instrumentNamed = copy => copy.readFrom?.kind === 'recording' && !copy.readFrom.instrument ? {
|
|
41
|
+
type: 'instrument-not-named',
|
|
42
|
+
note: 'The copy is known from a recording, but neither the instrument it was played on nor its regulation is named.'
|
|
43
|
+
} : undefined;
|
|
26
44
|
const featuresMeasured = copy => copy.readFrom && !isMeasured(copy.readFrom.kind) ? {
|
|
27
45
|
type: 'features-interpreted',
|
|
28
46
|
note: `The features come from ${sourceLabels[copy.readFrom.kind]}, in which the roll has already been read into notes and commands by somebody else.`
|
|
@@ -58,18 +76,50 @@ const systemKnown = copy => {
|
|
|
58
76
|
note: `The copy names ${system.name || 'a reproducing system'}, which the edition has no tracker bar for, so it is read by the T-100's.`
|
|
59
77
|
};
|
|
60
78
|
};
|
|
79
|
+
const keeperKnown = copy => copy.keeper ? undefined : {
|
|
80
|
+
type: 'keeper-unknown',
|
|
81
|
+
note: 'Nobody is known to hold the copy, so its paper cannot be consulted.'
|
|
82
|
+
};
|
|
83
|
+
/** A check on what a copy's features leave open, which has nothing to say of a copy without any. */
|
|
84
|
+
const onFeatures = (check) => copy => copy.features.length > 0 ? check(copy) : undefined;
|
|
61
85
|
const checks = [
|
|
62
86
|
sourceStated,
|
|
63
87
|
sourceDocumented,
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
88
|
+
softwareNamed,
|
|
89
|
+
instrumentNamed,
|
|
90
|
+
onFeatures(featuresMeasured),
|
|
91
|
+
onFeatures(physicalEvidence),
|
|
92
|
+
onFeatures(measurementDocumented),
|
|
93
|
+
onFeatures(calibrated),
|
|
94
|
+
onFeatures(systemKnown),
|
|
95
|
+
keeperKnown
|
|
69
96
|
];
|
|
70
97
|
/**
|
|
71
98
|
* What the edition cannot vouch for in a copy, in the order the
|
|
72
99
|
* checks are listed: where its features came from first, then what
|
|
73
|
-
* the measurement leaves open.
|
|
100
|
+
* the measurement leaves open, then who holds it.
|
|
74
101
|
*/
|
|
75
102
|
export const reservationsAbout = (copy) => checks.flatMap(check => check(copy) ?? []);
|
|
103
|
+
export const versionReservationTypes = [
|
|
104
|
+
'text-not-stated',
|
|
105
|
+
'type-not-stated',
|
|
106
|
+
'witnessed-by-statement-only'
|
|
107
|
+
];
|
|
108
|
+
const textStated = (_view, version) => version.edits ? undefined : {
|
|
109
|
+
type: 'text-not-stated',
|
|
110
|
+
note: 'The version does not state its edits, so it reads as the version it derives from.'
|
|
111
|
+
};
|
|
112
|
+
const typeStated = (_view, version) => version.versionType ? undefined : {
|
|
113
|
+
type: 'type-not-stated',
|
|
114
|
+
note: 'The version does not say whether it served as a master for several copies or exists on one only.'
|
|
115
|
+
};
|
|
116
|
+
const witnessedByFeatures = (view, version) => {
|
|
117
|
+
const witnesses = witnessesOf(view, version.id);
|
|
118
|
+
return witnesses.length > 0 && witnesses.every(({ by }) => by === 'statement') ? {
|
|
119
|
+
type: 'witnessed-by-statement-only',
|
|
120
|
+
note: 'No copy\'s features carry what the version inserts; only copies that state they carry it bear witness to it.'
|
|
121
|
+
} : undefined;
|
|
122
|
+
};
|
|
123
|
+
const versionChecks = [textStated, typeStated, witnessedByFeatures];
|
|
124
|
+
/** What the edition cannot vouch for in a version, in the order the checks are listed. */
|
|
125
|
+
export const reservationsAboutVersion = (view, version) => versionChecks.flatMap(check => check(view, version) ?? []);
|