linked-rolls 0.56.0 → 0.58.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.
Files changed (131) hide show
  1. package/README.md +54 -361
  2. package/lib/{constraints.d.ts → analysis/constraints.d.ts} +1 -1
  3. package/lib/{constraints.js → analysis/constraints.js} +9 -8
  4. package/lib/analysis/ownPaper.d.ts +26 -0
  5. package/lib/analysis/ownPaper.js +41 -0
  6. package/lib/{reservations.d.ts → analysis/reservations.d.ts} +3 -3
  7. package/lib/{reservations.js → analysis/reservations.js} +3 -3
  8. package/lib/{sigla.d.ts → analysis/sigla.d.ts} +2 -2
  9. package/lib/{sigla.js → analysis/sigla.js} +4 -4
  10. package/lib/{witnesses.d.ts → analysis/witnesses.d.ts} +2 -2
  11. package/lib/{witnesses.js → analysis/witnesses.js} +4 -4
  12. package/lib/{Collation.d.ts → collation/Collation.d.ts} +4 -4
  13. package/lib/{Collation.js → collation/Collation.js} +4 -4
  14. package/lib/{alignment.d.ts → collation/alignment.d.ts} +4 -4
  15. package/lib/{alignment.js → collation/alignment.js} +10 -16
  16. package/lib/{scatter.d.ts → collation/scatter.d.ts} +4 -4
  17. package/lib/{scatter.js → collation/scatter.js} +6 -6
  18. package/lib/{statistics.d.ts → collation/statistics.d.ts} +1 -1
  19. package/lib/{statistics.js → collation/statistics.js} +2 -2
  20. package/lib/{substitution.d.ts → collation/substitution.d.ts} +9 -24
  21. package/lib/{substitution.js → collation/substitution.js} +13 -37
  22. package/lib/emulation/Emulation.d.ts +64 -0
  23. package/lib/emulation/Emulation.js +282 -0
  24. package/lib/emulation/negotiation.d.ts +14 -0
  25. package/lib/emulation/negotiation.js +20 -0
  26. package/lib/index.d.ts +43 -35
  27. package/lib/index.js +36 -35
  28. package/lib/{asJsonLd.d.ts → io/asJsonLd.d.ts} +1 -1
  29. package/lib/{asJsonLd.js → io/asJsonLd.js} +22 -51
  30. package/lib/{context.d.ts → io/context.d.ts} +4 -4
  31. package/lib/{context.js → io/context.js} +4 -4
  32. package/lib/{importJsonLd.d.ts → io/importJsonLd.d.ts} +1 -1
  33. package/lib/io/importJsonLd.js +128 -0
  34. package/lib/{migrate.d.ts → io/migrate.d.ts} +9 -0
  35. package/lib/{migrate.js → io/migrate.js} +97 -54
  36. package/lib/{Agent.d.ts → model/Agent.d.ts} +1 -1
  37. package/lib/{Assumption.d.ts → model/Assumption.d.ts} +1 -1
  38. package/lib/{ConditionState.d.ts → model/ConditionState.d.ts} +1 -2
  39. package/lib/{Edit.d.ts → model/Edit.d.ts} +1 -1
  40. package/lib/{Edition.d.ts → model/Edition.d.ts} +2 -2
  41. package/lib/{Feature.d.ts → model/Feature.d.ts} +3 -1
  42. package/lib/{Feature.js → model/Feature.js} +2 -0
  43. package/lib/{FeatureSource.d.ts → model/FeatureSource.d.ts} +1 -1
  44. package/lib/{Perforator.d.ts → model/Perforator.d.ts} +1 -1
  45. package/lib/{RollCopy.d.ts → model/RollCopy.d.ts} +5 -12
  46. package/lib/{RollCopy.js → model/RollCopy.js} +3 -5
  47. package/lib/{Symbol.d.ts → model/Symbol.d.ts} +1 -1
  48. package/lib/{Version.d.ts → model/Version.d.ts} +11 -3
  49. package/lib/{Version.js → model/Version.js} +24 -1
  50. package/lib/{vocabulary.js → model/vocabulary.js} +2 -2
  51. package/lib/ops/beliefs.d.ts +9 -0
  52. package/lib/ops/beliefs.js +31 -0
  53. package/lib/ops/collation.d.ts +62 -0
  54. package/lib/ops/collation.js +228 -0
  55. package/lib/ops/commands.d.ts +9 -0
  56. package/lib/ops/commands.js +29 -0
  57. package/lib/ops/copies.d.ts +74 -0
  58. package/lib/ops/copies.js +135 -0
  59. package/lib/ops/draft.d.ts +59 -0
  60. package/lib/ops/draft.js +81 -0
  61. package/lib/ops/edits.d.ts +10 -0
  62. package/lib/ops/edits.js +82 -0
  63. package/lib/ops/features.d.ts +84 -0
  64. package/lib/ops/features.js +296 -0
  65. package/lib/ops/forget.d.ts +31 -0
  66. package/lib/ops/forget.js +110 -0
  67. package/lib/ops/immutable.d.ts +16 -0
  68. package/lib/ops/immutable.js +46 -0
  69. package/lib/ops/index.d.ts +13 -0
  70. package/lib/ops/index.js +7 -0
  71. package/lib/ops/versions.d.ts +33 -0
  72. package/lib/ops/versions.js +95 -0
  73. package/lib/readers/AtonParser.js +5 -7
  74. package/lib/readers/phillipsEroll.d.ts +3 -3
  75. package/lib/readers/phillipsEroll.js +4 -5
  76. package/lib/readers/spencerBar.d.ts +2 -2
  77. package/lib/readers/spencerBar.js +2 -3
  78. package/lib/readers/stanfordAton.d.ts +3 -3
  79. package/lib/readers/stanfordAton.js +2 -4
  80. package/lib/schema.json +11 -151
  81. package/lib/spec/context.json +2 -12
  82. package/lib/{ReproducingSystem.d.ts → systems/ReproducingSystem.d.ts} +3 -3
  83. package/lib/{TrackerBar.d.ts → systems/TrackerBar.d.ts} +48 -8
  84. package/lib/{TrackerBar.js → systems/TrackerBar.js} +11 -2
  85. package/lib/systems/index.d.ts +8 -2
  86. package/lib/systems/index.js +7 -1
  87. package/lib/systems/welte.d.ts +100 -0
  88. package/lib/systems/welte.js +119 -0
  89. package/lib/systems/welteLicensee/bar.d.ts +1 -1
  90. package/lib/systems/welteLicensee/bar.js +5 -2
  91. package/lib/systems/welteLicensee/system.d.ts +1 -1
  92. package/lib/systems/welteLicensee/system.js +1 -1
  93. package/lib/systems/welteT100/bar.d.ts +27 -1
  94. package/lib/systems/welteT100/bar.js +44 -2
  95. package/lib/systems/welteT100/system.d.ts +6 -39
  96. package/lib/systems/welteT100/system.js +19 -128
  97. package/lib/systems/welteT98/bar.d.ts +1 -1
  98. package/lib/systems/welteT98/bar.js +18 -2
  99. package/lib/systems/welteT98/system.d.ts +20 -38
  100. package/lib/systems/welteT98/system.js +20 -121
  101. package/lib/validate.d.ts +1 -1
  102. package/lib/{EditionView.d.ts → view/EditionView.d.ts} +38 -48
  103. package/lib/{EditionView.js → view/EditionView.js} +90 -96
  104. package/package.json +7 -2
  105. package/lib/Emulation.d.ts +0 -36
  106. package/lib/Emulation.js +0 -250
  107. package/lib/editionOps.d.ts +0 -260
  108. package/lib/editionOps.js +0 -1081
  109. package/lib/importJsonLd.js +0 -62
  110. /package/lib/{Agent.js → model/Agent.js} +0 -0
  111. /package/lib/{Assumption.js → model/Assumption.js} +0 -0
  112. /package/lib/{ConditionState.js → model/ConditionState.js} +0 -0
  113. /package/lib/{Edit.js → model/Edit.js} +0 -0
  114. /package/lib/{Edition.js → model/Edition.js} +0 -0
  115. /package/lib/{FeatureSource.js → model/FeatureSource.js} +0 -0
  116. /package/lib/{Perforator.js → model/Perforator.js} +0 -0
  117. /package/lib/{Quantity.d.ts → model/Quantity.d.ts} +0 -0
  118. /package/lib/{Quantity.js → model/Quantity.js} +0 -0
  119. /package/lib/{Symbol.js → model/Symbol.js} +0 -0
  120. /package/lib/{TrackCalibration.d.ts → model/TrackCalibration.d.ts} +0 -0
  121. /package/lib/{TrackCalibration.js → model/TrackCalibration.js} +0 -0
  122. /package/lib/{notes.d.ts → model/notes.d.ts} +0 -0
  123. /package/lib/{notes.js → model/notes.js} +0 -0
  124. /package/lib/{procedures.d.ts → model/procedures.d.ts} +0 -0
  125. /package/lib/{procedures.js → model/procedures.js} +0 -0
  126. /package/lib/{vocabulary.d.ts → model/vocabulary.d.ts} +0 -0
  127. /package/lib/{sorted.d.ts → shared/sorted.d.ts} +0 -0
  128. /package/lib/{sorted.js → shared/sorted.js} +0 -0
  129. /package/lib/{utils.d.ts → shared/utils.d.ts} +0 -0
  130. /package/lib/{utils.js → shared/utils.js} +0 -0
  131. /package/lib/{ReproducingSystem.js → systems/ReproducingSystem.js} +0 -0
