linked-rolls 0.53.0 → 0.54.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/lib/Feature.d.ts CHANGED
@@ -109,15 +109,6 @@ export type FeatureConditionAssignment = ObjectAssumption<ConditionState<Feature
109
109
  * @see reo:Hole
110
110
  */
111
111
  export interface Hole extends RollFeature<'Hole', typeof conditions.Hole[number]> {
112
- /**
113
- * The punching pattern of the hole. Regular holes have evenly-spaced
114
- * bridges, accelerating holes have decreasing bridge widths, and
115
- * staggering holes do not align in rows across the tracks, the mark
116
- * of an asynchronous perforator with a separate driver for each
117
- * punch (Phillips 2016, p. 112).
118
- * @see reo:pattern
119
- */
120
- pattern?: 'regular' | 'accelerating' | 'staggering';
121
112
  }
122
113
  /**
123
114
  * Something that lies on a face of the paper rather than through it. A
@@ -1,7 +1,7 @@
1
1
  import { ObjectAssumption } from "./Assumption.js";
2
2
  import { ConditionState } from "./ConditionState.js";
3
3
  import { Measure, Millimeters } from "./Quantity.js";
4
- import { WithId } from "./utils.js";
4
+ import { WithId, WithType } from "./utils.js";
5
5
  /**
6
6
  * The pitch in the engineering sense: the distance along the roll from
7
7
  * one punch of a chain to the next, which is the slot one firing cut
@@ -75,13 +75,44 @@ export interface PerforatorSetting extends ConditionState<'setting'> {
75
75
  */
76
76
  advance?: ObjectAssumption<Advance>;
77
77
  }
78
+ /**
79
+ * How the punches of a perforator were driven, after Phillips (2016,
80
+ * pp. 112 f.): all at once by one ram head, or each by a driver of its
81
+ * own. `ontology/types.ttl` defines them, and a test holds this list
82
+ * against it.
83
+ * @see crm:E55 Type
84
+ */
85
+ export declare const drives: readonly [{
86
+ readonly id: 'https://w3id.org/reo/type/drive/ram-head';
87
+ readonly name: 'ram head';
88
+ }, {
89
+ readonly id: 'https://w3id.org/reo/type/drive/asynchronous';
90
+ readonly name: 'asynchronous';
91
+ }];
92
+ export type DriveId = typeof drives[number]['id'];
93
+ /**
94
+ * A drive, named by its IRI alone.
95
+ * @see crm:E55 Type
96
+ */
97
+ export interface Drive {
98
+ /** The IRI the type vocabulary gives the drive. */
99
+ readonly id: DriveId;
100
+ }
78
101
  /**
79
102
  * The machine that punched the copy. It stands for this production
80
103
  * alone. Whether it is the one another copy was punched on is left to a
81
104
  * statement of identity made about it elsewhere, which its id allows.
82
105
  * @see crm:E22 Human-Made Object
83
106
  */
