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.
- package/README.md +62 -26
- package/lib/collation/Collation.d.ts +12 -42
- package/lib/collation/Collation.js +15 -48
- package/lib/filiation/adoption.d.ts +23 -4
- package/lib/filiation/adoption.js +81 -23
- package/lib/filiation/edits.d.ts +35 -19
- package/lib/filiation/edits.js +68 -34
- package/lib/filiation/index.d.ts +2 -1
- package/lib/filiation/index.js +2 -1
- package/lib/filiation/record.d.ts +49 -0
- package/lib/filiation/record.js +49 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/io/asJsonLd.js +5 -1
- package/lib/io/importJsonLd.js +42 -4
- package/lib/io/migrate.d.ts +7 -0
- package/lib/io/migrate.js +196 -2
- package/lib/model/Agent.d.ts +3 -1
- package/lib/model/Assumption.d.ts +8 -1
- package/lib/model/Assumption.js +2 -1
- package/lib/model/Edit.d.ts +76 -17
- package/lib/model/Edit.js +52 -3
- package/lib/model/Edition.d.ts +32 -3
- package/lib/model/RollCopy.js +1 -1
- package/lib/model/Version.d.ts +3 -13
- package/lib/model/Version.js +7 -2
- package/lib/ops/collation.d.ts +8 -4
- package/lib/ops/collation.js +40 -23
- package/lib/ops/copies.js +1 -2
- package/lib/ops/draft.d.ts +1 -9
- package/lib/ops/draft.js +0 -12
- package/lib/ops/edits.d.ts +20 -3
- package/lib/ops/edits.js +36 -15
- package/lib/ops/index.d.ts +1 -1
- package/lib/ops/index.js +1 -1
- package/lib/ops/versions.d.ts +3 -2
- package/lib/ops/versions.js +4 -5
- package/lib/schema.json +60 -64
- package/lib/software.d.ts +12 -0
- package/lib/software.js +10 -0
- package/lib/spec/context.json +8 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -132,6 +132,22 @@ edits the editor wrote, which hold their versions to what they insert
|
|
|
132
132
|
and delete. Motivations, beliefs and versions known only from a
|
|
133
133
|
recording remain the editor's to state.
|
|
134
134
|
|
|
135
|
+
What the program concluded is stated plainly, as an edition states its
|
|
136
|
+
stemma. The edition's creation names how it was found: the published
|
|
137
|
+
rules the costs carry out among its principles (`stemmaRules`), and
|
|
138
|
+
this release of the library among its software, which finds the
|
|
139
|
+
stemma again with the defaults it has. A derivation the editor holds
|
|
140
|
+
under a belief of their own, and an edit that says why it was made,
|
|
141
|
+
stay as they are. Among the versions, derivations and edits, whatever
|
|
142
|
+
carries neither a belief nor a motivation of the editor's is the
|
|
143
|
+
program's.
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
const adopted = produce(edition, adoptStemma(proposal))
|
|
147
|
+
adopted.creation.principles // ['https://welte225.org/rules#shared-addition', …]
|
|
148
|
+
adopted.creation.software // [{ name: 'linked-rolls', version: '0.76.0' }]
|
|
149
|
+
```
|
|
150
|
+
|
|
135
151
|
The costs are those with which the stemma of WM 225 comes out of its
|
|
136
152
|
six copies. They were found by searching for such values, so they show
|
|
137
153
|
that the stemma is consistent with these principles, not that the
|
|
@@ -139,24 +155,26 @@ principles confirm it.
|
|
|
139
155
|
|
|
140
156
|
## Proposing the edits
|
|
141
157
|
|
|
142
|
-
What a version inserts and deletes can be grouped into edits and
|
|
143
|
-
|
|
144
|
-
line, a latched function, a held one or a pitch, and
|
|
145
|
-
command both texts keep, so that an edit stays at one
|
|
146
|
-
turned on and off again is one edit,
|
|
147
|
-
the bar spells an accent so; a perforation put elsewhere
|
|
148
|
-
with the one it replaces,
|
|
149
|
-
where it begins about where the other did; overlapping notes
|
|
150
|
-
edit, a note struck again or two tied; a held command standing
|
|
151
|
-
latched pair is one recoding; a command the text makes no use of
|
|
152
|
-
redundancy added or removed; cancels punched across lines at one
|
|
153
|
-
are one row. `adoptEdits` puts the proposal in place of the
|
|
154
|
-
|
|
158
|
+
What a version inserts and deletes can be grouped into edits, and the
|
|
159
|
+
shape of each read off them alone. `proposeEdits` reads a version's
|
|
160
|
+
changes line by line, a latched function, a held one or a pitch, and
|
|
161
|
+
never across a command both texts keep, so that an edit stays at one
|
|
162
|
+
place. A function turned on and off again is one edit, an additional
|
|
163
|
+
accent where the bar spells an accent so; a perforation put elsewhere
|
|
164
|
+
is one move with the one it replaces, a shift, or shortened or
|
|
165
|
+
prolonged where it begins about where the other did; overlapping notes
|
|
166
|
+
are one edit, a note struck again or two tied; a held command standing
|
|
167
|
+
for a latched pair is one recoding; a command the text makes no use of
|
|
168
|
+
is a redundancy added or removed; cancels punched across lines at one
|
|
169
|
+
place are one row. `adoptEdits` puts the proposal in place of the
|
|
170
|
+
program's edits, those that say nothing of why they were made or only
|
|
171
|
+
that they are musical or technical changes, and keeps the rest. Its creation comes to
|
|
172
|
+
name the rule that keeps an edit at one place among its principles.
|
|
155
173
|
|
|
156
174
|
```ts
|
|
157
175
|
import { adoptEdits, adoptStemma, proposeEdits, proposeStemma } from 'linked-rolls'
|
|
158
176
|
|
|
159
|
-
proposeEdits(edition, versionId) // [{ insert, delete,
|
|
177
|
+
proposeEdits(edition, versionId) // [{ insert, delete, shape, grouping }, …]
|
|
160
178
|
|
|
161
179
|
// The stemma and the edits of its versions, as one undo step
|
|
162
180
|
const adopted = produce(edition, draft => {
|
|
@@ -165,12 +183,26 @@ const adopted = produce(edition, draft => {
|
|
|
165
183
|
})
|
|
166
184
|
```
|
|
167
185
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
186
|
+
Every change of a version that derives from another states a
|
|
187
|
+
motivation, and the motivation says what kind of change it is
|
|
188
|
+
(`kindOfChange`). A program states it from the shape of the change: a
|
|
189
|
+
redundancy cleaned up or added, or a command recoded for another
|
|
190
|
+
system, is a technical change (`technicalChange`), which the procedure
|
|
191
|
+
of the version's creation explains; an added accent, a shift, a
|
|
192
|
+
shortening or a prolongation is a musical change (`musicalChange`),
|
|
193
|
+
under the rule that later versions are the more refined. The editor
|
|
194
|
+
may say otherwise, and adopting the edits again keeps the kind an edit
|
|
195
|
+
over the same changes states. The editor speculates on the musical
|
|
196
|
+
changes only: a reason of their own, which the edition states once
|
|
197
|
+
(`Edition.motivations`) and any version's edits name, takes the place of
|
|
198
|
+
the generic musical motivation. The edits of a version that derives from none state its
|
|
199
|
+
text, and no motivation.
|
|
200
|
+
|
|
201
|
+
On WM 225 the proposal reproduces 601 of the 690 edits of the versions
|
|
202
|
+
that derive from another, from what each version changes, and from the
|
|
203
|
+
copies alone, through the proposed stemma, 554. It agrees with the
|
|
204
|
+
editor on what kind of change an edit is but for two, each a reason the
|
|
205
|
+
editor gives for what the program reads as a redundancy.
|
|
174
206
|
|
|
175
207
|
## Format
|
|
176
208
|
|
|
@@ -182,7 +214,10 @@ https://pfefferniels.github.io/linked-rolls/, to which the w3id.org
|
|
|
182
214
|
identifiers redirect.
|
|
183
215
|
|
|
184
216
|
Beliefs are written as JSON-LD-star annotations (`@annotation`), so you
|
|
185
|
-
need a processor that supports JSON-LD-star to read them.
|
|
217
|
+
need a processor that supports JSON-LD-star to read them. They are kept
|
|
218
|
+
for what the editor doubts; everything else, the stemma and the edits a
|
|
219
|
+
program found among it, is stated plainly and reaches RDF with any
|
|
220
|
+
JSON-LD processor.
|
|
186
221
|
|
|
187
222
|
## Development
|
|
188
223
|
|
|
@@ -199,11 +234,12 @@ TypeScript 7 no longer has the compiler API it reads the source with.
|
|
|
199
234
|
|
|
200
235
|
## Releasing
|
|
201
236
|
|
|
202
|
-
Raise the version in `package.json
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
237
|
+
Raise the version in `package.json`, in `CITATION.cff`, there with the
|
|
238
|
+
day as `date-released`, and in `src/software.ts`, which names the release
|
|
239
|
+
in the edition's creation when a proposal is adopted. Then commit, and push a tag
|
|
240
|
+
`v<version>`. The `publish.yml` workflow builds, tests and publishes to
|
|
241
|
+
npm, then makes a GitHub release of the tag, which Zenodo archives with
|
|
242
|
+
a DOI. A test fails while the versions differ.
|
|
207
243
|
|
|
208
244
|
## About
|
|
209
245
|
|
|
@@ -120,50 +120,20 @@ export type Collation = {
|
|
|
120
120
|
*/
|
|
121
121
|
export declare const collationsOf: (own: readonly Readonly<AnySymbol>[], inherited: readonly Readonly<AnySymbol>[], locate: Locate, tolerance?: CollationTolerance) => Collation[];
|
|
122
122
|
/**
|
|
123
|
-
*
|
|
124
|
-
* nobody has
|
|
123
|
+
* Whether the edit is the program's: one that a collation or a proposal
|
|
124
|
+
* wrote and nobody has explained, so that collating again or proposing
|
|
125
|
+
* the edits again may write it anew. It carries no belief and names no
|
|
126
|
+
* motivation of the editor's: only the kind of change it is, the generic
|
|
127
|
+
* musical or technical one a program states (`musicalChange`,
|
|
128
|
+
* `technicalChange`), or none.
|
|
125
129
|
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
* middle: the readings are there to be seen and argued with, and a
|
|
130
|
-
* reader can tell which of them anybody has weighed.
|
|
130
|
+
* Everything else is the editor's and stays: an edit that says why it
|
|
131
|
+
* was made, or that is held under a belief. A grouping of the editor's stays theirs once it says
|
|
132
|
+
* why; one that says nothing reads as the program's would.
|
|
131
133
|
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
* @category Collation and alignment
|
|
136
|
-
*/
|
|
137
|
-
export declare const unchecked = "unchecked";
|
|
138
|
-
/**
|
|
139
|
-
* The version's statement of what the unchecked motivation means, to stand in its `motivations`.
|
|
140
|
-
* @category Collation and alignment
|
|
141
|
-
*/
|
|
142
|
-
export declare const uncheckedMotivation: {
|
|
143
|
-
readonly type: 'motivation';
|
|
144
|
-
readonly id: "unchecked";
|
|
145
|
-
readonly note: 'Made by collating the two texts and not yet read by an editor.';
|
|
146
|
-
};
|
|
147
|
-
/**
|
|
148
|
-
* Whether the edit is one a collation writes by itself: a bare
|
|
149
|
-
* insertion or a bare deletion saying nothing further, or a recoding
|
|
150
|
-
* that exchanges two systems' spellings for one command.
|
|
151
|
-
*
|
|
152
|
-
* Collating again rewrites these and keeps the rest. An edit that says
|
|
153
|
-
* what the change is, or why it was made, or what it rests on, is an
|
|
154
|
-
* editor's reading of the difference between two texts, and collating
|
|
155
|
-
* the two again is no reason to discard it.
|
|
156
|
-
*
|
|
157
|
-
* Such an exchange counts as the collation's own even where an editor
|
|
158
|
-
* added a motivation to it, because it is derived rather than read:
|
|
159
|
-
* freezing it would leave the transfers, where nearly every edit is
|
|
160
|
-
* one, unable to be collated again at all. What an editor wrote on it
|
|
161
|
-
* is not lost by that, since `connectVersions` keeps an exchange it
|
|
162
|
-
* draws a second time over the very same symbols.
|
|
163
|
-
*
|
|
164
|
-
* A recoding that only inserts or only deletes is the editor's: a
|
|
165
|
-
* collation types no one-sided edit, so one typed so is a reading of
|
|
166
|
-
* the transfer that collating again must not undo.
|
|
134
|
+
* An exchange a collation draws again over the very same symbols is
|
|
135
|
+
* kept as it stands, with its identifier and whatever was written on
|
|
136
|
+
* it (`connectVersions`).
|
|
167
137
|
* @category Collation and alignment
|
|
168
138
|
*/
|
|
169
139
|
export declare const isCollationsOwn: (edit: Readonly<Edit>) => boolean;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { musicalChange, technicalChange } from "../model/Edit.js";
|
|
1
2
|
import { keyOf } from "../systems/TrackerBar.js";
|
|
2
3
|
import { distance, mm } from "../model/Quantity.js";
|
|
3
4
|
import { partitionPoint } from "../shared/sorted.js";
|
|
@@ -106,56 +107,22 @@ export const collationsOf = (own, inherited, locate, tolerance = defaultCollatio
|
|
|
106
107
|
.sort((a, b) => a.index - b.index)
|
|
107
108
|
.map(({ symbol: counterpart }) => ({ symbol, counterpart })));
|
|
108
109
|
};
|
|
109
|
-
/** The edit type a collation draws by itself, from the two systems' vocabularies rather than off the paper. */
|
|
110
|
-
const drawnByCollation = 'recoding';
|
|
111
110
|
/**
|
|
112
|
-
*
|
|
113
|
-
* nobody has
|
|
111
|
+
* Whether the edit is the program's: one that a collation or a proposal
|
|
112
|
+
* wrote and nobody has explained, so that collating again or proposing
|
|
113
|
+
* the edits again may write it anew. It carries no belief and names no
|
|
114
|
+
* motivation of the editor's: only the kind of change it is, the generic
|
|
115
|
+
* musical or technical one a program states (`musicalChange`,
|
|
116
|
+
* `technicalChange`), or none.
|
|
114
117
|
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
* middle: the readings are there to be seen and argued with, and a
|
|
119
|
-
* reader can tell which of them anybody has weighed.
|
|
118
|
+
* Everything else is the editor's and stays: an edit that says why it
|
|
119
|
+
* was made, or that is held under a belief. A grouping of the editor's stays theirs once it says
|
|
120
|
+
* why; one that says nothing reads as the program's would.
|
|
120
121
|
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
122
|
+
* An exchange a collation draws again over the very same symbols is
|
|
123
|
+
* kept as it stands, with its identifier and whatever was written on
|
|
124
|
+
* it (`connectVersions`).
|
|
124
125
|
* @category Collation and alignment
|
|
125
126
|
*/
|
|
126
|
-
export const
|
|
127
|
-
|
|
128
|
-
* The version's statement of what the unchecked motivation means, to stand in its `motivations`.
|
|
129
|
-
* @category Collation and alignment
|
|
130
|
-
*/
|
|
131
|
-
export const uncheckedMotivation = {
|
|
132
|
-
type: 'motivation',
|
|
133
|
-
id: unchecked,
|
|
134
|
-
note: 'Made by collating the two texts and not yet read by an editor.'
|
|
135
|
-
};
|
|
136
|
-
/**
|
|
137
|
-
* Whether the edit is one a collation writes by itself: a bare
|
|
138
|
-
* insertion or a bare deletion saying nothing further, or a recoding
|
|
139
|
-
* that exchanges two systems' spellings for one command.
|
|
140
|
-
*
|
|
141
|
-
* Collating again rewrites these and keeps the rest. An edit that says
|
|
142
|
-
* what the change is, or why it was made, or what it rests on, is an
|
|
143
|
-
* editor's reading of the difference between two texts, and collating
|
|
144
|
-
* the two again is no reason to discard it.
|
|
145
|
-
*
|
|
146
|
-
* Such an exchange counts as the collation's own even where an editor
|
|
147
|
-
* added a motivation to it, because it is derived rather than read:
|
|
148
|
-
* freezing it would leave the transfers, where nearly every edit is
|
|
149
|
-
* one, unable to be collated again at all. What an editor wrote on it
|
|
150
|
-
* is not lost by that, since `connectVersions` keeps an exchange it
|
|
151
|
-
* draws a second time over the very same symbols.
|
|
152
|
-
*
|
|
153
|
-
* A recoding that only inserts or only deletes is the editor's: a
|
|
154
|
-
* collation types no one-sided edit, so one typed so is a reading of
|
|
155
|
-
* the transfer that collating again must not undo.
|
|
156
|
-
* @category Collation and alignment
|
|
157
|
-
*/
|
|
158
|
-
export const isCollationsOwn = (edit) => (edit.editType === drawnByCollation && !!edit.insert?.length && !!edit.delete?.length)
|
|
159
|
-
|| (edit.editType === undefined
|
|
160
|
-
&& (edit.motivation === undefined || edit.motivation === unchecked)
|
|
161
|
-
&& edit['@annotation'] === undefined);
|
|
127
|
+
export const isCollationsOwn = (edit) => edit['@annotation'] === undefined
|
|
128
|
+
&& (edit.motivation === undefined || edit.motivation === musicalChange || edit.motivation === technicalChange);
|
|
@@ -15,6 +15,12 @@ export interface Adoption {
|
|
|
15
15
|
removed: string[];
|
|
16
16
|
/** The edits the editor wrote that the adoption leaves out, and why. */
|
|
17
17
|
dropped: Unpinned[];
|
|
18
|
+
/**
|
|
19
|
+
* The published rules the proposal follows, as far as its costs and
|
|
20
|
+
* settings carry them out, which the edition's creation comes to
|
|
21
|
+
* name among its principles.
|
|
22
|
+
*/
|
|
23
|
+
principles: string[];
|
|
18
24
|
}
|
|
19
25
|
/**
|
|
20
26
|
* What adopting the proposal makes of the edition's stemma, worked out
|
|
@@ -28,20 +34,33 @@ export interface Adoption {
|
|
|
28
34
|
* the edits the editor wrote that the proposal keeps, as they are, and
|
|
29
35
|
* one edit for each further reading it inserts or deletes, or for each
|
|
30
36
|
* recoding. An edit the version stated before over the very same
|
|
31
|
-
* readings is taken over with its id and what was written on it
|
|
32
|
-
*
|
|
37
|
+
* readings is taken over with its id and what was written on it, the
|
|
38
|
+
* kind of change it states among it, which the editor may have said
|
|
39
|
+
* otherwise than the program read it; the others are new. An edit that
|
|
40
|
+
* states no kind has the motivation the shape of the change calls for
|
|
41
|
+
* (`motivationProposedFor`): the generic musical one, whose reason is
|
|
42
|
+
* left to the editor, or the technical one, which a recoding always has.
|
|
43
|
+
* The edits of the root state its text, and no kind of change.
|
|
33
44
|
*
|
|
34
45
|
* A reading that stands for a symbol of the edition keeps that symbol's
|
|
35
46
|
* id and whatever it states beside its carriers. A version of the edition
|
|
36
47
|
* nothing stands for goes, unless it states no edits and derives from a
|
|
37
48
|
* version that stays, as a version known only from a recording does.
|
|
49
|
+
*
|
|
50
|
+
* What the program concluded is stated plainly, as an edition states its
|
|
51
|
+
* stemma. A derivation the editor holds under a belief of their own
|
|
52
|
+
* stays as it is, and so does every edit that says why it was made.
|
|
38
53
|
* @category Filiation
|
|
39
54
|
*/
|
|
40
55
|
export declare const adoptionOf: (edition: Edition, proposal: StemmaProposal) => Adoption;
|
|
41
56
|
/**
|
|
42
57
|
* Puts the proposed stemma in place of the edition's, as `adoptionOf`
|
|
43
|
-
* describes, and takes back a copy's statement that it carries a
|
|
44
|
-
* that goes.
|
|
58
|
+
* describes, and takes back a copy's statement that it carries a
|
|
59
|
+
* version that goes. The edition's creation comes to name the rules the
|
|
60
|
+
* proposal follows among its principles, in place of those of the
|
|
61
|
+
* stemma it no longer follows, and this release of the library among its
|
|
62
|
+
* software, which finds the stemma again with the defaults it has. One
|
|
63
|
+
* operation, and so one undo step.
|
|
45
64
|
* @category Operations
|
|
46
65
|
*/
|
|
47
66
|
export declare const adoptStemma: (proposal: StemmaProposal) => EditionOp;
|
|
@@ -1,21 +1,50 @@
|
|
|
1
1
|
/** Taking a proposed stemma into the edition, as one operation. */
|
|
2
2
|
import { v5 } from "uuid";
|
|
3
|
+
import { musicalChange, technicalChange } from "../model/Edit.js";
|
|
4
|
+
import { isCollationsOwn } from "../collation/Collation.js";
|
|
3
5
|
import { assignReference, idOf } from "../model/Assumption.js";
|
|
4
6
|
import { derivesFrom, editsOf, insertedBy, principalDerivationOf } from "../model/Version.js";
|
|
5
7
|
import { systemOf } from "../systems/TrackerBar.js";
|
|
6
|
-
import { unchecked } from "../collation/Collation.js";
|
|
7
8
|
import { versionIn } from "../lookup/lookup.js";
|
|
8
|
-
import {
|
|
9
|
+
import { reading } from "../ops/draft.js";
|
|
9
10
|
import { dropStatements } from "../ops/copies.js";
|
|
10
11
|
import { barNamed } from "./systems.js";
|
|
12
|
+
import { madeWith, stemmaRules } from "./record.js";
|
|
13
|
+
import { motivationOfChanges, proposedMotivations } from "./edits.js";
|
|
11
14
|
/** The namespace the names of adopted versions and edits are minted in, so that adopting again gives them again. */
|
|
12
15
|
const ADOPTED = '6f1d2c8e-93a4-4f0b-b8a1-2f4c5d7e9a31';
|
|
16
|
+
/** The rules the proposal followed, as far as its costs and settings carry them out. */
|
|
17
|
+
const rulesOf = (proposal) => [
|
|
18
|
+
...(proposal.costs.gain > 1 ? [stemmaRules.sharedAddition] : []),
|
|
19
|
+
...(proposal.costs.redundantLoss < 1 ? [stemmaRules.independentCleanup] : []),
|
|
20
|
+
...(proposal.costs.transferLoss < 1 ? [stemmaRules.recutLoss] : []),
|
|
21
|
+
...(Number.isFinite(proposal.costs.copyDeviation) ? [stemmaRules.copyDeviation] : []),
|
|
22
|
+
...(proposal.costs.lostState > 0 ? [stemmaRules.lostStates] : []),
|
|
23
|
+
...(proposal.sameText >= 0 ? [stemmaRules.oneText] : []),
|
|
24
|
+
stemmaRules.refinement,
|
|
25
|
+
stemmaRules.noContamination
|
|
26
|
+
];
|
|
13
27
|
const exchangeKey = (inserted, deleted) => `${[...inserted].sort().join(',')}/${[...deleted].sort().join(',')}`;
|
|
14
28
|
/** The carriers of the reading, keeping what the edition states of those it held already. */
|
|
15
29
|
const carriersOf = (reading, stated) => {
|
|
16
30
|
const known = new Map(stated.map(carrier => [idOf(carrier), carrier]));
|
|
17
31
|
return reading.carriers.map(id => known.get(id) ?? assignReference(id));
|
|
18
32
|
};
|
|
33
|
+
/** The version with its edits stating its text: no kind of change, though any reason the editor gave. */
|
|
34
|
+
const withoutKinds = (version) => {
|
|
35
|
+
const kindOnly = (edit) => edit.motivation === musicalChange || edit.motivation === technicalChange;
|
|
36
|
+
if (!editsOf(version).some(kindOnly))
|
|
37
|
+
return version;
|
|
38
|
+
return {
|
|
39
|
+
...version,
|
|
40
|
+
edits: editsOf(version).map(edit => {
|
|
41
|
+
if (!kindOnly(edit))
|
|
42
|
+
return edit;
|
|
43
|
+
const { motivation: _kind, ...text } = edit;
|
|
44
|
+
return text;
|
|
45
|
+
})
|
|
46
|
+
};
|
|
47
|
+
};
|
|
19
48
|
/**
|
|
20
49
|
* What adopting the proposal makes of the edition's stemma, worked out
|
|
21
50
|
* without changing it, so that it can be looked at first.
|
|
@@ -28,16 +57,26 @@ const carriersOf = (reading, stated) => {
|
|
|
28
57
|
* the edits the editor wrote that the proposal keeps, as they are, and
|
|
29
58
|
* one edit for each further reading it inserts or deletes, or for each
|
|
30
59
|
* recoding. An edit the version stated before over the very same
|
|
31
|
-
* readings is taken over with its id and what was written on it
|
|
32
|
-
*
|
|
60
|
+
* readings is taken over with its id and what was written on it, the
|
|
61
|
+
* kind of change it states among it, which the editor may have said
|
|
62
|
+
* otherwise than the program read it; the others are new. An edit that
|
|
63
|
+
* states no kind has the motivation the shape of the change calls for
|
|
64
|
+
* (`motivationProposedFor`): the generic musical one, whose reason is
|
|
65
|
+
* left to the editor, or the technical one, which a recoding always has.
|
|
66
|
+
* The edits of the root state its text, and no kind of change.
|
|
33
67
|
*
|
|
34
68
|
* A reading that stands for a symbol of the edition keeps that symbol's
|
|
35
69
|
* id and whatever it states beside its carriers. A version of the edition
|
|
36
70
|
* nothing stands for goes, unless it states no edits and derives from a
|
|
37
71
|
* version that stays, as a version known only from a recording does.
|
|
72
|
+
*
|
|
73
|
+
* What the program concluded is stated plainly, as an edition states its
|
|
74
|
+
* stemma. A derivation the editor holds under a belief of their own
|
|
75
|
+
* stays as it is, and so does every edit that says why it was made.
|
|
38
76
|
* @category Filiation
|
|
39
77
|
*/
|
|
40
78
|
export const adoptionOf = (edition, proposal) => {
|
|
79
|
+
const fresh = new Set();
|
|
41
80
|
const readingOf = new Map(proposal.collation.readings.map(reading => [reading.id, reading]));
|
|
42
81
|
const symbolIdOf = (reading) => proposal.symbols[reading] ?? reading;
|
|
43
82
|
const existing = new Map(edition.versions.flatMap(insertedBy).map(symbol => [symbol.id, symbol]));
|
|
@@ -112,16 +151,15 @@ export const adoptionOf = (edition, proposal) => {
|
|
|
112
151
|
const key = exchangeKey(inserted, deleted);
|
|
113
152
|
const same = statedBefore.get(key);
|
|
114
153
|
const insert = inserts.map(reading => symbolOf(reading, proposed.id));
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
};
|
|
154
|
+
const exchange = { ...(insert.length > 0 && { insert }), ...(deleted.length > 0 && { delete: deleted }) };
|
|
155
|
+
// An edit over the same changes stays, with the kind of change it states, which the editor may have said.
|
|
156
|
+
if (same && (!isCollationsOwn(same) || same.motivation !== undefined))
|
|
157
|
+
return { ...same, ...exchange };
|
|
158
|
+
const made = { ...(same ?? { type: 'edit', id: v5(`edit|${id}|${key}`, ADOPTED) }), ...(recoding && { motivation: technicalChange }), ...exchange };
|
|
159
|
+
// A recoding is technical; the motivation of any other change is read off its shape below.
|
|
160
|
+
if (!recoding)
|
|
161
|
+
fresh.add(made.id);
|
|
162
|
+
return made;
|
|
125
163
|
};
|
|
126
164
|
// A recoding an edit of the editor's cuts into is stated reading by reading.
|
|
127
165
|
const whole = proposed.recodings.filter(recoding => ![...recoding.by.map(reading => symbolIdAt(reading, proposed.id)), ...recoding.replaced.map(reading => inheritedAt(reading, proposed.id))]
|
|
@@ -133,11 +171,11 @@ export const adoptionOf = (edition, proposal) => {
|
|
|
133
171
|
...proposed.inserts.filter(reading => !recoded.has(reading)).map(reading => made([reading], [], false)),
|
|
134
172
|
...proposed.deletes.filter(reading => !recoded.has(reading)).map(reading => made([], [reading], false))
|
|
135
173
|
].filter((edit) => edit !== undefined);
|
|
174
|
+
// A derivation stated before is kept with what it states, a belief of the editor's among it.
|
|
136
175
|
const parent = proposed.parent ? ids.get(proposed.parent) : undefined;
|
|
137
176
|
const principal = before && principalDerivationOf(before);
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
: principal && idOf(principal) === parent ? principal : assignReference(parent);
|
|
177
|
+
const same = principal && idOf(principal) === parent ? principal : undefined;
|
|
178
|
+
const derivation = parent === undefined ? undefined : same ?? assignReference(parent);
|
|
141
179
|
const hypotheses = (before?.basedOn ?? [])
|
|
142
180
|
.filter(other => other !== principal && staying.has(idOf(other)) && idOf(other) !== parent);
|
|
143
181
|
const basedOn = [...(derivation ? [derivation] : []), ...hypotheses];
|
|
@@ -150,8 +188,7 @@ export const adoptionOf = (edition, proposal) => {
|
|
|
150
188
|
id,
|
|
151
189
|
system,
|
|
152
190
|
...(basedOn.length > 0 && { basedOn }),
|
|
153
|
-
edits
|
|
154
|
-
motivations: declaring(before?.motivations ?? [], edits)
|
|
191
|
+
edits
|
|
155
192
|
};
|
|
156
193
|
});
|
|
157
194
|
// A hypothesis may not name a version that now derives from the one stating it.
|
|
@@ -171,19 +208,40 @@ export const adoptionOf = (edition, proposal) => {
|
|
|
171
208
|
// The edition's order where a version stays, the new ones after it.
|
|
172
209
|
const rank = new Map(edition.versions.map((version, index) => [version.id, index]));
|
|
173
210
|
const ordered = [...pruned, ...statedOnly].sort((a, b) => (rank.get(a.id) ?? Infinity) - (rank.get(b.id) ?? Infinity));
|
|
174
|
-
|
|
211
|
+
// A new edit's motivation follows from the shape of the change, read in the stemma adopted.
|
|
212
|
+
const adopted = { ...edition, versions: ordered };
|
|
213
|
+
const motivated = ordered.map(version => {
|
|
214
|
+
if (!principalDerivationOf(version))
|
|
215
|
+
return withoutKinds(version);
|
|
216
|
+
if (!editsOf(version).some(edit => fresh.has(edit.id)))
|
|
217
|
+
return version;
|
|
218
|
+
const motivations = proposedMotivations(adopted, version.id);
|
|
219
|
+
return {
|
|
220
|
+
...version,
|
|
221
|
+
edits: editsOf(version).map(edit => fresh.has(edit.id)
|
|
222
|
+
? { ...edit, motivation: motivationOfChanges(motivations, [...(edit.insert ?? []).map(symbol => symbol.id), ...(edit.delete ?? [])]) }
|
|
223
|
+
: edit)
|
|
224
|
+
};
|
|
225
|
+
});
|
|
226
|
+
return { versions: motivated, ids: Object.fromEntries(ids), removed, dropped: proposal.unpinned, principles: rulesOf(proposal) };
|
|
175
227
|
};
|
|
176
228
|
/**
|
|
177
229
|
* Puts the proposed stemma in place of the edition's, as `adoptionOf`
|
|
178
|
-
* describes, and takes back a copy's statement that it carries a
|
|
179
|
-
* that goes.
|
|
230
|
+
* describes, and takes back a copy's statement that it carries a
|
|
231
|
+
* version that goes. The edition's creation comes to name the rules the
|
|
232
|
+
* proposal follows among its principles, in place of those of the
|
|
233
|
+
* stemma it no longer follows, and this release of the library among its
|
|
234
|
+
* software, which finds the stemma again with the defaults it has. One
|
|
235
|
+
* operation, and so one undo step.
|
|
180
236
|
* @category Operations
|
|
181
237
|
*/
|
|
182
238
|
export const adoptStemma = (proposal) => reading(edition => {
|
|
183
|
-
const { versions, removed } = adoptionOf(edition, proposal);
|
|
239
|
+
const { versions, removed, principles } = adoptionOf(edition, proposal);
|
|
184
240
|
const gone = new Set(removed);
|
|
241
|
+
const creation = madeWith(edition.creation, principles, Object.values(stemmaRules));
|
|
185
242
|
return draft => {
|
|
186
243
|
draft.versions = versions;
|
|
187
244
|
draft.copies.forEach(copy => dropStatements(copy, statement => gone.has(idOf(statement))));
|
|
245
|
+
draft.creation = creation;
|
|
188
246
|
};
|
|
189
247
|
});
|
package/lib/filiation/edits.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Edition } from "../model/Edition.js";
|
|
2
|
-
import {
|
|
2
|
+
import { EditShape } from "../model/Edit.js";
|
|
3
3
|
import { Millimeters } from "../model/Quantity.js";
|
|
4
4
|
import { EditionOp } from "../ops/draft.js";
|
|
5
5
|
/**
|
|
@@ -69,8 +69,8 @@ export interface ProposedEdit {
|
|
|
69
69
|
insert: string[];
|
|
70
70
|
/** The ids of the symbols it deletes, in the order of their places. */
|
|
71
71
|
delete: string[];
|
|
72
|
-
/** The
|
|
73
|
-
|
|
72
|
+
/** The shape of the change, where it takes one the program knows. */
|
|
73
|
+
shape?: EditShape;
|
|
74
74
|
grouping: EditGrouping;
|
|
75
75
|
}
|
|
76
76
|
/**
|
|
@@ -94,8 +94,8 @@ export interface ProposedEdit {
|
|
|
94
94
|
* punched across three lines or more at one place are one edit, as a
|
|
95
95
|
* cancel row is.
|
|
96
96
|
*
|
|
97
|
-
* The
|
|
98
|
-
* an additional accent, as is a note set off from its chord by a few
|
|
97
|
+
* The shape is read off the group: a pair the bar spells an accent with
|
|
98
|
+
* is an additional accent, as is a note set off from its chord by a few
|
|
99
99
|
* millimetres where the version puts an accent's On; a perforation put
|
|
100
100
|
* elsewhere is a shift, or where it begins about where the other did,
|
|
101
101
|
* shortened or prolonged; a note struck again is shortened, two tied
|
|
@@ -110,25 +110,41 @@ export interface ProposedEdit {
|
|
|
110
110
|
*/
|
|
111
111
|
export declare const proposeEdits: (edition: Edition, versionId: string, options?: EditOptions) => ProposedEdit[];
|
|
112
112
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
113
|
+
* The motivation a program states for each change the version makes,
|
|
114
|
+
* by the id of the symbol it inserts or deletes: the one the shape of
|
|
115
|
+
* the proposed edit it belongs to calls for (`motivationProposedFor`),
|
|
116
|
+
* musical or technical. A version that derives from none makes no
|
|
117
|
+
* change, and its symbols are given none.
|
|
115
118
|
* @category Filiation
|
|
116
119
|
*/
|
|
117
|
-
export declare const
|
|
120
|
+
export declare const proposedMotivations: (edition: Edition, versionId: string, options?: EditOptions) => ReadonlyMap<string, string>;
|
|
118
121
|
/**
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
122
|
+
* The motivation a program states for an edit making these changes:
|
|
123
|
+
* the generic musical one where any of them is a musical change, or one
|
|
124
|
+
* the proposal does not see, and the technical one where all are
|
|
125
|
+
* technical.
|
|
126
|
+
*/
|
|
127
|
+
export declare const motivationOfChanges: (motivations: ReadonlyMap<string, string>, symbolIds: readonly string[]) => string;
|
|
128
|
+
/**
|
|
129
|
+
* Puts the proposed edits (`proposeEdits`) in place of the program's
|
|
130
|
+
* edits of the versions, every version but the root where none are
|
|
131
|
+
* named: those that say nothing of why they were made, or only that they
|
|
132
|
+
* are musical or technical changes (`isCollationsOwn`). An edit with a
|
|
133
|
+
* motivation of the editor's or held under a belief stays as it is, and
|
|
134
|
+
* what a proposed edit shares with it stands symbol by symbol beside it.
|
|
135
|
+
* An edit stated already over the very same symbols as a proposed one
|
|
136
|
+
* is kept with its id and the kind of change it states, which the
|
|
137
|
+
* editor may have said otherwise than the program read it; the others
|
|
138
|
+
* are new, with ids that adopting again gives again. An edit that
|
|
139
|
+
* states no kind has the motivation its shape calls for
|
|
140
|
+
* (`motivationProposedFor`): the generic musical one for a musical
|
|
141
|
+
* change, whose reason is left to the editor, and the technical one for
|
|
142
|
+
* a technical change.
|
|
129
143
|
*
|
|
130
144
|
* Applied on the same draft after `adoptStemma`, it proposes the edits of
|
|
131
|
-
* the stemma adopted, as one undo step.
|
|
145
|
+
* the stemma adopted, as one undo step. The edition's creation comes to
|
|
146
|
+
* name the rule that keeps an edit at one place among its principles,
|
|
147
|
+
* and this release among its software.
|
|
132
148
|
* @category Operations
|
|
133
149
|
*/
|
|
134
150
|
export declare const adoptEdits: (versionIds?: readonly string[], options?: EditOptions) => EditionOp;
|