@@ -0,0 +1,282 @@
1
+ import { MIDIControlEvents } from "midifile-ts";
2
+ import { idOf } from "../model/Assumption.js";
3
+ import { isCommand, pairsAmong, placementsOf } from "../model/Symbol.js";
4
+ import { add, mean, mm, seconds, subtract } from "../model/Quantity.js";
5
+ import { punchDiameterOf } from "../model/RollCopy.js";
6
+ import { toOwnPaperOf } from "../analysis/ownPaper.js";
7
+ import { negotiatedEventOf } from "./negotiation.js";
8
+ /** The punch diameter the edition's copies report, where any of them does. */
9
+ const meanPunchDiameterOf = (view) => {
10
+ const measured = view.edition.copies
11
+ .map(punchDiameterOf)
12
+ .filter(value => value !== undefined);
13
+ return measured.length > 0 ? mean(measured) : undefined;
14
+ };
15
+ const propertiesOf = (view, version) => ({
16
+ punchDiameter: meanPunchDiameterOf(view),
17
+ tempo: view.edition.tempoAdjustment,
18
+ toOwnPaper: toOwnPaperOf(view, version)
19
+ });
20
+ /** The onset a symbol has on each copy carrying it, by the copy's id, as the mean of its chains there. */
21
+ const onsetsByCopy = (view, symbolId) => {
22
+ const symbol = view.symbol(symbolId);
23
+ if (!symbol)
24
+ return new Map();
25
+ const onsets = view.placedCarriersOf(symbol).flatMap((carrier) => {
26
+ const copy = view.copyOf(carrier.id);
27
+ return copy ? [[copy.id, carrier.horizontal.from]] : [];
28
+ });
29
+ const copies = new Set(onsets.map(([copy]) => copy));
30
+ return new Map([...copies].map(copy => [copy, mean(onsets.filter(([at]) => at === copy).map(([, onset]) => onset))]));
31
+ };
32
+ /**
33
+ * The measured distance from the onset of the reference to the onset of
34
+ * the follower on each copy carrying both, negative where the follower
35
+ * comes first there.
36
+ */
37
+ const offsetsBetween = (view, followerId, referenceId) => {
38
+ const references = onsetsByCopy(view, referenceId);
39
+ return [...onsetsByCopy(view, followerId)].flatMap(([copy, onset]) => {
40
+ const reference = references.get(copy);
41
+ return reference === undefined ? [] : [subtract(onset, reference)];
42
+ });
43
+ };
44
+ /**
45
+ * How far before or after its reference a follower is put when the
46
+ * measurement does not already have it there: as far as the copies
47
+ * that agree with the statement put it, and one gap where none does.
48
+ */
49
+ const distanceOnSide = (side, offsets, gap) => {
50
+ const agreeing = offsets.filter(offset => side === 'before' ? offset < 0 : offset > 0);
51
+ return agreeing.length > 0 ? mm(Math.abs(mean(agreeing))) : gap;
52
+ };
53
+ /**
54
+ * How far each event has to move for the placements to hold:
55
+ * an aligned event takes the onset of its reference, one placed before
56
+ * or after its reference keeps its place where the measurement has it
57
+ * on that side and is moved there where it does not, and a paired
58
+ * event follows its partner so that the distance between the two is
59
+ * kept. Events that stay where they are do not appear.
60
+ */
61
+ const displacementsOf = (events, offsetsBetween, gap) => {
62
+ const byId = new Map(events.map(event => [event.id, event]));
63
+ /** Where an event comes to lie once its statement and those of its references hold. */
64
+ const placedOnsetOf = (event, visited = new Set()) => {
65
+ const measured = event.horizontal.from;
66
+ const placement = placementsOf(event)[0];
67
+ const reference = placement && byId.get(idOf(placement.reference));
68
+ if (!placement || !reference || reference.id === event.id || visited.has(event.id))
69
+ return measured;
70
+ const referenceOnset = placedOnsetOf(reference, new Set([...visited, event.id]));
71
+ const distance = (side) => distanceOnSide(side, offsetsBetween(event.id, reference.id), gap);
72
+ switch (placement.relation) {
73
+ case 'alignedWith': return referenceOnset;
74
+ case 'before': return measured < referenceOnset ? measured : subtract(referenceOnset, distance('before'));
75
+ case 'after': return measured > referenceOnset ? measured : add(referenceOnset, distance('after'));
76
+ }
77
+ };
78
+ const displacements = new Map(events
79
+ .map((event) => [event, subtract(placedOnsetOf(event), event.horizontal.from)])
80
+ .filter(([, distance]) => distance !== 0));
81
+ pairsAmong(events).forEach(([one, other]) => {
82
+ const shared = displacements.get(one) ?? displacements.get(other);
83
+ if (shared === undefined)
84
+ return;
85
+ displacements.set(one, shared);
86
+ displacements.set(other, shared);
87
+ });
88
+ return displacements;
89
+ };
90
+ /** The earliest of the times, or the beginning of the roll where there are none. */
91
+ const earliestOf = (times) => times.length === 0 ? seconds(0) : times.reduce((soonest, at) => at < soonest ? at : soonest);
92
+ /**
93
+ * The events moved to where their statements put them, the events given
94
+ * left as they were. The view supplies the copies, whose measurements
95
+ * decide how far before or after its reference a command goes, and a
96
+ * punch diameter, or a millimetre, where no copy agrees with a statement.
97
+ */
98
+ export const withPlacementsApplied = (view, events) => {
99
+ const gap = meanPunchDiameterOf(view) ?? mm(1);
100
+ const offsets = (follower, reference) => offsetsBetween(view, follower, reference);
101
+ const displacements = displacementsOf(events, offsets, gap);
102
+ return events.map(event => {
103
+ const distance = displacements.get(event);
104
+ return distance === undefined ? event : {
105
+ ...event,
106
+ horizontal: { ...event.horizontal, from: add(event.horizontal.from, distance), to: add(event.horizontal.to, distance) }
107
+ };
108
+ });
109
+ };
110
+ /**
111
+ * The commands of a version as the bar performs them, in order of place,
112
+ * within the scope and with the placements applied. A note plays only
113
+ * where its onset falls in the range; expressions play throughout.
114
+ */
115
+ export const negotiatedEventsOf = (view, version, bar, { range } = {}) => {
116
+ const inScope = (event) => !range || event.type !== 'note' || (event.horizontal.from > range[0] && event.horizontal.from < range[1]);
117
+ return withPlacementsApplied(view, view.snapshot(version.id)
118
+ .filter(isCommand)
119
+ .map(symbol => negotiatedEventOf(view, symbol, bar))
120
+ .filter(event => event !== null)
121
+ .filter(inScope));
122
+ };
123
+ /**
124
+ * Performs a version on a reproducing system: the symbols are negotiated
125
+ * into placed events and the system plays them. Nothing given is changed.
126
+ */
127
+ export const emulate = (system, version, view, options = system.defaultOptions, { range, skipToFirstNote = false } = {}) => {
128
+ const negotiated = negotiatedEventsOf(view, version, system.trackerBar, { range });
129
+ if (negotiated.length === 0)
130
+ return { source: version.id, negotiated, events: [], curves: [] };
131
+ const performance = system.perform(negotiated, options, propertiesOf(view, version));
132
+ const onsets = performance.events.filter(event => event.type === 'noteOn').map(event => event.at);
133
+ const origin = skipToFirstNote ? earliestOf(onsets) : seconds(0);
134
+ return {
135
+ source: version.id,
136
+ negotiated,
137
+ curves: performance.curves,
138
+ events: performance.events
139
+ .map(event => ({ ...event, at: subtract(event.at, origin) }))
140
+ .filter(event => event.at >= 0)
141
+ .sort((a, b) => a.at - b.at)
142
+ };
143
+ };
144
+ /**
145
+ * The performed events as a MIDI file, in which every note and pedal step
146
+ * is labelled with the symbol it performs. The file names the system, the
147
+ * version and the options it was played with.
148
+ */
149
+ export const midiOf = (events, systemName, options, source) => {
150
+ const TICKS_PER_SECOND = 1000;
151
+ const midi = [];
152
+ const text = (text, deltaTime = 0) => ({ type: 'meta', subtype: 'text', text, deltaTime });
153
+ const controller = (controllerType, value, deltaTime = 0) => ({ type: 'channel', subtype: 'controller', controllerType, value, deltaTime, channel: 0 });
154
+ const controllerOf = (event) => event.type === 'damper' ? MIDIControlEvents.SUSTAIN : MIDIControlEvents.SOFT_PEDAL;
155
+ midi.push(text(`linked-rolls (${systemName})`));
156
+ if (source) {
157
+ midi.push(text(source));
158
+ }
159
+ for (const [key, value] of Object.entries(options)) {
160
+ midi.push(text(`${key}=${typeof value === 'object' ? JSON.stringify(value) : value}`));
161
+ }
162
+ midi.push({
163
+ type: 'meta',
164
+ subtype: 'setTempo',
165
+ microsecondsPerBeat: 1000000,
166
+ deltaTime: 0
167
+ });
168
+ // both pedals start at rest
169
+ midi.push(controller(MIDIControlEvents.SUSTAIN, 0), controller(MIDIControlEvents.SOFT_PEDAL, 0));
170
+ // a pedal step is labelled with its command only where that
171
+ // command changes, so the file is not swamped with labels
172
+ const lastCause = {};
173
+ let currentTick = 0;
174
+ for (const event of events.toSorted((a, b) => a.at - b.at)) {
175
+ const tick = Math.round(event.at * TICKS_PER_SECOND);
176
+ const deltaTime = tick - currentTick;
177
+ currentTick = tick;
178
+ if (event.type === 'noteOn') {
179
+ midi.push(text(event.performs.id, deltaTime));
180
+ midi.push({
181
+ type: 'channel',
182
+ subtype: 'noteOn',
183
+ noteNumber: event.pitch,
184
+ velocity: +event.velocity.toFixed(0),
185
+ deltaTime: 0,
186
+ channel: 0
187
+ });
188
+ }
189
+ else if (event.type === 'noteOff') {
190
+ midi.push({
191
+ type: 'channel',
192
+ subtype: 'noteOff',
193
+ noteNumber: event.pitch,
194
+ velocity: 127,
195
+ deltaTime,
196
+ channel: 0
197
+ });
198
+ }
199
+ else {
200
+ const labelled = lastCause[event.type] === event.performs.id;
201
+ lastCause[event.type] = event.performs.id;
202
+ if (!labelled) {
203
+ midi.push(text(event.performs.id, deltaTime));
204
+ }
205
+ midi.push(controller(controllerOf(event), event.value, labelled ? deltaTime : 0));
206
+ }
207
+ }
208
+ return {
209
+ header: {
210
+ ticksPerBeat: TICKS_PER_SECOND,
211
+ formatType: 0,
212
+ trackCount: 1
213
+ },
214
+ tracks: [midi]
215
+ };
216
+ };
217
+ /**
218
+ * A version of the edition, performed and kept: `emulate` and `midiOf`
219
+ * with the result held on the object between the two calls. Prefer the
220
+ * functions where nothing needs holding.
221
+ */
222
+ export class Emulation {
223
+ constructor(system, options = system.defaultOptions) {
224
+ Object.defineProperty(this, "system", {
225
+ enumerable: true,
226
+ configurable: true,
227
+ writable: true,
228
+ value: void 0
229
+ });
230
+ Object.defineProperty(this, "options", {
231
+ enumerable: true,
232
+ configurable: true,
233
+ writable: true,
234
+ value: void 0
235
+ });
236
+ Object.defineProperty(this, "midiEvents", {
237
+ enumerable: true,
238
+ configurable: true,
239
+ writable: true,
240
+ value: []
241
+ });
242
+ // sorted list of events with the negotiated assumptions already applied
243
+ Object.defineProperty(this, "negotiatedEvents", {
244
+ enumerable: true,
245
+ configurable: true,
246
+ writable: true,
247
+ value: []
248
+ });
249
+ Object.defineProperty(this, "curves", {
250
+ enumerable: true,
251
+ configurable: true,
252
+ writable: true,
253
+ value: []
254
+ });
255
+ Object.defineProperty(this, "source", {
256
+ enumerable: true,
257
+ configurable: true,
258
+ writable: true,
259
+ value: void 0
260
+ });
261
+ this.system = system;
262
+ this.options = options;
263
+ }
264
+ /** Moves the negotiated events to where their statements put them; see `withPlacementsApplied`. */
265
+ applyConstraints(view) {
266
+ this.negotiatedEvents = withPlacementsApplied(view, this.negotiatedEvents);
267
+ }
268
+ emulateVersion(version, view, scope = {}) {
269
+ const emulated = emulate(this.system, version, view, this.options, scope);
270
+ this.source = emulated.source;
271
+ this.negotiatedEvents = [...emulated.negotiated];
272
+ this.curves = emulated.curves;
273
+ this.midiEvents = [...emulated.events];
274
+ return this.midiEvents;
275
+ }
276
+ findEventsPerforming(id) {
277
+ return this.midiEvents.filter(event => event.performs.id === id);
278
+ }
279
+ asMIDI() {
280
+ return midiOf(this.midiEvents, this.system.name, this.options, this.source);
281
+ }
282
+ }
@@ -0,0 +1,14 @@
1
+ import type { EditionView } from "../view/EditionView.js";
2
+ import type { Expression, Note } from "../model/Symbol.js";
3
+ import type { TrackerBar } from "../systems/TrackerBar.js";
4
+ import type { NegotiatedEvent } from "../systems/ReproducingSystem.js";
5
+ /**
6
+ * The symbol as a performance needs it: where it lies, and the
7
+ * position the performing bar reads it on.
8
+ *
9
+ * Nothing where that bar reads nothing of it, which is the case a
10
+ * transfer between systems leaves behind: a red `ForzandoOn` a
11
+ * green version still inherits cannot be performed on a green
12
+ * machine, and an edit has yet to say what took its place.
13
+ */
14
+ export declare const negotiatedEventOf: (view: EditionView, symbol: Note | Expression, bar: TrackerBar) => NegotiatedEvent | null;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The symbol as a performance needs it: where it lies, and the
3
+ * position the performing bar reads it on.
4
+ *
5
+ * Nothing where that bar reads nothing of it, which is the case a
6
+ * transfer between systems leaves behind: a red `ForzandoOn` a
7
+ * green version still inherits cannot be performed on a green
8
+ * machine, and an edit has yet to say what took its place.
9
+ */
10
+ export const negotiatedEventOf = (view, symbol, bar) => {
11
+ const horizontal = view.placeOf(symbol);
12
+ const position = bar.positionOf(symbol);
13
+ if (!horizontal || position === undefined)
14
+ return null;
15
+ return {
16
+ ...symbol,
17
+ horizontal,
18
+ vertical: { unit: 'track', from: position }
19
+ };
20
+ };
package/lib/index.d.ts CHANGED
@@ -1,43 +1,51 @@
1
- export * from './utils.js';
2
- export * from './Quantity.js';
3
- export * from './Agent.js';
4
- export * from './Assumption.js';
5
- export * from './ConditionState.js';
6
- export * from './Symbol.js';
7
- export * from './Feature.js';
8
- export * from './Edit.js';
9
- export * from './Version.js';
10
- export * from './Collation.js';
11
- export * from './TrackCalibration.js';
12
- export * from './TrackerBar.js';
1
+ /**
2
+ * The public interface of the library. Everything else under lib/ is its
3
+ * implementation and may change in any release: the in-place helpers the
4
+ * operations are built from, the date conversions of the serialisation,
5
+ * and the general utilities.
6
+ */
7
+ export type { WithId, WithNote, WithType } from './shared/utils.js';
8
+ export * from './model/Quantity.js';
9
+ export * from './model/Agent.js';
10
+ export * from './model/Assumption.js';
11
+ export * from './model/ConditionState.js';
12
+ export * from './model/Symbol.js';
13
+ export * from './model/Feature.js';
14
+ export * from './model/Edit.js';
15
+ export * from './model/Version.js';
16
+ export * from './collation/Collation.js';
17
+ export * from './model/TrackCalibration.js';
18
+ export * from './systems/TrackerBar.js';
13
19
  export * from './systems/welteT100/bar.js';
