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/lib/io/asJsonLd.js
CHANGED
|
@@ -97,57 +97,42 @@ const withChanges = (edition) => Array.isArray(edition.copies) ? { ...edition, c
|
|
|
97
97
|
const silentTerms = new Set(Object.entries(context['@context'])
|
|
98
98
|
.filter(([, definition]) => definition === null)
|
|
99
99
|
.map(([term]) => term));
|
|
100
|
-
const doubtedSetsOf = (edition) => new Map((edition.propositionSets ?? [])
|
|
101
|
-
.filter(set => !isAsserted(set.belief.certainty))
|
|
102
|
-
.map(set => [set.id, set.belief.id]));
|
|
103
|
-
/** The set a value's annotation names instead of carrying a belief, where the edition doubts it. */
|
|
104
|
-
const doubtedSetOf = (value, doubted) => {
|
|
105
|
-
const annotation = value['@annotation'];
|
|
106
|
-
return isRecord(annotation) && annotation.belief === undefined && typeof annotation['@id'] === 'string'
|
|
107
|
-
? doubted.get(annotation['@id']) && annotation['@id']
|
|
108
|
-
: undefined;
|
|
109
|
-
};
|
|
110
100
|
/**
|
|
111
101
|
* A reference its belief does not hold to be so: it names a node, states
|
|
112
|
-
* nothing RDF would read besides, and its belief is below likely
|
|
113
|
-
* belief of the proposition set it belongs to is.
|
|
102
|
+
* nothing RDF would read besides, and its belief is below likely.
|
|
114
103
|
*/
|
|
115
|
-
const isDoubtedReference = (value
|
|
104
|
+
const isDoubtedReference = (value) => isRecord(value)
|
|
116
105
|
&& typeof value['@id'] === 'string'
|
|
117
106
|
&& isRecord(value['@annotation'])
|
|
118
|
-
&&
|
|
107
|
+
&& !isAsserted(certaintyOf(value))
|
|
119
108
|
&& Object.keys(value).every(key => key === '@id' || key === '@annotation' || silentTerms.has(key));
|
|
120
109
|
/**
|
|
121
110
|
* The statement a doubted reference makes, as a JSON-LD-star embedded
|
|
122
111
|
* node: the triple is named without being stated, and the belief is
|
|
123
112
|
* about it. The annotation's own id goes along under a key RDF does not
|
|
124
|
-
* read, so that an import can put it back.
|
|
125
|
-
* a proposition set names the set's belief by its id, which is stated
|
|
126
|
-
* with the set.
|
|
113
|
+
* read, so that an import can put it back.
|
|
127
114
|
*/
|
|
128
|
-
const quote = (subject, key, reference, listed
|
|
115
|
+
const quote = (subject, key, reference, listed) => {
|
|
129
116
|
const { '@annotation': { '@id': annotation, ...about }, ...object } = reference;
|
|
130
|
-
const set = doubtedSetOf(reference, doubted);
|
|
131
117
|
return {
|
|
132
118
|
'@id': { '@id': subject, [key]: listed ? [object] : object },
|
|
133
119
|
annotation,
|
|
134
|
-
...about
|
|
135
|
-
...(set !== undefined && { belief: { '@id': doubted.get(set) } })
|
|
120
|
+
...about
|
|
136
121
|
};
|
|
137
122
|
};
|
|
138
123
|
/** The value a node states under a key, less the doubted references, which go to the quoted. */
|
|
139
|
-
const unquoted = (subject, key, value, quoted
|
|
124
|
+
const unquoted = (subject, key, value, quoted) => {
|
|
140
125
|
if (Array.isArray(value)) {
|
|
141
126
|
return value.filter(item => {
|
|
142
|
-
if (!isDoubtedReference(item
|
|
127
|
+
if (!isDoubtedReference(item))
|
|
143
128
|
return true;
|
|
144
|
-
quoted.push(quote(subject, key, item, true
|
|
129
|
+
quoted.push(quote(subject, key, item, true));
|
|
145
130
|
return false;
|
|
146
131
|
});
|
|
147
132
|
}
|
|
148
|
-
if (!isDoubtedReference(value
|
|
133
|
+
if (!isDoubtedReference(value))
|
|
149
134
|
return value;
|
|
150
|
-
quoted.push(quote(subject, key, value, false
|
|
135
|
+
quoted.push(quote(subject, key, value, false));
|
|
151
136
|
return undefined;
|
|
152
137
|
};
|
|
153
138
|
/**
|
|
@@ -160,16 +145,16 @@ const unquoted = (subject, key, value, quoted, doubted) => {
|
|
|
160
145
|
* between nodes are quoted, since only they can be put back where they
|
|
161
146
|
* stood; a doubted date or attribution stays annotated in place.
|
|
162
147
|
*/
|
|
163
|
-
const withDoubtedReferencesQuoted = (value, quoted
|
|
148
|
+
const withDoubtedReferencesQuoted = (value, quoted) => {
|
|
164
149
|
if (Array.isArray(value))
|
|
165
|
-
return value.map(item => withDoubtedReferencesQuoted(item, quoted
|
|
150
|
+
return value.map(item => withDoubtedReferencesQuoted(item, quoted));
|
|
166
151
|
if (!isRecord(value))
|
|
167
152
|
return value;
|
|
168
153
|
const subject = value['@id'];
|
|
169
154
|
const node = {};
|
|
170
155
|
Object.entries(value).forEach(([key, child]) => {
|
|
171
|
-
const stated = typeof subject === 'string' && !key.startsWith('@') ? unquoted(subject, key, child, quoted
|
|
172
|
-
const below = withDoubtedReferencesQuoted(stated, quoted
|
|
156
|
+
const stated = typeof subject === 'string' && !key.startsWith('@') ? unquoted(subject, key, child, quoted) : child;
|
|
157
|
+
const below = withDoubtedReferencesQuoted(stated, quoted);
|
|
173
158
|
if (below !== undefined)
|
|
174
159
|
node[key] = below;
|
|
175
160
|
});
|
|
@@ -186,16 +171,12 @@ const atOwnPlacesAll = (edition) => edition.copies.some(copy => copy.measurement
|
|
|
186
171
|
* and every version carries the context of its own reproducing system.
|
|
187
172
|
* A reference the edition holds possible, unlikely or false is quoted
|
|
188
173
|
* rather than stated, so that a reader of the RDF does not take it for
|
|
189
|
-
* a fact
|
|
190
|
-
* statement that belongs to a set names the set in its annotation,
|
|
191
|
-
* which in RDF makes the set its reifier, and the set, stated once
|
|
192
|
-
* beside the document, carries the belief. The edition given is not
|
|
193
|
-
* changed.
|
|
174
|
+
* a fact. The edition given is not changed.
|
|
194
175
|
* @category Reading and writing
|
|
195
176
|
*/
|
|
196
177
|
export const asJsonLd = (edition) => {
|
|
197
178
|
const quoted = [];
|
|
198
|
-
const node = withDoubtedReferencesQuoted(withSystemContexts(withCreations(withChanges(asJsonLdEntity(atOwnPlacesAll(edition))))), quoted
|
|
179
|
+
const node = withDoubtedReferencesQuoted(withSystemContexts(withCreations(withChanges(asJsonLdEntity(atOwnPlacesAll(edition))))), quoted);
|
|
199
180
|
// The context is the export's own; one carried in from an import must not override it.
|
|
200
181
|
const { base, '@context': carried, ...rest } = node;
|
|
201
182
|
return {
|
package/lib/io/importJsonLd.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { derivedKeys } from "./asJsonLd.js";
|
|
2
|
-
import { migrate, plainCopyId } from "./migrate.js";
|
|
2
|
+
import { migrate, plainCopyId, uncheckedMotivation } from "./migrate.js";
|
|
3
3
|
import { isDateString } from "../shared/utils.js";
|
|
4
4
|
import { putOnAxis } from "../collation/alignment.js";
|
|
5
|
+
import { editsOf } from "../model/Version.js";
|
|
6
|
+
import { motivationOfChanges, proposedMotivations } from "../filiation/edits.js";
|
|
5
7
|
import schema from "../schema.json" with { type: 'json' };
|
|
6
8
|
export const importDate = (str) => {
|
|
7
9
|
const [y, m, d] = str.split('-').map(s => parseInt(s, 10));
|
|
@@ -84,14 +86,15 @@ const withoutEmptyCreations = (json) => Array.isArray(json.versions)
|
|
|
84
86
|
/** A statement an export quoted rather than stated: an included node whose id is a triple. */
|
|
85
87
|
const isQuotedStatement = (node) => node !== null && typeof node === 'object' && node['@id'] !== null && typeof node['@id'] === 'object';
|
|
86
88
|
/**
|
|
87
|
-
* A belief named by its id alone, as a quoted statement
|
|
88
|
-
*
|
|
89
|
+
* A belief named by its id alone, as a quoted statement of a document
|
|
90
|
+
* written before 0.76 named the belief of the proposition set it
|
|
91
|
+
* belonged to, which was stated with the set (`migrate`).
|
|
89
92
|
*/
|
|
90
93
|
const isNamedBelief = (belief) => belief !== null && typeof belief === 'object' && Object.keys(belief).every(key => key === '@id');
|
|
91
94
|
/**
|
|
92
95
|
* The reference a quoted statement made, annotated again with the belief
|
|
93
|
-
* the export set beside it, or where it
|
|
94
|
-
* naming the set again.
|
|
96
|
+
* the export set beside it, or where it belonged to a proposition set,
|
|
97
|
+
* naming the set again for `migrate` to resolve.
|
|
95
98
|
*/
|
|
96
99
|
const referenceOf = (statement) => {
|
|
97
100
|
const { '@id': { '@id': subject, ...made }, annotation, ...stated } = statement;
|
|
@@ -153,5 +156,29 @@ export const importJsonLd = (json) => {
|
|
|
153
156
|
? context.find((c) => c['@base'])?.['@base'] || ''
|
|
154
157
|
: '';
|
|
155
158
|
(edition.copies ?? []).forEach(putOnAxis);
|
|
156
|
-
return edition;
|
|
159
|
+
return withKindsReadOffShapes(edition);
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* Gives an edit that a document written before 0.76 left unchecked the
|
|
163
|
+
* motivation its shape calls for, read in the edition as it stands: the
|
|
164
|
+
* generic musical one or the technical one (`migrate`). The
|
|
165
|
+
* shapes are read off a copy, since what reads an edition settles it
|
|
166
|
+
* for good, and the edition an import returns is the caller's to change.
|
|
167
|
+
*/
|
|
168
|
+
const withKindsReadOffShapes = (edition) => {
|
|
169
|
+
if (!(edition.versions ?? []).some(version => editsOf(version).some(edit => edit.motivation === uncheckedMotivation)))
|
|
170
|
+
return edition;
|
|
171
|
+
const probe = structuredClone(edition);
|
|
172
|
+
const versions = edition.versions.map(version => {
|
|
173
|
+
if (!editsOf(version).some(edit => edit.motivation === uncheckedMotivation))
|
|
174
|
+
return version;
|
|
175
|
+
const motivations = proposedMotivations(probe, version.id);
|
|
176
|
+
return {
|
|
177
|
+
...version,
|
|
178
|
+
edits: editsOf(version).map(edit => edit.motivation === uncheckedMotivation
|
|
179
|
+
? { ...edit, motivation: motivationOfChanges(motivations, [...(edit.insert ?? []).map(symbol => symbol.id), ...(edit.delete ?? [])]) }
|
|
180
|
+
: edit)
|
|
181
|
+
};
|
|
182
|
+
});
|
|
183
|
+
return { ...edition, versions };
|
|
157
184
|
};
|
package/lib/io/migrate.d.ts
CHANGED
|
@@ -13,6 +13,13 @@
|
|
|
13
13
|
type Json = any;
|
|
14
14
|
/** A copy's id without the `copy/` that documents of earlier releases put before it. */
|
|
15
15
|
export declare const plainCopyId: (id: string) => string;
|
|
16
|
+
/**
|
|
17
|
+
* The motivation an edit of a version that derives from another is left
|
|
18
|
+
* with where only the edition can tell what kind of change it is: one
|
|
19
|
+
* that states neither a kind nor a reason, as a collation once left
|
|
20
|
+
* them. `importJsonLd` reads its kind off its shape (`proposedMotivations`).
|
|
21
|
+
*/
|
|
22
|
+
export declare const uncheckedMotivation = "unchecked";
|
|
16
23
|
/**
|
|
17
24
|
* Brings the JSON of an edition written by an earlier release of the
|
|
18
25
|
* format up to the current shape. A document that is current already
|
package/lib/io/migrate.js
CHANGED
|
@@ -4,6 +4,7 @@ import { trackerBars } from "../systems/index.js";
|
|
|
4
4
|
import { welteT100 } from "../systems/welteT100/bar.js";
|
|
5
5
|
import { isDateString } from "../shared/utils.js";
|
|
6
6
|
import { mapped, withValues } from "../ops/immutable.js";
|
|
7
|
+
import { musicalChange, technicalChange } from "../model/Edit.js";
|
|
7
8
|
const retiredVersionTypes = new Set(['edition', 'unicum']);
|
|
8
9
|
/**
|
|
9
10
|
* The vocabulary the steps below were written against, as it stood in
|
|
@@ -76,7 +77,9 @@ const isTypedCorrectError = (edit) => edit !== null && typeof edit === 'object'
|
|
|
76
77
|
* it. An edit typed so states it as its motivation instead, where it
|
|
77
78
|
* gives none of its own, and the version states what the motivation
|
|
78
79
|
* means; one that gives a motivation of its own keeps that one. Either
|
|
79
|
-
* way it states no kind, its shape being left to be read again.
|
|
80
|
+
* way it states no kind, its shape being left to be read again. Once
|
|
81
|
+
* motivations are the edition's, a corrected error is a musical change
|
|
82
|
+
* (`withMotivationsOfTheEdition`).
|
|
80
83
|
*/
|
|
81
84
|
const withCorrectedErrorsMotivated = (node) => {
|
|
82
85
|
if (!Array.isArray(node.edits) || !node.edits.some(isTypedCorrectError))
|
|
@@ -706,6 +709,168 @@ const withReferenceCopy = (edition) => {
|
|
|
706
709
|
: edition;
|
|
707
710
|
};
|
|
708
711
|
const editionSteps = [withoutFormatVersion, withoutTempoAdjustment, withoutEditionType, withSystems, withEditors, withDerivationTolerance, withReferenceCopy];
|
|
712
|
+
/**
|
|
713
|
+
* The motivation an edit of a version that derives from another is left
|
|
714
|
+
* with where only the edition can tell what kind of change it is: one
|
|
715
|
+
* that states neither a kind nor a reason, as a collation once left
|
|
716
|
+
* them. `importJsonLd` reads its kind off its shape (`proposedMotivations`).
|
|
717
|
+
*/
|
|
718
|
+
export const uncheckedMotivation = 'unchecked';
|
|
719
|
+
/** The kinds of edit, as they were stated once, whose shape is a musical decision. */
|
|
720
|
+
const musicalEditTypes = new Set(['additional-accent', 'shift', 'shorten', 'prolong']);
|
|
721
|
+
/** The kinds of edit, as they were stated once, whose shape is a technical change. */
|
|
722
|
+
const technicalEditTypes = new Set(['recoding', 'remove-redundancy', 'add-redundancy']);
|
|
723
|
+
const isRecord = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
724
|
+
/** Whether the version derives from another, so that its edits are changes rather than its text. */
|
|
725
|
+
const derives = (version) => Array.isArray(version?.basedOn) ? version.basedOn.length > 0 : version?.basedOn !== undefined;
|
|
726
|
+
/**
|
|
727
|
+
* The motivation an edit states once motivations say what kind of
|
|
728
|
+
* change it is, from the kind it was given and the reason it gave.
|
|
729
|
+
*/
|
|
730
|
+
const motivationOfEdit = (editType, motivation, derived) => {
|
|
731
|
+
// A corrected error put back a perforation in its place, and so made a musical change.
|
|
732
|
+
const stated = motivation === 'corrected-error' ? musicalChange : motivation;
|
|
733
|
+
if (!derived)
|
|
734
|
+
return stated === uncheckedMotivation || stated === musicalChange ? undefined : stated;
|
|
735
|
+
const technical = typeof editType === 'string' && technicalEditTypes.has(editType);
|
|
736
|
+
// A reason given for a technical change explained what the change or the procedure says already.
|
|
737
|
+
if (technical)
|
|
738
|
+
return technicalChange;
|
|
739
|
+
if (stated === undefined || stated === uncheckedMotivation) {
|
|
740
|
+
return typeof editType === 'string' && musicalEditTypes.has(editType) ? musicalChange : uncheckedMotivation;
|
|
741
|
+
}
|
|
742
|
+
return stated;
|
|
743
|
+
};
|
|
744
|
+
/** Whether the document still states what motivations and kinds of edit were before 0.76. */
|
|
745
|
+
const statesMotivationsPerVersion = (versions) => versions.some(version => Array.isArray(version?.motivations)
|
|
746
|
+
|| (Array.isArray(version?.edits) && version.edits.some((edit) => isRecord(edit) && (Object.hasOwn(edit, 'editType') || edit.motivation === 'corrected-error'))));
|
|
747
|
+
/**
|
|
748
|
+
* Before 0.76 each version stated the motivations its edits named, and
|
|
749
|
+
* an edit stated its kind beside its reason. The motivations are the
|
|
750
|
+
* edition's now, once each, and the motivation alone says what kind of
|
|
751
|
+
* change an edit is (`kindOfChange`):
|
|
752
|
+
*
|
|
753
|
+
* - A motivation two versions stated under one id with different notes
|
|
754
|
+
* is kept under an id of its own for the second.
|
|
755
|
+
* - The unchecked motivation goes, and so does the declaration of a
|
|
756
|
+
* corrected error: it put a perforation back in its place, and so is
|
|
757
|
+
* a musical change whose reason is not given.
|
|
758
|
+
* - An edit of a version that derives from another, that gave no reason
|
|
759
|
+
* or only that it was unchecked, is a musical change whose reason is
|
|
760
|
+
* not given where its kind was an added accent, a shift, a shortening
|
|
761
|
+
* or a prolongation, and a technical change where it was a recoding or
|
|
762
|
+
* a redundancy removed or added. One that stated no kind is left
|
|
763
|
+
* unchecked, for an import to read its kind off its shape.
|
|
764
|
+
* - A reason given for a recoding or a redundancy goes, since a
|
|
765
|
+
* technical change needs none, and a motivation nothing names any
|
|
766
|
+
* longer goes with it. Every other reason stays, and makes the change
|
|
767
|
+
* a musical one.
|
|
768
|
+
* - The edits of a version that derives from none state its text and
|
|
769
|
+
* keep no motivation but a reason someone gave.
|
|
770
|
+
*/
|
|
771
|
+
const withMotivationsOfTheEdition = (edition) => {
|
|
772
|
+
const versions = listAt(edition, 'versions');
|
|
773
|
+
if (!versions || !statesMotivationsPerVersion(versions))
|
|
774
|
+
return edition;
|
|
775
|
+
const notes = new Map((listAt(edition, 'motivations') ?? []).filter(isRecord).map(motivation => [motivation['@id'], motivation]));
|
|
776
|
+
const referencedBefore = new Set();
|
|
777
|
+
const migrated = versions.map((version, index) => {
|
|
778
|
+
if (!isRecord(version))
|
|
779
|
+
return version;
|
|
780
|
+
const renamed = new Map();
|
|
781
|
+
for (const motivation of Array.isArray(version.motivations) ? version.motivations.filter(isRecord) : []) {
|
|
782
|
+
const id = motivation['@id'];
|
|
783
|
+
if (typeof id !== 'string' || id === uncheckedMotivation || id === 'corrected-error')
|
|
784
|
+
continue;
|
|
785
|
+
const known = notes.get(id);
|
|
786
|
+
if (!known)
|
|
787
|
+
notes.set(id, motivation);
|
|
788
|
+
else if (known.note !== motivation.note) {
|
|
789
|
+
const own = `${id}-${index}`;
|
|
790
|
+
renamed.set(id, own);
|
|
791
|
+
notes.set(own, { ...motivation, '@id': own });
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
const derived = derives(version);
|
|
795
|
+
const { motivations: _declared, ...rest } = version;
|
|
796
|
+
if (!Array.isArray(version.edits))
|
|
797
|
+
return rest;
|
|
798
|
+
return {
|
|
799
|
+
...rest,
|
|
800
|
+
edits: version.edits.map((edit) => {
|
|
801
|
+
if (!isRecord(edit))
|
|
802
|
+
return edit;
|
|
803
|
+
const { editType, motivation: given, ...stated } = edit;
|
|
804
|
+
const named = typeof given === 'string' ? renamed.get(given) ?? given : given;
|
|
805
|
+
if (typeof named === 'string')
|
|
806
|
+
referencedBefore.add(named);
|
|
807
|
+
const motivation = motivationOfEdit(editType, named, derived);
|
|
808
|
+
return motivation === undefined ? stated : { ...stated, motivation };
|
|
809
|
+
})
|
|
810
|
+
};
|
|
811
|
+
});
|
|
812
|
+
const referenced = new Set(migrated.flatMap((version) => (Array.isArray(version?.edits) ? version.edits : []).map((edit) => edit?.motivation).filter((id) => typeof id === 'string')));
|
|
813
|
+
const motivations = [...notes.values()].filter(motivation => referenced.has(motivation['@id']) || !referencedBefore.has(motivation['@id']));
|
|
814
|
+
const { motivations: _stated, ...rest } = edition;
|
|
815
|
+
return { ...rest, versions: migrated, ...(motivations.length > 0 && { motivations }) };
|
|
816
|
+
};
|
|
817
|
+
/**
|
|
818
|
+
* Before 0.76 an adopted proposal was recorded as a proposition set: each
|
|
819
|
+
* statement of it named the set in its annotation, and the set held them
|
|
820
|
+
* under one belief whose inference named the release that found them and
|
|
821
|
+
* the rules it followed. The edition states what a program concluded
|
|
822
|
+
* plainly now, and its creation names the rules among its principles and
|
|
823
|
+
* the release among its software. A statement of a set the edition held
|
|
824
|
+
* below likely keeps the doubt, under a belief of its own that is the
|
|
825
|
+
* set's.
|
|
826
|
+
*/
|
|
827
|
+
const withoutPropositionSets = (edition) => {
|
|
828
|
+
const sets = listAt(edition, 'propositionSets');
|
|
829
|
+
if (!sets)
|
|
830
|
+
return edition;
|
|
831
|
+
const beliefOf = new Map(sets.filter(isRecord).map(set => [set['@id'], set.belief]));
|
|
832
|
+
const inferences = sets.filter(isRecord).flatMap(set => Array.isArray(set.belief?.reasons) ? set.belief.reasons : []);
|
|
833
|
+
const rules = inferences.flatMap(inference => Array.isArray(inference?.applies) ? inference.applies : []);
|
|
834
|
+
const programs = inferences.flatMap(inference => Array.isArray(inference?.software) ? inference.software : []);
|
|
835
|
+
let held = 0;
|
|
836
|
+
const unset = (value) => {
|
|
837
|
+
if (Array.isArray(value))
|
|
838
|
+
return mapped(value, unset);
|
|
839
|
+
if (!isRecord(value))
|
|
840
|
+
return value;
|
|
841
|
+
const annotation = value['@annotation'];
|
|
842
|
+
const set = isRecord(annotation) && typeof annotation['@id'] === 'string' ? beliefOf.get(annotation['@id']) : undefined;
|
|
843
|
+
if (!set || (isRecord(annotation.belief) && Object.keys(annotation.belief).some(key => key !== '@id')))
|
|
844
|
+
return withValues(value, unset);
|
|
845
|
+
const { '@annotation': _member, ...rest } = value;
|
|
846
|
+
if (set.certainty === 'true' || set.certainty === 'likely')
|
|
847
|
+
return withValues(rest, unset);
|
|
848
|
+
held += 1;
|
|
849
|
+
return withValues({
|
|
850
|
+
...rest,
|
|
851
|
+
'@annotation': { '@id': `${annotation['@id']}/${held}`, belief: { ...set, '@id': `${set['@id']}/${held}` } }
|
|
852
|
+
}, unset);
|
|
853
|
+
};
|
|
854
|
+
const { propositionSets: _recorded, ...rest } = edition;
|
|
855
|
+
const unsetted = unset(rest);
|
|
856
|
+
const creation = isRecord(unsetted.creation) ? unsetted.creation : undefined;
|
|
857
|
+
if (!creation)
|
|
858
|
+
return unsetted;
|
|
859
|
+
const principles = [...new Set([...(Array.isArray(creation.principles) ? creation.principles : []), ...rules])];
|
|
860
|
+
const known = Array.isArray(creation.software) ? creation.software : [];
|
|
861
|
+
const software = [...known, ...programs.filter((program, index) => !known.some((other) => other?.name === program?.name && other?.version === program?.version)
|
|
862
|
+
&& programs.findIndex(other => other?.name === program?.name && other?.version === program?.version) === index)];
|
|
863
|
+
return {
|
|
864
|
+
...unsetted,
|
|
865
|
+
creation: {
|
|
866
|
+
...creation,
|
|
867
|
+
...(principles.length > 0 && { principles }),
|
|
868
|
+
...(software.length > 0 && { software })
|
|
869
|
+
}
|
|
870
|
+
};
|
|
871
|
+
};
|
|
872
|
+
/** Steps that read the document as the node steps leave it, an old document's kinds of edit renamed. */
|
|
873
|
+
const finalSteps = [withoutPropositionSets, withMotivationsOfTheEdition];
|
|
709
874
|
/**
|
|
710
875
|
* Brings the JSON of an edition written by an earlier release of the
|
|
711
876
|
* format up to the current shape. A document that is current already
|
|
@@ -714,4 +879,4 @@ const editionSteps = [withoutFormatVersion, withoutTempoAdjustment, withoutEditi
|
|
|
714
879
|
* to look at an old document as JSON.
|
|
715
880
|
* @category Reading and writing
|
|
716
881
|
*/
|
|
717
|
-
export const migrate = (edition) => walk(editionSteps.reduce((result, step) => step(result), edition));
|
|
882
|
+
export const migrate = (edition) => finalSteps.reduce((result, step) => step(result), walk(editionSteps.reduce((result, step) => step(result), edition)));
|
package/lib/model/Agent.d.ts
CHANGED
|
@@ -107,7 +107,9 @@ export type Concept = (WithId & Partial<Named>) | (Named & Partial<WithId>);
|
|
|
107
107
|
/**
|
|
108
108
|
* Software that captured a copy or measured it: the transcriber that
|
|
109
109
|
* read a recording into notes, the emulator that wrote a MIDI file, the
|
|
110
|
-
* program that found the holes on a scan or aligned two copies.
|
|
110
|
+
* program that found the holes on a scan or aligned two copies. Or the
|
|
111
|
+
* software an edition was made with, such as the release of this
|
|
112
|
+
* library that found its stemma.
|
|
111
113
|
* @see crmdig:D14 Software
|
|
112
114
|
* @category Format types
|
|
113
115
|
*/
|
|
@@ -21,10 +21,8 @@ export type Certainty = typeof certainties[number];
|
|
|
21
21
|
*/
|
|
22
22
|
export declare const isAsserted: (certainty: Certainty) => boolean;
|
|
23
23
|
/**
|
|
24
|
-
* The certainty a statement is held with
|
|
25
|
-
*
|
|
26
|
-
* proposition set is held with the set's belief, which `certaintyIn`
|
|
27
|
-
* reads.
|
|
24
|
+
* The certainty a statement is held with. One that carries no belief is
|
|
25
|
+
* stated plainly, and so held true.
|
|
28
26
|
* @category Assumptions and beliefs
|
|
29
27
|
*/
|
|
30
28
|
export declare const certaintyOf: (assumption: Readonly<Assumption>) => Certainty;
|
|
@@ -93,24 +91,6 @@ export interface Inference extends Argumentation<'inference'> {
|
|
|
93
91
|
* @see crminf:J3 applied
|
|
94
92
|
*/
|
|
95
93
|
applies?: string[];
|
|
96
|
-
/**
|
|
97
|
-
* The programs that drew the conclusion, each with its version,
|
|
98
|
-
* where a program drew it: a stemma `proposeStemma` found, which the
|
|
99
|
-
* editor ran and holds. The actor is the one who ran it, since a
|
|
100
|
-
* program holds no belief. Naming software makes the inference a
|
|
101
|
-
* digital machine event in the sense of CRMdig, which can be run
|
|
102
|
-
* again on what it used, and the note states what it was run with.
|
|
103
|
-
* @see crmdig:L23 used software or firmware
|
|
104
|
-
*/
|
|
105
|
-
software?: Software[];
|
|
106
|
-
/**
|
|
107
|
-
* When the conclusion was drawn. It is part of the reason and
|
|
108
|
-
* carries no belief of its own, and it tells a run of a program
|
|
109
|
-
* from the next, since a program may conclude otherwise once it, or
|
|
110
|
-
* what it used, has changed.
|
|
111
|
-
* @see crm:P4 has time-span
|
|
112
|
-
*/
|
|
113
|
-
date?: TimeSpan;
|
|
114
94
|
}
|
|
115
95
|
/**
|
|
116
96
|
* A belief adoption takes over someone else's belief without checking it:
|
|
@@ -224,76 +204,20 @@ export interface Assumption {
|
|
|
224
204
|
* Uses the JSON-LD-star `@annotation` mechanism to attach
|
|
225
205
|
* epistemic metadata (certainty and reasons) to any triple.
|
|
226
206
|
*
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
* the
|
|
207
|
+
* A statement that carries none is stated plainly, and what a
|
|
208
|
+
* program concluded is stated so too: an edition asserts its stemma
|
|
209
|
+
* and its edits, as a printed edition does, and its creation names
|
|
210
|
+
* the principles and the release they were found by
|
|
211
|
+
* (`EditionCreation`). A belief is kept for what the editor doubts.
|
|
231
212
|
*/
|
|
232
213
|
'@annotation'?: WithId & {
|
|
233
214
|
/**
|
|
234
|
-
* The belief held about the annotated statement
|
|
235
|
-
* held for itself rather than as one of a proposition set.
|
|
215
|
+
* The belief held about the annotated statement.
|
|
236
216
|
* @see crminf:J4i is subject of
|
|
237
217
|
*/
|
|
238
|
-
belief
|
|
218
|
+
belief: Belief;
|
|
239
219
|
};
|
|
240
220
|
}
|
|
241
|
-
/**
|
|
242
|
-
* Statements held together under one belief, because one reasoning
|
|
243
|
-
* concluded them together: the derivations and edits of a stemma, which
|
|
244
|
-
* a search such as `proposeStemma` scores as a whole rather than one
|
|
245
|
-
* derivation at a time, or the edits a proposal grouped the changes of
|
|
246
|
-
* versions into. Each statement belongs to the set by naming it in its
|
|
247
|
-
* annotation, which carries the set's id and no belief of its own, and
|
|
248
|
-
* the belief is stated here, once, with the reasoning that concluded
|
|
249
|
-
* it. Read as RDF, the set is the reifier of each statement that names
|
|
250
|
-
* it, which RDF 1.2 lets reify several.
|
|
251
|
-
*
|
|
252
|
-
* A statement the editor takes out of the set by giving it a belief of
|
|
253
|
-
* its own is the editor's, and its reasons can name the set's belief as
|
|
254
|
-
* a premise, so that what the editor decided apart from the program
|
|
255
|
-
* stays apart from it.
|
|
256
|
-
* @see crminf:I4 Proposition Set
|
|
257
|
-
* @category Format types
|
|
258
|
-
*/
|
|
259
|
-
export interface PropositionSet extends WithId {
|
|
260
|
-
type: 'propositionSet';
|
|
261
|
-
/**
|
|
262
|
-
* The belief the statements of the set are held with, and the
|
|
263
|
-
* reasons for it.
|
|
264
|
-
* @see crminf:J4i is subject of
|
|
265
|
-
*/
|
|
266
|
-
belief: Belief;
|
|
267
|
-
}
|
|
268
|
-
/**
|
|
269
|
-
* Whether the statement carries a belief of its own, rather than none
|
|
270
|
-
* or the belief of the proposition set it belongs to.
|
|
271
|
-
* @category Assumptions and beliefs
|
|
272
|
-
*/
|
|
273
|
-
export declare const isHeldForItself: (assumption: Readonly<Assumption>) => boolean;
|
|
274
|
-
/**
|
|
275
|
-
* The id of the proposition set the statement belongs to, where its
|
|
276
|
-
* annotation names one instead of carrying a belief.
|
|
277
|
-
* @category Assumptions and beliefs
|
|
278
|
-
*/
|
|
279
|
-
export declare const propositionSetOf: (assumption: Readonly<Assumption>) => string | undefined;
|
|
280
|
-
/**
|
|
281
|
-
* The belief the statement is held with in the edition: its own, or
|
|
282
|
-
* that of the proposition set it belongs to.
|
|
283
|
-
* @category Assumptions and beliefs
|
|
284
|
-
*/
|
|
285
|
-
export declare const beliefIn: (edition: {
|
|
286
|
-
propositionSets?: readonly PropositionSet[];
|
|
287
|
-
}, assumption: Readonly<Assumption>) => Belief | undefined;
|
|
288
|
-
/**
|
|
289
|
-
* The certainty the statement is held with in the edition: that of its
|
|
290
|
-
* own belief, or of the proposition set it belongs to. One that carries
|
|
291
|
-
* neither is stated plainly, and so held true.
|
|
292
|
-
* @category Assumptions and beliefs
|
|
293
|
-
*/
|
|
294
|
-
export declare const certaintyIn: (edition: {
|
|
295
|
-
propositionSets?: readonly PropositionSet[];
|
|
296
|
-
}, assumption: Readonly<Assumption>) => Certainty;
|
|
297
221
|
/**
|
|
298
222
|
* A value assumption wraps a literal value, e.g. a string, a number, a date, with an optional annotation.
|
|
299
223
|
* Used for properties where the value itself may be uncertain,
|
package/lib/model/Assumption.js
CHANGED
|
@@ -19,47 +19,11 @@ export const certainties = [
|
|
|
19
19
|
*/
|
|
20
20
|
export const isAsserted = (certainty) => certainty === 'true' || certainty === 'likely';
|
|
21
21
|
/**
|
|
22
|
-
* The certainty a statement is held with
|
|
23
|
-
*
|
|
24
|
-
* proposition set is held with the set's belief, which `certaintyIn`
|
|
25
|
-
* reads.
|
|
22
|
+
* The certainty a statement is held with. One that carries no belief is
|
|
23
|
+
* stated plainly, and so held true.
|
|
26
24
|
* @category Assumptions and beliefs
|
|
27
25
|
*/
|
|
28
|
-
export const certaintyOf = (assumption) => assumption['@annotation']?.belief
|
|
29
|
-
/**
|
|
30
|
-
* Whether the statement carries a belief of its own, rather than none
|
|
31
|
-
* or the belief of the proposition set it belongs to.
|
|
32
|
-
* @category Assumptions and beliefs
|
|
33
|
-
*/
|
|
34
|
-
export const isHeldForItself = (assumption) => assumption['@annotation']?.belief !== undefined;
|
|
35
|
-
/**
|
|
36
|
-
* The id of the proposition set the statement belongs to, where its
|
|
37
|
-
* annotation names one instead of carrying a belief.
|
|
38
|
-
* @category Assumptions and beliefs
|
|
39
|
-
*/
|
|
40
|
-
export const propositionSetOf = (assumption) => {
|
|
41
|
-
const annotation = assumption['@annotation'];
|
|
42
|
-
return annotation && annotation.belief === undefined ? annotation.id : undefined;
|
|
43
|
-
};
|
|
44
|
-
/**
|
|
45
|
-
* The belief the statement is held with in the edition: its own, or
|
|
46
|
-
* that of the proposition set it belongs to.
|
|
47
|
-
* @category Assumptions and beliefs
|
|
48
|
-
*/
|
|
49
|
-
export const beliefIn = (edition, assumption) => {
|
|
50
|
-
const own = assumption['@annotation']?.belief;
|
|
51
|
-
if (own)
|
|
52
|
-
return own;
|
|
53
|
-
const set = propositionSetOf(assumption);
|
|
54
|
-
return set === undefined ? undefined : edition.propositionSets?.find(candidate => candidate.id === set)?.belief;
|
|
55
|
-
};
|
|
56
|
-
/**
|
|
57
|
-
* The certainty the statement is held with in the edition: that of its
|
|
58
|
-
* own belief, or of the proposition set it belongs to. One that carries
|
|
59
|
-
* neither is stated plainly, and so held true.
|
|
60
|
-
* @category Assumptions and beliefs
|
|
61
|
-
*/
|
|
62
|
-
export const certaintyIn = (edition, assumption) => beliefIn(edition, assumption)?.certainty ?? 'true';
|
|
26
|
+
export const certaintyOf = (assumption) => assumption['@annotation']?.belief.certainty ?? 'true';
|
|
63
27
|
/**
|
|
64
28
|
* The value the assumption holds, without the belief about it.
|
|
65
29
|
* @category Assumptions and beliefs
|