@cosyte/terminology 0.0.7 → 0.0.8

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.d.cts CHANGED
@@ -963,8 +963,8 @@ interface LoadWarning {
963
963
  }
964
964
  /**
965
965
  * A loaded, immutable code-system release — the queryable model {@link loadCodeSystem} produces and
966
- * {@link lookup} / {@link validateCode} run over. Concepts are keyed by code for O(1) identity; the
967
- * map is exposed `readonly` and every concept is frozen.
966
+ * {@link lookup} / {@link validateCode} run over. Concepts are keyed by code for O(1) identity, and
967
+ * every concept is frozen.
968
968
  */
969
969
  interface CodeSystem {
970
970
  /** The code system's canonical URI, when supplied by the source. */
@@ -975,7 +975,14 @@ interface CodeSystem {
975
975
  readonly name?: string;
976
976
  /** The number of loaded concepts. */
977
977
  readonly count: number;
978
- /** The concepts, keyed by `code`. Read-only; every value frozen. */
978
+ /**
979
+ * The concepts, keyed by `code`. A **read-only view**, not a `Map` you were handed: reads and
980
+ * iteration behave as a `Map`'s do, adding / deleting / clearing is refused however it is
981
+ * attempted, and every value is frozen.
982
+ *
983
+ * A view is not a `Map` instance — `instanceof Map` is `false` and this model cannot be
984
+ * `structuredClone`d or posted to a worker; copy out what you need (`new Map(…)`).
985
+ */
979
986
  readonly concepts: ReadonlyMap<string, Concept>;
980
987
  /** The skipped-row warnings surfaced during load, in line order. Frozen; may be empty. */
981
988
  readonly warnings: readonly LoadWarning[];
@@ -2382,6 +2389,13 @@ interface GemEntry {
2382
2389
  /**
2383
2390
  * A loaded, immutable GEM map. Entries are keyed by source code (a source may have many entries — the
2384
2391
  * maps are 1:many). Applied **only** in its {@link direction}; never inverted.
2392
+ *
2393
+ * {@link entries} is a **read-only view**, not a `Map` you were handed, and each source's candidate
2394
+ * list is frozen: nothing that holds a loaded map can delete a source's mapping, or add a target the
2395
+ * steward's file never authored, and have {@link applyGem} answer from it.
2396
+ *
2397
+ * A view is not a `Map` instance — `instanceof Map` is `false` and this model cannot be
2398
+ * `structuredClone`d or posted to a worker; copy out what you need (`new Map(…)`).
2385
2399
  */
2386
2400
  interface GemMap {
2387
2401
  /** Which direction this file maps. Applied only this way. */
@@ -2390,7 +2404,7 @@ interface GemMap {
2390
2404
  readonly version?: string;
2391
2405
  /** The number of loaded entries. */
2392
2406
  readonly count: number;
2393
- /** Entries keyed by source code, each list in file order. Read-only; frozen. */
2407
+ /** Entries keyed by source code, each list in file order. Each list frozen. */
2394
2408
  readonly entries: ReadonlyMap<string, readonly GemEntry[]>;
2395
2409
  /** The skipped-row warnings surfaced during load, in line order. Frozen; may be empty. */
2396
2410
  readonly warnings: readonly GemLoadWarning[];
@@ -2481,6 +2495,13 @@ interface ComplexMapEntry {
2481
2495
  /**
2482
2496
  * A loaded, immutable SNOMED→ICD-10-CM complex map. Entries are keyed by source concept id; within a
2483
2497
  * source they are ordered by (group, priority). Applied **only** SNOMED→ICD-10-CM; never inverted.
2498
+ *
2499
+ * {@link entries} is a **read-only view**, not a `Map` you were handed, and each source's rule list
2500
+ * is frozen: nothing that holds a loaded map can delete a source concept's rules, or add one your
2501
+ * refset never carried, and have {@link applyComplexMap} resolve from it.
2502
+ *
2503
+ * A view is not a `Map` instance — `instanceof Map` is `false` and this model cannot be
2504
+ * `structuredClone`d or posted to a worker; copy out what you need (`new Map(…)`).
2484
2505
  */
2485
2506
  interface ComplexMap {
2486
2507
  /** The map version/release, when supplied — mappings are release-scoped. */
@@ -3057,16 +3078,25 @@ interface RxNormLoadWarning {
3057
3078
  }
3058
3079
  /**
3059
3080
  * A loaded, immutable RxNorm drug graph: concepts keyed by `RXCUI`, edges indexed by subject, and the
3060
- * NDC→RXCUI attribute index — all frozen. Applied only in the authored edge direction; never inverted.
3081
+ * NDC→RXCUI attribute index. Applied only in the authored edge direction; never inverted.
3082
+ *
3083
+ * Its three indexes are **read-only views**, not `Map`s you were handed: reads and iteration behave
3084
+ * as a `Map`'s do, and adding / deleting / clearing is refused however it is attempted. What that
3085
+ * buys is the never-fabricate invariant surviving the handover — nothing that holds a loaded graph
3086
+ * can empty a medication's ingredient edges, or add an edge or concept the release never authored,
3087
+ * and leave {@link conceptCount} / {@link edgeCount} still reporting the loaded figures.
3088
+ *
3089
+ * A view is not a `Map` instance — `instanceof Map` is `false` and this model cannot be
3090
+ * `structuredClone`d or posted to a worker; copy out what you need (`new Map(…)`).
3061
3091
  */
3062
3092
  interface RxNormGraph {
3063
3093
  /** The release version (e.g. `"RXNORM_2026AA"`), when supplied — mappings are release-scoped. */
3064
3094
  readonly version?: string;
3065
- /** Concepts keyed by `RXCUI` (first `SAB=RXNORM` atom per `RXCUI` wins). Frozen. */
3095
+ /** Concepts keyed by `RXCUI` (first `SAB=RXNORM` atom per `RXCUI` wins). Each frozen. */
3066
3096
  readonly concepts: ReadonlyMap<string, RxNormConcept>;
3067
- /** Directed edges indexed by `subject` `RXCUI`, each list in file order. Frozen. */
3097
+ /** Directed edges indexed by `subject` `RXCUI`, each list in file order. Each list frozen. */
3068
3098
  readonly edges: ReadonlyMap<string, readonly RxNormEdge[]>;
3069
- /** NDC → { rxcui, status } index from `RXNSAT` `ATN=NDC` attributes. Frozen; may be empty. */
3099
+ /** NDC → { rxcui, status } index from `RXNSAT` `ATN=NDC` attributes. Each frozen; may be empty. */
3070
3100
  readonly ndcs: ReadonlyMap<string, {
3071
3101
  readonly rxcui: string;
3072
3102
  readonly status: NdcStatus;
package/dist/index.d.ts CHANGED
@@ -963,8 +963,8 @@ interface LoadWarning {
963
963
  }
964
964
  /**
965
965
  * A loaded, immutable code-system release — the queryable model {@link loadCodeSystem} produces and
966
- * {@link lookup} / {@link validateCode} run over. Concepts are keyed by code for O(1) identity; the
967
- * map is exposed `readonly` and every concept is frozen.
966
+ * {@link lookup} / {@link validateCode} run over. Concepts are keyed by code for O(1) identity, and
967
+ * every concept is frozen.
968
968
  */
969
969
  interface CodeSystem {
970
970
  /** The code system's canonical URI, when supplied by the source. */
@@ -975,7 +975,14 @@ interface CodeSystem {
975
975
  readonly name?: string;
976
976
  /** The number of loaded concepts. */
977
977
  readonly count: number;
978
- /** The concepts, keyed by `code`. Read-only; every value frozen. */
978
+ /**
979
+ * The concepts, keyed by `code`. A **read-only view**, not a `Map` you were handed: reads and
980
+ * iteration behave as a `Map`'s do, adding / deleting / clearing is refused however it is
981
+ * attempted, and every value is frozen.
982
+ *
983
+ * A view is not a `Map` instance — `instanceof Map` is `false` and this model cannot be
984
+ * `structuredClone`d or posted to a worker; copy out what you need (`new Map(…)`).
985
+ */
979
986
  readonly concepts: ReadonlyMap<string, Concept>;
980
987
  /** The skipped-row warnings surfaced during load, in line order. Frozen; may be empty. */
981
988
  readonly warnings: readonly LoadWarning[];
@@ -2382,6 +2389,13 @@ interface GemEntry {
2382
2389
  /**
2383
2390
  * A loaded, immutable GEM map. Entries are keyed by source code (a source may have many entries — the
2384
2391
  * maps are 1:many). Applied **only** in its {@link direction}; never inverted.
2392
+ *
2393
+ * {@link entries} is a **read-only view**, not a `Map` you were handed, and each source's candidate
2394
+ * list is frozen: nothing that holds a loaded map can delete a source's mapping, or add a target the
2395
+ * steward's file never authored, and have {@link applyGem} answer from it.
2396
+ *
2397
+ * A view is not a `Map` instance — `instanceof Map` is `false` and this model cannot be
2398
+ * `structuredClone`d or posted to a worker; copy out what you need (`new Map(…)`).
2385
2399
  */
2386
2400
  interface GemMap {
2387
2401
  /** Which direction this file maps. Applied only this way. */
@@ -2390,7 +2404,7 @@ interface GemMap {
2390
2404
  readonly version?: string;
2391
2405
  /** The number of loaded entries. */
2392
2406
  readonly count: number;
2393
- /** Entries keyed by source code, each list in file order. Read-only; frozen. */
2407
+ /** Entries keyed by source code, each list in file order. Each list frozen. */
2394
2408
  readonly entries: ReadonlyMap<string, readonly GemEntry[]>;
2395
2409
  /** The skipped-row warnings surfaced during load, in line order. Frozen; may be empty. */
2396
2410
  readonly warnings: readonly GemLoadWarning[];
@@ -2481,6 +2495,13 @@ interface ComplexMapEntry {
2481
2495
  /**
2482
2496
  * A loaded, immutable SNOMED→ICD-10-CM complex map. Entries are keyed by source concept id; within a
2483
2497
  * source they are ordered by (group, priority). Applied **only** SNOMED→ICD-10-CM; never inverted.
2498
+ *
2499
+ * {@link entries} is a **read-only view**, not a `Map` you were handed, and each source's rule list
2500
+ * is frozen: nothing that holds a loaded map can delete a source concept's rules, or add one your
2501
+ * refset never carried, and have {@link applyComplexMap} resolve from it.
2502
+ *
2503
+ * A view is not a `Map` instance — `instanceof Map` is `false` and this model cannot be
2504
+ * `structuredClone`d or posted to a worker; copy out what you need (`new Map(…)`).
2484
2505
  */
2485
2506
  interface ComplexMap {
2486
2507
  /** The map version/release, when supplied — mappings are release-scoped. */
@@ -3057,16 +3078,25 @@ interface RxNormLoadWarning {
3057
3078
  }
3058
3079
  /**
3059
3080
  * A loaded, immutable RxNorm drug graph: concepts keyed by `RXCUI`, edges indexed by subject, and the
3060
- * NDC→RXCUI attribute index — all frozen. Applied only in the authored edge direction; never inverted.
3081
+ * NDC→RXCUI attribute index. Applied only in the authored edge direction; never inverted.
3082
+ *
3083
+ * Its three indexes are **read-only views**, not `Map`s you were handed: reads and iteration behave
3084
+ * as a `Map`'s do, and adding / deleting / clearing is refused however it is attempted. What that
3085
+ * buys is the never-fabricate invariant surviving the handover — nothing that holds a loaded graph
3086
+ * can empty a medication's ingredient edges, or add an edge or concept the release never authored,
3087
+ * and leave {@link conceptCount} / {@link edgeCount} still reporting the loaded figures.
3088
+ *
3089
+ * A view is not a `Map` instance — `instanceof Map` is `false` and this model cannot be
3090
+ * `structuredClone`d or posted to a worker; copy out what you need (`new Map(…)`).
3061
3091
  */
3062
3092
  interface RxNormGraph {
3063
3093
  /** The release version (e.g. `"RXNORM_2026AA"`), when supplied — mappings are release-scoped. */
3064
3094
  readonly version?: string;
3065
- /** Concepts keyed by `RXCUI` (first `SAB=RXNORM` atom per `RXCUI` wins). Frozen. */
3095
+ /** Concepts keyed by `RXCUI` (first `SAB=RXNORM` atom per `RXCUI` wins). Each frozen. */
3066
3096
  readonly concepts: ReadonlyMap<string, RxNormConcept>;
3067
- /** Directed edges indexed by `subject` `RXCUI`, each list in file order. Frozen. */
3097
+ /** Directed edges indexed by `subject` `RXCUI`, each list in file order. Each list frozen. */
3068
3098
  readonly edges: ReadonlyMap<string, readonly RxNormEdge[]>;
3069
- /** NDC → { rxcui, status } index from `RXNSAT` `ATN=NDC` attributes. Frozen; may be empty. */
3099
+ /** NDC → { rxcui, status } index from `RXNSAT` `ATN=NDC` attributes. Each frozen; may be empty. */
3070
3100
  readonly ndcs: ReadonlyMap<string, {
3071
3101
  readonly rxcui: string;
3072
3102
  readonly status: NdcStatus;
package/dist/index.mjs CHANGED
@@ -565,6 +565,31 @@ function translate(sourceCoding, map) {
565
565
  );
566
566
  }
567
567
 
568
+ // src/common/frozen-map.ts
569
+ function frozenMap(source, what) {
570
+ const refuse = () => {
571
+ throw new TypeError(`Cannot mutate ${what} (it is immutable)`);
572
+ };
573
+ const view = {
574
+ get size() {
575
+ return source.size;
576
+ },
577
+ get: (key) => source.get(key),
578
+ has: (key) => source.has(key),
579
+ keys: () => source.keys(),
580
+ values: () => source.values(),
581
+ entries: () => source.entries(),
582
+ forEach: (callback, thisArg) => {
583
+ for (const [key, value] of source) callback.call(thisArg, value, key, view);
584
+ },
585
+ [Symbol.iterator]: () => source[Symbol.iterator](),
586
+ set: refuse,
587
+ delete: refuse,
588
+ clear: refuse
589
+ };
590
+ return Object.freeze(view);
591
+ }
592
+
568
593
  // src/codesystem/status.ts
569
594
  var defaultStatusMapper = (raw) => {
570
595
  switch (raw.trim().toUpperCase()) {
@@ -971,15 +996,6 @@ function parseRrf(source) {
971
996
  }
972
997
 
973
998
  // src/codesystem/load.ts
974
- function sealConceptMap(map) {
975
- const guard = () => {
976
- throw new TypeError("Cannot mutate a loaded CodeSystem's concepts map (it is immutable)");
977
- };
978
- for (const method of ["set", "delete", "clear"]) {
979
- Object.defineProperty(map, method, { value: guard, writable: false, configurable: false });
980
- }
981
- return map;
982
- }
983
999
  function loadCodeSystem(source) {
984
1000
  let concepts;
985
1001
  let warnings;
@@ -1017,7 +1033,7 @@ function loadCodeSystem(source) {
1017
1033
  }
1018
1034
  }
1019
1035
  out.count = concepts.size;
1020
- out.concepts = sealConceptMap(concepts);
1036
+ out.concepts = frozenMap(concepts, "a loaded CodeSystem's concepts map");
1021
1037
  out.warnings = Object.freeze(warnings);
1022
1038
  return Object.freeze(out);
1023
1039
  }
@@ -4067,21 +4083,25 @@ function loadGems(source) {
4067
4083
  if (trimmed === "") continue;
4068
4084
  const fields = trimmed.split(/\s+/);
4069
4085
  if (fields.length !== 3) {
4070
- warnings.push({
4071
- code: "TERM_GEM_MALFORMED_ROW",
4072
- line: i + 1,
4073
- detail: `expected 3 whitespace-delimited fields, found ${String(fields.length)}`
4074
- });
4086
+ warnings.push(
4087
+ Object.freeze({
4088
+ code: "TERM_GEM_MALFORMED_ROW",
4089
+ line: i + 1,
4090
+ detail: `expected 3 whitespace-delimited fields, found ${String(fields.length)}`
4091
+ })
4092
+ );
4075
4093
  continue;
4076
4094
  }
4077
4095
  const [src, tgt, flagStr] = fields;
4078
4096
  const flags = decodeFlags(flagStr);
4079
4097
  if (flags === void 0) {
4080
- warnings.push({
4081
- code: "TERM_GEM_MALFORMED_ROW",
4082
- line: i + 1,
4083
- detail: "flag field is not a 5-digit code"
4084
- });
4098
+ warnings.push(
4099
+ Object.freeze({
4100
+ code: "TERM_GEM_MALFORMED_ROW",
4101
+ line: i + 1,
4102
+ detail: "flag field is not a 5-digit code"
4103
+ })
4104
+ );
4085
4105
  continue;
4086
4106
  }
4087
4107
  const entry = { source: src, flags };
@@ -4092,11 +4112,12 @@ function loadGems(source) {
4092
4112
  else entries.set(src, [frozen]);
4093
4113
  count++;
4094
4114
  }
4115
+ for (const list of entries.values()) Object.freeze(list);
4095
4116
  return Object.freeze({
4096
4117
  direction: source.direction,
4097
4118
  ...source.version !== void 0 ? { version: source.version } : {},
4098
4119
  count,
4099
- entries,
4120
+ entries: frozenMap(entries, "a loaded GEM map's entries"),
4100
4121
  warnings: Object.freeze(warnings)
4101
4122
  });
4102
4123
  }
@@ -4244,11 +4265,13 @@ function parseRf2(content) {
4244
4265
  const groupN = Number(at(f, iGroup));
4245
4266
  const priorityN = Number(at(f, iPriority));
4246
4267
  if (source === "" || !Number.isFinite(groupN) || !Number.isFinite(priorityN)) {
4247
- warnings.push({
4248
- code: "TERM_COMPLEX_MAP_MALFORMED_ROW",
4249
- line: i + 1,
4250
- detail: "row is missing referencedComponentId / mapGroup / mapPriority"
4251
- });
4268
+ warnings.push(
4269
+ Object.freeze({
4270
+ code: "TERM_COMPLEX_MAP_MALFORMED_ROW",
4271
+ line: i + 1,
4272
+ detail: "row is missing referencedComponentId / mapGroup / mapPriority"
4273
+ })
4274
+ );
4252
4275
  continue;
4253
4276
  }
4254
4277
  rows.push({
@@ -4291,7 +4314,7 @@ function loadComplexMap(input) {
4291
4314
  }
4292
4315
  const out = {
4293
4316
  count,
4294
- entries,
4317
+ entries: frozenMap(entries, "a loaded complex map's entries"),
4295
4318
  warnings
4296
4319
  };
4297
4320
  if (input.version !== void 0) out.version = input.version;
@@ -4585,9 +4608,9 @@ function loadRxNormGraph(source) {
4585
4608
  const ndcs = source.sat !== void 0 ? parseNdcs(source.sat, warnings) : /* @__PURE__ */ new Map();
4586
4609
  for (const list of edges.values()) Object.freeze(list);
4587
4610
  const out = {
4588
- concepts,
4589
- edges,
4590
- ndcs,
4611
+ concepts: frozenMap(concepts, "a loaded RxNorm graph's concepts"),
4612
+ edges: frozenMap(edges, "a loaded RxNorm graph's edges"),
4613
+ ndcs: frozenMap(ndcs, "a loaded RxNorm graph's NDC index"),
4591
4614
  conceptCount: concepts.size,
4592
4615
  edgeCount,
4593
4616
  warnings: Object.freeze(warnings)
@@ -4751,7 +4774,7 @@ function approximateMatch(graph, query, options = {}) {
4751
4774
  }
4752
4775
 
4753
4776
  // src/index.ts
4754
- var VERSION = "0.0.7";
4777
+ var VERSION = "0.0.8";
4755
4778
 
4756
4779
  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 };
4757
4780
  //# sourceMappingURL=index.mjs.map