14
20
  export * from './systems/welteLicensee/bar.js';
15
21
  export * from './systems/welteT98/bar.js';
16
22
  export * from './systems/index.js';
17
- export * from './ReproducingSystem.js';
18
- export * from './FeatureSource.js';
19
- export * from './Perforator.js';
20
- export * from './RollCopy.js';
21
- export * from './procedures.js';
22
- export * from './vocabulary.js';
23
- export * from './reservations.js';
24
- export * from './witnesses.js';
25
- export * from './alignment.js';
26
- export * from './statistics.js';
27
- export * from './Edition.js';
28
- export * from './EditionView.js';
29
- export * from './scatter.js';
30
- export * from './editionOps.js';
31
- export * from './Emulation.js';
23
+ export * from './systems/ReproducingSystem.js';
24
+ export * from './model/FeatureSource.js';
25
+ export * from './model/Perforator.js';
26
+ export * from './model/RollCopy.js';
27
+ export * from './model/procedures.js';
28
+ export * from './model/vocabulary.js';
29
+ export * from './analysis/reservations.js';
30
+ export * from './analysis/witnesses.js';
31
+ export { alignFeatures, tooShortToShorten, type AlignmentResult } from './collation/alignment.js';
32
+ export * from './collation/statistics.js';
33
+ export * from './model/Edition.js';
34
+ export * from './view/EditionView.js';
35
+ export * from './analysis/ownPaper.js';
36
+ export * from './emulation/negotiation.js';
37
+ export * from './collation/scatter.js';
38
+ export * from './ops/index.js';
39
+ export * from './emulation/Emulation.js';
32
40
  export * from './validate.js';
