@cosyte/terminology 0.0.13 → 0.1.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/dist/index.mjs CHANGED
@@ -70,19 +70,43 @@ var DIAGNOSTIC_CODES = {
70
70
  TERM_CONCEPT_HEADER_NOT_BILLABLE: "TERM_CONCEPT_HEADER_NOT_BILLABLE",
71
71
  /**
72
72
  * A ValueSet `compose` part could **not be expanded**: an intensional `include`/`exclude` whose
73
- * code system was not supplied, an unresolvable referenced value set, or a `filter` operator the
74
- * engine does not implement. Surfaced as a typed outcome that marks the expansion **incomplete**;
73
+ * code system was not supplied, an unresolvable referenced value set, a `filter` operator the
74
+ * engine does not implement, or a component whose declared code system version disagrees with the
75
+ * supplied release (or names a pin that release carries no version to confirm). Surfaced as a
76
+ * typed outcome that marks the expansion **incomplete**;
75
77
  * the engine **never** fabricates a member and **never** returns a silently-empty "no members"
76
78
  * answer for a part it could not compute (a false "not a member" is a clinical error).
77
79
  */
78
80
  TERM_VALUESET_CANNOT_EXPAND: "TERM_VALUESET_CANNOT_EXPAND",
79
81
  /**
80
82
  * A **pre-computed** `ValueSet.expansion` is **incomplete**: its `total` exceeds the number of
81
- * `contains` entries, or it is flagged too-costly (the VSAC `$expand` >1200-code truncation
82
- * hazard). The engine **never treats a truncated expansion as complete membership**: a code
83
- * absent from a truncated expansion is `undetermined`, never a confident "not a member".
83
+ * `contains` entries, it is flagged too-costly (the VSAC `$expand` >1200-code truncation
84
+ * hazard), or it is marked `unclosed` (the value set is unbounded because it includes
85
+ * post-coordinated content, so no expansion can enumerate it). The engine **never treats an
86
+ * incomplete expansion as complete membership**: a code absent from one is `undetermined`, never
87
+ * a confident "not a member". The diagnostic's `detail` says which of those it was.
84
88
  */
85
89
  TERM_VALUESET_EXPANSION_TRUNCATED: "TERM_VALUESET_EXPANSION_TRUNCATED",
90
+ /**
91
+ * A `ValueSet.compose` component **enumerated** a code the release supplied for its `system` does
92
+ * not define, so the code was **not admitted** as a member. The never-fabricate invariant applied
93
+ * to an extensional selection: enumerating a code is the value set's claim that it exists, and
94
+ * asserting membership for it while holding the very release that shows it does not is the engine
95
+ * deciding against its own evidence.
96
+ *
97
+ * Raised **only** where the evidence is in hand: a release keyed by the component's `system` that
98
+ * the component's declared `version` (if any) agrees with. No release for that system, a declared
99
+ * version the supplied release does not agree with, or a component naming no `system` at all
100
+ * leaves the engine with no contrary evidence, so every enumerated code is carried and **no
101
+ * diagnostic is raised**: absence of evidence is not evidence the code is undefined.
102
+ *
103
+ * The answer stays **decided**, unlike {@link TERM_VALUESET_CANNOT_EXPAND}: the engine computed
104
+ * membership on the evidence it was given, so `expand` reports `complete: true` and
105
+ * `validateCodeInValueSet` reports a decided non-member for the dropped code, rather than a lower
106
+ * bound or a refusal. One diagnostic is raised per affected component, located by that
107
+ * component's own index path, however many of its codes were dropped.
108
+ */
109
+ TERM_VALUESET_ENUMERATED_CODE_UNDEFINED: "TERM_VALUESET_ENUMERATED_CODE_UNDEFINED",
86
110
  /**
87
111
  * A UCUM unit expression is **not valid**: it does not parse against the UCUM grammar, or it
88
112
  * names an atom absent from the vendored UCUM table. A **first-class typed outcome, never an
@@ -487,7 +511,7 @@ function provenanceOf(map, group, sourceSystem) {
487
511
  if (group?.target !== void 0) out.targetSystem = group.target;
488
512
  return Object.freeze(out);
489
513
  }
490
- function unmappedResult(source, mode, provenance, fixedTarget, otherMapUrl) {
514
+ function unmappedResult(source, mode, provenance, fixedTarget, otherMapUrl, notRelated = []) {
491
515
  const out = {
492
516
  unmapped: true,
493
517
  code: "TERM_TRANSLATE_UNMAPPED",
@@ -497,13 +521,15 @@ function unmappedResult(source, mode, provenance, fixedTarget, otherMapUrl) {
497
521
  };
498
522
  if (fixedTarget !== void 0) out.fixedTarget = fixedTarget;
499
523
  if (otherMapUrl !== void 0) out.otherMapUrl = otherMapUrl;
524
+ if (notRelated.length > 0) out.notRelated = Object.freeze(notRelated);
500
525
  return Object.freeze(out);
501
526
  }
502
527
  function translate(sourceCoding, map) {
503
528
  const source = coding(sourceCoding);
504
529
  const system = source.system;
505
- const matches = [];
506
- let firstMatchGroup;
530
+ const rows = [];
531
+ const notRelated = [];
532
+ let firstRowGroup;
507
533
  let sourceCodePresent = false;
508
534
  let fallbackGroup;
509
535
  for (const group of map.group) {
@@ -520,23 +546,45 @@ function translate(sourceCoding, map) {
520
546
  ...t.display !== void 0 ? { display: t.display } : {},
521
547
  ...group.targetVersion !== void 0 ? { version: group.targetVersion } : {}
522
548
  });
523
- const match = {
524
- target: targetCoding,
525
- relationship: equivalenceToRelationship(t.equivalence),
526
- equivalence: t.equivalence
527
- };
528
- if (t.comment !== void 0) match.comment = t.comment;
529
- matches.push(Object.freeze(match));
530
- if (firstMatchGroup === void 0) firstMatchGroup = group;
549
+ if (t.equivalence === "disjoint") {
550
+ const assertion = {
551
+ target: targetCoding,
552
+ relationship: equivalenceToRelationship(t.equivalence),
553
+ equivalence: t.equivalence
554
+ };
555
+ if (t.comment !== void 0) assertion.comment = t.comment;
556
+ const frozen = Object.freeze(assertion);
557
+ notRelated.push(frozen);
558
+ rows.push(frozen);
559
+ } else {
560
+ const match = {
561
+ target: targetCoding,
562
+ relationship: equivalenceToRelationship(t.equivalence),
563
+ equivalence: t.equivalence
564
+ };
565
+ if (t.comment !== void 0) match.comment = t.comment;
566
+ rows.push(Object.freeze(match));
567
+ }
568
+ if (firstRowGroup === void 0) firstRowGroup = group;
531
569
  }
532
570
  }
533
571
  }
534
- if (matches.length > 0) {
535
- return Object.freeze({
536
- unmapped: false,
537
- matches: Object.freeze(matches),
538
- provenance: provenanceOf(map, firstMatchGroup, system)
539
- });
572
+ if (rows.length > 0) {
573
+ if (notRelated.length < rows.length) {
574
+ return Object.freeze({
575
+ unmapped: false,
576
+ matches: Object.freeze(rows),
577
+ provenance: provenanceOf(map, firstRowGroup, system)
578
+ });
579
+ }
580
+ return unmappedResult(
581
+ source,
582
+ "none",
583
+ provenanceOf(map, firstRowGroup, system),
584
+ void 0,
585
+ void 0,
586
+ notRelated
587
+ );
540
588
  }
541
589
  if (!sourceCodePresent && fallbackGroup?.unmapped !== void 0) {
542
590
  const um = fallbackGroup.unmapped;
@@ -559,7 +607,7 @@ function translate(sourceCoding, map) {
559
607
  return unmappedResult(
560
608
  source,
561
609
  "none",
562
- provenanceOf(map, firstMatchGroup, system),
610
+ provenanceOf(map, firstRowGroup, system),
563
611
  void 0,
564
612
  void 0
565
613
  );
@@ -1069,6 +1117,7 @@ function validateCode(cs, code) {
1069
1117
 
1070
1118
  // src/valueset/load.ts
1071
1119
  var TOO_COSTLY_EXTENSION = "http://hl7.org/fhir/StructureDefinition/valueset-toocostly";
1120
+ var UNCLOSED_EXTENSION = "http://hl7.org/fhir/StructureDefinition/valueset-unclosed";
1072
1121
  function malformed2(path, fault) {
1073
1122
  throw new TerminologyError(FATAL_CODES.TERM_VALUESET_MALFORMED, `ValueSet ${path}: ${fault}`);
1074
1123
  }
@@ -1147,7 +1196,13 @@ function loadCompose(raw, path) {
1147
1196
  (c, i) => loadComponent(c, `${path}.exclude[${String(i)}]`)
1148
1197
  )
1149
1198
  );
1150
- return Object.freeze({ include, exclude });
1199
+ const out = { include, exclude };
1200
+ if (raw["inactive"] !== void 0) {
1201
+ const inactive = getBoolean(raw, "inactive");
1202
+ if (inactive === void 0) malformed2(`${path}.inactive`, "'inactive' is not a boolean");
1203
+ out.inactive = inactive;
1204
+ }
1205
+ return Object.freeze(out);
1151
1206
  }
1152
1207
  function loadContains(raw, path) {
1153
1208
  if (!isJsonObject(raw)) malformed2(path, "contains entry is not an object");
@@ -1167,6 +1222,18 @@ function isTooCostly(raw) {
1167
1222
  }
1168
1223
  return false;
1169
1224
  }
1225
+ function isUnclosed(raw) {
1226
+ for (const ext of getArray(raw, "extension") ?? []) {
1227
+ if (typeof ext === "string") {
1228
+ if (ext === UNCLOSED_EXTENSION) return true;
1229
+ continue;
1230
+ }
1231
+ if (getString(ext, "url") !== UNCLOSED_EXTENSION) continue;
1232
+ if (getBoolean(ext, "valueBoolean") === false) continue;
1233
+ return true;
1234
+ }
1235
+ return false;
1236
+ }
1170
1237
  function loadExpansion(raw, path) {
1171
1238
  if (!isJsonObject(raw)) malformed2(path, "expansion is not an object");
1172
1239
  const contains = Object.freeze(
@@ -1175,8 +1242,9 @@ function loadExpansion(raw, path) {
1175
1242
  )
1176
1243
  );
1177
1244
  const total = getNumber(raw, "total");
1178
- const truncated2 = total !== void 0 && total > contains.length || isTooCostly(raw);
1179
- const out = { contains, truncated: truncated2 };
1245
+ const unclosed = isUnclosed(raw);
1246
+ const truncated2 = total !== void 0 && total > contains.length || isTooCostly(raw) || unclosed;
1247
+ const out = { contains, truncated: truncated2, unclosed };
1180
1248
  if (total !== void 0) out.total = total;
1181
1249
  return Object.freeze(out);
1182
1250
  }
@@ -1246,11 +1314,12 @@ function valueSet(value) {
1246
1314
  value.split(",").map((v) => v.trim()).filter((v) => v.length > 0)
1247
1315
  );
1248
1316
  }
1249
- function propertyValue(concept, property) {
1317
+ function propertyValues(concept, property) {
1318
+ const values = [];
1250
1319
  for (const p of concept.properties) {
1251
- if (p.code === property) return typeof p.value === "string" ? p.value : String(p.value);
1320
+ if (p.code === property) values.push(typeof p.value === "string" ? p.value : String(p.value));
1252
1321
  }
1253
- return void 0;
1322
+ return values;
1254
1323
  }
1255
1324
  var UNSUPPORTED = Object.freeze({ matched: false, supported: false });
1256
1325
  function matchesFilter(concept, filter, sub) {
@@ -1266,21 +1335,30 @@ function matchesFilter(concept, filter, sub) {
1266
1335
  case "is-not-a":
1267
1336
  return { matched: !isA(sub, concept.code, filter.value), supported: true };
1268
1337
  case "=": {
1269
- const actual = onCode ? concept.code : propertyValue(concept, filter.property);
1270
- return { matched: actual === filter.value, supported: true };
1338
+ if (onCode) return { matched: concept.code === filter.value, supported: true };
1339
+ return {
1340
+ matched: propertyValues(concept, filter.property).includes(filter.value),
1341
+ supported: true
1342
+ };
1271
1343
  }
1272
1344
  case "in": {
1273
1345
  const set = valueSet(filter.value);
1274
- const actual = onCode ? concept.code : propertyValue(concept, filter.property);
1275
- return { matched: actual !== void 0 && set.has(actual), supported: true };
1346
+ if (onCode) return { matched: set.has(concept.code), supported: true };
1347
+ return {
1348
+ matched: propertyValues(concept, filter.property).some((v) => set.has(v)),
1349
+ supported: true
1350
+ };
1276
1351
  }
1277
1352
  case "not-in": {
1278
1353
  const set = valueSet(filter.value);
1279
- const actual = onCode ? concept.code : propertyValue(concept, filter.property);
1280
- return { matched: actual === void 0 || !set.has(actual), supported: true };
1354
+ if (onCode) return { matched: !set.has(concept.code), supported: true };
1355
+ return {
1356
+ matched: propertyValues(concept, filter.property).every((v) => !set.has(v)),
1357
+ supported: true
1358
+ };
1281
1359
  }
1282
1360
  case "exists": {
1283
- const present = onCode ? true : propertyValue(concept, filter.property) !== void 0;
1361
+ const present = onCode ? true : propertyValues(concept, filter.property).length > 0;
1284
1362
  const wantPresent = filter.value.trim().toLowerCase() === "true";
1285
1363
  return { matched: present === wantPresent, supported: true };
1286
1364
  }
@@ -1321,6 +1399,43 @@ function truncated(detail, path) {
1321
1399
  d.path = path;
1322
1400
  return Object.freeze(d);
1323
1401
  }
1402
+ function enumeratedUndefined(detail, path) {
1403
+ const d = {
1404
+ code: "TERM_VALUESET_ENUMERATED_CODE_UNDEFINED",
1405
+ detail
1406
+ };
1407
+ if (path !== void 0) d.path = path;
1408
+ return Object.freeze(d);
1409
+ }
1410
+ function expansionIncompleteDetail(unclosed) {
1411
+ return unclosed ? "pre-computed expansion is incomplete (marked unclosed: the value set is unbounded, so the snapshot is a sample of its membership)" : "pre-computed expansion is incomplete (truncated or too-costly)";
1412
+ }
1413
+ var ACTIVITY_UNCHECKABLE_DETAIL = "active-only value set: no usable code system release to check whether a selected code is active";
1414
+ var ENUMERATED_UNDEFINED_DETAIL = "enumerated code is not defined by the supplied code system release, so it is not a member";
1415
+ function usableRelease(component, system, ctx) {
1416
+ if (system === void 0) return void 0;
1417
+ const cs = ctx.codeSystems?.get(system);
1418
+ if (cs === void 0) return void 0;
1419
+ if (system === component.system && component.version !== void 0 && cs.version !== component.version) {
1420
+ return void 0;
1421
+ }
1422
+ return cs;
1423
+ }
1424
+ function screenActive(members, component, ctx) {
1425
+ const kept = /* @__PURE__ */ new Map();
1426
+ let uncheckable = false;
1427
+ for (const [key, member] of members) {
1428
+ const cs = usableRelease(component, member.system, ctx);
1429
+ if (cs === void 0) {
1430
+ uncheckable = true;
1431
+ continue;
1432
+ }
1433
+ const concept = cs.concepts.get(member.code);
1434
+ if (concept?.status !== void 0 && !concept.status.active) continue;
1435
+ kept.set(key, member);
1436
+ }
1437
+ return { members: kept, uncheckable };
1438
+ }
1324
1439
  function underPath(d, prefix) {
1325
1440
  const out = { code: d.code, detail: d.detail };
1326
1441
  out.path = d.path === void 0 ? prefix : `${prefix}/${d.path}`;
@@ -1358,7 +1473,7 @@ function expandReferencedValueSets(urls, ctx, visited, path) {
1358
1473
  }
1359
1474
  return { members: acc ?? /* @__PURE__ */ new Map(), complete, diagnostics };
1360
1475
  }
