glossarist 0.4.20 → 0.4.22
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/package.json +1 -1
- package/src/migration/partitive-relation-migrator.js +20 -46
- package/src/models/index.js +5 -6
- package/src/models/multiplicity.js +24 -0
- package/src/models/partitive-member.js +43 -26
- package/src/models/partitive-relation.js +14 -23
- package/src/rdf/gloss-partitive-relation.js +15 -36
- package/src/rdf/predicates.d.ts +4 -12
- package/src/rdf/predicates.js +2 -6
- package/src/validators/partitive-relation-coherence-rule.js +4 -13
- package/src/models/member-certainty.js +0 -21
- package/src/models/type-shared-plurality.js +0 -71
package/package.json
CHANGED
|
@@ -4,25 +4,24 @@
|
|
|
4
4
|
// PartitiveRelation hash. Idempotent. Used by the parser when loading
|
|
5
5
|
// legacy YAML; available as a public API for one-shot dataset migrations.
|
|
6
6
|
//
|
|
7
|
-
// Field mapping (per TODO.partitive-relation-v2 items 01–05
|
|
7
|
+
// Field mapping (per TODO.partitive-relation-v2 items 01–05 and the
|
|
8
|
+
// ISO 704:2022 correction):
|
|
8
9
|
//
|
|
9
10
|
// comprehensive → comprehensive (unchanged shape)
|
|
10
|
-
// parts: [ref, ...] → partitives: [{ ref,
|
|
11
|
+
// parts: [ref, ...] → partitives: [{ ref, multiplicity: 'compulsory' }, ...]
|
|
11
12
|
// enumeration: open → completeness: partial
|
|
12
13
|
// enumeration: closed→ completeness: complete
|
|
13
|
-
// markers: [
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
14
|
+
// markers: [...] → (dropped — v2 uses per-member multiplicity
|
|
15
|
+
// + is_delimiting; v1 markers encoded the
|
|
16
|
+
// same information imprecisely and cannot
|
|
17
|
+
// round-trip losslessly)
|
|
18
|
+
// content: "..." → (dropped — structural edges carry no prose)
|
|
17
19
|
//
|
|
18
20
|
// Cardinality check: v1 allowed [1..*] parts; v2 requires [2..*].
|
|
19
21
|
// A v1 hyperedge with exactly 1 part cannot migrate to v2 and is
|
|
20
22
|
// returned with a `migrationWarning` field set so callers can decide
|
|
21
23
|
// whether to surface it (the parser drops these with a warning).
|
|
22
24
|
|
|
23
|
-
const MARKER_DOUBLE = 'double';
|
|
24
|
-
const MARKER_DASHED = 'dashed';
|
|
25
|
-
|
|
26
25
|
export function migrateHyperedgeToRelation(v1Hash) {
|
|
27
26
|
if (v1Hash == null) return null;
|
|
28
27
|
if (Array.isArray(v1Hash)) {
|
|
@@ -36,17 +35,12 @@ export function migrateHyperedgeToRelation(v1Hash) {
|
|
|
36
35
|
const parts = Array.isArray(v1Hash.parts) ? v1Hash.parts : [];
|
|
37
36
|
out.partitives = parts.map(ref => ({
|
|
38
37
|
ref: { ...ref },
|
|
39
|
-
|
|
38
|
+
multiplicity: 'compulsory',
|
|
40
39
|
}));
|
|
41
40
|
|
|
42
41
|
out.completeness = _migrateEnumeration(v1Hash.enumeration);
|
|
43
42
|
|
|
44
|
-
|
|
45
|
-
if (plurality != null) out.plurality = plurality;
|
|
46
|
-
|
|
47
|
-
// v1 content field is dropped per TODO.partitive-relation-v2 item 04.
|
|
48
|
-
// Caller (parser) may surface this as a warning if the text matters.
|
|
49
|
-
|
|
43
|
+
// v1 content + markers fields are dropped per TODO.partitive-relation-v2.
|
|
50
44
|
if (parts.length < 2) {
|
|
51
45
|
out.migrationWarning =
|
|
52
46
|
`v1 PartitiveHyperedge had ${parts.length} part(s); v2 requires ≥2. ` +
|
|
@@ -59,12 +53,19 @@ export function migrateHyperedgeToRelation(v1Hash) {
|
|
|
59
53
|
`move valuable text to the comprehensive concept's notes).`;
|
|
60
54
|
}
|
|
61
55
|
|
|
56
|
+
if (Array.isArray(v1Hash.markers) && v1Hash.markers.length > 0) {
|
|
57
|
+
out.migrationWarning = (out.migrationWarning ?? '') +
|
|
58
|
+
` v1 'markers' field (${v1Hash.markers.join(', ')}) was dropped; ` +
|
|
59
|
+
`v2 uses per-member 'multiplicity' + 'is_delimiting'. Reviewer ` +
|
|
60
|
+
`should set these per partitive based on ISO 704:2022 notation.`;
|
|
61
|
+
}
|
|
62
|
+
|
|
62
63
|
return out;
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
// Inverse — v2 → v1 — exists only for tooling that must round-trip
|
|
66
67
|
// through v1 consumers. NOT used by the parser; the serializer emits
|
|
67
|
-
// v2 only.
|
|
68
|
+
// v2 only. Lossy: drops criterion, multiplicity, is_delimiting.
|
|
68
69
|
export function downgradeRelationToHyperedge(v2Hash) {
|
|
69
70
|
if (v2Hash == null) return null;
|
|
70
71
|
if (Array.isArray(v2Hash)) {
|
|
@@ -78,11 +79,8 @@ export function downgradeRelationToHyperedge(v2Hash) {
|
|
|
78
79
|
out.parts = (v2Hash.partitives ?? []).map(m => ({ ...(m.ref ?? {}) }));
|
|
79
80
|
out.enumeration = _downgradeCompleteness(v2Hash.completeness);
|
|
80
81
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
// criterion has no v1 equivalent — dropped silently
|
|
85
|
-
// per-member certainty has no v1 equivalent — dropped silently
|
|
82
|
+
// criterion, multiplicity, is_delimiting have no v1 equivalent —
|
|
83
|
+
// dropped silently.
|
|
86
84
|
|
|
87
85
|
return out;
|
|
88
86
|
}
|
|
@@ -99,27 +97,3 @@ function _downgradeCompleteness(value) {
|
|
|
99
97
|
if (value === 'partial') return 'open';
|
|
100
98
|
return 'closed';
|
|
101
99
|
}
|
|
102
|
-
|
|
103
|
-
function _migrateMarkers(markers) {
|
|
104
|
-
if (!Array.isArray(markers) || markers.length === 0) return null;
|
|
105
|
-
|
|
106
|
-
const isShared = markers.includes(MARKER_DOUBLE);
|
|
107
|
-
const isUncertain = markers.includes(MARKER_DASHED);
|
|
108
|
-
|
|
109
|
-
// Per TODO.partitive-relation-v2 item 03 migration table:
|
|
110
|
-
// [dashed] alone is semantically odd (broken line qualifies
|
|
111
|
-
// plurality; without double, what's being qualified?). We
|
|
112
|
-
// migrate it to is_shared=false, is_uncertain=true and rely on
|
|
113
|
-
// the PartitiveRelationCoherenceRule to warn.
|
|
114
|
-
if (!isShared && !isUncertain) return null;
|
|
115
|
-
|
|
116
|
-
return { is_shared: isShared, is_uncertain: isUncertain };
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function _downgradePlurality(plurality) {
|
|
120
|
-
if (plurality == null) return [];
|
|
121
|
-
const markers = [];
|
|
122
|
-
if (plurality.is_shared) markers.push(MARKER_DOUBLE);
|
|
123
|
-
if (plurality.is_uncertain) markers.push(MARKER_DASHED);
|
|
124
|
-
return markers;
|
|
125
|
-
}
|
package/src/models/index.js
CHANGED
|
@@ -38,7 +38,6 @@ export {
|
|
|
38
38
|
// backward-compat input. New code should use v2 exclusively.
|
|
39
39
|
export { PartitiveRelation } from './partitive-relation.js';
|
|
40
40
|
export { PartitiveMember } from './partitive-member.js';
|
|
41
|
-
export { TypeSharedPlurality } from './type-shared-plurality.js';
|
|
42
41
|
export {
|
|
43
42
|
COMPLETENESS,
|
|
44
43
|
COMPLETENESS_VALUES,
|
|
@@ -46,11 +45,11 @@ export {
|
|
|
46
45
|
isValidCompleteness,
|
|
47
46
|
} from './completeness.js';
|
|
48
47
|
export {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
} from './
|
|
48
|
+
MULTIPLICITY,
|
|
49
|
+
MULTIPLICITY_VALUES,
|
|
50
|
+
DEFAULT_MULTIPLICITY,
|
|
51
|
+
isValidMultiplicity,
|
|
52
|
+
} from './multiplicity.js';
|
|
54
53
|
|
|
55
54
|
// v1 → v2 migration helper. Pure function; idempotent.
|
|
56
55
|
export {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Multiplicity — ISO 704:2022 partitive member multiplicity.
|
|
2
|
+
//
|
|
3
|
+
// Encodes the diagram line notation as structured data:
|
|
4
|
+
// compulsory — 1 solid line (must exist in every instance)
|
|
5
|
+
// optional — 1 dashed line (exists in some instances only)
|
|
6
|
+
// compulsory_multiple — 2 solid lines (multiple must exist)
|
|
7
|
+
// optional_multiple — 2 dashed lines (multiple may exist)
|
|
8
|
+
// at_least_one — 1 solid + 1 dashed line (at least one must exist)
|
|
9
|
+
//
|
|
10
|
+
// Defaults to `compulsory` when omitted.
|
|
11
|
+
|
|
12
|
+
import { makeEnum } from './enum.js';
|
|
13
|
+
|
|
14
|
+
export const MULTIPLICITY = makeEnum('MULTIPLICITY', {
|
|
15
|
+
COMPULSORY: 'compulsory',
|
|
16
|
+
OPTIONAL: 'optional',
|
|
17
|
+
COMPULSORY_MULTIPLE: 'compulsory_multiple',
|
|
18
|
+
OPTIONAL_MULTIPLE: 'optional_multiple',
|
|
19
|
+
AT_LEAST_ONE: 'at_least_one',
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export const MULTIPLICITY_VALUES = MULTIPLICITY.VALUES;
|
|
23
|
+
export const DEFAULT_MULTIPLICITY = MULTIPLICITY.COMPULSORY;
|
|
24
|
+
export const isValidMultiplicity = MULTIPLICITY.isValid;
|
|
@@ -1,21 +1,29 @@
|
|
|
1
1
|
// PartitiveMember — one member of a PartitiveRelation.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// no certainty field is implicitly confirmed.
|
|
3
|
+
// Carries a ConceptRef (the subordinate concept partitive) plus
|
|
4
|
+
// ISO 704:2022 multiplicity and delimiting metadata.
|
|
6
5
|
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
6
|
+
// ISO 704:2022 partitive member notation:
|
|
7
|
+
//
|
|
8
|
+
// multiplicity (diagram line notation):
|
|
9
|
+
// compulsory — 1 solid line (must exist in every instance)
|
|
10
|
+
// optional — 1 dashed line (exists in some instances only)
|
|
11
|
+
// compulsory_multiple — 2 solid lines (multiple must exist)
|
|
12
|
+
// optional_multiple — 2 dashed lines (multiple may exist)
|
|
13
|
+
// at_least_one — 1 solid + 1 dashed line (≥1 must exist)
|
|
14
|
+
//
|
|
15
|
+
// is_delimiting (orthogonal, bold 3x-width line in diagram):
|
|
16
|
+
// A delimiting part behaves like a delimiting characteristic:
|
|
17
|
+
// it distinguishes the comprehensive from coordinate concepts.
|
|
11
18
|
|
|
12
19
|
import { GlossaristModel } from './base.js';
|
|
13
20
|
import { ConceptRef } from './concept-ref.js';
|
|
14
21
|
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
22
|
+
MULTIPLICITY,
|
|
23
|
+
DEFAULT_MULTIPLICITY,
|
|
24
|
+
MULTIPLICITY_VALUES,
|
|
25
|
+
isValidMultiplicity,
|
|
26
|
+
} from './multiplicity.js';
|
|
19
27
|
|
|
20
28
|
export class PartitiveMember extends GlossaristModel {
|
|
21
29
|
constructor(data = {}) {
|
|
@@ -23,17 +31,22 @@ export class PartitiveMember extends GlossaristModel {
|
|
|
23
31
|
this.ref = data.ref instanceof ConceptRef
|
|
24
32
|
? data.ref
|
|
25
33
|
: new ConceptRef(data.ref ?? {});
|
|
26
|
-
this.
|
|
34
|
+
this.multiplicity = _resolveMultiplicity(data.multiplicity);
|
|
35
|
+
this.is_delimiting = data.is_delimiting === true;
|
|
27
36
|
|
|
28
37
|
_assertNonEmptyRef(this.ref);
|
|
29
38
|
}
|
|
30
39
|
|
|
31
|
-
get
|
|
32
|
-
return this.
|
|
40
|
+
get isCompulsory() {
|
|
41
|
+
return this.multiplicity === MULTIPLICITY.COMPULSORY;
|
|
33
42
|
}
|
|
34
43
|
|
|
35
|
-
get
|
|
36
|
-
return this.
|
|
44
|
+
get isOptional() {
|
|
45
|
+
return this.multiplicity === MULTIPLICITY.OPTIONAL;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
get isDelimiting() {
|
|
49
|
+
return this.is_delimiting === true;
|
|
37
50
|
}
|
|
38
51
|
|
|
39
52
|
identity() {
|
|
@@ -42,8 +55,11 @@ export class PartitiveMember extends GlossaristModel {
|
|
|
42
55
|
|
|
43
56
|
toJSON() {
|
|
44
57
|
const obj = { ref: this.ref.toJSON() };
|
|
45
|
-
if (this.
|
|
46
|
-
obj.
|
|
58
|
+
if (this.multiplicity !== DEFAULT_MULTIPLICITY) {
|
|
59
|
+
obj.multiplicity = this.multiplicity;
|
|
60
|
+
}
|
|
61
|
+
if (this.is_delimiting === true) {
|
|
62
|
+
obj.is_delimiting = true;
|
|
47
63
|
}
|
|
48
64
|
return obj;
|
|
49
65
|
}
|
|
@@ -51,7 +67,7 @@ export class PartitiveMember extends GlossaristModel {
|
|
|
51
67
|
static identityOf(value) {
|
|
52
68
|
const v = value ?? {};
|
|
53
69
|
const ref = v.ref ?? {};
|
|
54
|
-
return `${ref.source ?? ''}
|
|
70
|
+
return `${ref.source ?? ''}:${ref.id ?? ''}`;
|
|
55
71
|
}
|
|
56
72
|
|
|
57
73
|
static fromJSON(data) {
|
|
@@ -59,21 +75,22 @@ export class PartitiveMember extends GlossaristModel {
|
|
|
59
75
|
}
|
|
60
76
|
}
|
|
61
77
|
|
|
62
|
-
function
|
|
63
|
-
|
|
64
|
-
if (!
|
|
78
|
+
function _resolveMultiplicity(value) {
|
|
79
|
+
if (value == null) return DEFAULT_MULTIPLICITY;
|
|
80
|
+
if (!isValidMultiplicity(value)) {
|
|
65
81
|
throw new Error(
|
|
66
|
-
`
|
|
67
|
-
`must be one of
|
|
82
|
+
`invalid multiplicity ${JSON.stringify(value)}; ` +
|
|
83
|
+
`must be one of ${MULTIPLICITY_VALUES.join(', ')}`,
|
|
68
84
|
);
|
|
69
85
|
}
|
|
70
|
-
return
|
|
86
|
+
return value;
|
|
71
87
|
}
|
|
72
88
|
|
|
73
89
|
function _assertNonEmptyRef(ref) {
|
|
74
90
|
if (!ref.source && !ref.id && !ref.text) {
|
|
75
91
|
throw new Error(
|
|
76
|
-
'PartitiveMember
|
|
92
|
+
'PartitiveMember#ref must be a non-empty ConceptRef ' +
|
|
93
|
+
'(source, id, or text required)',
|
|
77
94
|
);
|
|
78
95
|
}
|
|
79
96
|
}
|
|
@@ -1,31 +1,29 @@
|
|
|
1
|
-
// PartitiveRelation —
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// Renamed from the v1 `PartitiveHyperedge` per TODO.partitive-relation-v2
|
|
8
|
-
// item 01. ISO 704 / 1087-1 / 12620 call this a *partitive relation*,
|
|
9
|
-
// not a hyperedge.
|
|
1
|
+
// PartitiveRelation — an ISO 704 / ISO 1087-1 / ISO 12620
|
|
2
|
+
// partitive relation connecting a comprehensive concept
|
|
3
|
+
// (superordinate concept partitive) to two or more partitive
|
|
4
|
+
// concepts (subordinate concepts partitive) which fitted together
|
|
5
|
+
// constitute the comprehensive.
|
|
10
6
|
//
|
|
11
7
|
// Field renames (v1 → v2):
|
|
12
8
|
// parts [1..*] → partitives [2..*] (as PartitiveMember)
|
|
13
9
|
// enumeration: closed|open → completeness: complete|partial
|
|
14
|
-
// markers: [double, dashed] → plurality: TypeSharedPlurality (structured)
|
|
15
10
|
// content: LocalizedString → (dropped — structural edges carry no prose)
|
|
16
11
|
//
|
|
12
|
+
// Per-member metadata (ISO 704:2022):
|
|
13
|
+
// multiplicity (5 values) + is_delimiting (boolean)
|
|
14
|
+
//
|
|
17
15
|
// New field:
|
|
18
16
|
// criterion: LocalizedString [0..1] (ISO 12620 coordinate-concept coherence)
|
|
19
17
|
//
|
|
20
18
|
// Distinguished from binary `has_part` / `is_part_of` edges, which
|
|
21
|
-
// express pairwise part-of assertions without completeness,
|
|
22
|
-
// or criterion claims. A single partitive should be
|
|
23
|
-
// binary edge, not a PartitiveRelation (ISO requires
|
|
19
|
+
// express pairwise part-of assertions without completeness,
|
|
20
|
+
// multiplicity, or criterion claims. A single partitive should be
|
|
21
|
+
// expressed as a binary edge, not a PartitiveRelation (ISO requires
|
|
22
|
+
// "two or more").
|
|
24
23
|
|
|
25
24
|
import { GlossaristModel } from './base.js';
|
|
26
25
|
import { ConceptRef } from './concept-ref.js';
|
|
27
26
|
import { PartitiveMember } from './partitive-member.js';
|
|
28
|
-
import { TypeSharedPlurality } from './type-shared-plurality.js';
|
|
29
27
|
import {
|
|
30
28
|
COMPLETENESS,
|
|
31
29
|
COMPLETENESS_VALUES,
|
|
@@ -39,11 +37,6 @@ export class PartitiveRelation extends GlossaristModel {
|
|
|
39
37
|
this.comprehensive = _ensureComprehensive(data.comprehensive);
|
|
40
38
|
this.partitives = _ensurePartitives(data.partitives);
|
|
41
39
|
this.completeness = _resolveCompleteness(data.completeness);
|
|
42
|
-
this.plurality = data.plurality == null
|
|
43
|
-
? null
|
|
44
|
-
: (data.plurality instanceof TypeSharedPlurality
|
|
45
|
-
? data.plurality
|
|
46
|
-
: new TypeSharedPlurality(data.plurality));
|
|
47
40
|
this.criterion = _normalizeCriterion(data.criterion);
|
|
48
41
|
|
|
49
42
|
_assertNoSelfLoop(this.comprehensive, this.partitives);
|
|
@@ -57,7 +50,6 @@ export class PartitiveRelation extends GlossaristModel {
|
|
|
57
50
|
// coordinate concepts by definition).
|
|
58
51
|
get isCoordinate() { return this.partitives.length >= 2; }
|
|
59
52
|
|
|
60
|
-
hasPlurality() { return this.plurality != null; }
|
|
61
53
|
hasCriterion() { return this.criterion != null; }
|
|
62
54
|
|
|
63
55
|
identity() {
|
|
@@ -70,15 +62,14 @@ export class PartitiveRelation extends GlossaristModel {
|
|
|
70
62
|
partitives: this.partitives.map(p => p.toJSON()),
|
|
71
63
|
completeness: this.completeness,
|
|
72
64
|
};
|
|
73
|
-
if (this.plurality != null) obj.plurality = this.plurality.toJSON();
|
|
74
65
|
if (this.criterion != null) obj.criterion = { ...this.criterion };
|
|
75
66
|
return obj;
|
|
76
67
|
}
|
|
77
68
|
|
|
78
69
|
// Stable identity for diffing: same comprehensive + same partitive
|
|
79
70
|
// set (by ref identity) = same relation. Changes to completeness,
|
|
80
|
-
//
|
|
81
|
-
// add+remove.
|
|
71
|
+
// multiplicity, is_delimiting, or criterion produce "changed"
|
|
72
|
+
// entries rather than add+remove.
|
|
82
73
|
static identityOf(value) {
|
|
83
74
|
const v = value ?? {};
|
|
84
75
|
const c = v.comprehensive ?? {};
|
|
@@ -7,16 +7,11 @@
|
|
|
7
7
|
// gloss:comprehensive <base>/concept/<comprehensive-id> (named node)
|
|
8
8
|
// gloss:hasPartitive <base>/concept/<partitive-id> (named node, one per member)
|
|
9
9
|
// gloss:completeness "complete"|"partial" (literal)
|
|
10
|
-
// gloss:hasPlurality <plurality bnode> (when plurality present)
|
|
11
10
|
// gloss:criterion "..."@lang (one per language, when present)
|
|
12
11
|
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
// rdf:type gloss:TypeSharedPlurality
|
|
17
|
-
// gloss:isShared true|false (literal)
|
|
18
|
-
// gloss:isUncertain true|false (literal, when non-default)
|
|
19
|
-
// gloss:sharedType <base>/concept/<shared-type-id> (when shared_type present)
|
|
12
|
+
// Per-member multiplicity + is_delimiting are emitted as part of
|
|
13
|
+
// each member's named-node object via the partitiveMemberToQuads
|
|
14
|
+
// helper (separate file).
|
|
20
15
|
//
|
|
21
16
|
// The carrying concept links via `gloss:hasPartitiveRelation`.
|
|
22
17
|
//
|
|
@@ -25,7 +20,6 @@
|
|
|
25
20
|
|
|
26
21
|
import { PRED } from './predicates.js';
|
|
27
22
|
import { WELL_KNOWN } from './prefixes.js';
|
|
28
|
-
import { deterministicBnode } from './deterministic-id.js';
|
|
29
23
|
import { namedNode, literal, quad } from './terms.js';
|
|
30
24
|
|
|
31
25
|
export function* partitiveRelationToQuads(relation, { parentUri, index }) {
|
|
@@ -44,20 +38,24 @@ export function* partitiveRelationToQuads(relation, { parentUri, index }) {
|
|
|
44
38
|
for (const member of members) {
|
|
45
39
|
const ref = member?.ref ?? member;
|
|
46
40
|
if (!ref || (!ref.source && !ref.id)) continue;
|
|
47
|
-
|
|
48
|
-
|
|
41
|
+
const memberUri = conceptRefUri(ref, parentUri);
|
|
42
|
+
yield quad(s, namedNode(PRED.gloss.hasPartitive), namedNode(memberUri));
|
|
43
|
+
|
|
44
|
+
// Per-member multiplicity (ISO 704:2022) and is_delimiting.
|
|
45
|
+
if (member?.multiplicity) {
|
|
46
|
+
yield quad(namedNode(memberUri), namedNode(PRED.gloss.multiplicity),
|
|
47
|
+
literal(member.multiplicity));
|
|
48
|
+
}
|
|
49
|
+
if (member?.is_delimiting === true) {
|
|
50
|
+
yield quad(namedNode(memberUri), namedNode(PRED.gloss.isDelimiting),
|
|
51
|
+
literal('true', 'xsd:boolean'));
|
|
52
|
+
}
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
if (relation.completeness) {
|
|
52
56
|
yield quad(s, namedNode(PRED.gloss.completeness), literal(relation.completeness));
|
|
53
57
|
}
|
|
54
58
|
|
|
55
|
-
if (relation.plurality != null) {
|
|
56
|
-
const pSubject = deterministicBnode(subjectUri, 'plurality', 0);
|
|
57
|
-
yield quad(s, namedNode(PRED.gloss.hasPlurality), namedNode(pSubject));
|
|
58
|
-
yield* pluralityToQuads(relation.plurality, pSubject);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
59
|
if (relation.criterion && typeof relation.criterion === 'object') {
|
|
62
60
|
for (const [lang, text] of Object.entries(relation.criterion)) {
|
|
63
61
|
if (typeof text !== 'string') continue;
|
|
@@ -66,25 +64,6 @@ export function* partitiveRelationToQuads(relation, { parentUri, index }) {
|
|
|
66
64
|
}
|
|
67
65
|
}
|
|
68
66
|
|
|
69
|
-
function* pluralityToQuads(plurality, subjectUri) {
|
|
70
|
-
const s = namedNode(subjectUri);
|
|
71
|
-
yield quad(s, namedNode(WELL_KNOWN.rdfType), namedNode(PRED.gloss.TypeSharedPlurality));
|
|
72
|
-
yield quad(s, namedNode(PRED.gloss.isShared), literal(plurality.isShared ? 'true' : 'false', 'xsd:boolean'));
|
|
73
|
-
if (plurality.isUncertain) {
|
|
74
|
-
yield quad(s, namedNode(PRED.gloss.isUncertain), literal('true', 'xsd:boolean'));
|
|
75
|
-
}
|
|
76
|
-
if (plurality.sharedType) {
|
|
77
|
-
// sharedType is a ConceptRef-like object; emit as a concept URI.
|
|
78
|
-
// We don't have parentUri here, but sharedType typically points at
|
|
79
|
-
// an external concept. Fall back to urn form.
|
|
80
|
-
const st = plurality.sharedType;
|
|
81
|
-
const uri = st.id
|
|
82
|
-
? `urn:glossarist:${st.source ?? 'unknown'}:${st.id}`
|
|
83
|
-
: `urn:glossarist:${st.source ?? 'unknown'}:`;
|
|
84
|
-
yield quad(s, namedNode(PRED.gloss.sharedType), namedNode(uri));
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
67
|
// Subject URI scheme: `<base>/partitive-relation/<carrying-id>/<comprehensive-id>`.
|
|
89
68
|
// Matches the Ruby emitter's scheme. Falls back to an index suffix if
|
|
90
69
|
// the comprehensive has no id, so two relations on the same concept
|
package/src/rdf/predicates.d.ts
CHANGED
|
@@ -107,16 +107,12 @@ export declare const PRED = {
|
|
|
107
107
|
"hyperedgeContent": "https://www.glossarist.org/ontologies/hyperedgeContent",
|
|
108
108
|
"PartitiveRelation": "https://www.glossarist.org/ontologies/PartitiveRelation",
|
|
109
109
|
"PartitiveMember": "https://www.glossarist.org/ontologies/PartitiveMember",
|
|
110
|
-
"TypeSharedPlurality": "https://www.glossarist.org/ontologies/TypeSharedPlurality",
|
|
111
110
|
"hasPartitiveRelation": "https://www.glossarist.org/ontologies/hasPartitiveRelation",
|
|
112
111
|
"hasPartitive": "https://www.glossarist.org/ontologies/hasPartitive",
|
|
113
112
|
"completeness": "https://www.glossarist.org/ontologies/completeness",
|
|
114
|
-
"
|
|
115
|
-
"
|
|
116
|
-
"isUncertain": "https://www.glossarist.org/ontologies/isUncertain",
|
|
117
|
-
"sharedType": "https://www.glossarist.org/ontologies/sharedType",
|
|
113
|
+
"multiplicity": "https://www.glossarist.org/ontologies/multiplicity",
|
|
114
|
+
"isDelimiting": "https://www.glossarist.org/ontologies/isDelimiting",
|
|
118
115
|
"criterion": "https://www.glossarist.org/ontologies/criterion",
|
|
119
|
-
"certainty": "https://www.glossarist.org/ontologies/certainty",
|
|
120
116
|
"provides": "https://www.glossarist.org/ontologies/provides",
|
|
121
117
|
"providedBy": "https://www.glossarist.org/ontologies/providedBy",
|
|
122
118
|
"refType": "https://www.glossarist.org/ontologies/refType",
|
|
@@ -393,16 +389,12 @@ export type Predicate =
|
|
|
393
389
|
| "https://www.glossarist.org/ontologies/hyperedgeContent"
|
|
394
390
|
| "https://www.glossarist.org/ontologies/PartitiveRelation"
|
|
395
391
|
| "https://www.glossarist.org/ontologies/PartitiveMember"
|
|
396
|
-
| "https://www.glossarist.org/ontologies/TypeSharedPlurality"
|
|
397
392
|
| "https://www.glossarist.org/ontologies/hasPartitiveRelation"
|
|
398
393
|
| "https://www.glossarist.org/ontologies/hasPartitive"
|
|
399
394
|
| "https://www.glossarist.org/ontologies/completeness"
|
|
400
|
-
| "https://www.glossarist.org/ontologies/
|
|
401
|
-
| "https://www.glossarist.org/ontologies/
|
|
402
|
-
| "https://www.glossarist.org/ontologies/isUncertain"
|
|
403
|
-
| "https://www.glossarist.org/ontologies/sharedType"
|
|
395
|
+
| "https://www.glossarist.org/ontologies/multiplicity"
|
|
396
|
+
| "https://www.glossarist.org/ontologies/isDelimiting"
|
|
404
397
|
| "https://www.glossarist.org/ontologies/criterion"
|
|
405
|
-
| "https://www.glossarist.org/ontologies/certainty"
|
|
406
398
|
| "https://www.glossarist.org/ontologies/provides"
|
|
407
399
|
| "https://www.glossarist.org/ontologies/providedBy"
|
|
408
400
|
| "https://www.glossarist.org/ontologies/refType"
|
package/src/rdf/predicates.js
CHANGED
|
@@ -107,16 +107,12 @@ export const PRED = {
|
|
|
107
107
|
"hyperedgeContent": "https://www.glossarist.org/ontologies/hyperedgeContent",
|
|
108
108
|
"PartitiveRelation": "https://www.glossarist.org/ontologies/PartitiveRelation",
|
|
109
109
|
"PartitiveMember": "https://www.glossarist.org/ontologies/PartitiveMember",
|
|
110
|
-
"TypeSharedPlurality": "https://www.glossarist.org/ontologies/TypeSharedPlurality",
|
|
111
110
|
"hasPartitiveRelation": "https://www.glossarist.org/ontologies/hasPartitiveRelation",
|
|
112
111
|
"hasPartitive": "https://www.glossarist.org/ontologies/hasPartitive",
|
|
113
112
|
"completeness": "https://www.glossarist.org/ontologies/completeness",
|
|
114
|
-
"
|
|
115
|
-
"
|
|
116
|
-
"isUncertain": "https://www.glossarist.org/ontologies/isUncertain",
|
|
117
|
-
"sharedType": "https://www.glossarist.org/ontologies/sharedType",
|
|
113
|
+
"multiplicity": "https://www.glossarist.org/ontologies/multiplicity",
|
|
114
|
+
"isDelimiting": "https://www.glossarist.org/ontologies/isDelimiting",
|
|
118
115
|
"criterion": "https://www.glossarist.org/ontologies/criterion",
|
|
119
|
-
"certainty": "https://www.glossarist.org/ontologies/certainty",
|
|
120
116
|
"provides": "https://www.glossarist.org/ontologies/provides",
|
|
121
117
|
"providedBy": "https://www.glossarist.org/ontologies/providedBy",
|
|
122
118
|
"refType": "https://www.glossarist.org/ontologies/refType",
|
|
@@ -71,19 +71,10 @@ export class PartitiveRelationCoherenceRule extends ValidationRule {
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
// Check 4
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if (plural.isUncertain && !plural.isShared) {
|
|
79
|
-
result.addWarning(
|
|
80
|
-
`${path}partitiveRelations[${i}].plurality`,
|
|
81
|
-
`plurality has isUncertain=true without isShared=true (semantically odd: ` +
|
|
82
|
-
`ISO 704 broken line qualifies the close-set double line plurality; ` +
|
|
83
|
-
`without double, what is being qualified?)`,
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
74
|
+
// (Check 4 — plurality coherence — removed. The prior plurality
|
|
75
|
+
// block was based on a misreading of ISO 704; the corrected model
|
|
76
|
+
// uses per-member multiplicity + is_delimiting, which are validated
|
|
77
|
+
// at construction by PartitiveMember itself.)
|
|
87
78
|
}
|
|
88
79
|
}
|
|
89
80
|
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
// MemberCertainty — per-partitive certainty for a PartitiveMember.
|
|
2
|
-
//
|
|
3
|
-
// Glossarist extension beyond ISO 704 notation. ISO 704's broken-line
|
|
4
|
-
// notation marks plurality-level uncertainty; per-member certainty
|
|
5
|
-
// lets a relation assert "member b is confirmed, member d is possible"
|
|
6
|
-
// at the member level.
|
|
7
|
-
//
|
|
8
|
-
// Defaults to `confirmed` when omitted (a member with no certainty
|
|
9
|
-
// field is implicitly confirmed).
|
|
10
|
-
|
|
11
|
-
import { makeEnum } from './enum.js';
|
|
12
|
-
|
|
13
|
-
export const MEMBER_CERTAINTY = makeEnum('MEMBER_CERTAINTY', {
|
|
14
|
-
CONFIRMED: 'confirmed',
|
|
15
|
-
POSSIBLE: 'possible',
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
export const MEMBER_CERTAINTY_VALUES = MEMBER_CERTAINTY.VALUES;
|
|
19
|
-
export const isValidMemberCertainty = MEMBER_CERTAINTY.isValid;
|
|
20
|
-
|
|
21
|
-
export const DEFAULT_MEMBER_CERTAINTY = MEMBER_CERTAINTY.CONFIRMED;
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
// TypeSharedPlurality — semantic claims encoded by ISO 704's
|
|
2
|
-
// close-set double line and broken line notation, promoted from
|
|
3
|
-
// diagram-notation flags to structured data.
|
|
4
|
-
//
|
|
5
|
-
// is_shared — ISO 704 close-set double line. True when several
|
|
6
|
-
// partitives of a given type are involved.
|
|
7
|
-
// is_uncertain — ISO 704 broken line. True when the type-shared
|
|
8
|
-
// plurality is uncertain (asserted to exist but its
|
|
9
|
-
// boundaries are not firmly established).
|
|
10
|
-
// Defaults to false when omitted.
|
|
11
|
-
// shared_type — Glossarist extension. The type the partitives
|
|
12
|
-
// share, when known. ISO notation does not encode
|
|
13
|
-
// this; left for the reader to infer. Optional even
|
|
14
|
-
// when is_shared is true.
|
|
15
|
-
//
|
|
16
|
-
// A PartitiveRelation has at most one TypeSharedPlurality block.
|
|
17
|
-
// Absent means: no type-shared plurality claim is being made.
|
|
18
|
-
//
|
|
19
|
-
// Replaces the v1 `markers: [double, dashed]` field per
|
|
20
|
-
// TODO.partitive-relation-v2 item 03.
|
|
21
|
-
|
|
22
|
-
import { GlossaristModel } from './base.js';
|
|
23
|
-
import { ConceptRef } from './concept-ref.js';
|
|
24
|
-
|
|
25
|
-
export class TypeSharedPlurality extends GlossaristModel {
|
|
26
|
-
constructor(data = {}) {
|
|
27
|
-
super();
|
|
28
|
-
if (typeof data.isShared !== 'boolean' && typeof data.is_shared !== 'boolean') {
|
|
29
|
-
throw new Error(
|
|
30
|
-
'TypeSharedPlurality requires isShared (boolean); got: ' +
|
|
31
|
-
`${JSON.stringify(data.isShared ?? data.is_shared)}`,
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
this.isShared = data.isShared ?? data.is_shared;
|
|
35
|
-
this.isUncertain = data.isUncertain ?? data.is_uncertain ?? false;
|
|
36
|
-
this.sharedType = data.sharedType
|
|
37
|
-
? (data.sharedType instanceof ConceptRef ? data.sharedType : new ConceptRef(data.sharedType))
|
|
38
|
-
: null;
|
|
39
|
-
|
|
40
|
-
_validate(this);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
hasSharedType() {
|
|
44
|
-
return this.sharedType != null;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
toJSON() {
|
|
48
|
-
const obj = { is_shared: this.isShared };
|
|
49
|
-
if (this.isUncertain) obj.is_uncertain = this.isUncertain;
|
|
50
|
-
if (this.sharedType != null) obj.shared_type = this.sharedType.toJSON();
|
|
51
|
-
return obj;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
static fromJSON(data) {
|
|
55
|
-
return new TypeSharedPlurality(data);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function _validate(plurality) {
|
|
60
|
-
if (typeof plurality.isShared !== 'boolean') {
|
|
61
|
-
throw new Error('TypeSharedPlurality.isShared must be boolean');
|
|
62
|
-
}
|
|
63
|
-
if (typeof plurality.isUncertain !== 'boolean') {
|
|
64
|
-
throw new Error('TypeSharedPlurality.isUncertain must be boolean');
|
|
65
|
-
}
|
|
66
|
-
// ISO 704 semantic check: a broken line qualifies the close-set
|
|
67
|
-
// double-line plurality claim. is_uncertain without is_shared is
|
|
68
|
-
// semantically odd. The model accepts it (data is data); the
|
|
69
|
-
// PartitiveRelationCoherenceRule surfaces it as a warning so
|
|
70
|
-
// reviewers can decide whether the data shape is intentional.
|
|
71
|
-
}
|