33
- export * from './constraints.js';
34
- export * from './substitution.js';
35
- export * from './context.js';
36
- export * from './sigla.js';
37
- export * from './notes.js';
38
- export * from './asJsonLd.js';
39
- export * from './importJsonLd.js';
40
- export * from './migrate.js';
41
+ export * from './analysis/constraints.js';
42
+ export * from './collation/substitution.js';
43
+ export * from './io/context.js';
44
+ export * from './analysis/sigla.js';
45
+ export * from './model/notes.js';
46
+ export { asJsonLd } from './io/asJsonLd.js';
47
+ export { importJsonLd } from './io/importJsonLd.js';
48
+ export { formatVersion, migrate } from './io/migrate.js';
41
49
  export { readFromStanfordAton, type StanfordAtonOptions } from './readers/stanfordAton.js';
42
50
  export { readFromPhillipsEroll, CONTROL_OFFSET, phillipsSystems, type PhillipsErollOptions } from './readers/phillipsEroll.js';
43
51
  export { readFromSpencerBar, readSpencerAnn, paperSpeedOfSpencerAnn, SPENCER_ROWS_PER_INCH, type SpencerBarOptions } from './readers/spencerBar.js';
package/lib/index.js CHANGED
@@ -1,43 +1,44 @@
1
- export * from './utils.js';
2
- export * from './Quantity.js';
3
- export * from './Agent.js';
4
- export * from './Assumption.js';
5
- export * from './ConditionState.js';
6
- export * from './Symbol.js';
7
- export * from './Feature.js';
8
- export * from './Edit.js';
9
- export * from './Version.js';
10
- export * from './Collation.js';
11
- export * from './TrackCalibration.js';
12
- export * from './TrackerBar.js';
1
+ export * from './model/Quantity.js';
2
+ export * from './model/Agent.js';
3
+ export * from './model/Assumption.js';
4
+ export * from './model/ConditionState.js';
5
+ export * from './model/Symbol.js';
6
+ export * from './model/Feature.js';
7
+ export * from './model/Edit.js';
8
+ export * from './model/Version.js';
9
+ export * from './collation/Collation.js';
10
+ export * from './model/TrackCalibration.js';
11
+ export * from './systems/TrackerBar.js';
13
12
  export * from './systems/welteT100/bar.js';
