@molgenis/vip-report-template 6.1.1 → 7.0.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 (285) hide show
  1. package/.nvmrc +1 -1
  2. package/.travis.yml +9 -11
  3. package/README.md +411 -1
  4. package/eslint.config.mjs +11 -0
  5. package/package.json +40 -35
  6. package/scripts/deploy_npm_registry.sh +5 -0
  7. package/src/App.tsx +35 -29
  8. package/src/assets/sass/main.scss +12 -4
  9. package/src/components/Allele.tsx +95 -0
  10. package/src/components/Anchor.tsx +1 -1
  11. package/src/components/Breadcrumb.tsx +8 -5
  12. package/src/components/DatasetDropdown.tsx +10 -23
  13. package/src/components/ErrorNotification.tsx +9 -0
  14. package/src/components/GenomeBrowser.tsx +40 -23
  15. package/src/components/HpoTerm.tsx +1 -1
  16. package/src/components/{record/Pager.tsx → Pager.tsx} +21 -14
  17. package/src/components/RecordsPerPage.tsx +9 -7
  18. package/src/components/RecordsTable.tsx +130 -0
  19. package/src/components/SampleTable.tsx +70 -98
  20. package/src/components/SearchBox.tsx +8 -2
  21. package/src/components/Sort.tsx +28 -25
  22. package/src/components/Table.tsx +16 -0
  23. package/src/components/Tooltip.tsx +20 -0
  24. package/src/components/VariantBreadcrumb.tsx +54 -0
  25. package/src/components/VariantConsequenceContainer.tsx +100 -0
  26. package/src/components/VariantConsequenceTable.tsx +58 -0
  27. package/src/components/VariantContainer.tsx +71 -0
  28. package/src/components/VariantFilters.tsx +27 -0
  29. package/src/components/VariantGenotypeTable.tsx +44 -0
  30. package/src/components/VariantInfoTable.tsx +24 -33
  31. package/src/components/VariantResults.tsx +103 -0
  32. package/src/components/VariantTable.tsx +62 -66
  33. package/src/components/VariantTypeSelect.tsx +34 -0
  34. package/src/components/VariantsContainer.tsx +150 -0
  35. package/src/components/VariantsContainerHeader.tsx +70 -0
  36. package/src/components/field/Field.tsx +80 -0
  37. package/src/components/field/FieldAlt.tsx +19 -0
  38. package/src/components/field/FieldChrom.tsx +6 -0
  39. package/src/components/{record/Id.tsx → field/FieldFilter.tsx} +2 -1
  40. package/src/components/field/FieldFormat.tsx +10 -0
  41. package/src/components/{record/Filter.tsx → field/FieldId.tsx} +1 -1
  42. package/src/components/field/FieldPos.tsx +6 -0
  43. package/src/components/field/FieldQual.tsx +6 -0
  44. package/src/components/field/FieldRef.tsx +8 -0
  45. package/src/components/field/composed/FieldClinVar.tsx +72 -0
  46. package/src/components/field/composed/FieldComposed.tsx +68 -0
  47. package/src/components/field/composed/FieldGene.tsx +39 -0
  48. package/src/components/field/composed/FieldGenotype.tsx +35 -0
  49. package/src/components/{record/format/GenotypeField.tsx → field/composed/FieldGenotypeSnvSv.tsx} +20 -16
  50. package/src/components/field/composed/FieldGenotypeStr.tsx +31 -0
  51. package/src/components/field/composed/FieldGnomAd.tsx +58 -0
  52. package/src/components/field/composed/FieldHpo.tsx +50 -0
  53. package/src/components/field/composed/FieldInheritanceModes.tsx +32 -0
  54. package/src/components/field/composed/FieldLocus.tsx +18 -0
  55. package/src/components/field/composed/FieldVipC.tsx +25 -0
  56. package/src/components/field/composed/FieldVipCS.tsx +15 -0
  57. package/src/components/field/composed/FieldVkgl.tsx +37 -0
  58. package/src/components/field/genotype/FieldGenotype.tsx +19 -0
  59. package/src/components/field/genotype/FieldGenotypeType.tsx +9 -0
  60. package/src/components/field/info/FieldConsequence.tsx +15 -0
  61. package/src/components/{record/info/Hgvs.tsx → field/info/FieldHgvs.tsx} +4 -6
  62. package/src/components/field/info/FieldInfo.tsx +27 -0
  63. package/src/components/{record/info/PubMed.tsx → field/info/FieldPubMed.tsx} +4 -7
  64. package/src/components/field/typed/FieldCategorical.tsx +17 -0
  65. package/src/components/{record/field/FieldValueCharacter.tsx → field/typed/FieldCharacter.tsx} +3 -2
  66. package/src/components/{record/field/FieldValueFlag.tsx → field/typed/FieldFlag.tsx} +3 -2
  67. package/src/components/{record/field/FieldValueFloat.tsx → field/typed/FieldFloat.tsx} +3 -2
  68. package/src/components/{record/field/FieldValueInteger.tsx → field/typed/FieldInteger.tsx} +3 -2
  69. package/src/components/{record/field/FieldValueString.tsx → field/typed/FieldString.tsx} +3 -2
  70. package/src/components/field/typed/FieldTyped.tsx +20 -0
  71. package/src/components/field/typed/FieldTypedItem.tsx +49 -0
  72. package/src/components/field/typed/FieldTypedMultiple.tsx +21 -0
  73. package/src/components/filter/Filter.tsx +56 -48
  74. package/src/components/filter/FilterWrapper.scss +23 -0
  75. package/src/components/filter/FilterWrapper.tsx +63 -0
  76. package/src/components/filter/composed/FilterAllelicImbalance.tsx +26 -0
  77. package/src/components/filter/composed/FilterComposed.tsx +92 -0
  78. package/src/components/filter/composed/FilterDeNovo.tsx +35 -0
  79. package/src/components/filter/composed/FilterHpo.tsx +16 -0
  80. package/src/components/filter/composed/FilterInheritance.tsx +42 -0
  81. package/src/components/filter/composed/FilterLocus.tsx +75 -0
  82. package/src/components/filter/composed/FilterVipC.tsx +16 -0
  83. package/src/components/filter/composed/FilterVipCS.tsx +16 -0
  84. package/src/components/filter/fixed/FilterAlt.tsx +20 -0
  85. package/src/components/filter/fixed/FilterChrom.tsx +22 -0
  86. package/src/components/filter/fixed/FilterFilter.tsx +20 -0
  87. package/src/components/filter/fixed/FilterFixed.tsx +96 -0
  88. package/src/components/filter/fixed/FilterId.tsx +20 -0
  89. package/src/components/filter/fixed/FilterPos.tsx +22 -0
  90. package/src/components/filter/fixed/FilterQual.tsx +21 -0
  91. package/src/components/filter/fixed/FilterRef.tsx +22 -0
  92. package/src/components/filter/typed/FilterCategorical.tsx +119 -0
  93. package/src/components/filter/typed/FilterFlag.tsx +23 -0
  94. package/src/components/filter/typed/FilterInterval.tsx +72 -0
  95. package/src/components/filter/typed/FilterString.tsx +43 -0
  96. package/src/components/filter/typed/FilterTyped.tsx +56 -0
  97. package/src/components/form/ButtonApply.tsx +11 -0
  98. package/src/components/form/ButtonDownload.tsx +11 -0
  99. package/src/components/form/ButtonReset.tsx +9 -0
  100. package/src/components/{Checkbox.tsx → form/Checkbox.tsx} +4 -9
  101. package/src/components/form/Input.tsx +19 -0
  102. package/src/components/form/Select.scss +7 -0
  103. package/src/components/form/Select.tsx +34 -0
  104. package/src/components/tree/DecisionTreeBoolMultiQuery.tsx +1 -1
  105. package/src/components/tree/DecisionTreeBoolQuery.tsx +1 -1
  106. package/src/components/tree/DecisionTreeNode.tsx +41 -39
  107. package/src/components/tree/DecisionTreeNodeBool.tsx +1 -1
  108. package/src/components/tree/DecisionTreeNodeBoolMulti.tsx +1 -1
  109. package/src/components/tree/DecisionTreeNodeCategorical.tsx +1 -1
  110. package/src/components/tree/DecisionTreeNodeExists.tsx +1 -1
  111. package/src/components/tree/DecisionTreeNodeLeaf.tsx +1 -1
  112. package/src/components/tree/DecisionTreeOutcomeNode.tsx +1 -1
  113. package/src/components/tree/DecisionTreePath.tsx +1 -1
  114. package/src/igv.d.ts +2 -1
  115. package/src/index.tsx +48 -19
  116. package/src/mocks/GRCh37/decisionTree.json +23 -22
  117. package/src/mocks/GRCh37/field_metadata.json +435 -95
  118. package/src/mocks/GRCh37/sampleTree.json +143 -0
  119. package/src/mocks/GRCh37/static.ts +63 -133
  120. package/src/mocks/GRCh37/vcf/family.vcf.blob +37 -31
  121. package/src/mocks/GRCh38/decisionTree.json +52 -33
  122. package/src/mocks/GRCh38/decisionTreeStr.json +572 -0
  123. package/src/mocks/GRCh38/fasta/chr1_149380406-149403321.fasta.gz.blob +0 -0
  124. package/src/mocks/GRCh38/field_metadata.json +435 -95
  125. package/src/mocks/GRCh38/sampleTree.json +175 -0
  126. package/src/mocks/GRCh38/static.ts +101 -42
  127. package/src/mocks/GRCh38/str.cram.blob +0 -0
  128. package/src/mocks/GRCh38/str.cram.crai.blob +0 -0
  129. package/src/mocks/GRCh38/vcf/family.vcf.blob +25 -24
  130. package/src/mocks/GRCh38/vcf/no_vep.vcf.blob +29 -28
  131. package/src/mocks/GRCh38/vcf/samples_0.vcf.blob +28 -27
  132. package/src/mocks/GRCh38/vcf/samples_1.vcf.blob +29 -28
  133. package/src/mocks/GRCh38/vcf/samples_100.vcf.blob +28 -27
  134. package/src/mocks/GRCh38/vcf/str.vcf.blob +321 -0
  135. package/src/mocks/MockApiClient.ts +341 -328
  136. package/src/mocks/config_cram.json +701 -0
  137. package/src/mocks/config_vcf.json +699 -0
  138. package/src/store/app.ts +30 -0
  139. package/src/store/index.tsx +3 -168
  140. package/src/store/variants.ts +182 -0
  141. package/src/types/config.d.ts +190 -0
  142. package/src/types/configCellComposed.d.ts +86 -0
  143. package/src/types/configCells.d.ts +129 -0
  144. package/src/types/configFilter.d.ts +80 -0
  145. package/src/types/configFilterComposed.d.ts +60 -0
  146. package/src/types/configSort.d.ts +13 -0
  147. package/src/types/filter.d.ts +17 -0
  148. package/src/types/store.d.ts +34 -0
  149. package/src/utils/api.ts +281 -0
  150. package/src/utils/config/config.ts +182 -0
  151. package/src/utils/config/configCells.ts +74 -0
  152. package/src/utils/config/configCellsComposed.ts +508 -0
  153. package/src/utils/config/configCellsField.ts +61 -0
  154. package/src/utils/config/configCellsFixed.ts +126 -0
  155. package/src/utils/config/configFilters.ts +46 -0
  156. package/src/utils/config/configFiltersComposed.ts +208 -0
  157. package/src/utils/config/configFiltersField.ts +49 -0
  158. package/src/utils/config/configFiltersFixed.ts +106 -0
  159. package/src/utils/config/configSorts.ts +44 -0
  160. package/src/utils/config/configValidator.ts +380 -0
  161. package/src/utils/config/configVip.ts +25 -0
  162. package/src/utils/csq.ts +115 -0
  163. package/src/utils/decisionTree.ts +45 -0
  164. package/src/utils/download.ts +30 -0
  165. package/src/utils/error.ts +69 -0
  166. package/src/utils/query/query.ts +55 -0
  167. package/src/utils/query/queryFilter.ts +132 -0
  168. package/src/utils/query/queryFilterComposed.ts +247 -0
  169. package/src/utils/query/queryFilterField.ts +75 -0
  170. package/src/utils/query/queryFilterFixed.ts +44 -0
  171. package/src/utils/query/querySample.ts +18 -0
  172. package/src/utils/query/queryVariantType.ts +76 -0
  173. package/src/utils/query/selector.ts +41 -0
  174. package/src/utils/{sortUtils.ts → query/sort.ts} +32 -11
  175. package/src/utils/sample.ts +19 -35
  176. package/src/utils/utils.ts +66 -2
  177. package/src/utils/variantType.ts +43 -0
  178. package/src/utils/vcf.ts +352 -0
  179. package/src/views/Help.tsx +109 -114
  180. package/src/views/Home.tsx +3 -2
  181. package/src/views/Sample.tsx +12 -7
  182. package/src/views/SampleVariant.tsx +23 -112
  183. package/src/views/SampleVariantConsequence.tsx +54 -114
  184. package/src/views/SampleVariants.tsx +33 -445
  185. package/src/views/SampleVariantsRedirect.tsx +20 -0
  186. package/src/views/Samples.tsx +7 -10
  187. package/src/views/Variant.tsx +31 -61
  188. package/src/views/VariantConsequence.tsx +42 -72
  189. package/src/views/Variants.tsx +29 -138
  190. package/src/views/VariantsRedirect.tsx +25 -0
  191. package/src/views/data/data.tsx +32 -6
  192. package/tests/store/variants.test.ts +122 -0
  193. package/tests/utils/config/config.test.ts +167 -0
  194. package/tests/utils/config/configCells.test.ts +86 -0
  195. package/tests/utils/config/configCellsComposed.test.ts +1163 -0
  196. package/tests/utils/config/configCellsField.test.ts +164 -0
  197. package/tests/utils/config/configCellsFixed.test.ts +99 -0
  198. package/tests/utils/config/configFilters.test.ts +80 -0
  199. package/tests/utils/config/configFiltersComposed.test.ts +504 -0
  200. package/tests/utils/config/configFiltersField.test.ts +140 -0
  201. package/tests/utils/config/configFiltersFixed.test.ts +81 -0
  202. package/tests/utils/config/configSorts.test.ts +55 -0
  203. package/tests/utils/config/configValidator.test.ts +56 -0
  204. package/tests/utils/config/configVip.test.ts +53 -0
  205. package/tests/utils/decisionTree.test.ts +71 -0
  206. package/tests/utils/download.test.ts +20 -0
  207. package/tests/utils/query/query.test.ts +84 -0
  208. package/tests/utils/query/queryFilter.test.ts +243 -0
  209. package/tests/utils/query/queryFilterComposed.test.ts +301 -0
  210. package/tests/utils/query/queryFilterField.test.ts +75 -0
  211. package/tests/utils/query/queryFilterFixed.test.ts +86 -0
  212. package/tests/utils/query/querySample.test.ts +45 -0
  213. package/tests/utils/query/queryVariantType.test.ts +56 -0
  214. package/{src/__tests__/sortUtils.test.ts → tests/utils/query/sort.test.ts} +3 -4
  215. package/tests/utils/sample.test.ts +259 -0
  216. package/tests/utils/utils.test.ts +120 -0
  217. package/tests/utils/variantType.test.ts +48 -0
  218. package/tests/utils/vcf.test.ts +649 -0
  219. package/tsconfig.json +6 -2
  220. package/vite.config.mts +20 -3
  221. package/.eslintignore +0 -4
  222. package/.eslintrc.js +0 -23
  223. package/src/Api.ts +0 -12
  224. package/src/__tests__/decisionTreeUtils.test.ts +0 -75
  225. package/src/__tests__/field.test.ts +0 -107
  226. package/src/__tests__/query.test.ts +0 -188
  227. package/src/__tests__/sample.test.ts +0 -184
  228. package/src/__tests__/utils.test.ts +0 -24
  229. package/src/__tests__/viewUtils.test.ts +0 -125
  230. package/src/components/ConsequenceTable.tsx +0 -45
  231. package/src/components/Error.tsx +0 -9
  232. package/src/components/FieldHeader.tsx +0 -26
  233. package/src/components/InfoCollapsablePane.tsx +0 -90
  234. package/src/components/VariantInfoNestedTable.tsx +0 -127
  235. package/src/components/VariantSampleTable.tsx +0 -58
  236. package/src/components/VariantsSampleTable.tsx +0 -183
  237. package/src/components/VariantsTable.tsx +0 -124
  238. package/src/components/filter/FilterAllelicBalance.tsx +0 -81
  239. package/src/components/filter/FilterCategorical.tsx +0 -81
  240. package/src/components/filter/FilterClinVar.tsx +0 -21
  241. package/src/components/filter/FilterGene.tsx +0 -34
  242. package/src/components/filter/FilterHpo.tsx +0 -161
  243. package/src/components/filter/FilterInheritance.tsx +0 -162
  244. package/src/components/filter/FilterIntegerGq.tsx +0 -47
  245. package/src/components/filter/FilterVI.tsx +0 -68
  246. package/src/components/filter/FilterVariantType.tsx +0 -146
  247. package/src/components/filter/Filters.tsx +0 -29
  248. package/src/components/filter/InfoFilter.tsx +0 -39
  249. package/src/components/filter/InfoFilters.tsx +0 -35
  250. package/src/components/filter/SampleFilters.tsx +0 -93
  251. package/src/components/filter/SamplesFilters.tsx +0 -33
  252. package/src/components/record/Allele.tsx +0 -38
  253. package/src/components/record/AlleleBreakend.tsx +0 -5
  254. package/src/components/record/AlleleMissing.tsx +0 -5
  255. package/src/components/record/AlleleNucs.tsx +0 -49
  256. package/src/components/record/AlleleSymbolic.tsx +0 -5
  257. package/src/components/record/Alt.tsx +0 -17
  258. package/src/components/record/Chrom.tsx +0 -5
  259. package/src/components/record/Format.tsx +0 -40
  260. package/src/components/record/Info.tsx +0 -55
  261. package/src/components/record/Pos.tsx +0 -5
  262. package/src/components/record/Qual.tsx +0 -5
  263. package/src/components/record/RecordDownload.tsx +0 -66
  264. package/src/components/record/Ref.tsx +0 -6
  265. package/src/components/record/field/Field.tsx +0 -36
  266. package/src/components/record/field/FieldMultipleValue.tsx +0 -22
  267. package/src/components/record/field/FieldSingleValue.tsx +0 -35
  268. package/src/components/record/info/ClinVar.tsx +0 -81
  269. package/src/components/record/info/Consequence.tsx +0 -18
  270. package/src/components/record/info/Gene.tsx +0 -56
  271. package/src/components/record/info/GnomAD.tsx +0 -54
  272. package/src/components/record/info/Hpo.tsx +0 -52
  273. package/src/components/record/info/InheritanceModes.tsx +0 -22
  274. package/src/components/record/info/VipC.tsx +0 -23
  275. package/src/components/record/info/Vkgl.tsx +0 -42
  276. package/src/mocks/GRCh37/vcf/no_vep.vcf.blob +0 -61
  277. package/src/mocks/GRCh37/vcf/samples_0.vcf.blob +0 -93
  278. package/src/mocks/GRCh37/vcf/samples_1.vcf.blob +0 -93
  279. package/src/mocks/GRCh37/vcf/samples_100.vcf.blob +0 -93
  280. package/src/utils/ApiUtils.ts +0 -259
  281. package/src/utils/csqUtils.ts +0 -27
  282. package/src/utils/decisionTreeUtils.ts +0 -14
  283. package/src/utils/field.ts +0 -49
  284. package/src/utils/query.ts +0 -154
  285. package/src/utils/viewUtils.ts +0 -32
