linked-rolls 0.4.0 → 0.4.1

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/lib/Plan.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Draft } from "immer";
2
2
  import { EditionView } from "./EditionView";
3
3
  import { Edition } from "./Edition";
4
+ import { AnySymbol } from "./Symbol";
4
5
  import { CollationTolerance } from "./Collation";
5
6
  import { Edit } from "./Edit";
6
7
  import { RollCopy } from "./RollCopy";
@@ -175,6 +176,13 @@ export declare class RemoveFeature extends BasePlan {
175
176
  constructor(copyID: string, featureIDs: string[]);
176
177
  build(): EditionOp[];
177
178
  }
179
+ /** The symbols of the versions that no other copy carries. */
180
+ export declare const symbolsCarriedOnlyBy: (edition: Edition, copyId: string) => AnySymbol[];
181
+ /**
182
+ * Takes the copy out of the edition together with the symbols only it
183
+ * carries, and with every reference the versions made to those symbols.
184
+ */
185
+ export declare const removeCopy: (copyId: string) => EditionOp;
178
186
  export declare class MergeEdits extends BasePlan {
179
187
  private versionId;
180
188
  private toMerge;
package/lib/Plan.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { getAt } from "./EditionView";
2
+ import { isPerforation, placementRelations } from "./Symbol";
2
3
  import { v4 } from "uuid";
3
4
  import { asSymbols } from "./RollCopy";
4
5
  import { assignReference, idOf } from "./Assumption";
@@ -378,6 +379,60 @@ export class RemoveFeature extends BasePlan {
378
379
  ];
379
380
  }
380
381
  }