14
13
  export * from './systems/welteLicensee/bar.js';
15
14
  export * from './systems/welteT98/bar.js';
16
15
  export * from './systems/index.js';
17
- export * from './ReproducingSystem.js';
18
- export * from './FeatureSource.js';
19
- export * from './Perforator.js';
20
- export * from './RollCopy.js';
21
- export * from './procedures.js';
22
- export * from './vocabulary.js';
23
- export * from './reservations.js';
24
- export * from './witnesses.js';
25
- export * from './alignment.js';
26
- export * from './statistics.js';
27
- export * from './Edition.js';
28
- export * from './EditionView.js';
29
- export * from './scatter.js';
30
- export * from './editionOps.js';
31
- export * from './Emulation.js';
16
+ export * from './systems/ReproducingSystem.js';
17
+ export * from './model/FeatureSource.js';
18
+ export * from './model/Perforator.js';
19
+ export * from './model/RollCopy.js';
20
+ export * from './model/procedures.js';
21
+ export * from './model/vocabulary.js';
22
+ export * from './analysis/reservations.js';
23
+ export * from './analysis/witnesses.js';
24
+ export { alignFeatures, tooShortToShorten } from './collation/alignment.js';
25
+ export * from './collation/statistics.js';
26
+ export * from './model/Edition.js';
27
+ export * from './view/EditionView.js';
28
+ export * from './analysis/ownPaper.js';
29
+ export * from './emulation/negotiation.js';
30
+ export * from './collation/scatter.js';
31
+ export * from './ops/index.js';
32
+ export * from './emulation/Emulation.js';
32
33
  export * from './validate.js';
