glossarist 0.4.26 → 0.4.28

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glossarist",
3
- "version": "0.4.26",
3
+ "version": "0.4.28",
4
4
  "description": "JavaScript SDK for Glossarist GCR packages — read, write, validate, and manage terminology concepts",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -1,4 +1,5 @@
1
1
  import { TextDiff } from './text-diff.js';
2
+ import { resolveMultiplicity } from '../models/multiplicity.js';
2
3
 
3
4
  const COLORS = {
4
5
  red: s => `\x1b[31m${s}\x1b[0m`,
@@ -206,7 +207,7 @@ function relationLabel(r) {
206
207
  ? r.partitives.map(m => {
207
208
  const ref = m?.ref ?? m ?? {};
208
209
  let tail = '';
209
- const mult = m?.multiplicity;
210
+ const mult = resolveMultiplicity(m);
210
211
  if (mult && mult !== 'compulsory') tail = ` (${mult})`;
211
212
  if (m?.is_delimiting === true) tail += ' ⊘';
212
213
  return `${ref.id ?? ref.source ?? ref.text ?? '?'}${tail}`;
@@ -236,7 +237,7 @@ export function multiplicityStats(relations) {
236
237
  for (const rel of relations ?? []) {
237
238
  for (const m of rel?.partitives ?? []) {
238
239
  total += 1;
239
- const mult = m?.multiplicity ?? 'compulsory';
240
+ const mult = resolveMultiplicity(m);
240
241
  byMultiplicity[mult] = (byMultiplicity[mult] ?? 0) + 1;
241
242
  const p = m?.presence ?? 'required';
242
243
  const c = m?.count ?? 'exactly_one';
@@ -8,7 +8,7 @@
8
8
  // ISO 704:2022 correction):
9
9
  //
10
10
  // comprehensive → comprehensive (unchanged shape)
11
- // parts: [ref, ...] → partitives: [{ ref, multiplicity: 'compulsory' }, ...]
11
+ // parts: [ref, ...] → partitives: [{ ref, presence: 'required', count: 'exactly_one' }, ...]
12
12
  // enumeration: open → completeness: partial
13
13
  // enumeration: closed→ completeness: complete
14
14
  // markers: [...] → (dropped — v2 uses per-member multiplicity
@@ -63,6 +63,7 @@ export {
63
63
  isValidMultiplicity,
64
64
  multiplicityFromPair,
65
65
  pairFromMultiplicity,
66
+ resolveMultiplicity,
66
67
  } from './multiplicity.js';
67
68
 
68
69
  // v1 → v2 migration helper. Pure function; idempotent.
@@ -66,6 +66,32 @@ export function isValidMultiplicity(name) {
66
66
  return Object.prototype.hasOwnProperty.call(PAIR_BY_NAME, name);
67
67
  }
68
68
 
69
+ /**
70
+ * Resolve the ISO 704 multiplicity name from any object carrying
71
+ * `presence` + `count`, OR a legacy object that still has a literal
72
+ * `multiplicity` field (pre-v4 JSON).
73
+ *
74
+ * For v4 `PartitiveMember` instances, `presence` + `count` are always
75
+ * set (defaults applied at construction), so the legacy branch never
76
+ * fires on a real instance — it exists purely to round-trip raw JSON
77
+ * that bypassed the model constructor.
78
+ *
79
+ * Throws on the invalid `(optional, at_least_one)` combination — the
80
+ * model already rejects this at construction, so reaching the throw
81
+ * here means the caller bypassed the model. Let the error propagate
82
+ * rather than silently returning 'compulsory' (which would mask the
83
+ * data corruption).
84
+ */
85
+ export function resolveMultiplicity(member) {
86
+ if (member?.presence && member?.count) {
87
+ return multiplicityFromPair(member.presence, member.count);
88
+ }
89
+ if (typeof member?.multiplicity === 'string') {
90
+ return member.multiplicity;
91
+ }
92
+ return DEFAULT_MULTIPLICITY;
93
+ }
94
+
69
95
  function invalidCombinationError(presence, count) {
70
96
  return new Error(
71
97
  `Invalid multiplicity combination: presence=${presence}, count=${count}. ` +
@@ -21,6 +21,7 @@
21
21
 
22
22
  import { PRED } from './predicates.js';
23
23
  import { namedNode, literal, quad } from './terms.js';
24
+ import { resolveMultiplicity } from '../models/multiplicity.js';
24
25
 
25
26
  // SKOS taxonomy namespaces (concept-model will ship these taxonomies).
26
27
  // Until then, the URIs are forward-compatible and resolve once the
@@ -45,11 +46,15 @@ export function* partitiveMemberToQuads(member, { memberUri }) {
45
46
  );
46
47
  }
47
48
  // Derived multiplicity URI for v3 RDF consumer backward compat.
48
- // multiplicity is computed from (presence, count) via the model's
49
- // accessor; fall back to the raw field for raw JSON input.
50
- const mult = typeof member?.multiplicity === 'string'
51
- ? member.multiplicity
52
- : null;
49
+ // v4 PartitiveMember carries presence + count natively; the legacy
50
+ // multiplicity name is derived via the SSOT resolveMultiplicity().
51
+ // For raw pre-v4 JSON that bypassed the model constructor and still
52
+ // carries a literal multiplicity field, the resolver falls back to
53
+ // that field. The invalid (optional, at_least_one) combination is
54
+ // rejected at model construction — if it reaches the throw here,
55
+ // the caller bypassed the model and we want the error to surface
56
+ // rather than silently producing wrong RDF.
57
+ const mult = resolveMultiplicity(member);
53
58
  if (mult) {
54
59
  yield quad(
55
60
  namedNode(memberUri),