glossarist 0.4.36 → 0.4.37

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.
@@ -1,117 +0,0 @@
1
- // ConceptSystem — first-class concept system entity per ISO 12620 A.7.
2
- //
3
- // Promotes the previously-implicit concept system (domains + tags +
4
- // relation graph) to an explicit first-class entity. Per-file at
5
- // `concept-systems/<id>.yaml`.
6
- //
7
- // See docs/design/concept-systems.md (concept-model repo).
8
-
9
- import { GlossaristModel } from './base.js';
10
- import { ConceptRef } from './concept-ref.js';
11
- import {
12
- CONCEPT_SYSTEM_TYPE,
13
- CONCEPT_SYSTEM_TYPE_VALUES,
14
- isValidConceptSystemType,
15
- } from './concept-system-type.js';
16
-
17
- export class ConceptSystem extends GlossaristModel {
18
- constructor(data = {}) {
19
- super();
20
- this.id = _ensureNonEmptyString(data.id, 'id');
21
- this.name = _ensureName(data.name);
22
- this.type = _resolveType(data.type);
23
- this.domain = data.domain ?? null;
24
- this.purpose = data.purpose ?? null;
25
- this.members = _ensureMembers(data.members);
26
- this.hyperedges = Array.isArray(data.hyperedges) ? [...data.hyperedges] : [];
27
- this.rootConcepts = Array.isArray(data.rootConcepts)
28
- ? data.rootConcepts.map(c => c instanceof ConceptRef ? c : new ConceptRef(c))
29
- : [];
30
- this.sources = Array.isArray(data.sources) ? [...data.sources] : [];
31
- this.status = data.status ?? null;
32
- }
33
-
34
- get isGeneric() { return this.type === CONCEPT_SYSTEM_TYPE.GENERIC; }
35
- get isPartitive() { return this.type === CONCEPT_SYSTEM_TYPE.PARTITIVE; }
36
- get isSequential() { return this.type === CONCEPT_SYSTEM_TYPE.SEQUENTIAL; }
37
- get isAssociative() { return this.type === CONCEPT_SYSTEM_TYPE.ASSOCIATIVE; }
38
- get isMixed() { return this.type === CONCEPT_SYSTEM_TYPE.MIXED; }
39
-
40
- hasHyperedge(edgeId) {
41
- return this.hyperedges.includes(edgeId);
42
- }
43
-
44
- hasMember(refOrUri) {
45
- const uri = typeof refOrUri === 'string' ? refOrUri : _refUri(refOrUri);
46
- return this.members.some(m => _refUri(m) === uri);
47
- }
48
-
49
- identity() {
50
- return this.id;
51
- }
52
-
53
- toJSON() {
54
- const obj = {
55
- id: this.id,
56
- name: { ...this.name },
57
- type: this.type,
58
- members: this.members.map(m => m.toJSON()),
59
- };
60
- if (this.domain != null) obj.domain = this.domain;
61
- if (this.purpose != null) obj.purpose = { ...this.purpose };
62
- if (this.hyperedges.length > 0) obj.hyperedges = [...this.hyperedges];
63
- if (this.rootConcepts.length > 0) obj.rootConcepts = this.rootConcepts.map(c => c.toJSON());
64
- if (this.sources.length > 0) obj.sources = [...this.sources];
65
- if (this.status != null) obj.status = this.status;
66
- return obj;
67
- }
68
-
69
- static fromJSON(data) {
70
- return new ConceptSystem(data);
71
- }
72
- }
73
-
74
- function _ensureNonEmptyString(value, fieldName) {
75
- if (typeof value !== 'string' || value.length === 0) {
76
- throw new Error(`ConceptSystem#${fieldName} must be a non-empty string`);
77
- }
78
- return value;
79
- }
80
-
81
- function _ensureName(value) {
82
- if (value == null) return {};
83
- if (typeof value !== 'object' || Array.isArray(value)) {
84
- throw new Error('ConceptSystem#name must be a localized object (e.g. { eng: "..." })');
85
- }
86
- return { ...value };
87
- }
88
-
89
- function _resolveType(value) {
90
- if (value == null) {
91
- throw new Error(
92
- 'ConceptSystem#type is required; one of ' +
93
- CONCEPT_SYSTEM_TYPE_VALUES.join(', '),
94
- );
95
- }
96
- if (!isValidConceptSystemType(value)) {
97
- throw new Error(
98
- `ConceptSystem#type ${JSON.stringify(value)} invalid; ` +
99
- `must be one of: ${CONCEPT_SYSTEM_TYPE_VALUES.join(', ')}`,
100
- );
101
- }
102
- return value;
103
- }
104
-
105
- function _ensureMembers(values) {
106
- if (!Array.isArray(values) || values.length === 0) {
107
- throw new Error('ConceptSystem#members must be a non-empty array');
108
- }
109
- return values.map(v => v instanceof ConceptRef ? v : new ConceptRef(v));
110
- }
111
-
112
- function _refUri(ref) {
113
- const r = ref?.ref ?? ref ?? {};
114
- return `${r.source ?? ''}:${r.id ?? ''}`;
115
- }
116
-
117
- export default ConceptSystem;
@@ -1,55 +0,0 @@
1
- // GenericHyperedge — an ISO 704 / ISO 1087-1 / ISO 12620 generic
2
- // relation connecting a comprehensive concept (the genus) to two
3
- // or more specific concepts (the species) which together constitute
4
- // a decomposition by some criterion of subdivision.
5
- //
6
- // Mirror of PartitiveHyperedge. Multiple GenericRelations on the same
7
- // comprehensive distinguished by `criterion` is the OIML pattern
8
- // (5.1 measurement standard has 6 criterion groups).
9
- //
10
- // See docs/design/generic-relation.md (concept-model repo).
11
-
12
- import { AbstractHyperedge } from './abstract-hyperedge.js';
13
- import { GenericMember } from './generic-member.js';
14
- import { HyperedgeRegistry } from './hyperedge-registry.js';
15
-
16
- export class GenericHyperedge extends AbstractHyperedge {
17
- // Per-class metadata block — the OCP contract. See PartitiveHyperedge
18
- // for field documentation.
19
- static wireKey = 'generic_relations';
20
- static typeTag = 'generic_relation';
21
- static rdfType = 'gloss:GenericRelation';
22
- static memberClass = GenericMember;
23
- static v1WireKeys = [];
24
- static kindLabel = 'GEN';
25
-
26
- constructor(data = {}) {
27
- super(data);
28
- this.members = data?.members == null
29
- ? this.members
30
- : (Array.isArray(data.members)
31
- ? data.members.map(m =>
32
- m instanceof GenericMember ? m : new GenericMember(m))
33
- : this.members);
34
- }
35
-
36
- static identityOf(value) {
37
- const v = value ?? {};
38
- const c = v.comprehensive ?? {};
39
- const memberKeys = Array.isArray(v.members)
40
- ? v.members.map(m => {
41
- const r = m?.ref ?? m ?? {};
42
- return `${r.source ?? ''}:${r.id ?? ''}`;
43
- }).sort()
44
- : [];
45
- return `${c.source ?? ''}:${c.id ?? ''}|${memberKeys.join('|')}`;
46
- }
47
-
48
- static fromJSON(data) {
49
- return new GenericHyperedge(data);
50
- }
51
- }
52
-
53
- export default GenericHyperedge;
54
-
55
- HyperedgeRegistry.register(GenericHyperedge);
@@ -1,82 +0,0 @@
1
- // GenericMember — one member of a GenericHyperedge.
2
- //
3
- // Per ISO 704:2022 §5.5.4.2.1 (Generic relations and general concepts):
4
- //
5
- // "In a generic relation, the intension of the subordinate concept
6
- // includes the intension of the superordinate concept plus at least
7
- // one additional delimiting characteristic."
8
- //
9
- // In hyperedge terms: when a GenericHyperedge has comprehensive=computer mouse
10
- // and criterion=means of movement detection, each member (mechanical mouse,
11
- // optomechanical mouse, optical mouse) carries a delimitingCharacteristic —
12
- // the value of the criterion for that specific concept:
13
- //
14
- // mechanical mouse → 'detecting movement by means of rollers'
15
- // optomechanical mouse → 'detecting movement by means of rollers and light sensors'
16
- // optical mouse → 'detecting movement by means of light sensors'
17
- //
18
- // Multidimensionality (§5.6.3): the same comprehensive can be the
19
- // '1' side of multiple generic hyperedges simultaneously, each by a
20
- // different criterion. computer mouse is also comprehensive of
21
- // {wired mouse, wireless mouse} under criterion=computer connection.
22
- // That second hyperedge's members carry their own delimitingCharacteristic
23
- // values ('using a corded electrical connection', 'using a cordless
24
- // light or sound connection').
25
- //
26
- // delimitingCharacteristic is REQUIRED on GenericMember. Without it,
27
- // the member is just a coordinate concept with no semantic content
28
- // tying it to the criterion — ISO 704 says the relation is meaningless
29
- // without the delimiting characteristic.
30
- //
31
- // LocalizedString shape (mirrors criterion on the parent hyperedge):
32
- // { eng: 'detecting movement by means of light sensors' }
33
- // { eng: '...', fra: '...' } — multiple languages supported
34
-
35
- import { HyperedgeMember } from './hyperedge-member.js';
36
-
37
- export class GenericMember extends HyperedgeMember {
38
- constructor(data = {}) {
39
- super(data);
40
- this.delimitingCharacteristic = _resolveDelimitingCharacteristic(data.delimitingCharacteristic);
41
- }
42
-
43
- toJSON() {
44
- const base = super.toJSON();
45
- base.delimitingCharacteristic = { ...this.delimitingCharacteristic };
46
- return base;
47
- }
48
- }
49
-
50
- function _resolveDelimitingCharacteristic(value) {
51
- if (value == null) {
52
- throw new Error(
53
- 'GenericMember.delimitingCharacteristic is required per ISO 704:2022 §5.5.4.2.1 ' +
54
- '(the intension of a subordinate concept must include at least one additional ' +
55
- 'delimiting characteristic beyond the superordinate).',
56
- );
57
- }
58
- if (typeof value === 'string') {
59
- if (value.length === 0) {
60
- throw new Error(
61
- 'GenericMember.delimitingCharacteristic cannot be empty (ISO 704:2022 §5.5.4.2.1)',
62
- );
63
- }
64
- return { default: value };
65
- }
66
- if (typeof value === 'object') {
67
- const entries = Object.entries(value).filter(([, v]) => typeof v === 'string' && v.length > 0);
68
- if (entries.length === 0) {
69
- throw new Error(
70
- 'GenericMember.delimitingCharacteristic must have at least one non-empty string ' +
71
- 'value (ISO 704:2022 §5.5.4.2.1)',
72
- );
73
- }
74
- return Object.fromEntries(entries);
75
- }
76
- throw new Error(
77
- `GenericMember.delimitingCharacteristic must be a string or a language-keyed object; ` +
78
- `got ${typeof value}`,
79
- );
80
- }
81
-
82
- export default GenericMember;
@@ -1,91 +0,0 @@
1
- // PartitiveHyperedge — an ISO 704:2022 / 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.
6
- //
7
- // Extends AbstractHyperedge; the leaf-specific concern is the
8
- // PartitiveMember type for `members`. The wire-level field name
9
- // stays `partitives` for v1/v2 backward compat.
10
- //
11
- // ISO 704:2022 rake diagram semantics:
12
- //
13
- // comprehensive concept
14
- // ─────────────────────
15
- // │ partitive (one or more) with per-member multiplicity + optional delimiting
16
- // ─────────────────────
17
- //
18
- // All partitives within one relation are coordinate concepts
19
- // (ISO 12620): they share the comprehensive AND share the
20
- // criterion of subdivision.
21
- //
22
- // "Delimiting" parts (bold/3x-width line in source diagrams) behave
23
- // like delimiting characteristics — they distinguish the comprehensive
24
- // from coordinate concepts. Whether a part is delimiting depends on
25
- // the concept system, the coordinate concepts, the inheritance
26
- // principle, and the criterion of subdivision used
27
- // (ISO 704:2022 §5.5.4.2.1).
28
- //
29
- // Distinguished from binary `has_part` / `is_part_of` edges, which
30
- // express pairwise part-of assertions without completeness,
31
- // multiplicity, or criterion claims. A single partitive should be
32
- // expressed as a binary edge, not a PartitiveHyperedge (ISO requires
33
- // "two or more").
34
-
35
- import { AbstractHyperedge } from './abstract-hyperedge.js';
36
- import { PartitiveMember } from './partitive-member.js';
37
- import { HyperedgeRegistry } from './hyperedge-registry.js';
38
-
39
- export class PartitiveHyperedge extends AbstractHyperedge {
40
- // Per-class metadata block — the OCP contract. External systems
41
- // (parser, serializer, diff, RDF emitter, validators) read from
42
- // these statics and the HyperedgeRegistry. Adding a new hyperedge
43
- // type = declaring these fields on a new subclass + registering
44
- // it. Nothing else in the codebase changes.
45
- static wireKey = 'partitive_relations';
46
- static typeTag = 'partitive_relation';
47
- static rdfType = 'gloss:PartitiveRelation';
48
- static memberClass = PartitiveMember;
49
- static v1WireKeys = ['partitive_hyperedges'];
50
- static kindLabel = 'PART';
51
-
52
- constructor(data = {}) {
53
- const members = data?.members ?? data?.partitives;
54
- super({ ...data, members });
55
- this.members = members == null
56
- ? this.members
57
- : (Array.isArray(members)
58
- ? members.map(m =>
59
- m instanceof PartitiveMember ? m : new PartitiveMember(m))
60
- : this.members);
61
- }
62
-
63
- get partitives() { return this.members; }
64
-
65
- toJSON() {
66
- const base = super.toJSON();
67
- const { members, ...rest } = base;
68
- return { ...rest, partitives: members };
69
- }
70
-
71
- static identityOf(value) {
72
- const v = value ?? {};
73
- const c = v.comprehensive ?? {};
74
- const partKeys = Array.isArray(v.partitives ?? v.members)
75
- ? (v.partitives ?? v.members).map(p => {
76
- const r = p?.ref ?? p ?? {};
77
- return `${r.source ?? ''}:${r.id ?? ''}`;
78
- }).sort()
79
- : [];
80
- return `${c.source ?? ''}:${c.id ?? ''}|${partKeys.join('|')}`;
81
- }
82
-
83
- static fromJSON(data) {
84
- const normalized = { ...(data ?? {}), members: data?.partitives ?? data?.members };
85
- return new PartitiveHyperedge(normalized);
86
- }
87
- }
88
-
89
- export default PartitiveHyperedge;
90
-
91
- HyperedgeRegistry.register(PartitiveHyperedge);
@@ -1,56 +0,0 @@
1
- // SequentialHyperedge — an ISO 12620 A.6.3 / ISO 704:2022 §5.5.5
2
- // sequential relation connecting a comprehensive concept to two or
3
- // more subordinate concepts in an ORDERED sequence (temporal,
4
- // spatial, causal, developmental).
5
- //
6
- // Mirror of PartitiveHyperedge and GenericHyperedge. Member array
7
- // order IS significant — reversing the array reverses the sequence.
8
- // Use cases: manufacturing process steps, biological life cycles,
9
- // software release lifecycles, supply chain stages, geological eras.
10
- //
11
- // See docs/design/abstract-nary-relation.md (concept-model repo).
12
-
13
- import { AbstractHyperedge } from './abstract-hyperedge.js';
14
- import { SequentialMember } from './sequential-member.js';
15
- import { HyperedgeRegistry } from './hyperedge-registry.js';
16
-
17
- export class SequentialHyperedge extends AbstractHyperedge {
18
- // Per-class metadata block — the OCP contract.
19
- static wireKey = 'sequential_relations';
20
- static typeTag = 'sequential_relation';
21
- static rdfType = 'gloss:SequentialRelation';
22
- static memberClass = SequentialMember;
23
- static v1WireKeys = [];
24
- static kindLabel = 'SEQ';
25
-
26
- constructor(data = {}) {
27
- super(data);
28
- this.members = data?.members == null
29
- ? this.members
30
- : (Array.isArray(data.members)
31
- ? data.members.map(m =>
32
- m instanceof SequentialMember ? m : new SequentialMember(m))
33
- : this.members);
34
- }
35
-
36
- static identityOf(value) {
37
- const v = value ?? {};
38
- const c = v.comprehensive ?? {};
39
- // For sequential, member order IS significant — do NOT sort.
40
- const memberKeys = Array.isArray(v.members)
41
- ? v.members.map(m => {
42
- const r = m?.ref ?? m ?? {};
43
- return `${r.source ?? ''}:${r.id ?? ''}`;
44
- })
45
- : [];
46
- return `${c.source ?? ''}:${c.id ?? ''}|${memberKeys.join('|')}`;
47
- }
48
-
49
- static fromJSON(data) {
50
- return new SequentialHyperedge(data);
51
- }
52
- }
53
-
54
- export default SequentialHyperedge;
55
-
56
- HyperedgeRegistry.register(SequentialHyperedge);