33
- export * from './constraints.js';
34
- export * from './substitution.js';
35
- export * from './context.js';
36
- export * from './sigla.js';
37
- export * from './notes.js';
38
- export * from './asJsonLd.js';
39
- export * from './importJsonLd.js';
40
- export * from './migrate.js';
34
+ export * from './analysis/constraints.js';
35
+ export * from './collation/substitution.js';
36
+ export * from './io/context.js';
37
+ export * from './analysis/sigla.js';
38
+ export * from './model/notes.js';
39
+ export { asJsonLd } from './io/asJsonLd.js';
40
+ export { importJsonLd } from './io/importJsonLd.js';
41
+ export { formatVersion, migrate } from './io/migrate.js';
41
42
  export { readFromStanfordAton } from './readers/stanfordAton.js';
42
43
  export { readFromPhillipsEroll, CONTROL_OFFSET, phillipsSystems } from './readers/phillipsEroll.js';
43
44
  export { readFromSpencerBar, readSpencerAnn, paperSpeedOfSpencerAnn, SPENCER_ROWS_PER_INCH } from './readers/spencerBar.js';
@@ -1,4 +1,4 @@
1
- import { Edition } from "./Edition.js";
1
+ import { Edition } from "../model/Edition.js";
2
2
  /**
3
3
  * The keys an export derives from the tree, which no node of the
4
4
  * edition states itself. An import reads them off again.
@@ -1,11 +1,12 @@
1
- import { systemIdIn } from "./TrackerBar.js";
2
- import { certaintyOf, isAsserted } from "./Assumption.js";
3
- import context from "./spec/context.json" with { type: 'json' };
1
+ import { systemIdIn } from "../systems/TrackerBar.js";
2
+ import { certaintyOf, isAsserted } from "../model/Assumption.js";
3
+ import context from "../spec/context.json" with { type: 'json' };
4
+ import { formatVersion } from "./migrate.js";
4
5
  /**
5
6
  * The keys an export derives from the tree, which no node of the
6
7
  * edition states itself. An import reads them off again.
7
8
  */