382
+ const featureIdsOf = (copy) => new Set(copy.features.map(feature => feature.id));
383
+ const insertedIn = (versions) => versions.flatMap(version => version.edits).flatMap(edit => edit.insert ?? []);
384
+ /**
385
+ * A symbol every carrier of which lies on the copy loses its evidence
386
+ * with the copy. A symbol without carriers, such as a label, stands
387
+ * on its own.
388
+ */
389
+ const carriedOnlyOn = (features) => (symbol) => symbol.carriers.length > 0 && symbol.carriers.every(carrier => features.has(idOf(carrier)));
390
+ /** The symbols of the versions that no other copy carries. */
391
+ export const symbolsCarriedOnlyBy = (edition, copyId) => {
392
+ const copy = edition.copies.find(c => c.id === copyId);
393
+ return copy ? insertedIn(edition.versions).filter(carriedOnlyOn(featureIdsOf(copy))) : [];
394
+ };
395
+ const references = [...placementRelations, 'pairedWith'];
396
+ const forgetPerforations = (perforation, dropped) => references
397
+ .filter(relation => {
398
+ const reference = perforation[relation];
399
+ return reference && dropped.has(idOf(reference));
400
+ })
401
+ .forEach(relation => { delete perforation[relation]; });
402
+ const forgetFeatures = (symbol, features, dropped) => {
403
+ symbol.carriers = symbol.carriers.filter(carrier => !features.has(idOf(carrier)));
404
+ if (isPerforation(symbol))
405
+ forgetPerforations(symbol, dropped);
406
+ };
407
+ const forgetCopy = (edit, features, dropped) => {
408
+ if (edit.insert) {
409
+ edit.insert = edit.insert.filter(symbol => !dropped.has(symbol.id));
410
+ edit.insert.forEach(symbol => forgetFeatures(symbol, features, dropped));
411
+ }
412
+ if (edit.delete) {
413
+ edit.delete = edit.delete.filter(id => !dropped.has(id));
414
+ }
415
+ };
416
+ const isEmpty = (edit) => !edit.insert?.length && !edit.delete?.length;
417
+ /** Drops the edits the removal has emptied and leaves those that were empty before alone. */
418
+ const forgetCopyIn = (version, features, dropped) => {
419
+ const emptyBefore = new Set(version.edits.filter(isEmpty).map(edit => edit.id));
420
+ version.edits.forEach(edit => forgetCopy(edit, features, dropped));
421
+ version.edits = version.edits.filter(edit => !isEmpty(edit) || emptyBefore.has(edit.id));
422
+ };
423
+ /**
424
+ * Takes the copy out of the edition together with the symbols only it
425
+ * carries, and with every reference the versions made to those symbols.
426
+ */
427
+ export const removeCopy = (copyId) => draft => {
428
+ const copy = draft.copies.find(c => c.id === copyId);
429
+ if (!copy)
430
+ return;
431
+ const features = featureIdsOf(copy);
432
+ const dropped = new Set(insertedIn(draft.versions).filter(carriedOnlyOn(features)).map(symbol => symbol.id));
433
+ draft.copies = draft.copies.filter(c => c.id !== copyId);
434
+ draft.versions.forEach(version => forgetCopyIn(version, features, dropped));
435
+ };
381
436
  export class MergeEdits extends BasePlan {
382
437
  constructor(versionId, toMerge) {
383
438
  super();
package/lib/Symbol.d.ts CHANGED
@@ -19,6 +19,7 @@ export interface Symbol<T extends string> extends WithId {
19
19
  carriers: ReferenceAssumption[];
20
20
  }
21
21
  export declare const isSymbol: (object: any) => object is AnySymbol;
22
+ export declare const isPerforation: (symbol: AnySymbol) => symbol is Note | Expression;
22
23
  /**
23
24
  * A perforation is a symbol that is typically encoded as a single punched
24
25
  * hole or a group of punched holes in the physical carrier.
package/lib/Symbol.js CHANGED
@@ -3,6 +3,7 @@ export const isSymbol = (object) => {
3
3
  return ('type' in object
4
4
  && (object.type === 'note' || object.type === 'expression' || object.type === 'text'));
5
5
  };
6
+ export const isPerforation = (symbol) => symbol.type !== 'text';
6
7
  export const placementRelations = ['alignedWith', 'before', 'after'];
7
8
  /**
8
9
  * The statements placing a perforation relative to others, alignment
package/lib/schema.json CHANGED
@@ -1189,7 +1189,7 @@
1189
1189
  ],
1190
1190
  "type": "object"
1191
1191
  },
1192
- "ObjectAssumption<alias-731470504-73739-73887-731470504-0-217694<def-interface-src_Symbol.ts-5565-5929-src_Symbol.ts-0-6137400334313,\"carriers\">>": {
1192
+ "ObjectAssumption<alias-731470504-73739-73887-731470504-0-217694<def-interface-src_Symbol.ts-5670-6034-src_Symbol.ts-0-6242400334313,\"carriers\">>": {
1193
1193
  "description": "An object assumption wraps a complex object with an optional annotation. Used for structured values (e.g. persons, conditions) whose properties may be uncertain.",
1194
1194
  "properties": {
1195
1195
  "@annotation": {
@@ -1760,7 +1760,7 @@
1760
1760
  "description": "The method by which this writing was produced (e.g. through print, handwriting, or stamping). [ontology: crm:P2 has type]"
1761
1761
  },
1762
1762
  "transcription": {
1763
- "$ref": "#/definitions/ObjectAssumption%3Calias-731470504-73739-73887-731470504-0-217694%3Cdef-interface-src_Symbol.ts-5565-5929-src_Symbol.ts-0-6137400334313%2C%22carriers%22%3E%3E",
1763
+ "$ref": "#/definitions/ObjectAssumption%3Calias-731470504-73739-73887-731470504-0-217694%3Cdef-interface-src_Symbol.ts-5670-6034-src_Symbol.ts-0-6242400334313%2C%22carriers%22%3E%3E",
1764
1764
  "description": "A transcription of the text content of the writing. This is an object assumption so that the transcription can be annotated with a belief about its correctness. [ontology: crm:P128 carries]"
1765
1765
  },
1766
1766
  "vertical": {
package/lib/validate.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import Ajv from "ajv";
2
2
  import * as schema from "./schema.json";
3
3
  import { idOf } from "./Assumption";
4
- import { pairsAmong, placementsOf } from "./Symbol";
4
+ import { isPerforation, pairsAmong, placementsOf } from "./Symbol";
5
5
  const ajv = new Ajv({
6
6
  strict: false,
7
7
  formats: {
@@ -15,7 +15,6 @@ const missingReference = {
15
15
  before: 'before-reference-missing',
16
16
  after: 'after-reference-missing'
17
17
  };
18
- const isPerforation = (symbol) => symbol.type !== 'text';
19
18
  const problemsIn = (version, perforations) => {
20
19
  const ids = new Set(perforations.map(p => p.id));
21
20
  const report = (symbol, problem) => ({ version, symbol, problem });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linked-rolls",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Digital editions of piano rolls: import, collation, editorial assumptions, JSON-LD export, and emulation through a reproducing system",
5
5
  "license": "MIT",
6
6
  "repository": {