linked-rolls 0.75.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 +53 -47
- package/lib/collation/Collation.d.ts +12 -46
- package/lib/collation/Collation.js +15 -53
- package/lib/filiation/adoption.d.ts +22 -26
- package/lib/filiation/adoption.js +71 -73
- package/lib/filiation/edits.d.ts +36 -31
- package/lib/filiation/edits.js +70 -85
- package/lib/filiation/index.d.ts +2 -2
- package/lib/filiation/index.js +1 -1
- package/lib/filiation/record.d.ts +14 -44
- package/lib/filiation/record.js +12 -83
- package/lib/io/asJsonLd.d.ts +1 -5
- package/lib/io/asJsonLd.js +17 -36
- package/lib/io/importJsonLd.js +33 -6
- package/lib/io/migrate.d.ts +7 -0
- package/lib/io/migrate.js +167 -2
- package/lib/model/Agent.d.ts +3 -1
- package/lib/model/Assumption.d.ts +9 -85
- package/lib/model/Assumption.js +3 -39
- package/lib/model/Edit.d.ts +75 -20
- package/lib/model/Edit.js +52 -5
- package/lib/model/Edition.d.ts +31 -11
- package/lib/model/Version.d.ts +5 -41
- package/lib/model/Version.js +6 -30
- 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 -5
- package/lib/ops/edits.js +29 -21
- 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 +121 -140
- package/lib/software.d.ts +7 -6
- package/lib/software.js +7 -6
- package/lib/spec/context.json +8 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -132,22 +132,20 @@ 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
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
an edit the editor holds for reasons of their own stays theirs, outside
|
|
145
|
-
the set.
|
|
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.
|
|
146
144
|
|
|
147
145
|
```ts
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
adopted.
|
|
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' }]
|
|
151
149
|
```
|
|
152
150
|
|
|
153
151
|
The costs are those with which the stemma of WM 225 comes out of its
|
|
@@ -157,28 +155,26 @@ principles confirm it.
|
|
|
157
155
|
|
|
158
156
|
## Proposing the edits
|
|
159
157
|
|
|
160
|
-
What a version inserts and deletes can be grouped into edits and
|
|
161
|
-
|
|
162
|
-
line, a latched function, a held one or a pitch, and
|
|
163
|
-
command both texts keep, so that an edit stays at one
|
|
164
|
-
turned on and off again is one edit,
|
|
165
|
-
the bar spells an accent so; a perforation put elsewhere
|
|
166
|
-
with the one it replaces,
|
|
167
|
-
where it begins about where the other did; overlapping notes
|
|
168
|
-
edit, a note struck again or two tied; a held command standing
|
|
169
|
-
latched pair is one recoding; a command the text makes no use of
|
|
170
|
-
redundancy added or removed; cancels punched across lines at one
|
|
171
|
-
are one row. `adoptEdits` puts the proposal in place of the
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
versions are held with as its premises, so that edits grouped against
|
|
176
|
-
a proposed stemma rest on it.
|
|
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.
|
|
177
173
|
|
|
178
174
|
```ts
|
|
179
175
|
import { adoptEdits, adoptStemma, proposeEdits, proposeStemma } from 'linked-rolls'
|
|
180
176
|
|
|
181
|
-
proposeEdits(edition, versionId) // [{ insert, delete,
|
|
177
|
+
proposeEdits(edition, versionId) // [{ insert, delete, shape, grouping }, …]
|
|
182
178
|
|
|
183
179
|
// The stemma and the edits of its versions, as one undo step
|
|
184
180
|
const adopted = produce(edition, draft => {
|
|
@@ -187,14 +183,26 @@ const adopted = produce(edition, draft => {
|
|
|
187
183
|
})
|
|
188
184
|
```
|
|
189
185
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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.
|
|
198
206
|
|
|
199
207
|
## Format
|
|
200
208
|
|
|
@@ -206,12 +214,10 @@ https://pfefferniels.github.io/linked-rolls/, to which the w3id.org
|
|
|
206
214
|
identifiers redirect.
|
|
207
215
|
|
|
208
216
|
Beliefs are written as JSON-LD-star annotations (`@annotation`), so you
|
|
209
|
-
need a processor that supports JSON-LD-star to read them.
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
once, under `propositionSets`, as a `crminf:I4_Proposition_Set` with its
|
|
214
|
-
belief.
|
|
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.
|
|
215
221
|
|
|
216
222
|
## Development
|
|
217
223
|
|
|
@@ -230,7 +236,7 @@ TypeScript 7 no longer has the compiler API it reads the source with.
|
|
|
230
236
|
|
|
231
237
|
Raise the version in `package.json`, in `CITATION.cff`, there with the
|
|
232
238
|
day as `date-released`, and in `src/software.ts`, which names the release
|
|
233
|
-
in the
|
|
239
|
+
in the edition's creation when a proposal is adopted. Then commit, and push a tag
|
|
234
240
|
`v<version>`. The `publish.yml` workflow builds, tests and publishes to
|
|
235
241
|
npm, then makes a GitHub release of the tag, which Zenodo archives with
|
|
236
242
|
a DOI. A test fails while the versions differ.
|
|
@@ -120,54 +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.
|
|
167
|
-
*
|
|
168
|
-
* An edit a program proposed and typed is no reading of the editor's
|
|
169
|
-
* either, as long as nobody has motivated it: it says so by belonging
|
|
170
|
-
* to the proposition set the program's run concluded (`adoptEdits`).
|
|
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`).
|
|
171
137
|
* @category Collation and alignment
|
|
172
138
|
*/
|
|
173
139
|
export declare const isCollationsOwn: (edit: Readonly<Edit>) => boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { musicalChange, technicalChange } from "../model/Edit.js";
|
|
2
2
|
import { keyOf } from "../systems/TrackerBar.js";
|
|
3
3
|
import { distance, mm } from "../model/Quantity.js";
|
|
4
4
|
import { partitionPoint } from "../shared/sorted.js";
|
|
@@ -107,60 +107,22 @@ export const collationsOf = (own, inherited, locate, tolerance = defaultCollatio
|
|
|
107
107
|
.sort((a, b) => a.index - b.index)
|
|
108
108
|
.map(({ symbol: counterpart }) => ({ symbol, counterpart })));
|
|
109
109
|
};
|
|
110
|
-
/** The edit type a collation draws by itself, from the two systems' vocabularies rather than off the paper. */
|
|
111
|
-
const drawnByCollation = 'recoding';
|
|
112
110
|
/**
|
|
113
|
-
*
|
|
114
|
-
* 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.
|
|
115
117
|
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
* middle: the readings are there to be seen and argued with, and a
|
|
120
|
-
* 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.
|
|
121
121
|
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
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`).
|
|
125
125
|
* @category Collation and alignment
|
|
126
126
|
*/
|
|
127
|
-
export const
|
|
128
|
-
|
|
129
|
-
* The version's statement of what the unchecked motivation means, to stand in its `motivations`.
|
|
130
|
-
* @category Collation and alignment
|
|
131
|
-
*/
|
|
132
|
-
export const uncheckedMotivation = {
|
|
133
|
-
type: 'motivation',
|
|
134
|
-
id: unchecked,
|
|
135
|
-
note: 'Made by collating the two texts and not yet read by an editor.'
|
|
136
|
-
};
|
|
137
|
-
/**
|
|
138
|
-
* Whether the edit is one a collation writes by itself: a bare
|
|
139
|
-
* insertion or a bare deletion saying nothing further, or a recoding
|
|
140
|
-
* that exchanges two systems' spellings for one command.
|
|
141
|
-
*
|
|
142
|
-
* Collating again rewrites these and keeps the rest. An edit that says
|
|
143
|
-
* what the change is, or why it was made, or what it rests on, is an
|
|
144
|
-
* editor's reading of the difference between two texts, and collating
|
|
145
|
-
* the two again is no reason to discard it.
|
|
146
|
-
*
|
|
147
|
-
* Such an exchange counts as the collation's own even where an editor
|
|
148
|
-
* added a motivation to it, because it is derived rather than read:
|
|
149
|
-
* freezing it would leave the transfers, where nearly every edit is
|
|
150
|
-
* one, unable to be collated again at all. What an editor wrote on it
|
|
151
|
-
* is not lost by that, since `connectVersions` keeps an exchange it
|
|
152
|
-
* draws a second time over the very same symbols.
|
|
153
|
-
*
|
|
154
|
-
* A recoding that only inserts or only deletes is the editor's: a
|
|
155
|
-
* collation types no one-sided edit, so one typed so is a reading of
|
|
156
|
-
* the transfer that collating again must not undo.
|
|
157
|
-
*
|
|
158
|
-
* An edit a program proposed and typed is no reading of the editor's
|
|
159
|
-
* either, as long as nobody has motivated it: it says so by belonging
|
|
160
|
-
* to the proposition set the program's run concluded (`adoptEdits`).
|
|
161
|
-
* @category Collation and alignment
|
|
162
|
-
*/
|
|
163
|
-
export const isCollationsOwn = (edit) => (edit.editType === drawnByCollation && !!edit.insert?.length && !!edit.delete?.length)
|
|
164
|
-
|| ((edit.editType === undefined || propositionSetOf(edit) !== undefined)
|
|
165
|
-
&& (edit.motivation === undefined || edit.motivation === unchecked)
|
|
166
|
-
&& !isHeldForItself(edit));
|
|
127
|
+
export const isCollationsOwn = (edit) => edit['@annotation'] === undefined
|
|
128
|
+
&& (edit.motivation === undefined || edit.motivation === musicalChange || edit.motivation === technicalChange);
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { Edition } from "../model/Edition.js";
|
|
2
|
-
import { PropositionSet } from "../model/Assumption.js";
|
|
3
2
|
import { Version } from "../model/Version.js";
|
|
4
3
|
import { EditionOp } from "../ops/draft.js";
|
|
5
4
|
import { StemmaProposal, Unpinned } from "./proposal.js";
|
|
6
|
-
import { Run } from "./record.js";
|
|
7
5
|
/**
|
|
8
6
|
* What adopting a proposal makes of the stemma: the versions it puts in
|
|
9
7
|
* place of the edition's, and what of the edition it leaves out.
|
|
@@ -18,11 +16,11 @@ export interface Adoption {
|
|
|
18
16
|
/** The edits the editor wrote that the adoption leaves out, and why. */
|
|
19
17
|
dropped: Unpinned[];
|
|
20
18
|
/**
|
|
21
|
-
* The
|
|
22
|
-
*
|
|
23
|
-
*
|
|
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.
|
|
24
22
|
*/
|
|
25
|
-
|
|
23
|
+
principles: string[];
|
|
26
24
|
}
|
|
27
25
|
/**
|
|
28
26
|
* What adopting the proposal makes of the edition's stemma, worked out
|
|
@@ -36,35 +34,33 @@ export interface Adoption {
|
|
|
36
34
|
* the edits the editor wrote that the proposal keeps, as they are, and
|
|
37
35
|
* one edit for each further reading it inserts or deletes, or for each
|
|
38
36
|
* recoding. An edit the version stated before over the very same
|
|
39
|
-
* readings is taken over with its id and what was written on it
|
|
40
|
-
*
|
|
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.
|
|
41
44
|
*
|
|
42
45
|
* A reading that stands for a symbol of the edition keeps that symbol's
|
|
43
46
|
* id and whatever it states beside its carriers. A version of the edition
|
|
44
47
|
* nothing stands for goes, unless it states no edits and derives from a
|
|
45
48
|
* version that stays, as a version known only from a recording does.
|
|
46
49
|
*
|
|
47
|
-
* What the program concluded is
|
|
48
|
-
* the
|
|
49
|
-
*
|
|
50
|
-
* holds them under one belief, likely unless the run says otherwise,
|
|
51
|
-
* concluded by an inference that names this library and its release,
|
|
52
|
-
* the copies it collated, the rules it followed and, in its note, what
|
|
53
|
-
* it was computed with. A derivation or an edit that is the editor's,
|
|
54
|
-
* held under a belief of its own or saying more than a program says,
|
|
55
|
-
* stays the editor's and outside the set. The run gives who ran the
|
|
56
|
-
* program and when (`Run`).
|
|
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.
|
|
57
53
|
* @category Filiation
|
|
58
54
|
*/
|
|
59
|
-
export declare const adoptionOf: (edition: Edition, proposal: StemmaProposal
|
|
55
|
+
export declare const adoptionOf: (edition: Edition, proposal: StemmaProposal) => Adoption;
|
|
60
56
|
/**
|
|
61
57
|
* Puts the proposed stemma in place of the edition's, as `adoptionOf`
|
|
62
|
-
* describes,
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* the
|
|
67
|
-
* so one undo step.
|
|
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.
|
|
68
64
|
* @category Operations
|
|
69
65
|
*/
|
|
70
|
-
export declare const adoptStemma: (proposal: StemmaProposal
|
|
66
|
+
export declare const adoptStemma: (proposal: StemmaProposal) => EditionOp;
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
/** Taking a proposed stemma into the edition, as one operation. */
|
|
2
2
|
import { v5 } from "uuid";
|
|
3
|
-
import {
|
|
3
|
+
import { musicalChange, technicalChange } from "../model/Edit.js";
|
|
4
|
+
import { isCollationsOwn } from "../collation/Collation.js";
|
|
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 { isCollationsOwn, 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";
|
|
11
|
-
import {
|
|
12
|
+
import { madeWith, stemmaRules } from "./record.js";
|
|
13
|
+
import { motivationOfChanges, proposedMotivations } from "./edits.js";
|
|
12
14
|
/** The namespace the names of adopted versions and edits are minted in, so that adopting again gives them again. */
|
|
13
15
|
const ADOPTED = '6f1d2c8e-93a4-4f0b-b8a1-2f4c5d7e9a31';
|
|
14
16
|
/** The rules the proposal followed, as far as its costs and settings carry them out. */
|
|
@@ -22,35 +24,27 @@ const rulesOf = (proposal) => [
|
|
|
22
24
|
stemmaRules.refinement,
|
|
23
25
|
stemmaRules.noContamination
|
|
24
26
|
];
|
|
25
|
-
/** A number as a note gives it: to two places at most. */
|
|
26
|
-
const amount = (value) => String(Math.round(value * 100) / 100);
|
|
27
|
-
/**
|
|
28
|
-
* What the run of `proposeStemma` was, and what it was computed with, in
|
|
29
|
-
* words, so that it can be run again: the copies by siglum, the costs,
|
|
30
|
-
* the settings, and the margin by which the copies decide each grouping.
|
|
31
|
-
*/
|
|
32
|
-
const noteOn = (edition, proposal) => {
|
|
33
|
-
const siglumOf = new Map(edition.copies.map(copy => [copy.id, copy.siglum ?? copy.id]));
|
|
34
|
-
const named = (copies) => copies.map(copy => siglumOf.get(copy) ?? copy).join(', ');
|
|
35
|
-
const { costs } = proposal;
|
|
36
|
-
const supports = proposal.supports.map(support => support.ancestor
|
|
37
|
-
? `${named(support.ancestor)} above ${named(support.copies.filter(copy => !support.ancestor.includes(copy)))} by ${amount(support.margin)}`
|
|
38
|
-
: `${named(support.copies)} together by ${amount(support.margin)}`);
|
|
39
|
-
return [
|
|
40
|
-
`The stemma ${proposal.notation}, the best of ${proposal.scored} that ${named(proposal.copies)} admit, at a cost of ${amount(proposal.cost)}.`,
|
|
41
|
-
`A reading arising costs ${amount(costs.gain)}, a reading lost 1, a redundancy lost ${amount(costs.redundantLoss)}, a reading lost on the way into another system ${amount(costs.transferLoss)}, a copy lacking a reading of its version ${amount(costs.copyDeviation)}, and a lost state ${amount(costs.lostState)}.`,
|
|
42
|
-
`Copies of one system differing in ${proposal.sameText < 0 ? 'any reading' : `no more than ${proposal.sameText} readings`} are taken for one text; a reading of the same kind within ${inMillimetres(proposal.movedWithin)} on the other side of the root for a moved one; and ${inMillimetres(proposal.margin)} beyond a copy's text or a tear for what the copy cannot show.`,
|
|
43
|
-
...(supports.length > 0 ? [`The copies decide its groupings by: ${supports.join('; ')}.`] : [])
|
|
44
|
-
].join(' ');
|
|
45
|
-
};
|
|
46
|
-
/** The set the run of `proposeStemma` concluded, held with the belief the run gives it. */
|
|
47
|
-
const stemmaSetOf = (edition, proposal, run) => recorded('stemma', [proposal.copies, proposal.notation, proposal.costs, proposal.sameText, proposal.movedWithin, proposal.margin], { note: noteOn(edition, proposal), premises: [], used: [...proposal.copies], applies: rulesOf(proposal) }, run);
|
|
48
27
|
const exchangeKey = (inserted, deleted) => `${[...inserted].sort().join(',')}/${[...deleted].sort().join(',')}`;
|
|
49
28
|
/** The carriers of the reading, keeping what the edition states of those it held already. */
|
|
50
29
|
const carriersOf = (reading, stated) => {
|
|
51
30
|
const known = new Map(stated.map(carrier => [idOf(carrier), carrier]));
|
|
52
31
|
return reading.carriers.map(id => known.get(id) ?? assignReference(id));
|
|
53
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
|
+
};
|
|
54
48
|
/**
|
|
55
49
|
* What adopting the proposal makes of the edition's stemma, worked out
|
|
56
50
|
* without changing it, so that it can be looked at first.
|
|
@@ -63,28 +57,26 @@ const carriersOf = (reading, stated) => {
|
|
|
63
57
|
* the edits the editor wrote that the proposal keeps, as they are, and
|
|
64
58
|
* one edit for each further reading it inserts or deletes, or for each
|
|
65
59
|
* recoding. An edit the version stated before over the very same
|
|
66
|
-
* readings is taken over with its id and what was written on it
|
|
67
|
-
*
|
|
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.
|
|
68
67
|
*
|
|
69
68
|
* A reading that stands for a symbol of the edition keeps that symbol's
|
|
70
69
|
* id and whatever it states beside its carriers. A version of the edition
|
|
71
70
|
* nothing stands for goes, unless it states no edits and derives from a
|
|
72
71
|
* version that stays, as a version known only from a recording does.
|
|
73
72
|
*
|
|
74
|
-
* What the program concluded is
|
|
75
|
-
* the
|
|
76
|
-
*
|
|
77
|
-
* holds them under one belief, likely unless the run says otherwise,
|
|
78
|
-
* concluded by an inference that names this library and its release,
|
|
79
|
-
* the copies it collated, the rules it followed and, in its note, what
|
|
80
|
-
* it was computed with. A derivation or an edit that is the editor's,
|
|
81
|
-
* held under a belief of its own or saying more than a program says,
|
|
82
|
-
* stays the editor's and outside the set. The run gives who ran the
|
|
83
|
-
* program and when (`Run`).
|
|
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.
|
|
84
76
|
* @category Filiation
|
|
85
77
|
*/
|
|
86
|
-
export const adoptionOf = (edition, proposal
|
|
87
|
-
const
|
|
78
|
+
export const adoptionOf = (edition, proposal) => {
|
|
79
|
+
const fresh = new Set();
|
|
88
80
|
const readingOf = new Map(proposal.collation.readings.map(reading => [reading.id, reading]));
|
|
89
81
|
const symbolIdOf = (reading) => proposal.symbols[reading] ?? reading;
|
|
90
82
|
const existing = new Map(edition.versions.flatMap(insertedBy).map(symbol => [symbol.id, symbol]));
|
|
@@ -159,18 +151,15 @@ export const adoptionOf = (edition, proposal, run = {}) => {
|
|
|
159
151
|
const key = exchangeKey(inserted, deleted);
|
|
160
152
|
const same = statedBefore.get(key);
|
|
161
153
|
const insert = inserts.map(reading => symbolOf(reading, proposed.id));
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
...(insert.length > 0 && { insert }),
|
|
172
|
-
...(deleted.length > 0 && { delete: deleted })
|
|
173
|
-
});
|
|
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;
|
|
174
163
|
};
|
|
175
164
|
// A recoding an edit of the editor's cuts into is stated reading by reading.
|
|
176
165
|
const whole = proposed.recodings.filter(recoding => ![...recoding.by.map(reading => symbolIdAt(reading, proposed.id)), ...recoding.replaced.map(reading => inheritedAt(reading, proposed.id))]
|
|
@@ -182,13 +171,11 @@ export const adoptionOf = (edition, proposal, run = {}) => {
|
|
|
182
171
|
...proposed.inserts.filter(reading => !recoded.has(reading)).map(reading => made([reading], [], false)),
|
|
183
172
|
...proposed.deletes.filter(reading => !recoded.has(reading)).map(reading => made([], [reading], false))
|
|
184
173
|
].filter((edit) => edit !== undefined);
|
|
185
|
-
//
|
|
174
|
+
// A derivation stated before is kept with what it states, a belief of the editor's among it.
|
|
186
175
|
const parent = proposed.parent ? ids.get(proposed.parent) : undefined;
|
|
187
176
|
const principal = before && principalDerivationOf(before);
|
|
188
177
|
const same = principal && idOf(principal) === parent ? principal : undefined;
|
|
189
|
-
const derivation = parent === undefined
|
|
190
|
-
? undefined
|
|
191
|
-
: same && isHeldForItself(same) ? same : memberOf(set.id, same ?? assignReference(parent));
|
|
178
|
+
const derivation = parent === undefined ? undefined : same ?? assignReference(parent);
|
|
192
179
|
const hypotheses = (before?.basedOn ?? [])
|
|
193
180
|
.filter(other => other !== principal && staying.has(idOf(other)) && idOf(other) !== parent);
|
|
194
181
|
const basedOn = [...(derivation ? [derivation] : []), ...hypotheses];
|
|
@@ -201,8 +188,7 @@ export const adoptionOf = (edition, proposal, run = {}) => {
|
|
|
201
188
|
id,
|
|
202
189
|
system,
|
|
203
190
|
...(basedOn.length > 0 && { basedOn }),
|
|
204
|
-
edits
|
|
205
|
-
motivations: declaring(before?.motivations ?? [], edits)
|
|
191
|
+
edits
|
|
206
192
|
};
|
|
207
193
|
});
|
|
208
194
|
// A hypothesis may not name a version that now derives from the one stating it.
|
|
@@ -222,28 +208,40 @@ export const adoptionOf = (edition, proposal, run = {}) => {
|
|
|
222
208
|
// The edition's order where a version stays, the new ones after it.
|
|
223
209
|
const rank = new Map(edition.versions.map((version, index) => [version.id, index]));
|
|
224
210
|
const ordered = [...pruned, ...statedOnly].sort((a, b) => (rank.get(a.id) ?? Infinity) - (rank.get(b.id) ?? Infinity));
|
|
225
|
-
|
|
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) };
|
|
226
227
|
};
|
|
227
228
|
/**
|
|
228
229
|
* Puts the proposed stemma in place of the edition's, as `adoptionOf`
|
|
229
|
-
* describes,
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
* the
|
|
234
|
-
* so one undo step.
|
|
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.
|
|
235
236
|
* @category Operations
|
|
236
237
|
*/
|
|
237
|
-
export const adoptStemma = (proposal
|
|
238
|
-
const { versions, removed,
|
|
238
|
+
export const adoptStemma = (proposal) => reading(edition => {
|
|
239
|
+
const { versions, removed, principles } = adoptionOf(edition, proposal);
|
|
239
240
|
const gone = new Set(removed);
|
|
240
|
-
const
|
|
241
|
+
const creation = madeWith(edition.creation, principles, Object.values(stemmaRules));
|
|
241
242
|
return draft => {
|
|
242
243
|
draft.versions = versions;
|
|
243
244
|
draft.copies.forEach(copy => dropStatements(copy, statement => gone.has(idOf(statement))));
|
|
244
|
-
|
|
245
|
-
draft.propositionSets = sets;
|
|
246
|
-
else
|
|
247
|
-
delete draft.propositionSets;
|
|
245
|
+
draft.creation = creation;
|
|
248
246
|
};
|
|
249
247
|
});
|