@@ -0,0 +1,649 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import {
3
+ createFieldMap,
4
+ FieldMetadataWrapper,
5
+ getHeaderValue,
6
+ getInfoField,
7
+ getInfoFields,
8
+ getInfoFieldsRegex,
9
+ getInfoValue,
10
+ getInfoValueCount,
11
+ getInfoValues,
12
+ getSampleFieldsRegex,
13
+ getSampleValue,
14
+ getSampleValueCount,
15
+ getSampleValues,
16
+ isNumerical,
17
+ parseContigIds,
18
+ } from "../../src/utils/vcf.ts";
19
+ import { abbreviateHeader } from "../../src/utils/utils.ts";
20
+ import { FieldMetadata, VcfRecord } from "@molgenis/vip-report-vcf";
21
+ import { Item } from "@molgenis/vip-report-api";
22
+ import { SampleContainer, VcfMetadataContainer } from "../../src/utils/api.ts";
23
+
24
+ describe("vcf", () => {
25
+ const recordBase = {
26
+ id: 0,
27
+ data: {
28
+ c: "chr1",
29
+ p: 0,
30
+ i: [],
31
+ r: "A",
32
+ a: ["C", "T"],
33
+ q: null,
34
+ f: [],
35
+ n: {},
36
+ s: [],
37
+ },
38
+ } as Item<VcfRecord>;
39
+
40
+ describe("getInfoValue", () => {
41
+ test("field count=1", () => {
42
+ const record = { ...recordBase, data: { ...recordBase.data, n: { f: 1 } } };
43
+ const fieldMetadata = { id: "f", number: { count: 1 } } as FieldMetadataWrapper;
44
+ expect(getInfoValue(record, 0, fieldMetadata)).toStrictEqual(1);
45
+ });
46
+
47
+ test("field count=1 value=null", () => {
48
+ const record = { ...recordBase, data: { ...recordBase.data, n: { f: null } } };
49
+ const fieldMetadata = { id: "f", number: { count: 1 } } as FieldMetadataWrapper;
50
+ expect(getInfoValue(record, 0, fieldMetadata)).toStrictEqual(null);
51
+ });
52
+
53
+ test("field count=1 value=undefined", () => {
54
+ const record = { ...recordBase, data: { ...recordBase.data, n: {} } };
55
+ const fieldMetadata = { id: "f", number: { count: 1 } } as FieldMetadataWrapper;
56
+ expect(getInfoValue(record, 0, fieldMetadata)).toStrictEqual(null); // treat null and undefined the same
57
+ });
58
+
59
+ test("field categorical count=1", () => {
60
+ const record = { ...recordBase, data: { ...recordBase.data, n: { f: "cat1" } } };
61
+ const fieldMetadata = {
62
+ id: "f",
63
+ type: "CATEGORICAL",
64
+ categories: { cat1: { label: "my_label", description: "my_description" } },
65
+ number: { type: "NUMBER", count: 1 },
66
+ index: 0,
67
+ } as FieldMetadataWrapper;
68
+ expect(getInfoValue(record, 0, fieldMetadata)).toStrictEqual({
69
+ value: "cat1",
70
+ label: "my_label",
71
+ description: "my_description",
72
+ });
73
+ });
74
+
75
+ test("field categorical count=1 value=null", () => {
76
+ const record = { ...recordBase, data: { ...recordBase.data, n: { f: null } } };
77
+ const fieldMetadata = {
78
+ id: "f",
79
+ type: "CATEGORICAL",
80
+ categories: { cat1: { label: "my_label", description: "my_description" } },
81
+ number: { type: "NUMBER", count: 1 },
82
+ index: 0,
83
+ } as FieldMetadataWrapper;
84
+ expect(getInfoValue(record, 0, fieldMetadata)).toStrictEqual(null);
85
+ });
86
+
87
+ test("field categorical count=1 value=undefined", () => {
88
+ const record = { ...recordBase, data: { ...recordBase.data, n: {} } };
89
+ const fieldMetadata = {
90
+ id: "f",
91
+ type: "CATEGORICAL",
92
+ categories: { cat1: { label: "my_label", description: "my_description" } },
93
+ number: { type: "NUMBER", count: 1 },
94
+ index: 0,
95
+ } as FieldMetadataWrapper;
96
+ expect(getInfoValue(record, 0, fieldMetadata)).toStrictEqual(null);
97
+ });
98
+
99
+ test("field categorical count=1 value=null nullValue", () => {
100
+ const record = { ...recordBase, data: { ...recordBase.data, n: { f: null } } };
101
+ const fieldMetadata = {
102
+ id: "f",
103
+ type: "CATEGORICAL",
104
+ categories: { cat1: { label: "my_label", description: "my_description" } },
105
+ nullValue: {
106
+ label: "False",
107
+ description: "Null as false",
108
+ },
109
+ number: { type: "NUMBER", count: 1 },
110
+ index: 0,
111
+ } as FieldMetadataWrapper;
112
+ expect(getInfoValue(record, 0, fieldMetadata)).toStrictEqual({
113
+ value: null,
114
+ label: "False",
115
+ description: "Null as false",
116
+ });
117
+ });
118
+
119
+ test("field count=*", () => {
120
+ const record = { ...recordBase, data: { ...recordBase.data, n: { f: [1] } } };
121
+ const fieldMetadata = { id: "f", number: {} } as FieldMetadataWrapper;
122
+ expect(getInfoValue(record, 0, fieldMetadata)).toStrictEqual([1]);
123
+ });
124
+
125
+ test("field count=* value=empty", () => {
126
+ const record = { ...recordBase, data: { ...recordBase.data, n: { f: [] } } };
127
+ const fieldMetadata = { id: "f", number: {} } as FieldMetadataWrapper;
128
+ expect(getInfoValue(record, 0, fieldMetadata)).toStrictEqual([]);
129
+ });
130
+
131
+ test("field count=* value=undefined", () => {
132
+ const record = { ...recordBase, data: { ...recordBase.data, n: {} } };
133
+ const fieldMetadata = { id: "f", number: {} } as FieldMetadataWrapper;
134
+ expect(getInfoValue(record, 0, fieldMetadata)).toStrictEqual([]); // treat null and undefined the same
135
+ });
136
+
137
+ test("field categorical count=*", () => {
138
+ const record = { ...recordBase, data: { ...recordBase.data, n: { f: ["cat1", "cat2"] } } };
139
+ const fieldMetadata = {
140
+ id: "f",
141
+ type: "CATEGORICAL",
142
+ categories: {
143
+ cat1: { label: "cat1_label", description: "cat1_description" },
144
+ cat2: { label: "cat2_label", description: "cat2_description" },
145
+ },
146
+ number: { type: "OTHER" },
147
+ index: 0,
148
+ } as FieldMetadataWrapper;
149
+ expect(getInfoValue(record, 0, fieldMetadata)).toStrictEqual([
150
+ {
151
+ value: "cat1",
152
+ label: "cat1_label",
153
+ description: "cat1_description",
154
+ },
155
+ {
156
+ value: "cat2",
157
+ label: "cat2_label",
158
+ description: "cat2_description",
159
+ },
160
+ ]);
161
+ });
162
+
163
+ test("field categorical count=* value=null", () => {
164
+ const record = { ...recordBase, data: { ...recordBase.data, n: { f: [] } } };
165
+ const fieldMetadata = {
166
+ id: "f",
167
+ type: "CATEGORICAL",
168
+ categories: {},
169
+ number: { type: "OTHER" },
170
+ index: 0,
171
+ } as FieldMetadataWrapper;
172
+ expect(getInfoValue(record, 0, fieldMetadata)).toStrictEqual([]);
173
+ });
174
+
175
+ test("field categorical count=* value=null nullValue", () => {
176
+ const record = { ...recordBase, data: { ...recordBase.data, n: { f: [] } } };
177
+ const fieldMetadata = {
178
+ id: "f",
179
+ type: "CATEGORICAL",
180
+ categories: {},
181
+ nullValue: {
182
+ label: "False",
183
+ description: "Null as false",
184
+ },
185
+ number: { type: "OTHER" },
186
+ index: 0,
187
+ } as FieldMetadataWrapper;
188
+ // empty categorical array value should return array with nullValue
189
+ expect(getInfoValue(record, 0, fieldMetadata)).toStrictEqual([
190
+ {
191
+ value: null,
192
+ label: "False",
193
+ description: "Null as false",
194
+ },
195
+ ]);
196
+ });
197
+
198
+ test("field child count=1, parent count=1", () => {
199
+ const record = { ...recordBase, data: { ...recordBase.data, n: { f: [0, 1, 2, 3] } } };
200
+ const fieldMetadata = {
201
+ id: "f_child",
202
+ number: { count: 1 },
203
+ index: 2,
204
+ parent: { id: "f", number: { count: 1 } },
205
+ } as FieldMetadataWrapper;
206
+ expect(getInfoValue(record, 0, fieldMetadata)).toStrictEqual(2);
207
+ });
208
+
209
+ test("field child count=1, parent count=1 value=undefined", () => {
210
+ const record = { ...recordBase, data: { ...recordBase.data, n: {} } };
211
+ const fieldMetadata = {
212
+ id: "f_child",
213
+ number: { count: 1 },
214
+ index: 2,
215
+ parent: { id: "f", number: { count: 1 } },
216
+ } as FieldMetadataWrapper;
217
+ expect(getInfoValue(record, 0, fieldMetadata)).toStrictEqual(null);
218
+ });
219
+
220
+ test("field child count=*, parent count=1", () => {
221
+ const record = { ...recordBase, data: { ...recordBase.data, n: { f: [0, 1, [2, 3], 4] } } };
222
+ const fieldMetadata = {
223
+ id: "f_child",
224
+ number: {},
225
+ index: 2,
226
+ parent: { id: "f", number: { count: 1 } },
227
+ } as FieldMetadataWrapper;
228
+ expect(getInfoValue(record, 0, fieldMetadata)).toStrictEqual([2, 3]);
229
+ });
230
+
231
+ test("field child count=*, parent count=1 value=undefined", () => {
232
+ const record = { ...recordBase, data: { ...recordBase.data, n: {} } };
233
+ const fieldMetadata = {
234
+ id: "f_child",
235
+ number: {},
236
+ index: 2,
237
+ parent: { id: "f", number: { count: 1 } },
238
+ } as FieldMetadataWrapper;
239
+ expect(getInfoValue(record, 0, fieldMetadata)).toStrictEqual([]);
240
+ });
241
+
242
+ test("field child count=1, parent count=*", () => {
243
+ const record = {
244
+ ...recordBase,
245
+ data: {
246
+ ...recordBase.data,
247
+ n: {
248
+ f: [
249
+ [0, 1, 2],
250
+ [3, 4, 5],
251
+ [6, 7, 8],
252
+ ],
253
+ },
254
+ },
255
+ };
256
+ const fieldMetadata = {
257
+ id: "f_child",
258
+ number: { count: 1 },
259
+ index: 1,
260
+ parent: { id: "f", number: {} },
261
+ } as FieldMetadataWrapper;
262
+ expect(getInfoValue(record, 0, fieldMetadata)).toStrictEqual(1);
263
+ expect(getInfoValue(record, 1, fieldMetadata)).toStrictEqual(4);
264
+ expect(getInfoValue(record, 2, fieldMetadata)).toStrictEqual(7);
265
+ });
266
+
267
+ test("field child count=1, parent count=* value=undefined", () => {
268
+ const record = { ...recordBase, data: { ...recordBase.data, n: {} } };
269
+ const fieldMetadata = {
270
+ id: "f_child",
271
+ number: { count: 1 },
272
+ index: 2,
273
+ parent: { id: "f", number: {} },
274
+ } as FieldMetadataWrapper;
275
+ expect(getInfoValue(record, 0, fieldMetadata)).toStrictEqual(null);
276
+ });
277
+
278
+ test("field child count=*, parent count=*", () => {
279
+ const record = {
280
+ ...recordBase,
281
+ data: {
282
+ ...recordBase.data,
283
+ n: {
284
+ f: [
285
+ [0, ["1a", "1b"], 2],
286
+ [3, ["4a", "4b"], 5],
287
+ [6, ["7a", "7b"], 8],
288
+ ],
289
+ },
290
+ },
291
+ };
292
+ const fieldMetadata = {
293
+ id: "f_child",
294
+ number: {},
295
+ index: 1,
296
+ parent: { id: "f", number: {} },
297
+ } as FieldMetadataWrapper;
298
+ expect(getInfoValue(record, 0, fieldMetadata)).toStrictEqual(["1a", "1b"]);
299
+ expect(getInfoValue(record, 1, fieldMetadata)).toStrictEqual(["4a", "4b"]);
300
+ expect(getInfoValue(record, 2, fieldMetadata)).toStrictEqual(["7a", "7b"]);
301
+ });
302
+
303
+ test("field child count=*, parent count=* value=undefined", () => {
304
+ const record = { ...recordBase, data: { ...recordBase.data, n: {} } };
305
+ const fieldMetadata = {
306
+ id: "f_child",
307
+ number: {},
308
+ index: 2,
309
+ parent: { id: "f", number: {} },
310
+ } as FieldMetadataWrapper;
311
+ expect(getInfoValue(record, 0, fieldMetadata)).toStrictEqual([]);
312
+ });
313
+
314
+ test("field child count=*, parent count=* categorical", () => {
315
+ const record = {
316
+ ...recordBase,
317
+ data: {
318
+ ...recordBase.data,
319
+ n: {
320
+ f: [
321
+ [0, ["cat1", "cat2"], 2],
322
+ [3, ["cat1", null], 5],
323
+ [6, [], 8],
324
+ ],
325
+ },
326
+ },
327
+ };
328
+ const fieldMetadata = {
329
+ id: "f_child",
330
+ type: "CATEGORICAL",
331
+ categories: {
332
+ cat1: { label: "my_label1", description: "my_description1" },
333
+ cat2: { label: "my_label2", description: "my_description2" },
334
+ },
335
+ number: { type: "OTHER" },
336
+ index: 1,
337
+ parent: { id: "f", type: "STRING", number: { type: "OTHER" } },
338
+ } as FieldMetadataWrapper;
339
+ expect(getInfoValue(record, 0, fieldMetadata)).toStrictEqual([
340
+ {
341
+ value: "cat1",
342
+ label: "my_label1",
343
+ description: "my_description1",
344
+ },
345
+ {
346
+ value: "cat2",
347
+ label: "my_label2",
348
+ description: "my_description2",
349
+ },
350
+ ]);
351
+ expect(getInfoValue(record, 1, fieldMetadata)).toStrictEqual([
352
+ {
353
+ value: "cat1",
354
+ label: "my_label1",
355
+ description: "my_description1",
356
+ },
357
+ null,
358
+ ]);
359
+ expect(getInfoValue(record, 2, fieldMetadata)).toStrictEqual([]);
360
+ });
361
+ });
362
+
363
+ describe("getInfoValues", () => {
364
+ test("multiple fields", () => {
365
+ const record = { ...recordBase, data: { ...recordBase.data, n: { f0: 0, f1: 1 } } };
366
+ const field0Metadata = { id: "f0", number: { count: 1 } } as FieldMetadataWrapper;
367
+ const field1Metadata = { id: "f1", number: { count: 1 } } as FieldMetadataWrapper;
368
+ expect(getInfoValues(record, 0, field0Metadata, field1Metadata)).toStrictEqual([0, 1]);
369
+ });
370
+
371
+ test("undefined fields", () => {
372
+ const record = { ...recordBase, data: { ...recordBase.data, n: { f0: 0 } } };
373
+ const field0Metadata = { id: "f0", number: { count: 1 } } as FieldMetadataWrapper;
374
+ expect(getInfoValues(record, 0, undefined, field0Metadata)).toStrictEqual([undefined, 0]);
375
+ });
376
+ });
377
+
378
+ describe("getSampleValue", () => {
379
+ const sample = { item: { data: { index: 1 } } } as SampleContainer;
380
+
381
+ test("field", () => {
382
+ const record = {
383
+ ...recordBase,
384
+ data: {
385
+ ...recordBase.data,
386
+ s: [{ f0: 0 }, { f0: 1 }],
387
+ },
388
+ };
389
+ const field0Metadata = { id: "f0", number: { count: 1 } } as FieldMetadataWrapper;
390
+ expect(getSampleValue(sample, record, 0, field0Metadata)).toStrictEqual(1);
391
+ });
392
+
393
+ test("field undefined", () => {
394
+ const record = {
395
+ ...recordBase,
396
+ data: {
397
+ ...recordBase.data,
398
+ s: [{}, {}],
399
+ },
400
+ };
401
+ expect(getSampleValue(sample, record, 0, undefined)).toStrictEqual(undefined);
402
+ });
403
+ });
404
+
405
+ describe("getSampleValues", () => {
406
+ const sample = { item: { data: { index: 1 } } } as SampleContainer;
407
+
408
+ test("multiple fields", () => {
409
+ const record = {
410
+ ...recordBase,
411
+ data: {
412
+ ...recordBase.data,
413
+ s: [
414
+ { f0: 0, f1: 1 },
415
+ { f0: 2, f1: 3 },
416
+ ],
417
+ },
418
+ };
419
+ const field0Metadata = { id: "f0", number: { count: 1 } } as FieldMetadataWrapper;
420
+ const field1Metadata = { id: "f1", number: { count: 1 } } as FieldMetadataWrapper;
421
+ expect(getSampleValues(sample, record, 0, field0Metadata, field1Metadata)).toStrictEqual([2, 3]);
422
+ });
423
+
424
+ test("undefined fields", () => {
425
+ const record = {
426
+ ...recordBase,
427
+ data: {
428
+ ...recordBase.data,
429
+ s: [{ f0: 0 }, { f0: 2 }],
430
+ },
431
+ };
432
+ const field0Metadata = { id: "f0", number: { count: 1 } } as FieldMetadataWrapper;
433
+ expect(getSampleValues(sample, record, 0, field0Metadata, undefined)).toStrictEqual([2, undefined]);
434
+ });
435
+ });
436
+
437
+ describe("isNumerical", () => {
438
+ test("FLOAT is numerical", () => {
439
+ expect(isNumerical({ type: "FLOAT" } as FieldMetadata)).toBe(true);
440
+ });
441
+
442
+ test("INTEGER is numerical", () => {
443
+ expect(isNumerical({ type: "INTEGER" } as FieldMetadata)).toBe(true);
444
+ });
445
+
446
+ test("STRING is not numerical", () => {
447
+ expect(isNumerical({ type: "STRING" } as FieldMetadata)).toBe(false);
448
+ });
449
+
450
+ test("abbreviate header long text", () => {
451
+ expect(abbreviateHeader("abcdefghijklmnopqrstuvwxyz")).toBe("abcdefghijk\u2026");
452
+ });
453
+
454
+ test("abbreviate header short text", () => {
455
+ expect(abbreviateHeader("abcdef")).toBe("abcdef");
456
+ });
457
+ });
458
+
459
+ describe("getInfoValueCount", () => {
460
+ test("getInfoValueCount count=1", () => {
461
+ const fieldMetadata = { id: "f0", number: { count: 1 } } as FieldMetadataWrapper;
462
+ expect(getInfoValueCount(recordBase, fieldMetadata)).toStrictEqual(1);
463
+ });
464
+
465
+ test("getInfoValueCount count=*", () => {
466
+ const record = { ...recordBase, data: { ...recordBase.data, n: { f: [0, 1, 2, 3] } } };
467
+ const fieldMetadata = { id: "f", number: { type: "OTHER" } } as FieldMetadataWrapper;
468
+ expect(getInfoValueCount(record, fieldMetadata)).toStrictEqual(1); // not 4
469
+ });
470
+
471
+ test("getInfoValueCount parent=1 count=*", () => {
472
+ const fieldMetadata = {
473
+ id: "f_child",
474
+ number: { type: "OTHER" },
475
+ index: 2,
476
+ parent: { id: "f", number: { count: 1 } },
477
+ } as FieldMetadataWrapper;
478
+ expect(getInfoValueCount(recordBase, fieldMetadata)).toStrictEqual(1);
479
+ });
480
+
481
+ test("getInfoValueCount parent=* count=1", () => {
482
+ const record = {
483
+ ...recordBase,
484
+ data: {
485
+ ...recordBase.data,
486
+ n: {
487
+ f: [[], [0, 1], [2, 3, 4]],
488
+ },
489
+ },
490
+ };
491
+ const fieldMetadata = {
492
+ id: "f_child",
493
+ number: { count: 1 },
494
+ index: 2,
495
+ parent: { id: "f", number: { type: "OTHER" } },
496
+ } as FieldMetadataWrapper;
497
+ expect(getInfoValueCount(record, fieldMetadata)).toStrictEqual(3);
498
+ });
499
+ });
500
+
501
+ describe("getSampleValueCount", () => {
502
+ test("getInfoValueCount count=1", () => {
503
+ const fieldMetadata = { id: "f0", number: { count: 1 } } as FieldMetadataWrapper;
504
+ expect(getInfoValueCount(recordBase, fieldMetadata)).toStrictEqual(1);
505
+ });
506
+
507
+ test("getSampleValueCount count=*", () => {
508
+ const sample = { item: { data: { index: 1 } } } as SampleContainer;
509
+
510
+ const record = {
511
+ ...recordBase,
512
+ data: {
513
+ ...recordBase.data,
514
+ s: [{ f: [0, 1] }, { f: [2, 3, 4] }],
515
+ },
516
+ };
517
+
518
+ const fieldMetadata = { id: "f", number: { type: "OTHER" } } as FieldMetadataWrapper;
519
+ expect(getSampleValueCount(sample, record, fieldMetadata)).toStrictEqual(1); // 1, not 3
520
+ });
521
+ });
522
+
523
+ describe("getInfoField(s)", () => {
524
+ const fieldMetadata = { id: "f", number: { type: "OTHER" } } as FieldMetadataWrapper;
525
+ const vcfMetadata = {
526
+ fieldMap: { "INFO/f": fieldMetadata },
527
+ } as Partial<VcfMetadataContainer> as VcfMetadataContainer;
528
+
529
+ test("get field", () => {
530
+ expect(getInfoField(vcfMetadata, "f")).toStrictEqual(fieldMetadata);
531
+ });
532
+
533
+ test("get field undefined", () => {
534
+ const vcfMetadata = {
535
+ fieldMap: {},
536
+ } as Partial<VcfMetadataContainer> as VcfMetadataContainer;
537
+ expect(getInfoField(vcfMetadata, "f")).toStrictEqual(undefined);
538
+ });
539
+
540
+ test("get fields", () => {
541
+ const fieldMetadata0 = { id: "f0", number: { type: "OTHER" } } as FieldMetadataWrapper;
542
+ const fieldMetadata1 = { id: "f1", number: { type: "OTHER" } } as FieldMetadataWrapper;
543
+ const vcfMetadata = {
544
+ fieldMap: { "INFO/f0": fieldMetadata0, "INFO/f1": fieldMetadata1 },
545
+ } as Partial<VcfMetadataContainer> as VcfMetadataContainer;
546
+ expect(getInfoFields(vcfMetadata, "f0", "f1")).toStrictEqual([fieldMetadata0, fieldMetadata1]);
547
+ });
548
+
549
+ test("get fields undefined", () => {
550
+ const fieldMetadata0 = { id: "f0", number: { type: "OTHER" } } as FieldMetadataWrapper;
551
+ const vcfMetadata = {
552
+ fieldMap: { "INFO/f0": fieldMetadata0 },
553
+ } as Partial<VcfMetadataContainer> as VcfMetadataContainer;
554
+ expect(getInfoFields(vcfMetadata, "f0", "f1")).toStrictEqual([fieldMetadata0, undefined]);
555
+ });
556
+ });
557
+
558
+ describe("getHeaderValue", () => {
559
+ const vcfMetadata = {
560
+ lines: ["##my_key=my_value"],
561
+ } as Partial<VcfMetadataContainer> as VcfMetadataContainer;
562
+ test("get exists", () => {
563
+ expect(getHeaderValue(vcfMetadata, "my_key")).toStrictEqual("my_value");
564
+ });
565
+
566
+ test("get not exists", () => {
567
+ const vcfMetadata = {
568
+ lines: ["##my_key2=my_value"],
569
+ } as Partial<VcfMetadataContainer> as VcfMetadataContainer;
570
+ expect(getHeaderValue(vcfMetadata, "my_key")).toStrictEqual(null);
571
+ });
572
+ });
573
+
574
+ describe("parseContigIds", () => {
575
+ test("get not exists", () => {
576
+ const vcfMetadata = {
577
+ lines: ["##contig=<ID=chr1,length=248956422>", "##contig=<length=242193529,ID=chr2>"],
578
+ } as Partial<VcfMetadataContainer> as VcfMetadataContainer;
579
+
580
+ expect(parseContigIds(vcfMetadata)).toStrictEqual(["chr1", "chr2"]);
581
+ });
582
+
583
+ test("invalid", () => {
584
+ const vcfMetadata = {
585
+ lines: ["##contig=<KEY=value>"],
586
+ } as Partial<VcfMetadataContainer> as VcfMetadataContainer;
587
+
588
+ expect(() => parseContigIds(vcfMetadata)).toThrow();
589
+ });
590
+ });
591
+
592
+ test("createFieldMap", () => {
593
+ const f0 = { id: "f0" } as FieldMetadata;
594
+ const f1 = { id: "f1" } as FieldMetadata;
595
+ const p = {
596
+ id: "p",
597
+ nested: { items: [{ id: "c0" } as FieldMetadata, { id: "c1" } as FieldMetadata] },
598
+ } as FieldMetadata;
599
+
600
+ const vcfMetadata = {
601
+ info: { f0, f1 },
602
+ format: {
603
+ p,
604
+ },
605
+ } as Partial<VcfMetadataContainer> as VcfMetadataContainer;
606
+ expect(createFieldMap(vcfMetadata)).toStrictEqual({
607
+ "INFO/f0": { id: "f0", index: 0 },
608
+ "INFO/f1": { id: "f1", index: 1 },
609
+ "FORMAT/p": {
610
+ id: "p",
611
+ index: 0,
612
+ nested: {
613
+ items: [
614
+ { id: "c0", index: 0 },
615
+ { id: "c1", index: 1 },
616
+ ],
617
+ },
618
+ },
619
+ "FORMAT/p/c0": { id: "c0", index: 0 },
620
+ "FORMAT/p/c1": { id: "c1", index: 1 },
621
+ });
622
+ });
623
+
624
+ describe("getInfoFieldsRegex", () => {
625
+ const fieldMetadata0 = { id: "f", number: { type: "OTHER" } } as FieldMetadataWrapper;
626
+ const fieldMetadata1 = { id: "f_with_postfix", number: { type: "OTHER" } } as FieldMetadataWrapper;
627
+ const fieldMetadata2 = { id: "f", number: { type: "OTHER" } } as FieldMetadataWrapper;
628
+ const vcfMetadata = {
629
+ fieldMap: { "INFO/f": fieldMetadata0, "INFO/fx": fieldMetadata1, "FORMAT/f": fieldMetadata2 },
630
+ } as Partial<VcfMetadataContainer> as VcfMetadataContainer;
631
+
632
+ test("get", () => {
633
+ expect(getInfoFieldsRegex(vcfMetadata, /^f$/)).toStrictEqual([fieldMetadata0]);
634
+ });
635
+ });
636
+
637
+ describe("getSampleFieldsRegex", () => {
638
+ const fieldMetadata0 = { id: "f", number: { type: "OTHER" } } as FieldMetadataWrapper;
639
+ const fieldMetadata1 = { id: "fx", number: { type: "OTHER" } } as FieldMetadataWrapper;
640
+ const fieldMetadata2 = { id: "fx", number: { type: "OTHER" } } as FieldMetadataWrapper;
641
+ const vcfMetadata = {
642
+ fieldMap: { "FORMAT/f": fieldMetadata0, "FORMAT/fx": fieldMetadata1, "INFO/f": fieldMetadata2 },
643
+ } as Partial<VcfMetadataContainer> as VcfMetadataContainer;
644
+
645
+ test("get", () => {
646
+ expect(getSampleFieldsRegex(vcfMetadata, /^f$/)).toStrictEqual([fieldMetadata0]);
647
+ });
648
+ });
649
+ });
package/tsconfig.json CHANGED
@@ -4,12 +4,16 @@
4
4
  "target": "ESNext",
5
5
  "module": "ESNext",
6
6
  "moduleResolution": "bundler",
7
+ "allowImportingTsExtensions": true,
7
8
  "allowSyntheticDefaultImports": true,
8
9
  "esModuleInterop": true,
9
10
  "jsx": "preserve",
10
11
  "jsxImportSource": "solid-js",
11
- "types": ["vite/client"],
12
+ "types": [
13
+ "vite/client"
14
+ ],
12
15
  "noEmit": true,
13
- "isolatedModules": true
16
+ "isolatedModules": true,
17
+ "noUncheckedIndexedAccess": true
14
18
  }
15
19
  }