1361
- function expandComponent(component, ctx, visited, path) {
1476
+ function expandComponent(component, ctx, visited, path, activeOnly = false) {
1362
1477
  const diagnostics = [];
1363
1478
  let complete = true;
1364
1479
  const { system, version, concept, filter, valueSet: valueSet2 } = component;
@@ -1368,9 +1483,18 @@ function expandComponent(component, ctx, visited, path) {
1368
1483
  let base = null;
1369
1484
  if (hasConcept) {
1370
1485
  base = /* @__PURE__ */ new Map();
1486
+ const release = usableRelease(component, system, ctx);
1487
+ let anyUndefined = false;
1371
1488
  for (const c of concept) {
1372
- base.set(codingKey(system, c.code), makeCoding(system, c.code, c.display, version));
1489
+ const defined = release?.concepts.get(c.code);
1490
+ if (release !== void 0 && defined === void 0) {
1491
+ anyUndefined = true;
1492
+ continue;
1493
+ }
1494
+ const display = c.display ?? defined?.display;
1495
+ base.set(codingKey(system, c.code), makeCoding(system, c.code, display, version));
1373
1496
  }
1497
+ if (anyUndefined) diagnostics.push(enumeratedUndefined(ENUMERATED_UNDEFINED_DETAIL, path));
1374
1498
  } else if (hasFilter || system !== void 0 && !hasVs) {
1375
1499
  if (system === void 0) {
1376
1500
  diagnostics.push(cannotExpand("intensional filter without a code system 'system'", path));
@@ -1381,6 +1505,27 @@ function expandComponent(component, ctx, visited, path) {
1381
1505
  diagnostics.push(cannotExpand("code system not supplied for intensional include", path));
1382
1506
  return { members: /* @__PURE__ */ new Map(), complete: false, diagnostics };
1383
1507
  }
1508
+ let stampedVersion = version;
1509
+ if (version !== void 0 && cs.version !== version) {
1510
+ if (cs.version === void 0) {
1511
+ diagnostics.push(
1512
+ cannotExpand(
1513
+ "supplied code system declares no version, so the component's declared version is unconfirmed",
1514
+ path
1515
+ )
1516
+ );
1517
+ complete = false;
1518
+ stampedVersion = void 0;
1519
+ } else {
1520
+ diagnostics.push(
1521
+ cannotExpand(
1522
+ "supplied code system version disagrees with the component's declared version",
1523
+ path
1524
+ )
1525
+ );
1526
+ return { members: /* @__PURE__ */ new Map(), complete: false, diagnostics };
1527
+ }
1528
+ }
1384
1529
  if (hasFilter) {
1385
1530
  const unsupported = unsupportedOps(filter);
1386
1531
  if (unsupported.length > 0) {
@@ -1393,7 +1538,7 @@ function expandComponent(component, ctx, visited, path) {
1393
1538
  if (matchesAllFilters(concpt, filter, sub).matched) {
1394
1539
  base.set(
1395
1540
  codingKey(system, concpt.code),
1396
- makeCoding(system, concpt.code, concpt.display, version)
1541
+ makeCoding(system, concpt.code, concpt.display, stampedVersion)
1397
1542
  );
1398
1543
  }
1399
1544
  }
@@ -1402,7 +1547,7 @@ function expandComponent(component, ctx, visited, path) {
1402
1547
  for (const concpt of cs.concepts.values()) {
1403
1548
  base.set(
1404
1549
  codingKey(system, concpt.code),
1405
- makeCoding(system, concpt.code, concpt.display, version)
1550
+ makeCoding(system, concpt.code, concpt.display, stampedVersion)
1406
1551
  );
1407
1552
  }
1408
1553
  }
@@ -1416,7 +1561,14 @@ function expandComponent(component, ctx, visited, path) {
1416
1561
  for (const [k, c] of [...base]) if (c.system !== system) base.delete(k);
1417
1562
  }
1418
1563
  }
1419
- return { members: base ?? /* @__PURE__ */ new Map(), complete, diagnostics };
1564
+ const members = base ?? /* @__PURE__ */ new Map();
1565
+ if (!activeOnly) return { members, complete, diagnostics };
1566
+ const screened = screenActive(members, component, ctx);
1567
+ if (screened.uncheckable) {
1568
+ diagnostics.push(cannotExpand(ACTIVITY_UNCHECKABLE_DETAIL, path));
1569
+ complete = false;
1570
+ }
1571
+ return { members: screened.members, complete, diagnostics };
1420
1572
  }
1421
1573
  function expandInternal(vs, ctx, visited) {
1422
1574
  if (vs.expansion !== void 0) {
@@ -1432,9 +1584,7 @@ function expandInternal(vs, ctx, visited) {
1432
1584
  let complete = true;
1433
1585
  if (vs.expansion.truncated) {
1434
1586
  complete = false;
1435
- diagnostics.push(
1436
- truncated("pre-computed expansion is incomplete (truncated or too-costly)", "expansion")
1437
- );
1587
+ diagnostics.push(truncated(expansionIncompleteDetail(vs.expansion.unclosed), "expansion"));
1438
1588
  }
1439
1589
  const out = {
1440
1590
  complete,
@@ -1448,8 +1598,9 @@ function expandInternal(vs, ctx, visited) {
1448
1598
  const included = /* @__PURE__ */ new Map();
1449
1599
  const diagnostics = [];
1450
1600
  let complete = true;
1601
+ const activeOnly = vs.compose.inactive === false;
1451
1602
  for (const [i, inc] of vs.compose.include.entries()) {
1452
- const r = expandComponent(inc, ctx, visited, `compose.include[${String(i)}]`);
1603
+ const r = expandComponent(inc, ctx, visited, `compose.include[${String(i)}]`, activeOnly);
1453
1604
  if (!r.complete) complete = false;
1454
1605
  for (const d of r.diagnostics) diagnostics.push(d);
1455
1606
  for (const [k, c] of r.members) if (!included.has(k)) included.set(k, c);
@@ -1487,14 +1638,27 @@ function cannotExpand2(detail, path) {
1487
1638
  if (path !== void 0) d.path = path;
1488
1639
  return Object.freeze(d);
1489
1640
  }
1641
+ function expansionIncompleteDetail2(unclosed) {
1642
+ return unclosed ? "pre-computed expansion is incomplete (marked unclosed: the value set is unbounded, so the snapshot is a sample of its membership)" : "pre-computed expansion is incomplete (truncated or too-costly)";
1643
+ }
1644
+ var ACTIVITY_UNCHECKABLE_DETAIL2 = "active-only value set: no usable code system release to check whether a selected code is active";
1645
+ function usableRelease2(component, system, ctx) {
1646
+ if (system === void 0) return void 0;
1647
+ const cs = ctx.codeSystems?.get(system);
1648
+ if (cs === void 0) return void 0;
1649
+ if (system === component.system && component.version !== void 0 && cs.version !== component.version) {
1650
+ return void 0;
1651
+ }
1652
+ return cs;
1653
+ }
1490
1654
  function underPath2(d, prefix) {
1491
1655
  const out = { code: d.code, detail: d.detail };
1492
1656
  out.path = d.path === void 0 ? prefix : `${prefix}/${d.path}`;
1493
1657
  return Object.freeze(out);
1494
1658
  }
1495
- function matchComponent(target, component, ctx, visited, path) {
1659
+ function matchComponent(target, component, ctx, visited, path, activeOnly = false) {
1496
1660
  const diagnostics = [];
1497
- const { system, concept, filter, valueSet: valueSet2 } = component;
1661
+ const { system, version, concept, filter, valueSet: valueSet2 } = component;
1498
1662
  const hasConcept = concept !== void 0;
1499
1663
  const hasFilter = filter !== void 0 && filter.length > 0;
1500
1664
  const hasVs = valueSet2 !== void 0 && valueSet2.length > 0;
@@ -1503,7 +1667,8 @@ function matchComponent(target, component, ctx, visited, path) {
1503
1667
  if (system !== void 0 && target.system !== void 0 && system !== target.system) {
1504
1668
  baseMatched = false;
1505
1669
  } else if (hasConcept) {
1506
- baseMatched = concept.some((c) => c.code === target.code);
1670
+ const release = usableRelease2(component, system, ctx);
1671
+ baseMatched = concept.some((c) => c.code === target.code) && (release === void 0 || release.concepts.get(target.code) !== void 0);
1507
1672
  } else if (hasFilter || system !== void 0 && !hasVs) {
1508
1673
  if (system === void 0) {
1509
1674
  diagnostics.push(cannotExpand2("intensional filter without a code system 'system'", path));
@@ -1515,6 +1680,24 @@ function matchComponent(target, component, ctx, visited, path) {
1515
1680
  diagnostics.push(cannotExpand2("code system not supplied for intensional include", path));
1516
1681
  baseMatched = false;
1517
1682
  baseComplete = false;
1683
+ } else if (version !== void 0 && cs.version !== version) {
1684
+ if (cs.version === void 0) {
1685
+ diagnostics.push(
1686
+ cannotExpand2(
1687
+ "supplied code system declares no version, so the component's declared version is unconfirmed",
1688
+ path
1689
+ )
1690
+ );
1691
+ } else {
1692
+ diagnostics.push(
1693
+ cannotExpand2(
1694
+ "supplied code system version disagrees with the component's declared version",
1695
+ path
1696
+ )
1697
+ );
1698
+ }
1699
+ baseMatched = false;
1700
+ baseComplete = false;
1518
1701
  } else if (hasFilter) {
1519
1702
  if (unsupportedOps(filter).length > 0) {
1520
1703
  diagnostics.push(cannotExpand2("unsupported filter operator", path));
@@ -1529,6 +1712,7 @@ function matchComponent(target, component, ctx, visited, path) {
1529
1712
  }
1530
1713
  }
1531
1714
  }
1715
+ if (system !== void 0 && target.system === void 0 && baseComplete) baseMatched = false;
1532
1716
  let refDefiniteFalse = false;
1533
1717
  let refUndetermined = false;
1534
1718
  if (hasVs) {
@@ -1561,6 +1745,17 @@ function matchComponent(target, component, ctx, visited, path) {
1561
1745
  return { matched: false, complete: true, diagnostics };
1562
1746
  }
1563
1747
  if (baseDefiniteTrue && refDefiniteTrue) {
1748
+ if (activeOnly) {
1749
+ const cs = usableRelease2(component, target.system, ctx);
1750
+ if (cs === void 0) {
1751
+ diagnostics.push(cannotExpand2(ACTIVITY_UNCHECKABLE_DETAIL2, path));
1752
+ return { matched: false, complete: false, diagnostics };
1753
+ }
1754
+ const concept2 = cs.concepts.get(target.code);
1755
+ if (concept2?.status !== void 0 && !concept2.status.active) {
1756
+ return { matched: false, complete: true, diagnostics };
1757
+ }
1758
+ }
1564
1759
  return { matched: true, complete: true, diagnostics };
1565
1760
  }
1566
1761
  return { matched: false, complete: false, diagnostics };
@@ -1584,7 +1779,7 @@ function validateInternal(target, vs, ctx, visited) {
1584
1779
  if (found) return decided(true, target);
1585
1780
  if (vs.expansion.truncated) {
1586
1781
  return undetermined(target, [
1587
- cannotExpand2("pre-computed expansion is incomplete (truncated or too-costly)", "expansion")
1782
+ cannotExpand2(expansionIncompleteDetail2(vs.expansion.unclosed), "expansion")
1588
1783
  ]);
1589
1784
  }
1590
1785
  return decided(false, target);
@@ -1593,8 +1788,16 @@ function validateInternal(target, vs, ctx, visited) {
1593
1788
  const diagnostics = [];
1594
1789
  let includedDefinite = false;
1595
1790
  let anyIncludeUndetermined = false;
1791
+ const activeOnly = vs.compose.inactive === false;
1596
1792
  for (const [i, inc] of vs.compose.include.entries()) {
1597
- const m = matchComponent(target, inc, ctx, visited, `compose.include[${String(i)}]`);
1793
+ const m = matchComponent(
1794
+ target,
1795
+ inc,
1796
+ ctx,
1797
+ visited,
1798
+ `compose.include[${String(i)}]`,
1799
+ activeOnly
1800
+ );
1598
1801
  for (const d of m.diagnostics) diagnostics.push(d);
1599
1802
  if (m.complete && m.matched) includedDefinite = true;
1600
1803
  if (!m.complete) anyIncludeUndetermined = true;
@@ -4774,7 +4977,7 @@ function approximateMatch(graph, query, options = {}) {
4774
4977
  }
4775
4978
 
4776
4979
  // src/index.ts
4777
- var VERSION = "0.0.13";
4980
+ var VERSION = "0.1.0";
4778
4981
 
4779
4982
  export { COMPLEX_MAP_SOURCE_SYSTEM, DIAGNOSTIC_CODES, FATAL_CODES, HL7_V2_OID_ROOT, HL7_V2_URL_PREFIX, ICD10CM_ORDER_FILE_FIELDS, ICD10CM_SYSTEM, ICD9CM_SYSTEM, MAP_CATEGORIES, NO_MAP_CATEGORIES, RELA, RELA_INVERSE, RXNORM_SYSTEM, SNOMEDCT_SYSTEM, SYSTEM_IDENTITIES, TERM_TYPES, TerminologyError, VERSION, applyComplexMap, applyGem, approximateMatch, asTermType, brandsFor, buildSubsumption, codeableConcept, coding, consistsOf, defaultStatusMapper, doseFormsOf, expand, genericFor, getArray, getBoolean, getConcept, getNumber, getString, ingredientsOf, invertGem, isA, isJsonObject, isSynonymTermType, isUnknownSystem, loadCodeSystem, loadComplexMap, loadConceptMap, loadGems, loadRxNormGraph, loadUcumEssence, loadValueSet, lookup, makeStatus, matchesFilter, parseCsv, parseCsvSource, parseFhirCodeSystem, parseFixedWidth, parseRrf, parseRrfLine, parseUcum, reduce, relatedByRela, resolveNdc, resolveSystem, sliceField, translate, ucumEqual, unsupportedOps, validateCode, validateCodeInValueSet, validateUcum };
4780
4983
  //# sourceMappingURL=index.mjs.map