@sjcrh/proteinpaint-shared 2.186.0 → 2.188.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 (117) hide show
  1. package/README.md +10 -2
  2. package/constants/AiHisto.ts +27 -0
  3. package/constants/README.md +11 -0
  4. package/devTs.ts +3 -0
  5. package/dist/constants/AiHisto.d.ts +23 -0
  6. package/dist/constants/AiHisto.js +31 -0
  7. package/dist/constants/AiHisto.js.map +7 -0
  8. package/dist/src/aiHisto.d.ts +5 -0
  9. package/dist/src/aiHisto.js +15 -0
  10. package/dist/src/aiHisto.js.map +7 -0
  11. package/dist/src/bulk.cnv.js +83 -0
  12. package/dist/src/bulk.cnv.js.map +7 -0
  13. package/dist/src/bulk.del.js +119 -0
  14. package/dist/src/bulk.del.js.map +7 -0
  15. package/dist/src/bulk.itd.js +119 -0
  16. package/dist/src/bulk.itd.js.map +7 -0
  17. package/dist/src/bulk.js +183 -0
  18. package/dist/src/bulk.js.map +7 -0
  19. package/dist/src/bulk.snv.js +175 -0
  20. package/dist/src/bulk.snv.js.map +7 -0
  21. package/dist/src/bulk.sv.js +266 -0
  22. package/dist/src/bulk.sv.js.map +7 -0
  23. package/dist/src/bulk.svjson.js +151 -0
  24. package/dist/src/bulk.svjson.js.map +7 -0
  25. package/dist/src/bulk.trunc.js +122 -0
  26. package/dist/src/bulk.trunc.js.map +7 -0
  27. package/dist/src/clustering.js +71 -0
  28. package/dist/src/clustering.js.map +7 -0
  29. package/dist/src/common.js +1302 -0
  30. package/dist/src/common.js.map +7 -0
  31. package/dist/src/compute.percentile.js +10 -0
  32. package/dist/src/compute.percentile.js.map +7 -0
  33. package/dist/src/doc.d.ts +7 -0
  34. package/dist/src/doc.js +10 -0
  35. package/dist/src/doc.js.map +7 -0
  36. package/dist/src/fetch-helpers.js +177 -0
  37. package/dist/src/fetch-helpers.js.map +7 -0
  38. package/dist/src/fileSize.js +10 -0
  39. package/dist/src/fileSize.js.map +7 -0
  40. package/dist/src/filter.d.ts +62 -0
  41. package/dist/src/filter.js +194 -0
  42. package/dist/src/filter.js.map +7 -0
  43. package/dist/src/hash.js +20 -0
  44. package/dist/src/hash.js.map +7 -0
  45. package/dist/src/helpers.js +66 -0
  46. package/dist/src/helpers.js.map +7 -0
  47. package/dist/src/index.d.ts +26 -0
  48. package/dist/src/index.js +27 -0
  49. package/dist/src/index.js.map +7 -0
  50. package/dist/src/joinUrl.d.ts +1 -0
  51. package/dist/src/joinUrl.js +17 -0
  52. package/dist/src/joinUrl.js.map +7 -0
  53. package/dist/src/mds3tk.js +64 -0
  54. package/dist/src/mds3tk.js.map +7 -0
  55. package/dist/src/roundValue.js +57 -0
  56. package/dist/src/roundValue.js.map +7 -0
  57. package/dist/src/termdb.bins.js +272 -0
  58. package/dist/src/termdb.bins.js.map +7 -0
  59. package/dist/src/termdb.initbinconfig.js +79 -0
  60. package/dist/src/termdb.initbinconfig.js.map +7 -0
  61. package/dist/src/termdb.usecase.js +239 -0
  62. package/dist/src/termdb.usecase.js.map +7 -0
  63. package/dist/src/terms.d.ts +83 -0
  64. package/dist/src/terms.js +327 -0
  65. package/dist/src/terms.js.map +7 -0
  66. package/dist/src/time.d.ts +9 -0
  67. package/dist/src/time.js +23 -0
  68. package/dist/src/time.js.map +7 -0
  69. package/dist/src/tree.js +82 -0
  70. package/dist/src/tree.js.map +7 -0
  71. package/dist/src/urljson.d.ts +8 -0
  72. package/dist/src/urljson.js +31 -0
  73. package/dist/src/urljson.js.map +7 -0
  74. package/dist/src/vcf.ann.js +56 -0
  75. package/dist/src/vcf.ann.js.map +7 -0
  76. package/dist/src/vcf.csq.js +82 -0
  77. package/dist/src/vcf.csq.js.map +7 -0
  78. package/dist/src/vcf.info.js +40 -0
  79. package/dist/src/vcf.info.js.map +7 -0
  80. package/dist/src/vcf.js +439 -0
  81. package/dist/src/vcf.js.map +7 -0
  82. package/dist/src/vcf.type.js +17 -0
  83. package/dist/src/vcf.type.js.map +7 -0
  84. package/package.json +20 -11
  85. package/src/bulk.cnv.js +0 -86
  86. package/src/bulk.del.js +0 -124
  87. package/src/bulk.itd.js +0 -123
  88. package/src/bulk.js +0 -197
  89. package/src/bulk.snv.js +0 -271
  90. package/src/bulk.sv.js +0 -276
  91. package/src/bulk.svjson.js +0 -164
  92. package/src/bulk.trunc.js +0 -132
  93. package/src/clustering.js +0 -66
  94. package/src/common.js +0 -1608
  95. package/src/compute.percentile.js +0 -11
  96. package/src/doc.js +0 -6
  97. package/src/fetch-helpers.js +0 -323
  98. package/src/fileSize.js +0 -6
  99. package/src/filter.js +0 -221
  100. package/src/hash.js +0 -21
  101. package/src/helpers.js +0 -88
  102. package/src/index.js +0 -26
  103. package/src/joinUrl.js +0 -14
  104. package/src/mds3tk.js +0 -100
  105. package/src/roundValue.js +0 -94
  106. package/src/termdb.bins.js +0 -456
  107. package/src/termdb.initbinconfig.js +0 -130
  108. package/src/termdb.usecase.js +0 -317
  109. package/src/terms.js +0 -341
  110. package/src/time.js +0 -22
  111. package/src/tree.js +0 -138
  112. package/src/urljson.js +0 -41
  113. package/src/vcf.ann.js +0 -62
  114. package/src/vcf.csq.js +0 -153
  115. package/src/vcf.info.js +0 -50
  116. package/src/vcf.js +0 -654
  117. package/src/vcf.type.js +0 -24
