fhirsmith 0.3.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.
Files changed (277) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/FHIRsmith.png +0 -0
  3. package/README.md +277 -0
  4. package/config-template.json +144 -0
  5. package/library/folder-setup.js +58 -0
  6. package/library/html-server.js +166 -0
  7. package/library/html.js +835 -0
  8. package/library/i18nsupport.js +259 -0
  9. package/library/languages.js +779 -0
  10. package/library/logger-telnet.js +205 -0
  11. package/library/logger.js +279 -0
  12. package/library/package-manager.js +876 -0
  13. package/library/utilities.js +196 -0
  14. package/library/version-utilities.js +1056 -0
  15. package/npmprojector/config-example.json +13 -0
  16. package/npmprojector/indexer.js +394 -0
  17. package/npmprojector/npmprojector.js +395 -0
  18. package/npmprojector/readme.md +174 -0
  19. package/npmprojector/watcher.js +335 -0
  20. package/package.json +119 -0
  21. package/packages/package-crawler.js +846 -0
  22. package/packages/packages-template.html +126 -0
  23. package/packages/packages.js +2838 -0
  24. package/passwords.ini +2 -0
  25. package/publisher/publisher-template.html +208 -0
  26. package/publisher/publisher.js +2167 -0
  27. package/publisher/task-draft.js +458 -0
  28. package/registry/api.js +735 -0
  29. package/registry/crawler.js +637 -0
  30. package/registry/model.js +513 -0
  31. package/registry/readme.md +243 -0
  32. package/registry/registry-data.json +121015 -0
  33. package/registry/registry-template.html +126 -0
  34. package/registry/registry.js +1395 -0
  35. package/registry/test-runner.js +237 -0
  36. package/root-template.html +124 -0
  37. package/server.js +524 -0
  38. package/shl/private-key.pem +5 -0
  39. package/shl/public-key.pem +18 -0
  40. package/shl/shl.js +1125 -0
  41. package/shl/vhl.js +69 -0
  42. package/static/FHIRsmith128.png +0 -0
  43. package/static/FHIRsmith16.png +0 -0
  44. package/static/FHIRsmith32.png +0 -0
  45. package/static/FHIRsmith64.png +0 -0
  46. package/static/assets/css/bootstrap-fhir.css +5302 -0
  47. package/static/assets/css/bootstrap-glyphicons.css +2 -0
  48. package/static/assets/css/bootstrap.css +4097 -0
  49. package/static/assets/css/jquery-ui.css +523 -0
  50. package/static/assets/css/jquery-ui.structure.css +863 -0
  51. package/static/assets/css/jquery-ui.structure.min.css +5 -0
  52. package/static/assets/css/jquery-ui.theme.css +439 -0
  53. package/static/assets/css/jquery-ui.theme.min.css +5 -0
  54. package/static/assets/css/jquery.ui.all.css +7 -0
  55. package/static/assets/css/modules.css +18 -0
  56. package/static/assets/css/project.css +367 -0
  57. package/static/assets/css/pygments-manni.css +66 -0
  58. package/static/assets/css/tags.css +74 -0
  59. package/static/assets/css/xml.css +2 -0
  60. package/static/assets/fonts/glyphiconshalflings-regular.eot +0 -0
  61. package/static/assets/fonts/glyphiconshalflings-regular.otf +0 -0
  62. package/static/assets/fonts/glyphiconshalflings-regular.svg +175 -0
  63. package/static/assets/fonts/glyphiconshalflings-regular.ttf +0 -0
  64. package/static/assets/fonts/glyphiconshalflings-regular.woff +0 -0
  65. package/static/assets/ico/apple-touch-icon-114-precomposed.png +0 -0
  66. package/static/assets/ico/apple-touch-icon-144-precomposed.png +0 -0
  67. package/static/assets/ico/apple-touch-icon-57-precomposed.png +0 -0
  68. package/static/assets/ico/apple-touch-icon-72-precomposed.png +0 -0
  69. package/static/assets/ico/favicon.ico +0 -0
  70. package/static/assets/ico/favicon.png +0 -0
  71. package/static/assets/images/fhir-logo-www.png +0 -0
  72. package/static/assets/images/fhir-logo.png +0 -0
  73. package/static/assets/images/hl7-logo.png +0 -0
  74. package/static/assets/images/logo_ansinew.jpg +0 -0
  75. package/static/assets/images/search.png +0 -0
  76. package/static/assets/images/stripe.png +0 -0
  77. package/static/assets/images/target.png +0 -0
  78. package/static/assets/images/tx-registry-root.gif +0 -0
  79. package/static/assets/images/tx-registry.png +0 -0
  80. package/static/assets/images/tx-server.png +0 -0
  81. package/static/assets/images/tx-version.png +0 -0
  82. package/static/assets/js/bootstrap.min.js +6 -0
  83. package/static/assets/js/fhir-gw.js +259 -0
  84. package/static/assets/js/fhir.js +2 -0
  85. package/static/assets/js/html5shiv.js +8 -0
  86. package/static/assets/js/jcookie.js +96 -0
  87. package/static/assets/js/jquery-ui.min.js +6 -0
  88. package/static/assets/js/jquery.js +10716 -0
  89. package/static/assets/js/jquery.min.js +2 -0
  90. package/static/assets/js/jquery.ui.core.js +314 -0
  91. package/static/assets/js/jquery.ui.draggable.js +825 -0
  92. package/static/assets/js/jquery.ui.mouse.js +162 -0
  93. package/static/assets/js/jquery.ui.resizable.js +842 -0
  94. package/static/assets/js/jquery.ui.widget.js +268 -0
  95. package/static/assets/js/json2.js +487 -0
  96. package/static/assets/js/jtip.js +97 -0
  97. package/static/assets/js/respond.min.js +6 -0
  98. package/static/assets/js/statuspage.js +70 -0
  99. package/static/assets/js/xml.js +2 -0
  100. package/static/dist/js/bootstrap.js +1964 -0
  101. package/static/favicon.png +0 -0
  102. package/static/fhir.css +626 -0
  103. package/static/icon-fhir-16.png +0 -0
  104. package/static/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  105. package/static/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  106. package/static/images/ui-bg_flat_10_000000_40x100.png +0 -0
  107. package/static/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  108. package/static/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  109. package/static/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  110. package/static/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  111. package/static/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  112. package/static/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  113. package/static/images/ui-icons_222222_256x240.png +0 -0
  114. package/static/images/ui-icons_228ef1_256x240.png +0 -0
  115. package/static/images/ui-icons_ef8c08_256x240.png +0 -0
  116. package/static/images/ui-icons_ffd27a_256x240.png +0 -0
  117. package/static/images/ui-icons_ffffff_256x240.png +0 -0
  118. package/static/js/jquery.effects.blind.js +49 -0
  119. package/static/js/jquery.effects.bounce.js +78 -0
  120. package/static/js/jquery.effects.clip.js +54 -0
  121. package/static/js/jquery.effects.core.js +763 -0
  122. package/static/js/jquery.effects.drop.js +50 -0
  123. package/static/js/jquery.effects.explode.js +79 -0
  124. package/static/js/jquery.effects.fade.js +32 -0
  125. package/static/js/jquery.effects.fold.js +56 -0
  126. package/static/js/jquery.effects.highlight.js +50 -0
  127. package/static/js/jquery.effects.pulsate.js +51 -0
  128. package/static/js/jquery.effects.scale.js +178 -0
  129. package/static/js/jquery.effects.shake.js +57 -0
  130. package/static/js/jquery.effects.slide.js +50 -0
  131. package/static/js/jquery.effects.transfer.js +45 -0
  132. package/static/js/jquery.ui.accordion.js +611 -0
  133. package/static/js/jquery.ui.autocomplete.js +612 -0
  134. package/static/js/jquery.ui.button.js +416 -0
  135. package/static/js/jquery.ui.datepicker.js +1823 -0
  136. package/static/js/jquery.ui.dialog.js +878 -0
  137. package/static/js/jquery.ui.droppable.js +296 -0
  138. package/static/js/jquery.ui.position.js +252 -0
  139. package/static/js/jquery.ui.progressbar.js +109 -0
  140. package/static/js/jquery.ui.selectable.js +266 -0
  141. package/static/js/jquery.ui.slider.js +666 -0
  142. package/static/js/jquery.ui.sortable.js +1077 -0
  143. package/static/js/jquery.ui.tabs.js +758 -0
  144. package/stats.js +80 -0
  145. package/test-cache/vsac/vsac-valuesets.db +0 -0
  146. package/token/nginx_passport_setup.md +383 -0
  147. package/token/security_guide.md +294 -0
  148. package/token/token-template.html +330 -0
  149. package/token/token.js +1300 -0
  150. package/translations/Messages.properties +1510 -0
  151. package/translations/Messages_ar.properties +1399 -0
  152. package/translations/Messages_de.properties +836 -0
  153. package/translations/Messages_es.properties +737 -0
  154. package/translations/Messages_fr.properties +1 -0
  155. package/translations/Messages_ja.properties +893 -0
  156. package/translations/Messages_nl.properties +1357 -0
  157. package/translations/Messages_pt.properties +1302 -0
  158. package/translations/Messages_ru.properties +1 -0
  159. package/translations/Messages_uz.properties +1 -0
  160. package/translations/Messages_zh.properties +1 -0
  161. package/translations/rendering-phrases.properties +1128 -0
  162. package/translations/rendering-phrases_ar.properties +1091 -0
  163. package/translations/rendering-phrases_de.properties +6 -0
  164. package/translations/rendering-phrases_es.properties +6 -0
  165. package/translations/rendering-phrases_fr.properties +624 -0
  166. package/translations/rendering-phrases_ja.properties +21 -0
  167. package/translations/rendering-phrases_nl.properties +970 -0
  168. package/translations/rendering-phrases_pt.properties +1020 -0
  169. package/translations/rendering-phrases_ru.properties +1094 -0
  170. package/translations/rendering-phrases_uz.properties +1 -0
  171. package/translations/rendering-phrases_zh.properties +1 -0
  172. package/tx/README.md +418 -0
  173. package/tx/cm/cm-api.js +110 -0
  174. package/tx/cm/cm-database.js +735 -0
  175. package/tx/cm/cm-package.js +325 -0
  176. package/tx/cs/cs-api.js +789 -0
  177. package/tx/cs/cs-areacode.js +615 -0
  178. package/tx/cs/cs-country.js +1110 -0
  179. package/tx/cs/cs-cpt.js +785 -0
  180. package/tx/cs/cs-cs.js +1579 -0
  181. package/tx/cs/cs-currency.js +539 -0
  182. package/tx/cs/cs-db.js +1321 -0
  183. package/tx/cs/cs-hgvs.js +329 -0
  184. package/tx/cs/cs-lang.js +465 -0
  185. package/tx/cs/cs-loinc.js +1485 -0
  186. package/tx/cs/cs-mimetypes.js +238 -0
  187. package/tx/cs/cs-ndc.js +704 -0
  188. package/tx/cs/cs-omop.js +1025 -0
  189. package/tx/cs/cs-provider-api.js +43 -0
  190. package/tx/cs/cs-provider-list.js +37 -0
  191. package/tx/cs/cs-rxnorm.js +808 -0
  192. package/tx/cs/cs-snomed.js +1102 -0
  193. package/tx/cs/cs-ucum.js +514 -0
  194. package/tx/cs/cs-unii.js +271 -0
  195. package/tx/cs/cs-uri.js +218 -0
  196. package/tx/cs/cs-usstates.js +305 -0
  197. package/tx/dev.fhir.org.yml +14 -0
  198. package/tx/fixtures/test-cases-setup.json +18 -0
  199. package/tx/fixtures/test-cases.yml +16 -0
  200. package/tx/html/codesystem-operations.liquid +25 -0
  201. package/tx/html/home-metrics.liquid +247 -0
  202. package/tx/html/operations-form.liquid +148 -0
  203. package/tx/html/search-form.liquid +62 -0
  204. package/tx/html/tx-template.html +133 -0
  205. package/tx/html/valueset-operations.liquid +54 -0
  206. package/tx/importers/atc-to-fhir.js +316 -0
  207. package/tx/importers/import-loinc.module.js +1536 -0
  208. package/tx/importers/import-ndc.module.js +1088 -0
  209. package/tx/importers/import-rxnorm.module.js +898 -0
  210. package/tx/importers/import-sct.module.js +2457 -0
  211. package/tx/importers/import-unii.module.js +601 -0
  212. package/tx/importers/readme.md +453 -0
  213. package/tx/importers/subset-loinc.module.js +1081 -0
  214. package/tx/importers/subset-rxnorm.module.js +938 -0
  215. package/tx/importers/tx-import-base.js +351 -0
  216. package/tx/importers/tx-import-settings.js +310 -0
  217. package/tx/importers/tx-import.js +357 -0
  218. package/tx/library/canonical-resource.js +88 -0
  219. package/tx/library/capabilitystatement.js +292 -0
  220. package/tx/library/codesystem.js +774 -0
  221. package/tx/library/conceptmap.js +568 -0
  222. package/tx/library/designations.js +932 -0
  223. package/tx/library/errors.js +77 -0
  224. package/tx/library/extensions.js +117 -0
  225. package/tx/library/namingsystem.js +322 -0
  226. package/tx/library/operation-outcome.js +127 -0
  227. package/tx/library/parameters.js +105 -0
  228. package/tx/library/renderer.js +1559 -0
  229. package/tx/library/terminologycapabilities.js +418 -0
  230. package/tx/library/ucum-parsers.js +1029 -0
  231. package/tx/library/ucum-service.js +370 -0
  232. package/tx/library/ucum-types.js +1099 -0
  233. package/tx/library/valueset.js +543 -0
  234. package/tx/library.js +676 -0
  235. package/tx/ocl/cm-ocl.js +106 -0
  236. package/tx/ocl/cs-ocl.js +39 -0
  237. package/tx/ocl/vs-ocl.js +105 -0
  238. package/tx/operation-context.js +568 -0
  239. package/tx/params.js +613 -0
  240. package/tx/provider.js +403 -0
  241. package/tx/sct/ecl.js +1560 -0
  242. package/tx/sct/expressions.js +2077 -0
  243. package/tx/sct/structures.js +1396 -0
  244. package/tx/tx-html.js +1063 -0
  245. package/tx/tx.fhir.org.yml +39 -0
  246. package/tx/tx.js +927 -0
  247. package/tx/vs/vs-api.js +112 -0
  248. package/tx/vs/vs-database.js +786 -0
  249. package/tx/vs/vs-package.js +358 -0
  250. package/tx/vs/vs-vsac.js +366 -0
  251. package/tx/workers/batch-validate.js +129 -0
  252. package/tx/workers/batch.js +361 -0
  253. package/tx/workers/closure.js +32 -0
  254. package/tx/workers/expand.js +1845 -0
  255. package/tx/workers/lookup.js +407 -0
  256. package/tx/workers/metadata.js +467 -0
  257. package/tx/workers/operations.js +34 -0
  258. package/tx/workers/read.js +164 -0
  259. package/tx/workers/search.js +384 -0
  260. package/tx/workers/subsumes.js +334 -0
  261. package/tx/workers/translate.js +492 -0
  262. package/tx/workers/validate.js +2504 -0
  263. package/tx/workers/worker.js +904 -0
  264. package/tx/xml/capabilitystatement-xml.js +63 -0
  265. package/tx/xml/codesystem-xml.js +62 -0
  266. package/tx/xml/conceptmap-xml.js +65 -0
  267. package/tx/xml/namingsystem-xml.js +65 -0
  268. package/tx/xml/operationoutcome-xml.js +127 -0
  269. package/tx/xml/parameters-xml.js +312 -0
  270. package/tx/xml/terminologycapabilities-xml.js +64 -0
  271. package/tx/xml/valueset-xml.js +64 -0
  272. package/tx/xml/xml-base.js +603 -0
  273. package/vcl/vcl-parser.js +1098 -0
  274. package/vcl/vcl.js +253 -0
  275. package/windows-install.js +19 -0
  276. package/xig/xig-template.html +124 -0
  277. package/xig/xig.js +3049 -0
