linked-rolls 0.1.0 → 0.2.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/LICENSE +26 -0
- package/README.md +35 -0
- package/lib/Assumption.d.ts +7 -2
- package/lib/ConditionState.d.ts +8 -1
- package/lib/Edit.d.ts +4 -3
- package/lib/Edition.d.ts +65 -35
- package/lib/Edition.js +1 -1
- package/lib/Emulation.js +32 -10
- package/lib/Feature.d.ts +19 -4
- package/lib/Plan.js +2 -1
- package/lib/RollCopy.d.ts +65 -27
- package/lib/RollCopy.js +51 -7
- package/lib/Symbol.d.ts +37 -20
- package/lib/Symbol.js +12 -0
- package/lib/TrackerBar.d.ts +18 -0
- package/lib/TrackerBar.js +27 -0
- package/lib/Version.d.ts +12 -4
- package/lib/asJsonLd.js +16 -2
- package/lib/context.d.ts +2 -0
- package/lib/context.js +2 -0
- package/lib/importJsonLd.js +19 -5
- package/lib/migrate.d.ts +15 -0
- package/lib/migrate.js +77 -0
- package/lib/schema.json +322 -276
- package/lib/spec/context.json +201 -131
- package/lib/spec/welte-t100.context.json +10 -0
- package/lib/systems/welteT100.js +19 -17
- package/lib/validate.d.ts +26 -0
- package/lib/validate.js +46 -0
- package/package.json +2 -1
package/lib/asJsonLd.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { systemIdOf } from "./TrackerBar";
|
|
1
2
|
export const exportDate = (date) => {
|
|
2
3
|
const year = date.getFullYear();
|
|
3
4
|
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
@@ -32,13 +33,26 @@ const asJsonLdEntity = (obj) => {
|
|
|
32
33
|
result[key] = value;
|
|
33
34
|
}
|
|
34
35
|
}
|
|
36
|
+
if ('@value' in obj && obj['@value'] instanceof Date) {
|
|
37
|
+
result['@type'] = 'xsd:date';
|
|
38
|
+
}
|
|
35
39
|
return result;
|
|
36
40
|
};
|
|
41
|
+
/**
|
|
42
|
+
* The context of the roll's reproducing system, which reads the
|
|
43
|
+
* expression types as that system's terms.
|
|
44
|
+
*/
|
|
45
|
+
const systemContextOf = (edition) => {
|
|
46
|
+
const system = systemIdOf(edition.roll?.system);
|
|
47
|
+
return system ? [`https://w3id.org/reo/${system}/context.jsonld`] : [];
|
|
48
|
+
};
|
|
37
49
|
export const asJsonLd = (edition) => {
|
|
38
|
-
|
|
50
|
+
// The context is the export's own; one carried in from an import must not override it.
|
|
51
|
+
const { base, copies, '@context': carried, ...rest } = asJsonLdEntity(edition);
|
|
39
52
|
return {
|
|
40
53
|
'@context': [
|
|
41
|
-
'https://
|
|
54
|
+
'https://w3id.org/reo/context.jsonld',
|
|
55
|
+
...systemContextOf(edition),
|
|
42
56
|
{
|
|
43
57
|
'@base': edition.base
|
|
44
58
|
}
|
package/lib/context.d.ts
CHANGED
package/lib/context.js
CHANGED
package/lib/importJsonLd.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { migrate } from "./migrate";
|
|
1
2
|
const isDate = (value) => {
|
|
2
3
|
const datePattern = /^\d{4}-\d{1,2}-\d{1,2}$/;
|
|
3
4
|
return datePattern.test(value);
|
|
@@ -14,7 +15,11 @@ const fromJsonLdEntity = (json) => {
|
|
|
14
15
|
return json;
|
|
15
16
|
}
|
|
16
17
|
let result = json;
|
|
17
|
-
if ('@
|
|
18
|
+
if ('@value' in json) {
|
|
19
|
+
// the datatype of a value object, not a class
|
|
20
|
+
delete result['@type'];
|
|
21
|
+
}
|
|
22
|
+
else if ('@type' in json) {
|
|
18
23
|
result['type'] = json['@type'];
|
|
19
24
|
delete result['@type'];
|
|
20
25
|
}
|
|
@@ -49,10 +54,19 @@ const fromJsonLdEntity = (json) => {
|
|
|
49
54
|
}
|
|
50
55
|
return result;
|
|
51
56
|
};
|
|
57
|
+
// The export prefixes copy identifiers with `copy/`; this is its inverse.
|
|
58
|
+
const withPlainCopyIds = (json) => ({
|
|
59
|
+
...json,
|
|
60
|
+
copies: (json.copies ?? []).map((copy) => ({
|
|
61
|
+
...copy,
|
|
62
|
+
'@id': typeof copy['@id'] === 'string' ? copy['@id'].replace(/^copy\//, '') : copy['@id']
|
|
63
|
+
}))
|
|
64
|
+
});
|
|
52
65
|
export const importJsonLd = (json) => {
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
66
|
+
const { '@context': context, ...document } = withPlainCopyIds(migrate(json));
|
|
67
|
+
const edition = fromJsonLdEntity(document);
|
|
68
|
+
edition.base = Array.isArray(context)
|
|
69
|
+
? context.find((c) => c['@base'])?.['@base'] || ''
|
|
70
|
+
: '';
|
|
57
71
|
return edition;
|
|
58
72
|
};
|
package/lib/migrate.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Brings the JSON of an edition written by an earlier release of the
|
|
3
|
+
* format up to the current shape. The shapes are recognised
|
|
4
|
+
* structurally, so a file that is current already passes through
|
|
5
|
+
* unchanged, and a file may be migrated any number of times.
|
|
6
|
+
*
|
|
7
|
+
* Format 0.1 used the type discriminator of versions and conditions
|
|
8
|
+
* for their typology, held the keeper and the production metadata as
|
|
9
|
+
* strings, and named the roll system on each copy. Some 0.1 files
|
|
10
|
+
* also carry references written as values and two keys the format
|
|
11
|
+
* had renamed before.
|
|
12
|
+
*/
|
|
13
|
+
type Json = any;
|
|
14
|
+
export declare const migrate: (edition: Json) => Json;
|
|
15
|
+
export {};
|
package/lib/migrate.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { conditions } from "./Feature";
|
|
2
|
+
import { rollConditions } from "./RollCopy";
|
|
3
|
+
import { systemOf, welteT100 } from "./TrackerBar";
|
|
4
|
+
import { versionTypes } from "./Version";
|
|
5
|
+
const versionTypeValues = new Set(versionTypes);
|
|
6
|
+
const conditionTypeValues = new Set([...rollConditions, ...Object.values(conditions).flat()]);
|
|
7
|
+
const renamedKeys = {
|
|
8
|
+
productionEvent: 'production',
|
|
9
|
+
annotates: 'depiction',
|
|
10
|
+
classification: 'editType'
|
|
11
|
+
};
|
|
12
|
+
const referenceKeys = ['alignedWith', 'pairedWith', 'basedOn'];
|
|
13
|
+
const named = (name) => ({ name, sameAs: [] });
|
|
14
|
+
const withRenamedKeys = (node) => Object.fromEntries(Object.entries(node).map(([key, value]) => [renamedKeys[key] ?? key, value]));
|
|
15
|
+
const withTypology = (node) => {
|
|
16
|
+
if (versionTypeValues.has(node['@type'])) {
|
|
17
|
+
return { ...node, '@type': 'Version', versionType: node['@type'] };
|
|
18
|
+
}
|
|
19
|
+
if (conditionTypeValues.has(node['@type'])) {
|
|
20
|
+
return { ...node, '@type': 'ConditionState', conditionType: node['@type'] };
|
|
21
|
+
}
|
|
22
|
+
return node;
|
|
23
|
+
};
|
|
24
|
+
const withReferences = (node) => referenceKeys.reduce((result, key) => {
|
|
25
|
+
const reference = result[key];
|
|
26
|
+
if (reference && typeof reference === 'object' && '@value' in reference) {
|
|
27
|
+
const { '@value': id, ...rest } = reference;
|
|
28
|
+
return { ...result, [key]: { '@id': id, ...rest } };
|
|
29
|
+
}
|
|
30
|
+
return result;
|
|
31
|
+
}, node);
|
|
32
|
+
const withKeeper = (node) => {
|
|
33
|
+
if (typeof node.location !== 'string')
|
|
34
|
+
return node;
|
|
35
|
+
const { location, ...rest } = node;
|
|
36
|
+
return { ...rest, keeper: named(location) };
|
|
37
|
+
};
|
|
38
|
+
const withProductionNodes = (node) => {
|
|
39
|
+
const production = node.production;
|
|
40
|
+
if (!production || typeof production !== 'object')
|
|
41
|
+
return node;
|
|
42
|
+
const { company, paper, system, ...rest } = production;
|
|
43
|
+
return {
|
|
44
|
+
...node,
|
|
45
|
+
production: {
|
|
46
|
+
...rest,
|
|
47
|
+
...(typeof company === 'string' ? (company && { company: named(company) }) : { company }),
|
|
48
|
+
...(typeof paper === 'string' ? (paper && { paper: named(paper) }) : { paper }),
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
const migrateNode = (node) => [withRenamedKeys, withTypology, withReferences, withKeeper, withProductionNodes]
|
|
53
|
+
.reduce((result, step) => step(result), node);
|
|
54
|
+
const walk = (value) => {
|
|
55
|
+
if (Array.isArray(value))
|
|
56
|
+
return value.map(walk);
|
|
57
|
+
if (value && typeof value === 'object') {
|
|
58
|
+
return Object.fromEntries(Object.entries(migrateNode(value)).map(([key, child]) => [key, walk(child)]));
|
|
59
|
+
}
|
|
60
|
+
return value;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Every 0.1 edition was read with the T-100 tracker bar, so a roll
|
|
64
|
+
* without a system is a T-100 roll. The text a copy's production
|
|
65
|
+
* gave for the system is kept as the name.
|
|
66
|
+
*/
|
|
67
|
+
const withRollSystem = (edition) => {
|
|
68
|
+
if (!edition.roll || edition.roll.system)
|
|
69
|
+
return edition;
|
|
70
|
+
const stated = (edition.copies ?? [])
|
|
71
|
+
.map((copy) => copy.production?.system ?? copy.productionEvent?.system)
|
|
72
|
+
.find((system) => typeof system === 'string' && system !== '');
|
|
73
|
+
const { id, ...concept } = systemOf(welteT100);
|
|
74
|
+
const system = { '@id': id, ...concept, ...(stated && { name: stated }) };
|
|
75
|
+
return { ...edition, roll: { ...edition.roll, system } };
|
|
76
|
+
};
|
|
77
|
+
export const migrate = (edition) => walk(withRollSystem(edition));
|