8
- export const derivedKeys = new Set(['bears', 'composedOf', 'augmented', 'diminished']);
9
+ export const derivedKeys = new Set(['augmented', 'diminished']);
9
10
  export const exportDate = (date) => {
10
11
  const year = date.getFullYear();
11
12
  const month = String(date.getMonth() + 1).padStart(2, "0");
@@ -53,32 +54,12 @@ const asJsonLdEntity = (obj) => {
53
54
  * reading as whichever came last. An embedded context merges with the
54
55
  * active one, so the shared prefixes survive.
55
56
  */
56
- const withSystemContexts = (node) => {
57
- if (Array.isArray(node))
58
- return node.map(withSystemContexts);
59
- if (node === null || typeof node !== 'object')
60
- return node;
61
- const walked = Object.fromEntries(Object.entries(node).map(([key, value]) => [key, withSystemContexts(value)]));
62
- const system = node['@type'] === 'Version'
63
- ? systemIdIn(node.system?.['@id'])
64
- : undefined;
65
- return system
66
- ? { '@context': `https://w3id.org/reo/${system}/context.jsonld`, ...walked }
67
- : walked;
57
+ const withSystemContext = (version) => {
58
+ const system = systemIdIn(version?.system?.['@id']);
59
+ return system ? { '@context': `https://w3id.org/reo/${system}/context.jsonld`, ...version } : version;
68
60
  };
61
+ const withSystemContexts = (edition) => Array.isArray(edition.versions) ? { ...edition, versions: edition.versions.map(withSystemContext) } : edition;
69
62
  const isRecord = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);
70
- const nodesIn = (value) => Array.isArray(value) ? value.filter(isRecord) : [];
71
- /** What the acts of a copy brought onto it: the features they produced and the patches they glued on. */
72
- const madeOn = (copy) => [
73
- ...nodesIn(copy.production?.produced),
74
- ...nodesIn(copy.modifications).flatMap(act => [...nodesIn(act.produced), ...nodesIn(act.added)])
75
- ];
76
- const referencing = (nodes, patches) => nodes.filter(node => (node['@type'] === 'Patch') === patches && typeof node['@id'] === 'string')
77
- .map(node => ({ '@id': node['@id'] }));
78
- const featuresAmong = (nodes) => referencing(nodes, false);
79
- const patchesAmong = (nodes) => referencing(nodes, true);
80
- /** The key, where there is anything to state under it. */
81
- const stating = (key, references) => references.length > 0 ? { [key]: references } : {};
82
63
  /** The act with what it changed named: an attachment augments the copy, a removal diminishes it. */
83
64
  const changing = (copyId) => (act) => {
84
65
  if (typeof copyId !== 'string' || !isRecord(act))
@@ -90,31 +71,21 @@ const changing = (copyId) => (act) => {
90
71
  return act;
91
72
  };
92
73
  /**
93
- * The document with every bearing stated that its tree only implies. A
94
- * copy bears the features its acts brought about and is composed of the
95
- * patches they glued on, a patch bears the features glued onto it in
96
- * turn. Each feature stands in the act that made it and nothing reads a
97
- * bearing off that, so the export states it; a patch is no feature, and
98
- * P56 bears feature takes only features, so a patch is stated as a part.
74
+ * The document with what each act changed stated. Which of P110
75
+ * augmented and P112 diminished applies depends on the class of the
76
+ * act, which no property chain in OWL 2 RL can test, so the export
77
+ * states it. What a copy or a patch bears is left to a reasoner (see
78
+ * the entailments in reo.ttl).
99
79
  */
100
- const withBearings = (value) => {
80
+ const withChanges = (value) => {
101
81
  if (Array.isArray(value))
102
- return value.map(withBearings);
82
+ return value.map(withChanges);
103
83
  if (!isRecord(value))
104
84
  return value;
105
- const node = Object.fromEntries(Object.entries(value).map(([key, child]) => [key, withBearings(child)]));
106
- if (node['@type'] === 'RollCopy') {
107
- const made = madeOn(node);
108
- return {
109
- ...node,
110
- ...(Array.isArray(node.modifications) && { modifications: node.modifications.map(changing(node['@id'])) }),
111
- ...stating('bears', featuresAmong(made)),
112
- ...stating('composedOf', patchesAmong(made))
113
- };
114
- }
115
- if (node['@type'] === 'Patch')
116
- return { ...node, ...stating('bears', featuresAmong(nodesIn(node.features))) };
117
- return node;
85
+ const node = Object.fromEntries(Object.entries(value).map(([key, child]) => [key, withChanges(child)]));
86
+ return node['@type'] === 'RollCopy' && Array.isArray(node.modifications)
87
+ ? { ...node, modifications: node.modifications.map(changing(node['@id'])) }
88
+ : node;
118
89
  };
119
90
  /** Terms the context sets to null, which say nothing when the edition is read as RDF. */
120
91
  const silentTerms = new Set(Object.entries(context['@context'])
@@ -182,7 +153,7 @@ const withDoubtedReferencesQuoted = (value) => {
182
153
  };
183
154
  };
184
155
  export const asJsonLd = (edition) => {
185
- const { node, quoted } = withDoubtedReferencesQuoted(withSystemContexts(withBearings(asJsonLdEntity(edition))));
156
+ const { node, quoted } = withDoubtedReferencesQuoted(withSystemContexts(withChanges(asJsonLdEntity(edition))));
186
157
  // The context is the export's own; one carried in from an import must not override it.
187
158
  const { base, '@context': carried, ...rest } = node;
188
159
  return {
@@ -192,8 +163,8 @@ export const asJsonLd = (edition) => {
192
163
  '@base': edition.base
193
164
  }
194
165
  ],
195
- '@type': "Edition",
196
166
  '@id': edition.base,
167
+ formatVersion,
197
168
  ...rest,
198
169
  ...(quoted.length > 0 && { '@included': quoted })
199
170
  };
@@ -1,12 +1,12 @@
1
- export { default as jsonLdContext } from './spec/context.json';
1
+ export { default as jsonLdContext } from '../spec/context.json';
2
2
  /** The context of the Welte-Mignon T-100, added to a version coded for it. */
3
- export { default as welteT100JsonLdContext } from './spec/welte-t100.context.json';
3
+ export { default as welteT100JsonLdContext } from '../spec/welte-t100.context.json';
4
4
  /**
5
5
  * The context of the Welte-Mignon Licensee. Its expression terms are
6
6
  * the T-100's, the two systems differing in the tracker scale rather
7
7
  * than in the coding, so it reads them out of the T-100's vocabulary
8
8
  * rather than minting a second set of IRIs for the same commands.
9
9
  */
10
- export { default as welteLicenseeJsonLdContext } from './spec/welte-licensee.context.json';
10
+ export { default as welteLicenseeJsonLdContext } from '../spec/welte-licensee.context.json';
11
11
  /** The context of the Welte-Mignon T-98, added to an edition of a green roll. */
12
- export { default as welteT98JsonLdContext } from './spec/welte-t98.context.json';
12
+ export { default as welteT98JsonLdContext } from '../spec/welte-t98.context.json';
@@ -1,12 +1,12 @@
1
- export { default as jsonLdContext } from './spec/context.json' with { type: 'json' };
1
+ export { default as jsonLdContext } from '../spec/context.json' with { type: 'json' };
2
2
  /** The context of the Welte-Mignon T-100, added to a version coded for it. */
3
- export { default as welteT100JsonLdContext } from './spec/welte-t100.context.json' with { type: 'json' };
3
+ export { default as welteT100JsonLdContext } from '../spec/welte-t100.context.json' with { type: 'json' };
4
4
  /**
5
5
  * The context of the Welte-Mignon Licensee. Its expression terms are
6
6
  * the T-100's, the two systems differing in the tracker scale rather
7
7
  * than in the coding, so it reads them out of the T-100's vocabulary
8
8
  * rather than minting a second set of IRIs for the same commands.
9
9
  */
10
- export { default as welteLicenseeJsonLdContext } from './spec/welte-licensee.context.json' with { type: 'json' };
10
+ export { default as welteLicenseeJsonLdContext } from '../spec/welte-licensee.context.json' with { type: 'json' };
11
11
  /** The context of the Welte-Mignon T-98, added to an edition of a green roll. */
12
- export { default as welteT98JsonLdContext } from './spec/welte-t98.context.json' with { type: 'json' };
12
+ export { default as welteT98JsonLdContext } from '../spec/welte-t98.context.json' with { type: 'json' };
@@ -1,4 +1,4 @@
1
- import { Edition } from "./Edition.js";
1
+ import { Edition } from "../model/Edition.js";
2
2
  export declare const importDate: (str: string) => Date;
3
3
  type Json = any;
4
4
  export declare const importJsonLd: (json: Json) => Edition;