@@ -0,0 +1,1099 @@
1
+ /**
2
+ * UCUM Types - Core data structures and types for UCUM library
3
+ * BSD 3-Clause License
4
+ * Copyright (c) 2006+, Health Intersections Pty Ltd
5
+ */
6
+
7
+ class Decimal {
8
+ constructor(value, precision = null) {
9
+ this.precision = 0;
10
+ this.scientific = false;
11
+ this.negative = false;
12
+ this.digits = '';
13
+ this.decimal = 0;
14
+
15
+ if (typeof value === 'number') {
16
+ this._setValueDecimal(value.toString());
17
+ } else if (typeof value === 'string') {
18
+ const lowerValue = value.toLowerCase();
19
+ if (lowerValue.includes('e')) {
20
+ this._setValueScientific(lowerValue);
21
+ } else {
22
+ this._setValueDecimal(lowerValue);
23
+ }
24
+ if (precision !== null) {
25
+ this.precision = precision;
26
+ }
27
+ } else if (typeof value === 'undefined' || value === null) {
28
+ // Default constructor for internal use
29
+ } else {
30
+ throw new UcumException(`Invalid decimal value: ${value}`);
31
+ }
32
+ }
33
+
34
+ _setValueDecimal(value) {
35
+ this.scientific = false;
36
+ let dec = -1;
37
+ this.negative = value.startsWith('-');
38
+ if (this.negative) {
39
+ value = value.substring(1);
40
+ }
41
+
42
+ // Remove leading zeros
43
+ while (value.startsWith('0') && value.length > 1) {
44
+ value = value.substring(1);
45
+ }
46
+
47
+ // Find decimal point and validate
48
+ for (let i = 0; i < value.length; i++) {
49
+ if (value.charAt(i) === '.' && dec === -1) {
50
+ dec = i;
51
+ } else if (!/\d/.test(value.charAt(i))) {
52
+ throw new UcumException(`'${value}' is not a valid decimal`);
53
+ }
54
+ }
55
+
56
+ if (dec === -1) {
57
+ this.precision = value.length;
58
+ this.decimal = value.length;
59
+ this.digits = value;
60
+ } else if (dec === value.length - 1) {
61
+ throw new UcumException(`'${value}' is not a valid decimal`);
62
+ } else {
63
+ this.decimal = dec;
64
+ if (this._allZeros(value, 1)) {
65
+ this.precision = value.length - 1;
66
+ } else {
67
+ this.precision = this._countSignificants(value);
68
+ }
69
+ this.digits = this._delete(value, this.decimal, 1);
70
+ if (this._allZeros(this.digits, 0)) {
71
+ this.precision++;
72
+ } else {
73
+ while (this.digits.charAt(0) === '0') {
74
+ this.digits = this.digits.substring(1);
75
+ this.decimal--;
76
+ }
77
+ }
78
+ }
79
+ }
80
+
81
+ _setValueScientific(value) {
82
+ const eIndex = value.indexOf('e');
83
+ const s = value.substring(0, eIndex);
84
+ let e = value.substring(eIndex + 1);
85
+ if (e.startsWith('+')) {
86
+ e = e.substring(1);
87
+ }
88
+
89
+ if (!s || s === '-' || !this._isDecimal(s)) {
90
+ throw new UcumException(`'${value}' is not a valid decimal (numeric)`);
91
+ }
92
+ if (!e || e === '-' || !this._isInteger(e)) {
93
+ throw new UcumException(`'${value}' is not a valid decimal (exponent)`);
94
+ }
95
+
96
+ this._setValueDecimal(s);
97
+ this.scientific = true;
98
+
99
+ // Adjust for exponent
100
+ const exponent = parseInt(e);
101
+ this.decimal = this.decimal + exponent;
102
+ }
103
+
104
+ _allZeros(s, start) {
105
+ for (let i = start; i < s.length; i++) {
106
+ if (s.charAt(i) !== '0') {
107
+ return false;
108
+ }
109
+ }
110
+ return true;
111
+ }
112
+
113
+ _countSignificants(value) {
114
+ const i = value.indexOf('.');
115
+ if (i > -1) {
116
+ value = this._delete(value, i, 1);
117
+ }
118
+ while (value.charAt(0) === '0') {
119
+ value = value.substring(1);
120
+ }
121
+ return value.length;
122
+ }
123
+
124
+ _delete(value, offset, length) {
125
+ if (offset === 0) {
126
+ return value.substring(length);
127
+ } else {
128
+ return value.substring(0, offset) + value.substring(offset + length);
129
+ }
130
+ }
131
+
132
+ _isDecimal(s) {
133
+ const decimal = /^-?\d*\.?\d+$/;
134
+ return decimal.test(s);
135
+ }
136
+
137
+ _isInteger(s) {
138
+ const integer = /^-?\d+$/;
139
+ return integer.test(s);
140
+ }
141
+
142
+ _stringMultiply(c, count) {
143
+ return c.repeat(Math.max(0, count));
144
+ }
145
+
146
+ _trimLeadingZeros(s) {
147
+ if (s === null || s === undefined) {
148
+ return null;
149
+ }
150
+
151
+ let i = 0;
152
+ while (i < s.length && s.charAt(i) === '0') {
153
+ i++;
154
+ }
155
+ if (i === s.length) {
156
+ return "0";
157
+ } else {
158
+ return s.substring(i);
159
+ }
160
+ }
161
+
162
+ _stringAddition(s1, s2) {
163
+ if (s1.length !== s2.length) {
164
+ throw new Error("String lengths must be equal for addition");
165
+ }
166
+
167
+ const result = new Array(s2.length);
168
+ for (let i = 0; i < s2.length; i++) {
169
+ result[i] = '0';
170
+ }
171
+
172
+ let c = 0;
173
+ for (let i = s1.length - 1; i >= 0; i--) {
174
+ const t = c + this._dig(s1.charAt(i)) + this._dig(s2.charAt(i));
175
+ result[i] = this._cdig(t % 10);
176
+ c = Math.floor(t / 10);
177
+ }
178
+
179
+ // For the tens array calculation, we expect no final carry
180
+ if (c !== 0) {
181
+ // This could happen during tens array setup - just prepend the carry
182
+ return this._cdig(c) + result.join('');
183
+ }
184
+
185
+ return result.join('');
186
+ }
187
+
188
+ _stringSubtraction(s1, s2) {
189
+ if (s1.length !== s2.length) {
190
+ throw new Error("String lengths must be equal for subtraction");
191
+ }
192
+
193
+ const result = new Array(s2.length);
194
+ for (let i = 0; i < s2.length; i++) {
195
+ result[i] = '0';
196
+ }
197
+
198
+ let s1Array = s1.split('');
199
+
200
+ for (let i = s1.length - 1; i >= 0; i--) {
201
+ let t = this._dig(s1Array[i]) - this._dig(s2.charAt(i));
202
+ if (t < 0) {
203
+ t = t + 10;
204
+ if (i === 0) {
205
+ throw new Error("internal logic error");
206
+ } else {
207
+ s1Array[i - 1] = this._cdig(this._dig(s1Array[i - 1]) - 1);
208
+ }
209
+ }
210
+ result[i] = this._cdig(t);
211
+ }
212
+
213
+ return result.join('');
214
+ }
215
+
216
+ _insert(ins, value, offset) {
217
+ if (offset === 0) {
218
+ return ins + value;
219
+ } else {
220
+ return value.substring(0, offset) + ins + value.substring(offset);
221
+ }
222
+ }
223
+
224
+ _dig(c) {
225
+ return c.charCodeAt(0) - '0'.charCodeAt(0);
226
+ }
227
+
228
+ _cdig(i) {
229
+ return String.fromCharCode(i + '0'.charCodeAt(0));
230
+ }
231
+
232
+ toString() {
233
+ return this.asDecimal();
234
+ }
235
+
236
+ copy() {
237
+ const result = new Decimal();
238
+ result.precision = this.precision;
239
+ result.scientific = this.scientific;
240
+ result.negative = this.negative;
241
+ result.digits = this.digits;
242
+ result.decimal = this.decimal;
243
+ return result;
244
+ }
245
+
246
+ static zero() {
247
+ return new Decimal('0');
248
+ }
249
+
250
+ isZero() {
251
+ return this._allZeros(this.digits, 0);
252
+ }
253
+
254
+ static one() {
255
+ return new Decimal('1');
256
+ }
257
+
258
+ isOne() {
259
+ const one = Decimal.one();
260
+ return this.comparesTo(one) === 0;
261
+ }
262
+
263
+ equals(other) {
264
+ const o = Utilities._ensureDecimal(other);
265
+ return this.asDecimal() === o.asDecimal();
266
+ }
267
+
268
+ comparesTo(other) {
269
+ if (other === null || other === undefined) {
270
+ return 0;
271
+ }
272
+
273
+ if (this.negative && !other.negative) {
274
+ return -1;
275
+ } else if (!this.negative && other.negative) {
276
+ return 1;
277
+ } else {
278
+ const max = Math.max(this.decimal, other.decimal);
279
+ let s1 = this._stringMultiply('0', max - this.decimal + 1) + this.digits;
280
+ let s2 = this._stringMultiply('0', max - other.decimal + 1) + other.digits;
281
+
282
+ if (s1.length < s2.length) {
283
+ s1 = s1 + this._stringMultiply('0', s2.length - s1.length);
284
+ } else if (s2.length < s1.length) {
285
+ s2 = s2 + this._stringMultiply('0', s1.length - s2.length);
286
+ }
287
+
288
+ let result = s1.localeCompare(s2);
289
+ if (this.negative) {
290
+ result = -result;
291
+ }
292
+ return result;
293
+ }
294
+ }
295
+
296
+ isWholeNumber() {
297
+ return !this.asDecimal().includes('.');
298
+ }
299
+
300
+ asDecimal() {
301
+ let result = this.digits;
302
+ if (this.decimal !== this.digits.length) {
303
+ if (this.decimal < 0) {
304
+ result = '0.' + this._stringMultiply('0', 0 - this.decimal) + this.digits;
305
+ } else if (this.decimal < result.length) {
306
+ if (this.decimal === 0) {
307
+ result = '0.' + result;
308
+ } else {
309
+ result = this._insert('.', result, this.decimal);
310
+ }
311
+ } else {
312
+ result = result + this._stringMultiply('0', this.decimal - result.length);
313
+ }
314
+ }
315
+ if (this.negative && !this._allZeros(result, 0)) {
316
+ result = '-' + result;
317
+ }
318
+ return result;
319
+ }
320
+
321
+ asInteger() {
322
+ if (!this.isWholeNumber()) {
323
+ throw new UcumException(`Unable to represent ${this.toString()} as an integer`);
324
+ }
325
+ return parseInt(this.asDecimal());
326
+ }
327
+
328
+ multiply(other) {
329
+ if (other === null || other === undefined) {
330
+ return null;
331
+ }
332
+
333
+ if (this.isZero() || other.isZero()) {
334
+ return Decimal.zero();
335
+ }
336
+
337
+ const max = Math.max(this.decimal, other.decimal);
338
+ let s1 = this._stringMultiply('0', max - this.decimal + 1) + this.digits;
339
+ let s2 = this._stringMultiply('0', max - other.decimal + 1) + other.digits;
340
+
341
+ if (s1.length < s2.length) {
342
+ s1 = s1 + this._stringMultiply('0', s2.length - s1.length);
343
+ } else if (s2.length < s1.length) {
344
+ s2 = s2 + this._stringMultiply('0', s1.length - s2.length);
345
+ }
346
+
347
+ if (s2.localeCompare(s1) > 0) {
348
+ const s3 = s1;
349
+ s1 = s2;
350
+ s2 = s3;
351
+ }
352
+
353
+ const s = new Array(s2.length);
354
+
355
+ let t = 0;
356
+ for (let i = s2.length - 1; i >= 0; i--) {
357
+ s[i] = this._stringMultiply('0', s2.length - (i + 1));
358
+ let c = 0;
359
+ for (let j = s1.length - 1; j >= 0; j--) {
360
+ t = c + (this._dig(s1.charAt(j)) * this._dig(s2.charAt(i)));
361
+ s[i] = this._insert(String(this._cdig(t % 10)), s[i], 0);
362
+ c = Math.floor(t / 10);
363
+ }
364
+ while (c > 0) {
365
+ s[i] = this._insert(String(this._cdig(t % 10)), s[i], 0);
366
+ c = Math.floor(t / 10);
367
+ }
368
+ }
369
+
370
+ t = 0;
371
+ for (const sv of s) {
372
+ t = Math.max(t, sv.length);
373
+ }
374
+ for (let i = 0; i < s.length; i++) {
375
+ s[i] = this._stringMultiply('0', t - s[i].length) + s[i];
376
+ }
377
+
378
+ let res = "";
379
+ let c = 0;
380
+ for (let i = t - 1; i >= 0; i--) {
381
+ for (let j = 0; j < s.length; j++) {
382
+ c = c + this._dig(s[j].charAt(i));
383
+ }
384
+ res = this._insert(String(this._cdig(c % 10)), res, 0);
385
+ c = Math.floor(c / 10);
386
+ }
387
+
388
+ if (c > 0) {
389
+ throw new Error("internal logic error");
390
+ }
391
+
392
+ let dec = res.length - ((s1.length - (max + 1)) * 2);
393
+
394
+ while (res && res !== "0" && res.startsWith("0")) {
395
+ res = res.substring(1);
396
+ dec--;
397
+ }
398
+
399
+ let prec = 0;
400
+ if (this.isWholeNumber() && other.isWholeNumber()) {
401
+ // at least the specified precision, and possibly more
402
+ prec = Math.max(
403
+ Math.max(this.digits.length, other.digits.length),
404
+ Math.min(this.precision, other.precision)
405
+ );
406
+ } else if (this.isWholeNumber()) {
407
+ prec = other.precision;
408
+ } else if (other.isWholeNumber()) {
409
+ prec = this.precision;
410
+ } else {
411
+ prec = Math.min(this.precision, other.precision);
412
+ }
413
+
414
+ while (res.length > prec && res.charAt(res.length - 1) === '0') {
415
+ res = this._delete(res, res.length - 1, 1);
416
+ }
417
+
418
+ const result = new Decimal();
419
+ result._setValueDecimal(res);
420
+ result.precision = prec;
421
+ result.decimal = dec;
422
+ result.negative = this.negative !== other.negative;
423
+ result.scientific = this.scientific || other.scientific;
424
+ return result;
425
+ }
426
+
427
+ divide(other) {
428
+ if (other === null || other === undefined) {
429
+ return null;
430
+ }
431
+
432
+ if (this.isZero()) {
433
+ return Decimal.zero();
434
+ }
435
+
436
+ if (other.isZero()) {
437
+ throw new UcumException(`Attempt to divide ${this.toString()} by zero`);
438
+ }
439
+
440
+ const s = "0" + other.digits;
441
+ const m = Math.max(this.digits.length, other.digits.length) + 40; // max loops we'll do
442
+ const tens = new Array(10);
443
+
444
+ // Create multiples of the divisor (1x, 2x, 3x, ... 9x)
445
+ tens[0] = this._stringAddition(this._stringMultiply('0', s.length), s);
446
+ for (let i = 1; i < 10; i++) {
447
+ tens[i] = this._stringAddition(tens[i - 1], s);
448
+ }
449
+
450
+ let v = this.digits;
451
+ let r = "";
452
+ let l = 0;
453
+ let d = (this.digits.length - this.decimal + 1) - (other.digits.length - other.decimal + 1);
454
+
455
+ while (v.length < tens[0].length) {
456
+ v = v + "0";
457
+ d++;
458
+ }
459
+
460
+ let w;
461
+ let vi;
462
+ if (v.substring(0, other.digits.length).localeCompare(other.digits) < 0) {
463
+ if (v.length === tens[0].length) {
464
+ v = v + '0';
465
+ d++;
466
+ }
467
+ w = v.substring(0, other.digits.length + 1);
468
+ vi = w.length;
469
+ } else {
470
+ w = "0" + v.substring(0, other.digits.length);
471
+ vi = w.length - 1;
472
+ }
473
+
474
+ let handled = false;
475
+ let proc;
476
+
477
+ while (!(handled && ((l > m) || ((vi >= v.length) && ((!w || this._allZeros(w, 0))))))) {
478
+ l++;
479
+ handled = true;
480
+ proc = false;
481
+
482
+ for (let i = 8; i >= 0; i--) {
483
+ if (tens[i].localeCompare(w) <= 0) {
484
+ proc = true;
485
+ r = r + this._cdig(i + 1);
486
+ w = this._trimLeadingZeros(this._stringSubtraction(w, tens[i]));
487
+
488
+ if (!(handled && ((l > m) || ((vi >= v.length) && ((!w || this._allZeros(w, 0))))))) {
489
+ if (vi < v.length) {
490
+ w = w + v.charAt(vi);
491
+ vi++;
492
+ handled = false;
493
+ } else {
494
+ w = w + '0';
495
+ d++;
496
+ }
497
+ while (w.length < tens[0].length) {
498
+ w = '0' + w;
499
+ }
500
+ }
501
+ break;
502
+ }
503
+ }
504
+
505
+ if (!proc) {
506
+ if (w.charAt(0) !== '0') {
507
+ throw new Error("Expected leading zero");
508
+ }
509
+ w = this._delete(w, 0, 1);
510
+ r = r + "0";
511
+
512
+ if (!(handled && ((l > m) || ((vi >= v.length) && ((!w || this._allZeros(w, 0))))))) {
513
+ if (vi < v.length) {
514
+ w = w + v.charAt(vi);
515
+ vi++;
516
+ handled = false;
517
+ } else {
518
+ w = w + '0';
519
+ d++;
520
+ }
521
+ while (w.length < tens[0].length) {
522
+ w = '0' + w;
523
+ }
524
+ }
525
+ }
526
+ }
527
+
528
+ let prec;
529
+
530
+ if (this.isWholeNumber() && other.isWholeNumber() && (l < m)) {
531
+ for (let i = 0; i < d; i++) {
532
+ if (r.charAt(r.length - 1) === '0') {
533
+ r = this._delete(r, r.length - 1, 1);
534
+ d--;
535
+ }
536
+ }
537
+ prec = 100;
538
+ } else {
539
+ if (this.isWholeNumber() && other.isWholeNumber()) {
540
+ prec = Math.max(this.digits.length, other.digits.length);
541
+ } else if (this.isWholeNumber()) {
542
+ prec = Math.max(other.precision, r.length - d);
543
+ } else if (other.isWholeNumber()) {
544
+ prec = Math.max(this.precision, r.length - d);
545
+ } else {
546
+ prec = Math.max(Math.min(this.precision, other.precision), r.length - d);
547
+ }
548
+
549
+ if (r.length > prec) {
550
+ d = d - (r.length - prec);
551
+ const dig = r.charAt(prec);
552
+ const up = dig >= '5';
553
+
554
+ if (up) {
555
+ const rs = r.substring(0, prec).split('');
556
+ let i = rs.length - 1;
557
+ let carry = true;
558
+
559
+ while (carry && i >= 0) {
560
+ let ls = rs[i];
561
+ if (ls === '9') {
562
+ rs[i] = '0';
563
+ } else {
564
+ ls = this._cdig(this._dig(ls) + 1);
565
+ rs[i] = ls;
566
+ carry = false;
567
+ }
568
+ i--;
569
+ }
570
+
571
+ if (carry) {
572
+ r = "1" + rs.join('');
573
+ d++; // cause we added one at the start
574
+ } else {
575
+ r = rs.join('');
576
+ }
577
+ } else {
578
+ r = r.substring(0, prec);
579
+ }
580
+ }
581
+ }
582
+
583
+ const result = new Decimal();
584
+ result._setValueDecimal(r);
585
+ result.decimal = r.length - d;
586
+ result.negative = this.negative !== other.negative;
587
+ result.precision = prec;
588
+ result.scientific = this.scientific || other.scientific;
589
+ return result;
590
+ }
591
+
592
+ add(other) {
593
+ if (other === null || other === undefined) {
594
+ return null;
595
+ }
596
+
597
+ // Simplified addition - convert to numbers and create new Decimal
598
+ const thisVal = parseFloat(this.asDecimal());
599
+ const otherVal = parseFloat(other.asDecimal());
600
+ const result = thisVal + otherVal;
601
+
602
+ const newDecimal = new Decimal(result.toString());
603
+ newDecimal.scientific = this.scientific || other.scientific;
604
+
605
+ // Handle precision
606
+ if (this.decimal < other.decimal) {
607
+ newDecimal.precision = this.precision;
608
+ } else if (other.decimal < this.decimal) {
609
+ newDecimal.precision = other.precision;
610
+ } else {
611
+ newDecimal.precision = Math.min(this.precision, other.precision);
612
+ }
613
+
614
+ return newDecimal;
615
+ }
616
+
617
+ subtract(other) {
618
+ if (other === null || other === undefined) {
619
+ return null;
620
+ }
621
+
622
+ // Simplified subtraction - convert to numbers and create new Decimal
623
+ const thisVal = parseFloat(this.asDecimal());
624
+ const otherVal = parseFloat(other.asDecimal());
625
+ const result = thisVal - otherVal;
626
+
627
+ const newDecimal = new Decimal(result.toString());
628
+ newDecimal.scientific = this.scientific || other.scientific;
629
+
630
+ // Handle precision similar to add
631
+ if (this.decimal < other.decimal) {
632
+ newDecimal.precision = this.precision;
633
+ } else if (other.decimal < this.decimal) {
634
+ newDecimal.precision = other.precision;
635
+ } else {
636
+ newDecimal.precision = Math.min(this.precision, other.precision);
637
+ }
638
+
639
+ return newDecimal;
640
+ }
641
+
642
+ checkForCouldBeWholeNumber() {
643
+ // whole numbers are tricky - they have implied infinite precision, but we need to check for digit errors in the last couple of digits
644
+ // it's a whole number if all but the last one or two digits after the decimal place is 9 or 0 and the precision is >17 (arbitrary but enough)
645
+ if (this.precision > 17 && this.digits.length > 3) {
646
+ let i = this.digits.length - 2;
647
+ const ch = this.digits.charAt(i); // second last character
648
+ if (ch === '9') {
649
+ while (i > 0 && this.digits.charAt(i - 1) === '9') {
650
+ i--;
651
+ }
652
+ if (i > 0 && i < this.digits.length - 3) {
653
+ this.digits = this.digits.substring(0, i - 1) + String.fromCharCode(this.digits.charCodeAt(i - 1) + 1);
654
+ this.precision = this.digits.length;
655
+ }
656
+ } else if (ch === '0') {
657
+ while (i > 0 && this.digits.charAt(i - 1) === '0') {
658
+ i--;
659
+ }
660
+ if (i > 0 && i < this.digits.length - 3) {
661
+ this.digits = this.digits.substring(0, i);
662
+ this.precision = this.digits.length;
663
+ }
664
+ }
665
+ }
666
+ }
667
+ }
668
+
669
+ // Enums
670
+ const ConceptKind = {
671
+ PREFIX: 'prefix',
672
+ BASEUNIT: 'base-unit',
673
+ UNIT: 'unit'
674
+ };
675
+
676
+ const Operator = {
677
+ MULTIPLICATION: '*',
678
+ DIVISION: '/'
679
+ };
680
+
681
+ const TokenType = {
682
+ NONE: 'none',
683
+ SOLIDUS: 'solidus',
684
+ PERIOD: 'period',
685
+ OPEN: 'open',
686
+ CLOSE: 'close',
687
+ ANNOTATION: 'annotation',
688
+ NUMBER: 'number',
689
+ SYMBOL: 'symbol'
690
+ };
691
+
692
+ // Exception class
693
+ class UcumException extends Error {
694
+ constructor(message) {
695
+ super(message);
696
+ this.name = 'UcumException';
697
+ }
698
+ }
699
+
700
+ // Utilities class
701
+ class Utilities {
702
+ static isAsciiChar(ch) {
703
+ const code = ch.charCodeAt(0);
704
+ return code >= 0 && code <= 127;
705
+ }
706
+
707
+ static noString(str) {
708
+ return !str || !str.trim();
709
+ }
710
+
711
+ static _ensureDecimal(v) {
712
+ if (v == null) {
713
+ return null; // this is probably an error.
714
+ }
715
+ if (v instanceof Decimal) {
716
+ return v;
717
+ }
718
+ return new Decimal(v);
719
+ }
720
+ }
721
+
722
+ // Base concept class
723
+ class Concept {
724
+ constructor(code, codeUC) {
725
+ this.code = code;
726
+ this.codeUC = codeUC;
727
+ this.names = [];
728
+ this.printSymbol = '';
729
+ }
730
+ }
731
+
732
+ // Unit class (base for BaseUnit and DefinedUnit)
733
+ class Unit extends Concept {
734
+ constructor(code, codeUC) {
735
+ super(code, codeUC);
736
+ this.property = '';
737
+ }
738
+ }
739
+
740
+ // Base unit class
741
+ class BaseUnit extends Unit {
742
+ constructor(code, codeUC) {
743
+ super(code, codeUC);
744
+ this.kind = ConceptKind.BASEUNIT;
745
+ this.dim = '';
746
+ }
747
+ }
748
+
749
+ // Defined unit class
750
+ class DefinedUnit extends Unit {
751
+ constructor(code, codeUC) {
752
+ super(code, codeUC);
753
+ this.kind = ConceptKind.UNIT;
754
+ this.metric = false;
755
+ this.isSpecial = false;
756
+ this.class_ = '';
757
+ this.value = null;
758
+ }
759
+ }
760
+
761
+ // Prefix class
762
+ class Prefix extends Concept {
763
+ constructor(code, codeUC) {
764
+ super(code, codeUC);
765
+ this.kind = ConceptKind.PREFIX;
766
+ this.value = null;
767
+ }
768
+ }
769
+
770
+ // Value class
771
+ class Value {
772
+ constructor(unit, unitUC, value) {
773
+ this.unit = unit || '';
774
+ this.unitUC = unitUC || '';
775
+ this.value = value;
776
+ this.text = '';
777
+ }
778
+ }
779
+
780
+ // Pair class for value/unit combinations
781
+ class Pair {
782
+ constructor(value, code) {
783
+ this.value = value;
784
+ this.code = code;
785
+ }
786
+
787
+ getValue() {
788
+ return this.value;
789
+ }
790
+
791
+ getCode() {
792
+ return this.code;
793
+ }
794
+
795
+ equals(other) {
796
+ if (other instanceof Pair) {
797
+ return this.value.equals(other.value) && this.code === other.code;
798
+ }
799
+ return false;
800
+ }
801
+
802
+ hashCode() {
803
+ return this.toString().length; // Simple hash
804
+ }
805
+
806
+ toString() {
807
+ return `${this.value.toString()} ${this.code}`;
808
+ }
809
+ }
810
+
811
+ // Expression tree components
812
+ class Component {
813
+ // Base class for expression components
814
+ }
815
+
816
+ class Term extends Component {
817
+ constructor() {
818
+ super();
819
+ this.comp = null;
820
+ this.op = null;
821
+ this.term = null;
822
+ }
823
+ }
824
+
825
+ class Symbol extends Component {
826
+ constructor() {
827
+ super();
828
+ this.prefix = null;
829
+ this.unit = null;
830
+ this.exponent = 1;
831
+ }
832
+ }
833
+
834
+ class Factor extends Component {
835
+ constructor(value) {
836
+ super();
837
+ this.value = value;
838
+ }
839
+ }
840
+
841
+ // Expression class
842
+ class Expression {
843
+ constructor() {
844
+ this.term = null;
845
+ }
846
+ }
847
+
848
+ // Canonical unit for canonical form representation
849
+ class CanonicalUnit {
850
+ constructor(base, exponent = 1) {
851
+ this.base = base;
852
+ this.exponent = exponent;
853
+ }
854
+
855
+ getBase() {
856
+ return this.base;
857
+ }
858
+
859
+ getExponent() {
860
+ return this.exponent;
861
+ }
862
+
863
+ setExponent(exponent) {
864
+ this.exponent = exponent;
865
+ }
866
+ }
867
+
868
+ // Canonical form of a unit expression
869
+ class Canonical {
870
+ constructor(value) {
871
+ this.value = value || new Decimal("1.000000000000000000000000000000");
872
+ this.units = [];
873
+ }
874
+
875
+ getValue() {
876
+ return this.value;
877
+ }
878
+
879
+ getUnits() {
880
+ return this.units;
881
+ }
882
+
883
+ multiplyValue(val) {
884
+ const v = Utilities._ensureDecimal(val);
885
+ this.value = this.value.multiply(v);
886
+ }
887
+
888
+ divideValue(val) {
889
+ const v = Utilities._ensureDecimal(val)
890
+ this.value = this.value.divide(v);
891
+ }
892
+ }
893
+
894
+ // Version details class
895
+ class UcumVersionDetails {
896
+ constructor(releaseDate, version) {
897
+ this.releaseDate = releaseDate;
898
+ this.version = version;
899
+ }
900
+
901
+ getReleaseDate() {
902
+ return this.releaseDate;
903
+ }
904
+
905
+ getVersion() {
906
+ return this.version;
907
+ }
908
+ }
909
+
910
+ // Registry for special unit handlers
911
+ class Registry {
912
+ constructor() {
913
+ this.handlers = new Map();
914
+
915
+ this.register(new CelsiusHandler());
916
+ this.register(new FahrenheitHandler());
917
+ this.register(new HoldingHandler("[p'diop]", "deg"));
918
+ this.register(new HoldingHandler("%[slope]", "deg"));
919
+ this.register(new HoldingHandler("[hp_X]", "1"));
920
+ this.register(new HoldingHandler("[hp_C]", "1"));
921
+ this.register(new HoldingHandler("[pH]", "mol/l"));
922
+ this.register(new HoldingHandler("Np", "1"));
923
+ this.register(new HoldingHandler("B", "1"));
924
+ this.register(new HoldingHandler("B[SPL]", "10*-5.Pa", new Decimal(2)));
925
+ this.register(new HoldingHandler("B[V]", "V"));
926
+ this.register(new HoldingHandler("B[mV]", "mV"));
927
+ this.register(new HoldingHandler("B[uV]", "uV"));
928
+ this.register(new HoldingHandler("B[W]", "W"));
929
+ this.register(new HoldingHandler("B[kW]", "kW"));
930
+ this.register(new HoldingHandler("bit_s", "1"))
931
+ }
932
+
933
+ exists(code) {
934
+ return this.handlers.has(code);
935
+ }
936
+
937
+ get(code) {
938
+ return this.handlers.get(code);
939
+ }
940
+
941
+ register(handler) {
942
+ this.handlers.set(handler.code, handler);
943
+ }
944
+ }
945
+
946
+ // Special Unit Handler base class
947
+ class SpecialUnitHandler {
948
+ /**
949
+ * Used to connect this handler with the case sensitive unit
950
+ * @return {string}
951
+ */
952
+ getCode() {
953
+ throw new Error("getCode() must be implemented by subclass");
954
+ }
955
+
956
+ /**
957
+ * the alternate units to convert to
958
+ * @return {string}
959
+ */
960
+ getUnits() {
961
+ throw new Error("getUnits() must be implemented by subclass");
962
+ }
963
+
964
+ /**
965
+ * get the conversion value
966
+ * @return {Decimal}
967
+ */
968
+ getValue() {
969
+ throw new Error("getValue() must be implemented by subclass");
970
+ }
971
+
972
+ /**
973
+ * return true if the conversion offset value != 0
974
+ * @return {boolean}
975
+ */
976
+ hasOffset() {
977
+ throw new Error("hasOffset() must be implemented by subclass");
978
+ }
979
+
980
+ /**
981
+ * get the conversion offset value
982
+ * @return {Decimal}
983
+ * @throws {UcumException}
984
+ */
985
+ getOffset() {
986
+ throw new Error("getOffset() must be implemented by subclass");
987
+ }
988
+ }
989
+
990
+ // Celsius Handler
991
+ class CelsiusHandler extends SpecialUnitHandler {
992
+ getCode() {
993
+ return "Cel";
994
+ }
995
+
996
+ getUnits() {
997
+ return "K";
998
+ }
999
+
1000
+ getValue() {
1001
+ return Decimal.one();
1002
+ }
1003
+
1004
+ getOffset() {
1005
+ return new Decimal("-273.15", 24);
1006
+ }
1007
+
1008
+ hasOffset() {
1009
+ return true;
1010
+ }
1011
+ }
1012
+
1013
+ // Fahrenheit Handler
1014
+ class FahrenheitHandler extends SpecialUnitHandler {
1015
+ getCode() {
1016
+ return "[degF]";
1017
+ }
1018
+
1019
+ getUnits() {
1020
+ return "K";
1021
+ }
1022
+
1023
+ getValue() {
1024
+ try {
1025
+ return new Decimal("5").divide(new Decimal("9"));
1026
+ } catch (e) {
1027
+ // won't happen
1028
+ return null;
1029
+ }
1030
+ }
1031
+
1032
+ getOffset() {
1033
+ return new Decimal("32", 24);
1034
+ }
1035
+
1036
+ hasOffset() {
1037
+ return true;
1038
+ }
1039
+ }
1040
+
1041
+ // Holding Handler - generic handler for other special units
1042
+ class HoldingHandler extends SpecialUnitHandler {
1043
+ /**
1044
+ * @param {string} code
1045
+ * @param {string} units
1046
+ * @param {Decimal} value (optional, defaults to Decimal.one())
1047
+ */
1048
+ constructor(code, units, value = null) {
1049
+ super();
1050
+ this.code = code;
1051
+ this.units = units;
1052
+ this.value = value || Decimal.one();
1053
+ }
1054
+
1055
+ getCode() {
1056
+ return this.code;
1057
+ }
1058
+
1059
+ getUnits() {
1060
+ return this.units;
1061
+ }
1062
+
1063
+ getValue() {
1064
+ return this.value;
1065
+ }
1066
+
1067
+ getOffset() {
1068
+ return new Decimal("0", 24);
1069
+ }
1070
+
1071
+ hasOffset() {
1072
+ return false;
1073
+ }
1074
+ }
1075
+
1076
+ module.exports = {
1077
+ ConceptKind,
1078
+ Operator,
1079
+ TokenType,
1080
+ UcumException,
1081
+ Decimal,
1082
+ Utilities,
1083
+ Concept,
1084
+ Unit,
1085
+ BaseUnit,
1086
+ DefinedUnit,
1087
+ Prefix,
1088
+ Value,
1089
+ Pair,
1090
+ Component,
1091
+ Term,
1092
+ Symbol,
1093
+ Factor,
1094
+ Expression,
1095
+ Canonical,
1096
+ CanonicalUnit,
1097
+ Registry,
1098
+ UcumVersionDetails
1099
+ };