linked-rolls 0.32.0 → 0.34.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.
@@ -32,8 +32,8 @@ export declare class EditionView {
32
32
  getPath(anyId: string): Path | undefined;
33
33
  linksTo(anyId: string): Path[];
34
34
  travelUp(versionId: string, callback: (version: Readonly<Version>) => void): void;
35
- /** The version and its ancestors, from the version up to the root. */
36
- private lineageOf;
35
+ /** The version and its ancestors along the principal line, from the version up to the root. */
36
+ lineageOf(versionId: string): Readonly<Version>[];
37
37
  carriersOf(symbol: AnySymbol): Readonly<AnyFeature>[];
38
38
  /** The copy a feature sits on, a patch and everything it bears included. */
39
39
  copyOf(featureId: string): Readonly<RollCopy> | undefined;
@@ -143,7 +143,7 @@ export class EditionView {
143
143
  this.travelUp(idOf(principal), callback);
144
144
  }
145
145
  }
146
- /** The version and its ancestors, from the version up to the root. */
146
+ /** The version and its ancestors along the principal line, from the version up to the root. */
147
147
  lineageOf(versionId) {
148
148
  const lineage = [];
149
149
  this.travelUp(versionId, version => lineage.push(version));
@@ -24,7 +24,7 @@ export interface Reservation<T extends string = ReservationType> {
24
24
  * the measurement leaves open, then who holds it.
25
25
  */
26
26
  export declare const reservationsAbout: (copy: RollCopy) => Reservation[];
27
- export declare const versionReservationTypes: readonly ['text-not-stated', 'witnessed-by-statement-only'];
27
+ export declare const versionReservationTypes: readonly ['text-not-stated', 'witnessed-by-statement-only', 'no-direct-witness'];
28
28
  export type VersionReservationType = typeof versionReservationTypes[number];
29
29
  /** What the edition cannot vouch for in a version, in the order the checks are listed. */
30
30
  export declare const reservationsAboutVersion: (view: EditionView, version: Readonly<Version>) => Reservation<VersionReservationType>[];
@@ -102,7 +102,8 @@ const checks = [
102
102
  export const reservationsAbout = (copy) => checks.flatMap(check => check(copy) ?? []);
103
103
  export const versionReservationTypes = [
104
104
  'text-not-stated',
105
- 'witnessed-by-statement-only'
105
+ 'witnessed-by-statement-only',
106
+ 'no-direct-witness'
106
107
  ];
107
108
  const textStated = (_view, version) => version.edits ? undefined : {
108
109
  type: 'text-not-stated',
@@ -115,6 +116,18 @@ const witnessedByFeatures = (view, version) => {
115
116
  note: 'No copy\'s features carry what the version inserts; only copies that state they carry it bear witness to it.'
116
117
  } : undefined;
117
118
  };
118
- const versionChecks = [textStated, witnessedByFeatures];
119
+ /**
120
+ * A version every copy reaches only through a version derived from it.
121
+ * Its text is a reconstruction from below, as a lost state's is, and
122
+ * nothing surviving shows it as it stood.
123
+ */
124
+ const witnessedAtFirstHand = (view, version) => {
125
+ const carriers = witnessesOf(view, version.id).filter(({ by }) => by === 'carriers');
126
+ return carriers.length > 0 && carriers.every(({ through }) => through !== undefined) ? {
127
+ type: 'no-direct-witness',
128
+ note: 'No copy carries it at first hand; it is attested only through the versions derived from it.'
129
+ } : undefined;
130
+ };
131
+ const versionChecks = [textStated, witnessedByFeatures, witnessedAtFirstHand];
119
132
  /** What the edition cannot vouch for in a version, in the order the checks are listed. */
120
133
  export const reservationsAboutVersion = (view, version) => versionChecks.flatMap(check => check(view, version) ?? []);
@@ -7,6 +7,13 @@ export interface Witness {
7
7
  copy: string;
8
8
  /** Whether the copy's features carry what the version inserts, or the copy states that it carries the version. */
9
9
  by: WitnessBy;
10
+ /**
11
+ * The later version this copy reaches the version through, where its
12
+ * features carry what a version derived from this one inserts. It then
13
+ * attests the text only as that later version passed it on. A copy
14
+ * that bears witness at first hand names none.
15
+ */
16
+ through?: string;
10
17
  /** How certainly a statement is held. Carriage through features is no statement and holds none. */
11
18
  certainty?: Certainty;
12
19
  /** The belief a statement rests on, where it states one. */
@@ -18,8 +25,17 @@ export interface Witness {
18
25
  * it, with the certainty each statement is held with.
19
26
  *
20
27
  * What a version inherits is carried by nearly every copy of the roll, so
21
- * only what it inserts tells its witnesses apart. A version whose edits
22
- * are not stated is witnessed by statement alone.
28
+ * only what it inserts tells its witnesses apart from its ancestors'. Its
29
+ * insertions are in turn inherited downwards, and the copies of the
30
+ * versions derived from it carry them as well. Those bear witness to it
31
+ * only through the latest state they carry, which `through` names; a copy
32
+ * carrying nothing a later version inserts speaks for the version at first
33
+ * hand. A version no copy attests at first hand survives, as a lost state
34
+ * does, in what its descendants passed on.
35
+ *
36
+ * A statement is the editor's own about the version it names and is
37
+ * reported as it stands. A version whose edits are not stated inserts
38
+ * nothing and is witnessed by statement alone.
23
39
  */
24
40
  export declare const witnessesOf: (view: EditionView, versionId: string) => Witness[];
25
41
  /**
package/lib/witnesses.js CHANGED
@@ -7,25 +7,36 @@ const copiesCarrying = (view, symbols) => new Set(symbols
7
7
  const copy = view.copyOf(id);
8
8
  return copy ? [copy.id] : [];
9
9
  }));
10
- /**
11
- * The copies that bear witness to the version: those whose features carry
12
- * a symbol the version's own edits insert, and those that state they carry
13
- * it, with the certainty each statement is held with.
14
- *
15
- * What a version inherits is carried by nearly every copy of the roll, so
16
- * only what it inserts tells its witnesses apart. A version whose edits
17
- * are not stated is witnessed by statement alone.
18
- */
19
- export const witnessesOf = (view, versionId) => {
20
- const version = view.get(versionId);
21
- if (!version)
22
- return [];
10
+ /** Every copy carrying what a version inserts, version by version, the copies in the order the edition lists them. */
11
+ const carriagesIn = (view) => view.edition.versions.flatMap(version => {
23
12
  const carrying = copiesCarrying(view, insertedBy(version));
24
- const byCarriers = view.edition.copies
13
+ const depth = view.lineageOf(version.id).length;
14
+ return view.edition.copies
25
15
  .filter(copy => carrying.has(copy.id))
26
- .map((copy) => ({ copy: copy.id, by: 'carriers' }));
16
+ .map((copy) => ({ copy: copy.id, version: version.id, depth }));
17
+ });
18
+ const carriersIn = (view) => {
19
+ const carriages = carriagesIn(view);
20
+ return {
21
+ copiesOf: new Map(view.edition.versions.map(version => [
22
+ version.id,
23
+ carriages.filter(carriage => carriage.version === version.id).map(carriage => carriage.copy)
24
+ ])),
25
+ // Written in order of depth, so a copy's latest carriage is set last and stands.
26
+ latestOf: new Map([...carriages]
27
+ .sort((one, other) => one.depth - other.depth)
28
+ .map(carriage => [carriage.copy, carriage.version]))
29
+ };
30
+ };
31
+ const witnessesIn = (carriers, view, versionId) => {
32
+ const carrying = carriers.copiesOf.get(versionId) ?? [];
33
+ const byCarriers = carrying.map((copy) => {
34
+ const latest = carriers.latestOf.get(copy);
35
+ return { copy, by: 'carriers', ...(latest !== undefined && latest !== versionId && { through: latest }) };
36
+ });
37
+ const carryingIt = new Set(carrying);
27
38
  const byStatement = view.edition.copies
28
- .filter(copy => !carrying.has(copy.id))
39
+ .filter(copy => !carryingIt.has(copy.id))
29
40
  .flatMap(copy => (copy.carries ?? [])
30
41
  .filter(statement => idOf(statement) === versionId)
31
42
  .map((statement) => {
@@ -34,13 +45,35 @@ export const witnessesOf = (view, versionId) => {
34
45
  }));
35
46
  return [...byCarriers, ...byStatement];
36
47
  };
48
+ /**
49
+ * The copies that bear witness to the version: those whose features carry
50
+ * a symbol the version's own edits insert, and those that state they carry
51
+ * it, with the certainty each statement is held with.
52
+ *
53
+ * What a version inherits is carried by nearly every copy of the roll, so
54
+ * only what it inserts tells its witnesses apart from its ancestors'. Its
55
+ * insertions are in turn inherited downwards, and the copies of the
56
+ * versions derived from it carry them as well. Those bear witness to it
57
+ * only through the latest state they carry, which `through` names; a copy
58
+ * carrying nothing a later version inserts speaks for the version at first
59
+ * hand. A version no copy attests at first hand survives, as a lost state
60
+ * does, in what its descendants passed on.
61
+ *
62
+ * A statement is the editor's own about the version it names and is
63
+ * reported as it stands. A version whose edits are not stated inserts
64
+ * nothing and is witnessed by statement alone.
65
+ */
66
+ export const witnessesOf = (view, versionId) => view.get(versionId) ? witnessesIn(carriersIn(view), view, versionId) : [];
37
67
  /**
38
68
  * The versions the copy bears witness to, each with how, in the order the
39
69
  * edition lists its versions.
40
70
  */
41
- export const versionsWitnessedBy = (view, copyId) => view.edition.versions.flatMap(version => witnessesOf(view, version.id)
42
- .filter(witness => witness.copy === copyId)
43
- .map(witness => ({ ...witness, version: version.id })));
71
+ export const versionsWitnessedBy = (view, copyId) => {
72
+ const carriers = carriersIn(view);
73
+ return view.edition.versions.flatMap(version => witnessesIn(carriers, view, version.id)
74
+ .filter(witness => witness.copy === copyId)
75
+ .map(witness => ({ ...witness, version: version.id })));
76
+ };
44
77
  /**
45
78
  * Where a copy's statement that it carries a version cannot stand: one
46
79
  * made although the copy's features carry symbols, which say by
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linked-rolls",
3
- "version": "0.32.0",
3
+ "version": "0.34.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": {