84
- export interface Perforator extends WithId {
107
+ export interface Perforator extends WithType<'Perforator'>, WithId {
108
+ /**
109
+ * How its punches were driven, as the rows of its chains show it:
110
+ * in line across the tracks where one ram head drove them all, and
111
+ * staggered where each punch had a driver of its own. It is part of
112
+ * how the machine was built and so no part of its setting.
113
+ * @see reo:drive
114
+ */
115
+ drive?: ObjectAssumption<Drive>;
85
116
  /**
86
117
  * @see crm:P44 has condition
87
118
  */
package/lib/Perforator.js CHANGED
@@ -1 +1,11 @@
1
- export {};
1
+ /**
2
+ * How the punches of a perforator were driven, after Phillips (2016,
3
+ * pp. 112 f.): all at once by one ram head, or each by a driver of its
4
+ * own. `ontology/types.ttl` defines them, and a test holds this list
5
+ * against it.
6
+ * @see crm:E55 Type
7
+ */
8
+ export const drives = [
9
+ { id: 'https://w3id.org/reo/type/drive/ram-head', name: 'ram head' },
10
+ { id: 'https://w3id.org/reo/type/drive/asynchronous', name: 'asynchronous' }
11
+ ];
package/lib/RollCopy.d.ts CHANGED
@@ -116,8 +116,8 @@ export interface ProductionEvent {
116
116
  */
117
117
  speed?: ObjectAssumption<PaperSpeed>;
118
118
  /**
119
- * The perforator the copy was punched on, with the setting its
120
- * perforations show.
119
+ * The perforator the copy was punched on, with the drive and the
120
+ * setting its perforations show.
121
121
  * @see crm:P16 used specific object
122
122
  */
123
123
  perforator?: Perforator;
package/lib/migrate.js CHANGED
@@ -119,11 +119,15 @@ const withScale = (node) => {
119
119
  };
120
120
  /** A copy's id without the `copy/` that documents of earlier releases put before it. */
121
121
  export const plainCopyId = (id) => id.replace(/^copy\//, '');
122
+ /**
123
+ * The perforator the copy states, or a new one named after the copy, so
124
+ * that a file migrated twice names it the same way.
125
+ */
126
+ const perforatorOf = (copy) => copy.production?.perforator ?? { '@type': 'Perforator', '@id': `perforator_${plainCopyId(copy['@id'])}` };
122
127
  /**
123
128
  * The punch diameter was a measurement of the copy before it was stated
124
129
  * as the setting of the perforator that cut it. A diameter of -1 stood
125
- * for one nobody had measured and is left out. The perforator is named
126
- * after the copy, so that a file migrated twice names it the same way.
130
+ * for one nobody had measured and is left out.
127
131
  */
128
132
  const withPerforator = (node) => {
129
133
  const diameter = node.measurements?.punchDiameter;
@@ -132,7 +136,7 @@ const withPerforator = (node) => {
132
136
  const { punchDiameter: _moved, ...measurements } = node.measurements;
133
137
  if (!(diameter?.value > 0))
134
138
  return { ...node, measurements };
135
- const perforator = node.production?.perforator ?? { '@id': `perforator_${plainCopyId(node['@id'])}` };
139
+ const perforator = perforatorOf(node);
136
140
  return {
137
141
  ...node,
138
142
  measurements,
@@ -150,6 +154,37 @@ const withPerforator = (node) => {
150
154
  }
151
155
  };
152
156
  };
157
+ /** A perforator was first written without a type. */
158
+ const withTypedPerforator = (node) => {
159
+ const perforator = node.perforator;
160
+ if (!perforator || typeof perforator !== 'object' || perforator['@type'])
161
+ return node;
162
+ return { ...node, perforator: { '@type': 'Perforator', ...perforator } };
163
+ };
164
+ const asynchronous = 'https://w3id.org/reo/type/drive/asynchronous';
165
+ /**
166
+ * Each hole once stated its punching pattern. A staggering hole the copy
167
+ * was punched with shows that its perforator drove each punch on its
168
+ * own; one a later act made shows nothing about the machine. Regular
169
+ * and accelerating bridges are not carried over: the chain pitch states
170
+ * the one, and for the other no source was found. The features are in
171
+ * their acts here, since a node is migrated before its children are.
172
+ */
173
+ const withDriveOfStaggering = (node) => {
174
+ const produced = node.production?.produced;
175
+ if (!Array.isArray(produced) || !produced.some((feature) => feature?.pattern === 'staggering'))
176
+ return node;
177
+ const perforator = perforatorOf(node);
178
+ if (perforator.drive)
179
+ return node;
180
+ return { ...node, production: { ...node.production, perforator: { ...perforator, drive: { '@id': asynchronous } } } };
181
+ };
182
+ const withoutPattern = (node) => {
183
+ if (node['@type'] !== 'Hole' || !Object.hasOwn(node, 'pattern'))
184
+ return node;
185
+ const { pattern: _moved, ...rest } = node;
186
+ return rest;
187
+ };
153
188
  /** A derivation written as a single one, before a version could name several. */
154
189
  const isSingleDerivation = (basedOn) => basedOn !== null && typeof basedOn === 'object' && !Array.isArray(basedOn);
155
190
  const withDerivationList = (node) => isSingleDerivation(node.basedOn) ? { ...node, basedOn: [node.basedOn] } : node;
@@ -266,8 +301,8 @@ const withTimeSpanDates = (node) => {
266
301
  return { ...rest, within };
267
302
  };
268
303
  const migrateNode = (node) => [withRenamedKeys, withTypology, withoutVersionType, withoutVersionSiglum, withLowerCaseTerms, withSplitMethod, withReferences, withKeeper, withoutEmptyKeeper,
269
- withPerforator, withProductionNodes, withScale, withDerivationList, withReadingKind, withTimeSpanDates, withoutFeatureKind,
270
- withBorneFeaturesNamed, withFeaturesInActs]
304
+ withPerforator, withProductionNodes, withTypedPerforator, withScale, withDerivationList, withReadingKind, withTimeSpanDates,
305
+ withoutFeatureKind, withBorneFeaturesNamed, withFeaturesInActs, withDriveOfStaggering, withoutPattern]
271
306
  .reduce((result, step) => step(result), node);
272
307
  /** The items each walked, or the very same list where the walk changed none. */
273
308
  const walked = (items) => {
@@ -161,6 +161,7 @@ export function readFromStanfordAton(atonString, { trackShift, system = welteT10
161
161
  system: systemOf(system),
162
162
  ...(punchDiameter !== undefined && {
163
163
  perforator: {
164
+ type: 'Perforator',
164
165
  id: `perforator_${v4()}`,
165
166
  condition: {
166
167
  type: 'ConditionState',
package/lib/schema.json CHANGED
@@ -436,6 +436,13 @@
436
436
  "type": "object",
437
437
  "ontology": "lrmoo:R76 is derivative of"
438
438
  },
439
+ "DriveId": {
440
+ "enum": [
441
+ "https://w3id.org/reo/type/drive/ram-head",
442
+ "https://w3id.org/reo/type/drive/asynchronous"
443
+ ],
444
+ "type": "string"
445
+ },
439
446
  "Edit": {
440
447
  "description": "A set of edits transforms a version of a roll into another version. Edits insert or delete symbols, or both (= replace). Edits may be motivated by a given set of reasons, e.g. to add an additional accent or to correct an error. If an edit is the interpretation of a metamark, such as a pencil mark, this should be made explicit using a meaning comprehension on the `@annotation` field.",
441
448
  "properties": {
@@ -895,16 +902,6 @@
895
902
  "description": "Horizontal span of the feature on the roll.",
896
903
  "ontology": "crm:P43 has dimension"
897
904
  },
898
- "pattern": {
899
- "description": "The punching pattern of the hole. Regular holes have evenly-spaced bridges, accelerating holes have decreasing bridge widths, and staggering holes do not align in rows across the tracks, the mark of an asynchronous perforator with a separate driver for each punch (Phillips 2016, p. 112).",
900
- "enum": [
901
- "regular",
902
- "accelerating",
903
- "staggering"
904
- ],
905
- "type": "string",
906
- "ontology": "reo:pattern"
907
- },
908
905
  "vertical": {
909
906
  "$ref": "#/definitions/VerticalSpan",
910
907
  "description": "Vertical span of the feature on the roll.",
@@ -1448,16 +1445,6 @@
1448
1445
  "description": "Horizontal span of the feature on the roll. Left out by a feature a patch bears.",
1449
1446
  "ontology": "crm:P43 has dimension"
1450
1447
  },
1451
- "pattern": {
1452
- "description": "The punching pattern of the hole. Regular holes have evenly-spaced bridges, accelerating holes have decreasing bridge widths, and staggering holes do not align in rows across the tracks, the mark of an asynchronous perforator with a separate driver for each punch (Phillips 2016, p. 112).",
1453
- "enum": [
1454
- "regular",
1455
- "accelerating",
1456
- "staggering"
1457
- ],
1458
- "type": "string",
1459
- "ontology": "reo:pattern"
1460
- },
1461
1448
  "vertical": {
1462
1449
  "$ref": "#/definitions/VerticalSpan",
1463
1450
  "description": "Vertical span of the feature on the roll. Left out by a feature a patch bears.",
@@ -2294,6 +2281,38 @@
2294
2281
  ],
2295
2282
  "type": "object"
2296
2283
  },
2284
+ "ObjectAssumption<Drive>": {
2285
+ "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.",
2286
+ "properties": {
2287
+ "@annotation": {
2288
+ "description": "An optional annotation expressing a belief about this assumption. Uses the JSON-LD-star `@annotation` mechanism to attach epistemic metadata (certainty and reasons) to any triple.",
2289
+ "properties": {
2290
+ "belief": {
2291
+ "$ref": "#/definitions/Belief",
2292
+ "description": "The belief held about the annotated statement.",
2293
+ "ontology": "crminf:J4i is subject of"
2294
+ },
2295
+ "@id": {
2296
+ "description": "A unique identifier for this object.",
2297
+ "type": "string"
2298
+ }
2299
+ },
2300
+ "required": [
2301
+ "belief",
2302
+ "@id"
2303
+ ],
2304
+ "type": "object"
2305
+ },
2306
+ "@id": {
2307
+ "$ref": "#/definitions/DriveId",
2308
+ "description": "The IRI the type vocabulary gives the drive."
2309
+ }
2310
+ },
2311
+ "required": [
2312
+ "@id"
2313
+ ],
2314
+ "type": "object"
2315
+ },
2297
2316
  "ObjectAssumption<Instrument>": {
2298
2317
  "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.",
2299
2318
  "properties": {
@@ -2666,13 +2685,25 @@
2666
2685
  "$ref": "#/definitions/PerforatorSetting",
2667
2686
  "ontology": "crm:P44 has condition"
2668
2687
  },
2688
+ "drive": {
2689
+ "$ref": "#/definitions/ObjectAssumption%3CDrive%3E",
2690
+ "description": "How its punches were driven, as the rows of its chains show it: in line across the tracks where one ram head drove them all, and staggered where each punch had a driver of its own. It is part of how the machine was built and so no part of its setting.",
2691
+ "ontology": "reo:drive"
2692
+ },
2669
2693
  "@id": {
2670
2694
  "description": "A unique identifier for this object.",
2671
2695
  "type": "string"
2696
+ },
2697
+ "@type": {
2698
+ "const": "Perforator",
2699
+ "description": "The type discriminator for this object.",
2700
+ "type": "string",
2701
+ "ontology": "rdf:type"
2672
2702
  }
2673
2703
  },
2674
2704
  "required": [
2675
- "@id"
2705
+ "@id",
2706
+ "@type"
2676
2707
  ],
2677
2708
  "type": "object",
2678
2709
  "ontology": "crm:E22 Human-Made Object"
@@ -2773,7 +2804,7 @@
2773
2804
  },
2774
2805
  "perforator": {
2775
2806
  "$ref": "#/definitions/Perforator",
2776
- "description": "The perforator the copy was punched on, with the setting its perforations show.",
2807
+ "description": "The perforator the copy was punched on, with the drive and the setting its perforations show.",
2777
2808
  "ontology": "crm:P16 used specific object"
2778
2809
  },
2779
2810
  "produced": {
@@ -21,6 +21,7 @@
21
21
  "Attachment": "crm:E79_Part_Addition",
22
22
  "Removal": "crm:E80_Part_Removal",
23
23
  "Alteration": "crm:E12_Production",
24
+ "Perforator": "crm:E22_Human-Made_Object",
24
25
  "ConditionState": "crm:E3_Condition_State",
25
26
  "note": "reo:Note",
26
27
  "expression": "reo:Expression",
@@ -192,6 +193,7 @@
192
193
  }
193
194
  }
194
195
  },
196
+ "drive": "reo:drive",
195
197
  "company": "crm:P14_carried_out_by",
196
198
  "paper": "crm:P126_employed",
197
199
  "conditions": "crm:P44_has_condition",
@@ -249,11 +251,6 @@
249
251
  "@type": "@vocab",
250
252
  "@context": { "@vocab": "https://w3id.org/reo/type/" }
251
253
  },
252
- "pattern": {
253
- "@id": "reo:pattern",
254
- "@type": "@vocab",
255
- "@context": { "@vocab": "https://w3id.org/reo/type/" }
256
- },
257
254
  "technique": {
258
255
  "@id": "reo:technique",
259
256
  "@type": "@vocab",
@@ -1,8 +1,8 @@
1
1
  import { Concept } from "./Agent.js";
2
2
  /**
3
3
  * The concepts the type vocabulary declares, whatever kind they are:
4
- * the reproducing systems and the procedures. An edition names one of
5
- * them by its IRI alone.
4
+ * the reproducing systems, the procedures and the drives of a
5
+ * perforator. An edition names one of them by its IRI alone.
6
6
  */
7
7
  export declare const vocabulary: readonly Concept[];
8
8
  /** The concept of that IRI, where the vocabulary declares one. */
package/lib/vocabulary.js CHANGED
@@ -1,14 +1,16 @@
1
+ import { drives } from "./Perforator.js";
1
2
  import { procedures } from "./procedures.js";
2
3
  import { systemOf } from "./TrackerBar.js";
3
4
  import { trackerBars } from "./systems/index.js";
4
5
  /**
5
6
  * The concepts the type vocabulary declares, whatever kind they are:
6
- * the reproducing systems and the procedures. An edition names one of
7
- * them by its IRI alone.
7
+ * the reproducing systems, the procedures and the drives of a
8
+ * perforator. An edition names one of them by its IRI alone.
8
9
  */
9
10
  export const vocabulary = [
10
11
  ...trackerBars.map(systemOf),
11
- ...procedures
12
+ ...procedures,
13
+ ...drives
12
14
  ];
13
15
  /** The concept of that IRI, where the vocabulary declares one. */
14
16
  export const conceptOf = (id) => id === undefined ? undefined : vocabulary.find(concept => concept.id === id);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linked-rolls",
3
- "version": "0.53.0",
3
+ "version": "0.54.0",
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": {