@@ -0,0 +1,194 @@
1
+ function getFilteredSamples(sampleAnno, filter) {
2
+ setDatasetAnnotations(filter);
3
+ const samples = /* @__PURE__ */ new Set();
4
+ for (const anno of sampleAnno) {
5
+ if (samples.has(anno.sample)) continue;
6
+ const data = anno.s || anno.data;
7
+ if (data && sample_match_termvaluesetting(data, filter)) {
8
+ samples.add(anno.sample);
9
+ }
10
+ }
11
+ return samples;
12
+ }
13
+ function sample_match_termvaluesetting(row, filter, _term = null, sample = null) {
14
+ const lst = filter.type == "tvslst" ? filter.lst : [filter];
15
+ let numberofmatchedterms = 0;
16
+ for (const item of lst) {
17
+ if ("type" in item && item.type == "tvslst") {
18
+ if (sample_match_termvaluesetting(row, item, _term, sample)) {
19
+ numberofmatchedterms++;
20
+ }
21
+ } else {
22
+ const itemCopy = JSON.parse(JSON.stringify(item));
23
+ const t = itemCopy.tvs;
24
+ if (_term && t.term) {
25
+ if (!(_term.name == t.term.name && _term.type == t.term.type)) {
26
+ numberofmatchedterms++;
27
+ continue;
28
+ }
29
+ }
30
+ let samplevalue;
31
+ if (_term && !t.term) {
32
+ if (t.term$type && t.term$type !== _term.type) {
33
+ numberofmatchedterms++;
34
+ continue;
35
+ }
36
+ t.term = _term;
37
+ samplevalue = typeof row === "object" && t.term.id in row ? row[t.term.id] : row;
38
+ } else if (sample && t.term.$id) {
39
+ samplevalue = sample[t.term.$id].value;
40
+ } else {
41
+ samplevalue = t.term.id in row ? row[t.term.id] : row;
42
+ }
43
+ setDatasetAnnotations(itemCopy);
44
+ let thistermmatch;
45
+ if (t.term.type == "categorical") {
46
+ if (samplevalue === void 0) continue;
47
+ thistermmatch = t.valueset.has(samplevalue);
48
+ } else if (t.term.type == "integer" || t.term.type == "float") {
49
+ if (samplevalue === void 0) continue;
50
+ for (const range of t.ranges) {
51
+ if ("value" in range) {
52
+ thistermmatch = samplevalue === range.value;
53
+ if (thistermmatch) break;
54
+ } else if (samplevalue == range.name) {
55
+ thistermmatch = true;
56
+ break;
57
+ } else {
58
+ if (t.term.values) {
59
+ const v = t.term.values[samplevalue.toString()];
60
+ if (v && v.uncomputable) {
61
+ continue;
62
+ }
63
+ }
64
+ let left, right;
65
+ if (range.startunbounded) {
66
+ left = true;
67
+ } else if ("start" in range) {
68
+ if (range.startinclusive) {
69
+ left = samplevalue >= range.start;
70
+ } else {
71
+ left = samplevalue > range.start;
72
+ }
73
+ }
74
+ if (range.stopunbounded) {
75
+ right = true;
76
+ } else if ("stop" in range) {
77
+ if (range.stopinclusive) {
78
+ right = samplevalue <= range.stop;
79
+ } else {
80
+ right = samplevalue < range.stop;
81
+ }
82
+ }
83
+ thistermmatch = left && right;
84
+ }
85
+ if (thistermmatch) break;
86
+ }
87
+ } else if (t.term.type == "condition") {
88
+ const key = getPrecomputedKey(t);
89
+ const anno = samplevalue && samplevalue[key];
90
+ if (anno) {
91
+ thistermmatch = Array.isArray(anno) ? t.values.find((d) => anno.includes(d.key)) : t.values.find((d) => d.key == anno);
92
+ }
93
+ } else if (t.term.type == "geneVariant") {
94
+ const svalues = samplevalue.values || [samplevalue];
95
+ for (const sv of svalues) {
96
+ thistermmatch = t.values.find(
97
+ (v) => v.dt == sv.dt && (!v.origin || sv.origin == v.origin) && (!v.mclasslst || v.mclasslst.includes(sv.class))
98
+ ) && true;
99
+ if (thistermmatch) break;
100
+ }
101
+ } else {
102
+ throw "unknown term type [sample_match_termvaluesetting() shared/utils/src/filter.ts]";
103
+ }
104
+ if (t.isnot) {
105
+ thistermmatch = !thistermmatch;
106
+ }
107
+ if (thistermmatch) numberofmatchedterms++;
108
+ }
109
+ if (filter.join == "or") {
110
+ if (numberofmatchedterms && filter.in) return true;
111
+ if (!numberofmatchedterms && !filter.in) return true;
112
+ }
113
+ }
114
+ if (!("in" in filter)) filter.in = true;
115
+ return filter.in == (numberofmatchedterms == lst.length);
116
+ }
117
+ function setDatasetAnnotations(item, ds = null) {
118
+ if (item.type == "tvslst") {
119
+ for (const subitem of item.lst) {
120
+ setDatasetAnnotations(subitem, ds);
121
+ }
122
+ } else {
123
+ if (ds && typeof ds.setAnnoByTermId == "function") {
124
+ ds.setAnnoByTermId(item.tvs.term.id);
125
+ }
126
+ if (item.tvs.term.type == "categorical") {
127
+ const tvsAny = item.tvs;
128
+ tvsAny.valueset = new Set(tvsAny.values.map((i) => i.key));
129
+ }
130
+ }
131
+ }
132
+ function getPrecomputedKey(q) {
133
+ const precomputedKey = q.bar_by_children && q.value_by_max_grade ? "childrenAtMaxGrade" : q.bar_by_children && q.value_by_most_recent ? "childrenAtMostRecent" : q.bar_by_children && q.value_by_computable_grade ? "children" : q.bar_by_grade && q.value_by_max_grade ? "maxGrade" : q.bar_by_grade && q.value_by_most_recent ? "mostRecentGrades" : q.bar_by_grade && q.value_by_computable_grade ? "computableGrades" : "";
134
+ if (!precomputedKey) throw `unknown condition term bar_by_* and/or value_by_*`;
135
+ return precomputedKey;
136
+ }
137
+ function filterJoin(lst) {
138
+ if (!lst || lst.length == 0) return;
139
+ let f = JSON.parse(JSON.stringify(lst[0]));
140
+ if (lst.length == 1) return f;
141
+ if (f.lst.length < 2) {
142
+ if (f.join !== "") throw 'filter.join must be an empty string "" when filter.lst.length < 2';
143
+ f.join = "and";
144
+ } else if (f.join == "or") {
145
+ f = {
146
+ type: "tvslst",
147
+ join: "and",
148
+ in: true,
149
+ lst: [f]
150
+ };
151
+ } else if (f.join != "and") {
152
+ throw 'filter.join must be either "and" or "or" when .lst length > 1';
153
+ }
154
+ for (let i = 1; i < lst.length; i++) {
155
+ const f2 = JSON.parse(JSON.stringify(lst[i]));
156
+ if (f2.join == "or") f.lst.push(f2);
157
+ else f.lst.push(...f2.lst);
158
+ }
159
+ if (f.lst.length == 1 && f.lst[0].type == "tvs") {
160
+ f.join = "";
161
+ }
162
+ return f;
163
+ }
164
+ function getWrappedTvslst(lst = [], join = "", $id = null) {
165
+ const filter = {
166
+ type: "tvslst",
167
+ in: true,
168
+ join,
169
+ lst
170
+ };
171
+ if ($id !== null) filter.$id = $id;
172
+ return filter;
173
+ }
174
+ function validateTermCollectionTvs(lst1, lst2) {
175
+ if (!Array.isArray(lst1)) throw new Error("numerator not array");
176
+ if (!Array.isArray(lst2)) throw new Error("denominator not array");
177
+ if (lst1.length == 0) throw new Error("numerator empty");
178
+ if (lst2.length == 0) throw new Error("denominator empty");
179
+ if (lst1.length > lst2.length) throw new Error("numerator longer than denominator");
180
+ for (const s of lst1) {
181
+ if (typeof s != "string") throw new Error("one of numerator not string");
182
+ if (!s) throw new Error("empty string in numerator");
183
+ if (!lst2.includes(s)) throw new Error("one of numerator not in denominator");
184
+ }
185
+ }
186
+ export {
187
+ filterJoin,
188
+ getFilteredSamples,
189
+ getWrappedTvslst,
190
+ sample_match_termvaluesetting,
191
+ setDatasetAnnotations,
192
+ validateTermCollectionTvs
193
+ };
194
+ //# sourceMappingURL=filter.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/filter.ts"],
4
+ "sourcesContent": ["import type { Filter, Tvs } from '#types'\n\n/**\n * Sample annotation structure\n */\nexport interface SampleAnnotation {\n\tsample: string | number\n\ts?: Record<string, any>\n\tdata?: Record<string, any>\n}\n\n/**\n * Dataset with annotation functionality\n */\nexport interface Dataset {\n\tsetAnnoByTermId?: (termId: string) => void\n}\n\n/**\n * Filters an array of sample annotations and returns a Set of matching sample names\n * @param sampleAnno Array of sample annotations\n * @param filter Nested filter structure as used in the termdbapp\n * @returns Set of sample names that match the filter\n */\nexport function getFilteredSamples(sampleAnno: SampleAnnotation[], filter: Filter): Set<string | number> {\n\tsetDatasetAnnotations(filter)\n\n\tconst samples = new Set<string | number>()\n\tfor (const anno of sampleAnno) {\n\t\tif (samples.has(anno.sample)) continue\n\t\tconst data = anno.s || anno.data\n\t\tif (data && sample_match_termvaluesetting(data, filter)) {\n\t\t\tsamples.add(anno.sample)\n\t\t}\n\t}\n\treturn samples\n}\n\n/**\n * Given a value from a sample's annotation of a term, return true if a value matches the filter\n * @param row Sample annotation data\n * @param filter Filter structure or single tvs item\n * @param _term Optional term to filter by\n * @param sample Optional sample data\n * @returns True if the sample matches the filter\n */\nexport function sample_match_termvaluesetting(\n\trow: any,\n\tfilter: Filter,\n\t_term: any = null,\n\tsample: any = null\n): boolean {\n\tconst lst = filter.type == 'tvslst' ? filter.lst : [filter]\n\tlet numberofmatchedterms = 0\n\n\t/* for AND, require all terms to match */\n\tfor (const item of lst) {\n\t\tif ('type' in item && item.type == 'tvslst') {\n\t\t\tif (sample_match_termvaluesetting(row, item, _term, sample)) {\n\t\t\t\tnumberofmatchedterms++\n\t\t\t}\n\t\t} else {\n\t\t\tconst itemCopy = JSON.parse(JSON.stringify(item))\n\t\t\tconst t = itemCopy.tvs\n\n\t\t\tif (_term && t.term) {\n\t\t\t\tif (!(_term.name == t.term.name && _term.type == t.term.type)) {\n\t\t\t\t\t// for an filter from \"this.config.legendValueFilter\", if the filter is not for the tw\n\t\t\t\t\t// (not the same type and name), ignore the filter.\n\t\t\t\t\tnumberofmatchedterms++\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet samplevalue\n\t\t\tif (_term && !t.term) {\n\t\t\t\tif (t.term$type && t.term$type !== _term.type) {\n\t\t\t\t\t//when the filter is not for the term being tested, ignore the filter\n\t\t\t\t\tnumberofmatchedterms++\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tt.term = _term\n\t\t\t\tsamplevalue = typeof row === 'object' && t.term.id in row ? row[t.term.id] : row\n\t\t\t} else if (sample && t.term.$id) {\n\t\t\t\tsamplevalue = sample[t.term.$id].value\n\t\t\t} else {\n\t\t\t\tsamplevalue = t.term.id in row ? row[t.term.id] : row\n\t\t\t}\n\t\t\tsetDatasetAnnotations(itemCopy)\n\t\t\tlet thistermmatch\n\n\t\t\tif (t.term.type == 'categorical') {\n\t\t\t\tif (samplevalue === undefined) continue // this sample has no anno for this term, do not count\n\t\t\t\tthistermmatch = t.valueset.has(samplevalue)\n\t\t\t} else if (t.term.type == 'integer' || t.term.type == 'float') {\n\t\t\t\tif (samplevalue === undefined) continue // this sample has no anno for this term, do not count\n\t\t\t\tfor (const range of t.ranges) {\n\t\t\t\t\tif ('value' in range) {\n\t\t\t\t\t\tthistermmatch = samplevalue === range.value\n\t\t\t\t\t\tif (thistermmatch) break\n\t\t\t\t\t} else if (samplevalue == range.name) {\n\t\t\t\t\t\tthistermmatch = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// actual range\n\t\t\t\t\t\tif (t.term.values) {\n\t\t\t\t\t\t\tconst v = t.term.values[samplevalue.toString()]\n\t\t\t\t\t\t\tif (v && v.uncomputable) {\n\t\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlet left, right\n\t\t\t\t\t\tif (range.startunbounded) {\n\t\t\t\t\t\t\tleft = true\n\t\t\t\t\t\t} else if ('start' in range) {\n\t\t\t\t\t\t\tif (range.startinclusive) {\n\t\t\t\t\t\t\t\tleft = samplevalue >= range.start\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tleft = samplevalue > range.start\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (range.stopunbounded) {\n\t\t\t\t\t\t\tright = true\n\t\t\t\t\t\t} else if ('stop' in range) {\n\t\t\t\t\t\t\tif (range.stopinclusive) {\n\t\t\t\t\t\t\t\tright = samplevalue <= range.stop\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tright = samplevalue < range.stop\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthistermmatch = left && right\n\t\t\t\t\t}\n\t\t\t\t\tif (thistermmatch) break\n\t\t\t\t}\n\t\t\t} else if (t.term.type == 'condition') {\n\t\t\t\tconst key = getPrecomputedKey(t)\n\t\t\t\tconst anno = samplevalue && samplevalue[key]\n\t\t\t\tif (anno) {\n\t\t\t\t\tthistermmatch = Array.isArray(anno)\n\t\t\t\t\t\t? t.values.find((d: any) => anno.includes(d.key))\n\t\t\t\t\t\t: t.values.find((d: any) => d.key == anno)\n\t\t\t\t}\n\t\t\t} else if (t.term.type == 'geneVariant') {\n\t\t\t\t/*\n\t\t\t\tsamplevalue.values here can be an array or only one of the entries \n\t\t\t\t[\n\t\t\t\t\t{ dt: 1, class: 'WT', _SAMPLEID_: 21, origin: 'germline' },\n\t\t\t\t\t{ dt: 1, class: 'WT', _SAMPLEID_: 21, origin: 'somatic' },\n\t\t\t\t\t{ dt: 2, class: 'Blank', _SAMPLEID_: 21 },\n\t\t\t\t\t{ dt: 4, class: 'WT', _SAMPLEID_: 21 }\n\t\t\t\t]\n\t\t\t\t*/\n\t\t\t\t/* tvs.values is an array that stores classes (for each available dt) that have/haven't been crossed out by the user at this round of edit-and-apply, e.g.\n [\n {dt: 1, mclassLst: ['WT'], mclassExcludeLst: ['Blank'], origin: 'germline'}\n {dt: 1, mclassLst: ['Blank', 'WT', 'M'], mclassExcludeLst:[], origin:'somatic'},\n {dt: 2, mclassLst: ['Blank', 'WT'], mclassExcludeLst:[]}\n {dt: 4, mclassLst: ['WT', 'CNV_loss'], mclassExcludeLst:[]}\n ]\n */\n\t\t\t\tconst svalues = samplevalue.values || [samplevalue]\n\t\t\t\tfor (const sv of svalues) {\n\t\t\t\t\tthistermmatch =\n\t\t\t\t\t\tt.values.find(\n\t\t\t\t\t\t\t(v: any) =>\n\t\t\t\t\t\t\t\tv.dt == sv.dt &&\n\t\t\t\t\t\t\t\t(!v.origin || sv.origin == v.origin) &&\n\t\t\t\t\t\t\t\t(!v.mclasslst || v.mclasslst.includes(sv.class))\n\t\t\t\t\t\t) && true\n\t\t\t\t\tif (thistermmatch) break\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthrow 'unknown term type [sample_match_termvaluesetting() shared/utils/src/filter.ts]'\n\t\t\t}\n\n\t\t\tif (t.isnot) {\n\t\t\t\tthistermmatch = !thistermmatch\n\t\t\t}\n\t\t\tif (thistermmatch) numberofmatchedterms++\n\t\t}\n\n\t\t// if one tvslst is matched with an \"or\" (Set UNION), then sample is okay\n\t\tif (filter.join == 'or') {\n\t\t\tif (numberofmatchedterms && filter.in) return true\n\t\t\tif (!numberofmatchedterms && !filter.in) return true\n\t\t}\n\t}\n\t// for join=\"and\" (Set intersection)\n\tif (!('in' in filter)) (filter as any).in = true // casting to any avoids tsc err despite it's typed!\n\treturn filter.in == (numberofmatchedterms == lst.length)\n}\n\n/**\n * Recursively processes filter items and sets dataset annotations\n * @param item Filter item to process\n * @param ds Optional dataset with annotation functionality\n */\nexport function setDatasetAnnotations(item: Filter | { type: 'tvs'; tvs: Tvs }, ds: Dataset | null = null): void {\n\tif (item.type == 'tvslst') {\n\t\tfor (const subitem of item.lst) {\n\t\t\tsetDatasetAnnotations(subitem, ds)\n\t\t}\n\t} else {\n\t\tif (ds && typeof ds.setAnnoByTermId == 'function') {\n\t\t\tds.setAnnoByTermId(item.tvs.term.id)\n\t\t}\n\t\tif (item.tvs.term.type == 'categorical') {\n\t\t\tconst tvsAny = item.tvs as any\n\t\t\ttvsAny.valueset = new Set(tvsAny.values.map((i: any) => i.key))\n\t\t}\n\t}\n}\n\n/**\n * Gets the precomputed key for a condition term based on bar_by and value_by settings\n */\nfunction getPrecomputedKey(q: any): string {\n\tconst precomputedKey =\n\t\tq.bar_by_children && q.value_by_max_grade\n\t\t\t? 'childrenAtMaxGrade'\n\t\t\t: q.bar_by_children && q.value_by_most_recent\n\t\t\t? 'childrenAtMostRecent'\n\t\t\t: q.bar_by_children && q.value_by_computable_grade\n\t\t\t? 'children'\n\t\t\t: q.bar_by_grade && q.value_by_max_grade\n\t\t\t? 'maxGrade'\n\t\t\t: q.bar_by_grade && q.value_by_most_recent\n\t\t\t? 'mostRecentGrades'\n\t\t\t: q.bar_by_grade && q.value_by_computable_grade\n\t\t\t? 'computableGrades'\n\t\t\t: ''\n\tif (!precomputedKey) throw `unknown condition term bar_by_* and/or value_by_*`\n\treturn precomputedKey\n}\n\n/**\n * Joins a list of filters into the first filter with \"and\", returns joined filter\n * Used by caller app to join hidden filters into a visible filter\n * @param lst List of filters to join\n * @returns The joined filter\n */\nexport function filterJoin(lst: Filter[]): Filter | undefined {\n\tif (!lst || lst.length == 0) return\n\tlet f = JSON.parse(JSON.stringify(lst[0]))\n\tif (lst.length == 1) return f\n\t// more than 1 item, will join\n\tif (f.lst.length < 2) {\n\t\tif (f.join !== '') throw 'filter.join must be an empty string \"\" when filter.lst.length < 2'\n\t\tf.join = 'and'\n\t} else if (f.join == 'or') {\n\t\t// f is \"or\", wrap it with another root layer of \"and\"\n\t\tf = {\n\t\t\ttype: 'tvslst',\n\t\t\tjoin: 'and',\n\t\t\tin: true,\n\t\t\tlst: [f]\n\t\t}\n\t} else if (f.join != 'and') {\n\t\tthrow 'filter.join must be either \"and\" or \"or\" when .lst length > 1'\n\t}\n\t// now, f.join should be \"and\"\n\t// if the argument lst[0].join == \"and\",\n\t// then the f.in boolean value is reused\n\tfor (let i = 1; i < lst.length; i++) {\n\t\tconst f2 = JSON.parse(JSON.stringify(lst[i]))\n\t\tif (f2.join == 'or') f.lst.push(f2)\n\t\telse f.lst.push(...f2.lst)\n\t}\n\t// if f ends up single-tvs item (from joining single tvs to empty filter), need to set join to '' per filter spec\n\tif (f.lst.length == 1 && f.lst[0].type == 'tvs') {\n\t\tf.join = ''\n\t}\n\treturn f\n}\n\n/**\n * Creates a wrapped tvslst (term value settings list) filter object\n * @param lst List of filter items\n * @param join Join operation (and/or)\n * @param $id Optional filter ID\n * @returns Wrapped filter object\n */\nexport function getWrappedTvslst(lst: Filter['lst'] = [], join: string = '', $id: string | null = null): Filter {\n\tconst filter: Filter = {\n\t\ttype: 'tvslst',\n\t\tin: true,\n\t\tjoin,\n\t\tlst\n\t}\n\tif ($id !== null) filter.$id = $id\n\treturn filter\n}\n\n/**\n * Validates numerator and denominator term collections\n * @param lst1 Numerator list of term ids\n * @param lst2 Denominator list of term ids\n * @throws Error if validation fails\n */\nexport function validateTermCollectionTvs(lst1: any[], lst2: any[]): void {\n\t// lst1/lst2: numerator and denominator. both are lists of term ids\n\tif (!Array.isArray(lst1)) throw new Error('numerator not array')\n\tif (!Array.isArray(lst2)) throw new Error('denominator not array')\n\tif (lst1.length == 0) throw new Error('numerator empty')\n\tif (lst2.length == 0) throw new Error('denominator empty')\n\tif (lst1.length > lst2.length) throw new Error('numerator longer than denominator')\n\tfor (const s of lst1) {\n\t\tif (typeof s != 'string') throw new Error('one of numerator not string')\n\t\tif (!s) throw new Error('empty string in numerator')\n\t\tif (!lst2.includes(s)) throw new Error('one of numerator not in denominator')\n\t}\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,20 @@
1
+ const encoder = new TextEncoder();
2
+ async function hash(message) {
3
+ const msgUint8 = encoder.encode(message);
4
+ const hashBuffer = await crypto.subtle.digest("SHA-1", msgUint8);
5
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
6
+ const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
7
+ return hexToBase64(hashHex).replace("=", "-");
8
+ }
9
+ function hexToBase64(hexStr) {
10
+ return btoa(
11
+ [...hexStr].reduce(
12
+ (acc, _, i) => acc += !(i - 1 & 1) ? String.fromCharCode(parseInt(hexStr.substring(i - 1, i + 1), 16)) : "",
13
+ ""
14
+ )
15
+ );
16
+ }
17
+ export {
18
+ hash
19
+ };
20
+ //# sourceMappingURL=hash.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/hash.js"],
4
+ "sourcesContent": ["const encoder = new TextEncoder()\n\nexport async function hash(message) {\n\tconst msgUint8 = encoder.encode(message) // encode as (utf-8) Uint8Array\n\tconst hashBuffer = await crypto.subtle.digest('SHA-1', msgUint8) // hash the message\n\tconst hashArray = Array.from(new Uint8Array(hashBuffer)) // convert buffer to byte array\n\tconst hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('') // convert bytes to hex string\n\treturn hexToBase64(hashHex).replace('=', '-') // shorten from 40 to 28 chars\n}\n\nfunction hexToBase64(hexStr) {\n\treturn btoa(\n\t\t[...hexStr].reduce(\n\t\t\t(acc, _, i) => (acc += !((i - 1) & 1) ? String.fromCharCode(parseInt(hexStr.substring(i - 1, i + 1), 16)) : ''),\n\t\t\t''\n\t\t)\n\t)\n}\n"],
5
+ "mappings": "AAAA,MAAM,UAAU,IAAI,YAAY;AAEhC,eAAsB,KAAK,SAAS;AACnC,QAAM,WAAW,QAAQ,OAAO,OAAO;AACvC,QAAM,aAAa,MAAM,OAAO,OAAO,OAAO,SAAS,QAAQ;AAC/D,QAAM,YAAY,MAAM,KAAK,IAAI,WAAW,UAAU,CAAC;AACvD,QAAM,UAAU,UAAU,IAAI,OAAK,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE;AAC3E,SAAO,YAAY,OAAO,EAAE,QAAQ,KAAK,GAAG;AAC7C;AAEA,SAAS,YAAY,QAAQ;AAC5B,SAAO;AAAA,IACN,CAAC,GAAG,MAAM,EAAE;AAAA,MACX,CAAC,KAAK,GAAG,MAAO,OAAO,EAAG,IAAI,IAAK,KAAK,OAAO,aAAa,SAAS,OAAO,UAAU,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI;AAAA,MAC5G;AAAA,IACD;AAAA,EACD;AACD;",
6
+ "names": []
7
+ }
@@ -0,0 +1,66 @@
1
+ function isNumeric(n) {
2
+ const v = typeof n != "string" || n === "" ? n : Number(n);
3
+ const f = parseFloat(n);
4
+ return !isNaN(f) && Number.isFinite(v) && v === f;
5
+ }
6
+ function isStrictNumeric(n) {
7
+ return typeof n === "number" && Number.isFinite(n);
8
+ }
9
+ function convertUnits(v, fromUnit, toUnit, scaleFactor, compact) {
10
+ if (scaleFactor >= 1) {
11
+ const toUnitV2 = Math.floor(v * scaleFactor);
12
+ if (compact) return `${toUnitV2}${toUnit.charAt(0)}`;
13
+ return `${toUnitV2} ${toUnitV2 > 1 ? toUnit + "s" : ""}`;
14
+ }
15
+ const toUnitV = Math.floor(v * scaleFactor);
16
+ const fromUnitV = Math.ceil(v % (1 / scaleFactor));
17
+ if (fromUnitV == 0) {
18
+ if (compact) return `${toUnitV}${toUnit.charAt(0)}`;
19
+ return `${toUnitV} ${toUnitV > 1 ? toUnit + "s" : ""}`;
20
+ }
21
+ if (compact) return `${toUnitV}${toUnit.charAt(0)}${fromUnitV}${fromUnit.charAt(0)}`;
22
+ return `${toUnitV} ${toUnitV > 1 ? toUnit + "s" : toUnit} ${fromUnitV} ${fromUnitV > 1 ? fromUnit + "s" : fromUnit}`;
23
+ }
24
+ function deepEqual(x, y) {
25
+ if (x === y) {
26
+ return true;
27
+ } else if (typeof x == "object" && x != null && typeof y == "object" && y != null) {
28
+ if (Object.keys(x).length != Object.keys(y).length) {
29
+ return false;
30
+ }
31
+ for (var prop in x) {
32
+ if (y.hasOwnProperty(prop)) {
33
+ if (!deepEqual(x[prop], y[prop])) return false;
34
+ } else {
35
+ return false;
36
+ }
37
+ }
38
+ return true;
39
+ } else return false;
40
+ }
41
+ function deepFreeze(obj) {
42
+ Object.freeze(obj);
43
+ for (const value of Object.values(obj)) {
44
+ if (value !== null && typeof value == "object") deepFreeze(value);
45
+ }
46
+ return obj;
47
+ }
48
+ class CustomError extends Error {
49
+ level = "";
50
+ // '' | 'warn'
51
+ constructor(message, opts = {}) {
52
+ super(message);
53
+ if (opts.name) this.name = opts.name;
54
+ if (opts.code) this.code = opts.code;
55
+ if (opts.level) this.level = opts.level;
56
+ }
57
+ }
58
+ export {
59
+ CustomError,
60
+ convertUnits,
61
+ deepEqual,
62
+ deepFreeze,
63
+ isNumeric,
64
+ isStrictNumeric
65
+ };
66
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/helpers.js"],
4
+ "sourcesContent": ["/*\nthis is a helper file with a collection of functions to be used in backend and client side code. Here is a list.\n\n1. isNumeric(n)\n2. strictNumeric(n) \n2. convertUnits\n3. TODO - move computepercentile, roundValue, etc here?\n*/\n\n// checks whether given argument n is Numeric, with option to cast from string\nexport function isNumeric(n) {\n\tconst v = typeof n != 'string' || n === '' ? n : Number(n)\n\tconst f = parseFloat(n)\n\treturn !isNaN(f) && Number.isFinite(v) && v === f\n}\n\n// like isNumeric but does not cast from string\nexport function isStrictNumeric(n) {\n\treturn typeof n === 'number' && Number.isFinite(n)\n}\n\n// converts a value from a unit to another unit\nexport function convertUnits(v, fromUnit, toUnit, scaleFactor, compact) {\n\t// do floor() on toUnit\n\t// do ceil() on fromUnit, in case v is decimal (from violin range selection) and to keep showing integer fromUnit\n\tif (scaleFactor >= 1) {\n\t\tconst toUnitV = Math.floor(v * scaleFactor)\n\t\tif (compact) return `${toUnitV}${toUnit.charAt(0)}`\n\t\treturn `${toUnitV} ${toUnitV > 1 ? toUnit + 's' : ''}`\n\t}\n\tconst toUnitV = Math.floor(v * scaleFactor)\n\tconst fromUnitV = Math.ceil(v % (1 / scaleFactor))\n\n\tif (fromUnitV == 0) {\n\t\tif (compact) return `${toUnitV}${toUnit.charAt(0)}`\n\t\treturn `${toUnitV} ${toUnitV > 1 ? toUnit + 's' : ''}`\n\t}\n\n\tif (compact) return `${toUnitV}${toUnit.charAt(0)}${fromUnitV}${fromUnit.charAt(0)}`\n\treturn `${toUnitV} ${toUnitV > 1 ? toUnit + 's' : toUnit} ${fromUnitV} ${fromUnitV > 1 ? fromUnit + 's' : fromUnit}`\n}\n\nexport function deepEqual(x, y) {\n\tif (x === y) {\n\t\treturn true\n\t} else if (typeof x == 'object' && x != null && typeof y == 'object' && y != null) {\n\t\tif (Object.keys(x).length != Object.keys(y).length) {\n\t\t\treturn false\n\t\t}\n\n\t\tfor (var prop in x) {\n\t\t\tif (y.hasOwnProperty(prop)) {\n\t\t\t\tif (!deepEqual(x[prop], y[prop])) return false\n\t\t\t} else {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\t} else return false\n}\n\nexport function deepFreeze(obj) {\n\tObject.freeze(obj)\n\t// not using for..in loop, in order to not descend into inherited props/methods\n\tfor (const value of Object.values(obj)) {\n\t\tif (value !== null && typeof value == 'object') deepFreeze(value)\n\t}\n\treturn obj\n}\n\nexport class CustomError extends Error {\n\tlevel = '' // '' | 'warn'\n\n\tconstructor(message, opts = {}) {\n\t\tsuper(message)\n\t\tif (opts.name) this.name = opts.name\n\t\tif (opts.code) this.code = opts.code\n\t\tif (opts.level) this.level = opts.level\n\t}\n}\n"],
5
+ "mappings": "AAUO,SAAS,UAAU,GAAG;AAC5B,QAAM,IAAI,OAAO,KAAK,YAAY,MAAM,KAAK,IAAI,OAAO,CAAC;AACzD,QAAM,IAAI,WAAW,CAAC;AACtB,SAAO,CAAC,MAAM,CAAC,KAAK,OAAO,SAAS,CAAC,KAAK,MAAM;AACjD;AAGO,SAAS,gBAAgB,GAAG;AAClC,SAAO,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC;AAClD;AAGO,SAAS,aAAa,GAAG,UAAU,QAAQ,aAAa,SAAS;AAGvE,MAAI,eAAe,GAAG;AACrB,UAAMA,WAAU,KAAK,MAAM,IAAI,WAAW;AAC1C,QAAI,QAAS,QAAO,GAAGA,QAAO,GAAG,OAAO,OAAO,CAAC,CAAC;AACjD,WAAO,GAAGA,QAAO,IAAIA,WAAU,IAAI,SAAS,MAAM,EAAE;AAAA,EACrD;AACA,QAAM,UAAU,KAAK,MAAM,IAAI,WAAW;AAC1C,QAAM,YAAY,KAAK,KAAK,KAAK,IAAI,YAAY;AAEjD,MAAI,aAAa,GAAG;AACnB,QAAI,QAAS,QAAO,GAAG,OAAO,GAAG,OAAO,OAAO,CAAC,CAAC;AACjD,WAAO,GAAG,OAAO,IAAI,UAAU,IAAI,SAAS,MAAM,EAAE;AAAA,EACrD;AAEA,MAAI,QAAS,QAAO,GAAG,OAAO,GAAG,OAAO,OAAO,CAAC,CAAC,GAAG,SAAS,GAAG,SAAS,OAAO,CAAC,CAAC;AAClF,SAAO,GAAG,OAAO,IAAI,UAAU,IAAI,SAAS,MAAM,MAAM,IAAI,SAAS,IAAI,YAAY,IAAI,WAAW,MAAM,QAAQ;AACnH;AAEO,SAAS,UAAU,GAAG,GAAG;AAC/B,MAAI,MAAM,GAAG;AACZ,WAAO;AAAA,EACR,WAAW,OAAO,KAAK,YAAY,KAAK,QAAQ,OAAO,KAAK,YAAY,KAAK,MAAM;AAClF,QAAI,OAAO,KAAK,CAAC,EAAE,UAAU,OAAO,KAAK,CAAC,EAAE,QAAQ;AACnD,aAAO;AAAA,IACR;AAEA,aAAS,QAAQ,GAAG;AACnB,UAAI,EAAE,eAAe,IAAI,GAAG;AAC3B,YAAI,CAAC,UAAU,EAAE,IAAI,GAAG,EAAE,IAAI,CAAC,EAAG,QAAO;AAAA,MAC1C,OAAO;AACN,eAAO;AAAA,MACR;AAAA,IACD;AACA,WAAO;AAAA,EACR,MAAO,QAAO;AACf;AAEO,SAAS,WAAW,KAAK;AAC/B,SAAO,OAAO,GAAG;AAEjB,aAAW,SAAS,OAAO,OAAO,GAAG,GAAG;AACvC,QAAI,UAAU,QAAQ,OAAO,SAAS,SAAU,YAAW,KAAK;AAAA,EACjE;AACA,SAAO;AACR;AAEO,MAAM,oBAAoB,MAAM;AAAA,EACtC,QAAQ;AAAA;AAAA,EAER,YAAY,SAAS,OAAO,CAAC,GAAG;AAC/B,UAAM,OAAO;AACb,QAAI,KAAK,KAAM,MAAK,OAAO,KAAK;AAChC,QAAI,KAAK,KAAM,MAAK,OAAO,KAAK;AAChC,QAAI,KAAK,MAAO,MAAK,QAAQ,KAAK;AAAA,EACnC;AACD;",
6
+ "names": ["toUnitV"]
7
+ }
@@ -0,0 +1,26 @@
1
+ export * from '../constants/AiHisto.js';
2
+ export * from './aiHisto.js';
3
+ export * from './bulk.js';
4
+ export * from './clustering.js';
5
+ export * from './common.js';
6
+ export * from './compute.percentile.js';
7
+ export * from './fetch-helpers.js';
8
+ export * from './fileSize.js';
9
+ export * from './filter.js';
10
+ export * from './hash.js';
11
+ export * from './helpers.js';
12
+ export * from './joinUrl.js';
13
+ export * from './mds3tk.js';
14
+ export * from './roundValue.js';
15
+ export * from './termdb.bins.js';
16
+ export * from './termdb.initbinconfig.js';
17
+ export * from './termdb.usecase.js';
18
+ export * from './terms.js';
19
+ export * from './time.js';
20
+ export * from './tree.js';
21
+ export * from './urljson.js';
22
+ export * from './vcf.ann.js';
23
+ export * from './vcf.csq.js';
24
+ export * from './vcf.info.js';
25
+ export * from './vcf.js';
26
+ export * from './vcf.type.js';
@@ -0,0 +1,27 @@
1
+ export * from "../constants/AiHisto.js";
2
+ export * from "./aiHisto.js";
3
+ export * from "./bulk.js";
4
+ export * from "./clustering.js";
5
+ export * from "./common.js";
6
+ export * from "./compute.percentile.js";
7
+ export * from "./fetch-helpers.js";
8
+ export * from "./fileSize.js";
9
+ export * from "./filter.js";
10
+ export * from "./hash.js";
11
+ export * from "./helpers.js";
12
+ export * from "./joinUrl.js";
13
+ export * from "./mds3tk.js";
14
+ export * from "./roundValue.js";
15
+ export * from "./termdb.bins.js";
16
+ export * from "./termdb.initbinconfig.js";
17
+ export * from "./termdb.usecase.js";
18
+ export * from "./terms.js";
19
+ export * from "./time.js";
20
+ export * from "./tree.js";
21
+ export * from "./urljson.js";
22
+ export * from "./vcf.ann.js";
23
+ export * from "./vcf.csq.js";
24
+ export * from "./vcf.info.js";
25
+ export * from "./vcf.js";
26
+ export * from "./vcf.type.js";
27
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/index.ts"],
4
+ "sourcesContent": ["// IMPORTANT: import .js extension, even though the actual code files are .ts\nexport * from '../constants/AiHisto.js'\n\n// please list in alphanumeric order for readability\nexport * from './aiHisto.js'\nexport * from './bulk.js'\nexport * from './clustering.js'\nexport * from './common.js'\nexport * from './compute.percentile.js'\nexport * from './fetch-helpers.js'\nexport * from './fileSize.js'\nexport * from './filter.js'\nexport * from './hash.js'\nexport * from './helpers.js'\nexport * from './joinUrl.js'\nexport * from './mds3tk.js'\nexport * from './roundValue.js'\nexport * from './termdb.bins.js'\nexport * from './termdb.initbinconfig.js'\nexport * from './termdb.usecase.js'\nexport * from './terms.js'\nexport * from './time.js'\nexport * from './tree.js'\nexport * from './urljson.js'\nexport * from './vcf.ann.js'\nexport * from './vcf.csq.js'\nexport * from './vcf.info.js'\nexport * from './vcf.js'\nexport * from './vcf.type.js'\n"],
5
+ "mappings": "AACA,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
6
+ "names": []
7
+ }
@@ -0,0 +1 @@
1
+ export declare function joinUrl(p1: string, ...p2: string[]): string;
@@ -0,0 +1,17 @@
1
+ function joinUrl(p1, ...p2) {
2
+ if (typeof p1 != "string") throw `first argument must be string type`;
3
+ if (!p1) throw "blank string not allowed";
4
+ if (p1.indexOf("?") != -1) throw "search string not allowed";
5
+ let url = p1;
6
+ for (const p of p2) {
7
+ if (typeof p != "string") throw `all arguments must be string type`;
8
+ if (!p) throw "blank string not allowed";
9
+ if (url.slice(-1) != "/") url += "/";
10
+ url += p.startsWith("/") ? p.substring(1) : p;
11
+ }
12
+ return url;
13
+ }
14
+ export {
15
+ joinUrl
16
+ };
17
+ //# sourceMappingURL=joinUrl.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/joinUrl.ts"],
4
+ "sourcesContent": ["/*\njoins two parts of url into one\npart 1 must be https://domain, with optional \"path\" or \"path/\", must not include search value e.g. ?k=v\npart 2 must be a path of \"path\" or \"/path\"\n\nthe function is simple and doesn't support rest parameter.\nwhen you have 3 pieces to join, do joinUrl( joinUrl(p1,p2), p3)\n\ncannot do below:\n- path.join() normalizes double-slash '://' to ':/' single-slash\n also cannot use path on client\n- url.resolve() replaces the path string after the domain, instead of appending to it\n\nTODO: also handle './' and '../' path segments to match the path.join() behavior in nodejs,\n for consistency in expected function signatures/behavior (except for the '://' issue)\n*/\nexport function joinUrl(p1: string, ...p2: string[]): string {\n\t// p1 and p2 both shouldn't be blank string. if so, return null to alert\n\tif (typeof p1 != 'string') throw `first argument must be string type`\n\tif (!p1) throw 'blank string not allowed'\n\tif (p1.indexOf('?') != -1) throw 'search string not allowed' // search string not allowed in p1. if usecase arises can support it\n\n\tlet url = p1\n\tfor(const p of p2) {\n\t\tif (typeof p != 'string') throw `all arguments must be string type`\n\t\tif (!p) throw 'blank string not allowed'\n\t\tif (url.slice(-1) != '/') url += '/'\n\t\turl += p.startsWith('/') ? p.substring(1) : p\n\t}\n\t\n\treturn url\n}\n"],
5
+ "mappings": "AAgBO,SAAS,QAAQ,OAAe,IAAsB;AAE5D,MAAI,OAAO,MAAM,SAAU,OAAM;AACjC,MAAI,CAAC,GAAI,OAAM;AACf,MAAI,GAAG,QAAQ,GAAG,KAAK,GAAI,OAAM;AAEjC,MAAI,MAAM;AACV,aAAU,KAAK,IAAI;AAClB,QAAI,OAAO,KAAK,SAAU,OAAM;AAChC,QAAI,CAAC,EAAG,OAAM;AACd,QAAI,IAAI,MAAM,EAAE,KAAK,IAAK,QAAO;AACjC,WAAO,EAAE,WAAW,GAAG,IAAI,EAAE,UAAU,CAAC,IAAI;AAAA,EAC7C;AAEA,SAAO;AACR;",
6
+ "names": []
7
+ }
@@ -0,0 +1,64 @@
1
+ import { dtcnv, dtsnvindel, dtsv, dtfusionrna } from "./common.js";
2
+ const ssmIdFieldsSeparator = "__";
3
+ function summarize_mclass(mlst) {
4
+ const m2c = /* @__PURE__ */ new Map();
5
+ const cnvs = [];
6
+ for (const m of mlst) {
7
+ if (m.dt == dtcnv) {
8
+ cnvs.push(m);
9
+ continue;
10
+ }
11
+ const key = m.class || m.dt;
12
+ m2c.set(key, 1 + (m2c.get(key) || 0));
13
+ }
14
+ if (cnvs.length) {
15
+ if (Number.isFinite(cnvs[0].value)) {
16
+ m2c.set(dtcnv, cnvs.length);
17
+ } else {
18
+ for (const c of cnvs) {
19
+ if (!c.class) continue;
20
+ m2c.set(c.class, 1 + (m2c.get(c.class) || 0));
21
+ }
22
+ }
23
+ }
24
+ return [...m2c].sort((i, j) => j[1] - i[1]);
25
+ }
26
+ function guessSsmid(ssmid) {
27
+ const l = ssmid.split(ssmIdFieldsSeparator);
28
+ if (l.length == 4) {
29
+ const [chr, tmp, ref, alt] = l;
30
+ const pos = Number(tmp);
31
+ if (Number.isNaN(pos)) throw "ssmid snvindel pos not integer";
32
+ return { dt: dtsnvindel, l: [chr, pos, ref, alt] };
33
+ }
34
+ if (l.length == 5) {
35
+ const [chr, _start, _stop, _class, _value] = l;
36
+ const start = Number(_start), stop = Number(_stop), value = _value == "" ? null : Number(_value);
37
+ if (Number.isNaN(start) || Number.isNaN(stop)) throw "ssmid cnv start/stop not integer";
38
+ return { dt: dtcnv, l: [chr, start, stop, _class, value] };
39
+ }
40
+ if (l.length == 6) {
41
+ if (l[3] == "+" || l[3] == "-") {
42
+ const [_dt, chr2, _pos, strand, _pi, _mname] = l;
43
+ const mname = decodeURIComponent(_mname);
44
+ const dt = Number(_dt);
45
+ if (dt != dtsv && dt != dtfusionrna) throw "ssmid dt not sv/fusion";
46
+ const pos = Number(_pos);
47
+ if (Number.isNaN(pos)) throw "ssmid svfusion position not integer";
48
+ const pairlstIdx = Number(_pi);
49
+ if (Number.isNaN(pairlstIdx)) throw "ssmid pairlstIdx not integer";
50
+ return { dt, l: [dt, chr2, pos, strand, pairlstIdx, mname] };
51
+ }
52
+ const [chr, _start, _stop, _class, _value, sample] = l;
53
+ const start = Number(_start), stop = Number(_stop), value = _value == "" ? null : Number(_value);
54
+ if (Number.isNaN(start) || Number.isNaN(stop)) throw "ssmid cnv start/stop not integer";
55
+ return { dt: dtcnv, l: [chr, start, stop, _class, value, sample] };
56
+ }
57
+ throw "unknown ssmid";
58
+ }
59
+ export {
60
+ guessSsmid,
61
+ ssmIdFieldsSeparator,
62
+ summarize_mclass
63
+ };
64
+ //# sourceMappingURL=mds3tk.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/mds3tk.js"],
4
+ "sourcesContent": ["import { dtcnv, dtsnvindel, dtsv, dtfusionrna } from './common.js'\n\n// this script should contain mds3 track-related stuff shared between client and backend\n\n/*\nthe separator is used to join essential bits of a variant obj into a string as the \"ssm_id\", aims to uniquely identify a variant irrespective of sample\nthis is to mimic the GDC \"ssm_id\" which is a random id, with below benefits:\n- consistent way to pass request body for both gdc and non-gdc\n- uniform identification of ssm/cnv/sv in non-gdc backend code\n- uniform identification of all variants in client\n\nssm: chr + pos + ref + alt\ncnv: chr + start + stop + class\nsvfusion: dt + chr + pos + strand + pairlstidx + mname\n\nthe separator must avoid conflicting with characters from gene names, and can be changed based on needs\n*/\nexport const ssmIdFieldsSeparator = '__'\n\n/*\ninput: array of mixture of ssm, svfusion and cnv\n\noutput: sorted array. each element: [ class/dt, count of m ]\n*/\nexport function summarize_mclass(mlst) {\n\tconst m2c = new Map() // k: mclass, v: {}\n\tconst cnvs = []\n\tfor (const m of mlst) {\n\t\tif (m.dt == dtcnv) {\n\t\t\tcnvs.push(m)\n\t\t\tcontinue // process cnv later\n\t\t}\n\t\t// snvindel has m.class=str, svfusion has only dt=int\n\t\tconst key = m.class || m.dt\n\t\tm2c.set(key, 1 + (m2c.get(key) || 0))\n\t}\n\n\tif (cnvs.length) {\n\t\tif (Number.isFinite(cnvs[0].value)) {\n\t\t\t// first cnv uses numeric value (assumes all the same). record by dt\n\t\t\tm2c.set(dtcnv, cnvs.length)\n\t\t} else {\n\t\t\t// cnv not numeric and uses class; record by each class\n\t\t\tfor (const c of cnvs) {\n\t\t\t\tif (!c.class) continue // should not happen\n\t\t\t\tm2c.set(c.class, 1 + (m2c.get(c.class) || 0))\n\t\t\t}\n\t\t}\n\t}\n\treturn [...m2c].sort((i, j) => j[1] - i[1])\n}\n\n/*\nssmid is not specific for ssm, it covers all alterations\ngdc ssm are identified by a specific uuid, thus the design\n*/\nexport function guessSsmid(ssmid) {\n\tconst l = ssmid.split(ssmIdFieldsSeparator)\n\tif (l.length == 4) {\n\t\tconst [chr, tmp, ref, alt] = l\n\t\tconst pos = Number(tmp)\n\t\tif (Number.isNaN(pos)) throw 'ssmid snvindel pos not integer'\n\t\treturn { dt: dtsnvindel, l: [chr, pos, ref, alt] }\n\t}\n\tif (l.length == 5) {\n\t\t// cnv. if type=cat, _value is blank string\n\t\tconst [chr, _start, _stop, _class, _value] = l\n\t\tconst start = Number(_start),\n\t\t\tstop = Number(_stop),\n\t\t\tvalue = _value == '' ? null : Number(_value)\n\t\tif (Number.isNaN(start) || Number.isNaN(stop)) throw 'ssmid cnv start/stop not integer'\n\t\treturn { dt: dtcnv, l: [chr, start, stop, _class, value] }\n\t}\n\tif (l.length == 6) {\n\t\tif (l[3] == '+' || l[3] == '-') {\n\t\t\t// sv/fusion\n\t\t\tconst [_dt, chr, _pos, strand, _pi, _mname] = l\n\n\t\t\t// mname is encoded in case it contains comma (and is same as ssmIdFieldsSeparator)\n\t\t\tconst mname = decodeURIComponent(_mname)\n\t\t\tconst dt = Number(_dt)\n\t\t\tif (dt != dtsv && dt != dtfusionrna) throw 'ssmid dt not sv/fusion'\n\t\t\tconst pos = Number(_pos)\n\t\t\tif (Number.isNaN(pos)) throw 'ssmid svfusion position not integer'\n\t\t\tconst pairlstIdx = Number(_pi)\n\t\t\tif (Number.isNaN(pairlstIdx)) throw 'ssmid pairlstIdx not integer'\n\t\t\treturn { dt, l: [dt, chr, pos, strand, pairlstIdx, mname] }\n\t\t}\n\t\t// cnv with sample\n\t\tconst [chr, _start, _stop, _class, _value, sample] = l\n\t\tconst start = Number(_start),\n\t\t\tstop = Number(_stop),\n\t\t\tvalue = _value == '' ? null : Number(_value) // if cnv not using value, must avoid `Number('')=0`\n\t\tif (Number.isNaN(start) || Number.isNaN(stop)) throw 'ssmid cnv start/stop not integer'\n\t\treturn { dt: dtcnv, l: [chr, start, stop, _class, value, sample] }\n\t}\n\tthrow 'unknown ssmid'\n}\n"],
5
+ "mappings": "AAAA,SAAS,OAAO,YAAY,MAAM,mBAAmB;AAiB9C,MAAM,uBAAuB;AAO7B,SAAS,iBAAiB,MAAM;AACtC,QAAM,MAAM,oBAAI,IAAI;AACpB,QAAM,OAAO,CAAC;AACd,aAAW,KAAK,MAAM;AACrB,QAAI,EAAE,MAAM,OAAO;AAClB,WAAK,KAAK,CAAC;AACX;AAAA,IACD;AAEA,UAAM,MAAM,EAAE,SAAS,EAAE;AACzB,QAAI,IAAI,KAAK,KAAK,IAAI,IAAI,GAAG,KAAK,EAAE;AAAA,EACrC;AAEA,MAAI,KAAK,QAAQ;AAChB,QAAI,OAAO,SAAS,KAAK,CAAC,EAAE,KAAK,GAAG;AAEnC,UAAI,IAAI,OAAO,KAAK,MAAM;AAAA,IAC3B,OAAO;AAEN,iBAAW,KAAK,MAAM;AACrB,YAAI,CAAC,EAAE,MAAO;AACd,YAAI,IAAI,EAAE,OAAO,KAAK,IAAI,IAAI,EAAE,KAAK,KAAK,EAAE;AAAA,MAC7C;AAAA,IACD;AAAA,EACD;AACA,SAAO,CAAC,GAAG,GAAG,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;AAC3C;AAMO,SAAS,WAAW,OAAO;AACjC,QAAM,IAAI,MAAM,MAAM,oBAAoB;AAC1C,MAAI,EAAE,UAAU,GAAG;AAClB,UAAM,CAAC,KAAK,KAAK,KAAK,GAAG,IAAI;AAC7B,UAAM,MAAM,OAAO,GAAG;AACtB,QAAI,OAAO,MAAM,GAAG,EAAG,OAAM;AAC7B,WAAO,EAAE,IAAI,YAAY,GAAG,CAAC,KAAK,KAAK,KAAK,GAAG,EAAE;AAAA,EAClD;AACA,MAAI,EAAE,UAAU,GAAG;AAElB,UAAM,CAAC,KAAK,QAAQ,OAAO,QAAQ,MAAM,IAAI;AAC7C,UAAM,QAAQ,OAAO,MAAM,GAC1B,OAAO,OAAO,KAAK,GACnB,QAAQ,UAAU,KAAK,OAAO,OAAO,MAAM;AAC5C,QAAI,OAAO,MAAM,KAAK,KAAK,OAAO,MAAM,IAAI,EAAG,OAAM;AACrD,WAAO,EAAE,IAAI,OAAO,GAAG,CAAC,KAAK,OAAO,MAAM,QAAQ,KAAK,EAAE;AAAA,EAC1D;AACA,MAAI,EAAE,UAAU,GAAG;AAClB,QAAI,EAAE,CAAC,KAAK,OAAO,EAAE,CAAC,KAAK,KAAK;AAE/B,YAAM,CAAC,KAAKA,MAAK,MAAM,QAAQ,KAAK,MAAM,IAAI;AAG9C,YAAM,QAAQ,mBAAmB,MAAM;AACvC,YAAM,KAAK,OAAO,GAAG;AACrB,UAAI,MAAM,QAAQ,MAAM,YAAa,OAAM;AAC3C,YAAM,MAAM,OAAO,IAAI;AACvB,UAAI,OAAO,MAAM,GAAG,EAAG,OAAM;AAC7B,YAAM,aAAa,OAAO,GAAG;AAC7B,UAAI,OAAO,MAAM,UAAU,EAAG,OAAM;AACpC,aAAO,EAAE,IAAI,GAAG,CAAC,IAAIA,MAAK,KAAK,QAAQ,YAAY,KAAK,EAAE;AAAA,IAC3D;AAEA,UAAM,CAAC,KAAK,QAAQ,OAAO,QAAQ,QAAQ,MAAM,IAAI;AACrD,UAAM,QAAQ,OAAO,MAAM,GAC1B,OAAO,OAAO,KAAK,GACnB,QAAQ,UAAU,KAAK,OAAO,OAAO,MAAM;AAC5C,QAAI,OAAO,MAAM,KAAK,KAAK,OAAO,MAAM,IAAI,EAAG,OAAM;AACrD,WAAO,EAAE,IAAI,OAAO,GAAG,CAAC,KAAK,OAAO,MAAM,QAAQ,OAAO,MAAM,EAAE;AAAA,EAClE;AACA,QAAM;AACP;",
6
+ "names": ["chr"]
7
+ }
@@ -0,0 +1,57 @@
1
+ function roundValue(value, digits) {
2
+ const v = Number(value);
3
+ if (Number.isInteger(v)) return v;
4
+ if (Math.abs(v) < 1) return Number(v.toPrecision(digits));
5
+ return Number(v.toFixed(digits));
6
+ }
7
+ function roundValueAuto(value, format = false, defaultDigits = 2) {
8
+ if (!value && value != 0) return value;
9
+ const dp = decimalPlacesUntilFirstNonZero(value);
10
+ const digits = Math.abs(value) > 1 ? defaultDigits : dp > 0 ? dp + 1 : defaultDigits;
11
+ if (format) return formatValue(value, digits);
12
+ return roundValue(value, digits);
13
+ }
14
+ function decimalPlacesUntilFirstNonZero(number) {
15
+ const numberStr = number.toString();
16
+ const decimalIndex = numberStr.indexOf(".");
17
+ if (decimalIndex === -1 || decimalIndex === numberStr.length - 1) {
18
+ return 0;
19
+ }
20
+ let decimalPlaces = 0;
21
+ for (let i = decimalIndex + 1; i < numberStr.length; i++) {
22
+ if (numberStr[i] === "0") {
23
+ decimalPlaces++;
24
+ } else if (numberStr[i] >= "1" && numberStr[i] <= "9") {
25
+ break;
26
+ }
27
+ }
28
+ return decimalPlaces;
29
+ }
30
+ function roundValue2(value) {
31
+ if (!Number.isFinite(value)) return value;
32
+ if (Number.isInteger(value)) return value;
33
+ const abs = Math.abs(value);
34
+ if (abs > 100) return Math.round(value);
35
+ if (abs > 10) return Number(value.toFixed(1));
36
+ if (abs > 1) return Number(value.toFixed(2));
37
+ if (abs > 0.1) return Number(value.toFixed(3));
38
+ if (abs > 0.01) return Number(value.toFixed(4));
39
+ return value;
40
+ }
41
+ function formatValue(value, digits) {
42
+ const v = Number(value);
43
+ if (Number.isInteger(v)) return v;
44
+ const abs = Math.abs(v);
45
+ if (abs < 1 || abs > 9999) {
46
+ return abs > 9999 ? v.toPrecision(digits) : Number(v.toPrecision(digits));
47
+ }
48
+ return Number(v.toFixed(digits));
49
+ }
50
+ export {
51
+ decimalPlacesUntilFirstNonZero,
52
+ formatValue,
53
+ roundValue,
54
+ roundValue2,
55
+ roundValueAuto
56
+ };
57
+ //# sourceMappingURL=roundValue.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/roundValue.js"],
4
+ "sourcesContent": ["/*\nround a value to specified digits\n - if value is integer, value is returned\n - if value is a fractional float, round to precision\n - if value is not a fractional float, round to decimal point\n - TODO: handle scientific notation\nvalue: given value\ndigits: number of digits to round to\n*/\n\nexport function roundValue(value, digits) {\n\tconst v = Number(value)\n\tif (Number.isInteger(v)) return v\n\tif (Math.abs(v) < 1) return Number(v.toPrecision(digits))\n\treturn Number(v.toFixed(digits))\n}\n\n/** Rounds numbers to the appropriate decimal point\n * if format is true, returns either a number or string in\n * scientific notation.\n *\n * TODO: Review digit logic.\n */\n\nexport function roundValueAuto(value, format = false, defaultDigits = 2) {\n\tif (!value && value != 0) return value\n\tconst dp = decimalPlacesUntilFirstNonZero(value)\n\tconst digits = Math.abs(value) > 1 ? defaultDigits : dp > 0 ? dp + 1 : defaultDigits\n\tif (format) return formatValue(value, digits)\n\treturn roundValue(value, digits)\n}\n\nexport function decimalPlacesUntilFirstNonZero(number) {\n\t// Convert number to string\n\tconst numberStr = number.toString()\n\n\t// Find the position of the decimal point\n\tconst decimalIndex = numberStr.indexOf('.')\n\n\t// If decimal point is not found or number is an integer, return 0\n\tif (decimalIndex === -1 || decimalIndex === numberStr.length - 1) {\n\t\treturn 0\n\t}\n\n\t// Iterate through characters after the decimal point\n\tlet decimalPlaces = 0\n\tfor (let i = decimalIndex + 1; i < numberStr.length; i++) {\n\t\t// Increment the count of decimal places until a non-zero digit is found\n\t\tif (numberStr[i] === '0') {\n\t\t\tdecimalPlaces++\n\t\t} else if (numberStr[i] >= '1' && numberStr[i] <= '9') {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn decimalPlaces\n}\n\n/* \nsimple logic to return a number close to original while rounding up decimals.\nsupplements roundValueAuto which rounds 12345 to 1.2e4 which is only suitable for human quick glance but not subsequent computing\n\nTODO:\n10000 and 10001 to 1e4\n0.00001 to 1e-5\n1.00001 to 1\n*/\nexport function roundValue2(value) {\n\tif (!Number.isFinite(value)) return value // not a number\n\tif (Number.isInteger(value)) return value // is integer, do not convert\n\tconst abs = Math.abs(value)\n\tif (abs > 100) return Math.round(value) // 12345.1234 to 12345 (compared to 1.2e4 from roundValueAuto)\n\tif (abs > 10) return Number(value.toFixed(1)) // 99.1234 to 99.1\n\tif (abs > 1) return Number(value.toFixed(2)) // 9.1234 to 9.12\n\tif (abs > 0.1) return Number(value.toFixed(3)) // 0.12345 to 0.123\n\tif (abs > 0.01) return Number(value.toFixed(4)) // 0.012345 to 0.0123\n\treturn value // as is\n}\n\n/** Use to return displayed values in scientific notation\n * Do not use for values intended for calculation later.\n */\nexport function formatValue(value, digits) {\n\tconst v = Number(value)\n\tif (Number.isInteger(v)) return v\n\tconst abs = Math.abs(v)\n\tif (abs < 1 || abs > 9999) {\n\t\t//Number() reverts positive values less than 10^21 to a whole number\n\t\t//To return the value in scientific notation, use toPrecision without Number()\n\t\treturn abs > 9999 ? v.toPrecision(digits) : Number(v.toPrecision(digits))\n\t}\n\treturn Number(v.toFixed(digits))\n}\n"],
5
+ "mappings": "AAUO,SAAS,WAAW,OAAO,QAAQ;AACzC,QAAM,IAAI,OAAO,KAAK;AACtB,MAAI,OAAO,UAAU,CAAC,EAAG,QAAO;AAChC,MAAI,KAAK,IAAI,CAAC,IAAI,EAAG,QAAO,OAAO,EAAE,YAAY,MAAM,CAAC;AACxD,SAAO,OAAO,EAAE,QAAQ,MAAM,CAAC;AAChC;AASO,SAAS,eAAe,OAAO,SAAS,OAAO,gBAAgB,GAAG;AACxE,MAAI,CAAC,SAAS,SAAS,EAAG,QAAO;AACjC,QAAM,KAAK,+BAA+B,KAAK;AAC/C,QAAM,SAAS,KAAK,IAAI,KAAK,IAAI,IAAI,gBAAgB,KAAK,IAAI,KAAK,IAAI;AACvE,MAAI,OAAQ,QAAO,YAAY,OAAO,MAAM;AAC5C,SAAO,WAAW,OAAO,MAAM;AAChC;AAEO,SAAS,+BAA+B,QAAQ;AAEtD,QAAM,YAAY,OAAO,SAAS;AAGlC,QAAM,eAAe,UAAU,QAAQ,GAAG;AAG1C,MAAI,iBAAiB,MAAM,iBAAiB,UAAU,SAAS,GAAG;AACjE,WAAO;AAAA,EACR;AAGA,MAAI,gBAAgB;AACpB,WAAS,IAAI,eAAe,GAAG,IAAI,UAAU,QAAQ,KAAK;AAEzD,QAAI,UAAU,CAAC,MAAM,KAAK;AACzB;AAAA,IACD,WAAW,UAAU,CAAC,KAAK,OAAO,UAAU,CAAC,KAAK,KAAK;AACtD;AAAA,IACD;AAAA,EACD;AAEA,SAAO;AACR;AAWO,SAAS,YAAY,OAAO;AAClC,MAAI,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AACpC,MAAI,OAAO,UAAU,KAAK,EAAG,QAAO;AACpC,QAAM,MAAM,KAAK,IAAI,KAAK;AAC1B,MAAI,MAAM,IAAK,QAAO,KAAK,MAAM,KAAK;AACtC,MAAI,MAAM,GAAI,QAAO,OAAO,MAAM,QAAQ,CAAC,CAAC;AAC5C,MAAI,MAAM,EAAG,QAAO,OAAO,MAAM,QAAQ,CAAC,CAAC;AAC3C,MAAI,MAAM,IAAK,QAAO,OAAO,MAAM,QAAQ,CAAC,CAAC;AAC7C,MAAI,MAAM,KAAM,QAAO,OAAO,MAAM,QAAQ,CAAC,CAAC;AAC9C,SAAO;AACR;AAKO,SAAS,YAAY,OAAO,QAAQ;AAC1C,QAAM,IAAI,OAAO,KAAK;AACtB,MAAI,OAAO,UAAU,CAAC,EAAG,QAAO;AAChC,QAAM,MAAM,KAAK,IAAI,CAAC;AACtB,MAAI,MAAM,KAAK,MAAM,MAAM;AAG1B,WAAO,MAAM,OAAO,EAAE,YAAY,MAAM,IAAI,OAAO,EAAE,YAAY,MAAM,CAAC;AAAA,EACzE;AACA,SAAO,OAAO,EAAE,QAAQ,MAAM,CAAC;AAChC;",
6
+ "names": []
7
+ }