@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,508 @@
1
+ import { ConfigCellCustom } from "../../types/configCells";
2
+ import { Genotype, InfoMetadata, ValueFlag, ValueFloat, ValueString, VcfRecord } from "@molgenis/vip-report-vcf";
3
+ import { Item } from "@molgenis/vip-report-api";
4
+ import { getSampleLabel } from "../sample.ts";
5
+ import {
6
+ CellValueClinVar,
7
+ CellValueCustom,
8
+ CellValueGene,
9
+ CellValueGenotype,
10
+ CellValueGnomAd,
11
+ CellValueHpo,
12
+ CellValueInheritanceModes,
13
+ CellValueLocus,
14
+ CellValueVipC,
15
+ CellValueVipCS,
16
+ CellValueVkgl,
17
+ } from "../../types/configCellComposed";
18
+ import {
19
+ getInfoFields,
20
+ getInfoNestedField,
21
+ getInfoNestedFields,
22
+ getInfoValue,
23
+ getInfoValueCount,
24
+ getInfoValues,
25
+ getSampleField,
26
+ getSampleFields,
27
+ getSampleValue,
28
+ getSampleValues,
29
+ ValueCategorical,
30
+ } from "../vcf.ts";
31
+ import { VariantType } from "../variantType.ts";
32
+ import { composeSample, MetadataContainer, SampleContainer, VcfMetadataContainer } from "../api.ts";
33
+ import { href } from "../utils.ts";
34
+ import { ConfigJsonFieldComposed } from "../../types/config";
35
+ import { getDescription, getLabel } from "./config.ts";
36
+ import { ConfigInvalidError } from "../error.ts";
37
+
38
+ export function initConfigCellComposed(
39
+ configStatic: ConfigJsonFieldComposed,
40
+ variantType: VariantType,
41
+ metadata: MetadataContainer,
42
+ sample: SampleContainer | null,
43
+ ): ConfigCellCustom<CellValueCustom> | null {
44
+ const id = configStatic.name;
45
+ let fieldConfig: ConfigCellCustom<CellValueCustom> | null;
46
+ switch (id) {
47
+ case "clinVar":
48
+ fieldConfig = createConfigFieldCustomClinVar(configStatic, metadata.records);
49
+ break;
50
+ case "gene":
51
+ fieldConfig = createConfigFieldCustomGene(configStatic, metadata.records);
52
+ break;
53
+ case "genotype":
54
+ fieldConfig = createConfigFieldCustomGenotype(configStatic, metadata.records, sample);
55
+ break;
56
+ case "genotype_maternal":
57
+ fieldConfig = createConfigFieldCustomGenotypeMaternal(configStatic, metadata.records, sample);
58
+ break;
59
+ case "genotype_paternal":
60
+ fieldConfig = createConfigFieldCustomGenotypePaternal(configStatic, metadata.records, sample);
61
+ break;
62
+ case "gnomAdAf":
63
+ fieldConfig = createConfigFieldCustomGnomAd(configStatic, metadata.records);
64
+ break;
65
+ case "hpo":
66
+ fieldConfig = createConfigFieldCustomHpo(configStatic, metadata.records);
67
+ break;
68
+ case "inheritancePattern":
69
+ fieldConfig = createConfigFieldCustomInheritancePattern(configStatic, metadata.records, sample);
70
+ break;
71
+ case "locus":
72
+ fieldConfig = createConfigFieldCustomLocus(configStatic, sample, variantType);
73
+ break;
74
+ case "vipC":
75
+ fieldConfig = createConfigFieldCustomVipC(configStatic, metadata.records, sample, variantType);
76
+ break;
77
+ case "vipCS":
78
+ fieldConfig = createConfigFieldCustomVipCS(configStatic, metadata.records, sample);
79
+ break;
80
+ case "vkgl":
81
+ fieldConfig = createConfigFieldCustomVkgl(configStatic, metadata.records);
82
+ break;
83
+ default:
84
+ throw new ConfigInvalidError(`unknown composed cell name '${id}'`);
85
+ }
86
+ return fieldConfig;
87
+ }
88
+
89
+ function createConfigFieldCustomClinVar(
90
+ config: ConfigJsonFieldComposed,
91
+ metadata: VcfMetadataContainer,
92
+ ): ConfigCellCustom<CellValueClinVar> | null {
93
+ const [fieldClnSig, fieldClnId, fieldClnRevStat] = getInfoNestedFields(
94
+ metadata,
95
+ "CSQ",
96
+ "clinVar_CLNSIG",
97
+ "clinVar_CLNID",
98
+ "clinVar_CLNREVSTAT",
99
+ );
100
+ if (fieldClnSig === undefined) return null;
101
+
102
+ return {
103
+ type: "composed",
104
+ id: "clinVar",
105
+ label: () => getLabel(config, "ClinVar"),
106
+ description: () => getDescription(config),
107
+ valueCount: (record: Item<VcfRecord>) => getInfoValueCount(record, fieldClnSig),
108
+ value: (record: Item<VcfRecord>, valueIndex: number): CellValueClinVar => {
109
+ const [clnSigs, clnIds, clnRevStats] = getInfoValues(
110
+ record,
111
+ valueIndex,
112
+ fieldClnSig,
113
+ fieldClnId,
114
+ fieldClnRevStat,
115
+ ) as [ValueCategorical[], number[] | undefined, ValueCategorical[] | undefined];
116
+
117
+ return {
118
+ clnSigs,
119
+ clnIds,
120
+ clnRevStats,
121
+ };
122
+ },
123
+ };
124
+ }
125
+
126
+ function createConfigFieldCustomGene(
127
+ config: ConfigJsonFieldComposed,
128
+ metadata: VcfMetadataContainer,
129
+ ): ConfigCellCustom<CellValueGene> | null {
130
+ const [fieldSymbol, fieldGene, fieldIncPen, fieldSymbolSource] = getInfoNestedFields(
131
+ metadata,
132
+ "CSQ",
133
+ "SYMBOL",
134
+ "Gene",
135
+ "IncompletePenetrance",
136
+ "SYMBOL_SOURCE",
137
+ );
138
+ if (fieldSymbol === undefined) return null;
139
+
140
+ return {
141
+ type: "composed",
142
+ id: "gene",
143
+ label: () => getLabel(config, "Gene"),
144
+ description: () => getDescription(config),
145
+ valueCount: (record: Item<VcfRecord>) => getInfoValueCount(record, fieldSymbol),
146
+ value: (record: Item<VcfRecord>, valueIndex: number): CellValueGene => {
147
+ const [symbol, geneIdentifier, incompletePenetrance, symbolSource] = getInfoValues(
148
+ record,
149
+ valueIndex,
150
+ fieldSymbol,
151
+ fieldGene,
152
+ fieldIncPen,
153
+ fieldSymbolSource,
154
+ ) as [ValueString, ValueString | undefined, ValueCategorical | undefined, ValueString | undefined];
155
+
156
+ return {
157
+ symbol,
158
+ geneIdentifier,
159
+ incompletePenetrance,
160
+ symbolSource,
161
+ };
162
+ },
163
+ };
164
+ }
165
+
166
+ function createConfigFieldCustomGenotype(
167
+ config: ConfigJsonFieldComposed,
168
+ metadata: VcfMetadataContainer,
169
+ sample: SampleContainer | null,
170
+ ): ConfigCellCustom<CellValueGenotype> | null {
171
+ if (sample === null) return null;
172
+ return createConfigFieldCustomGenotypeForSample(config, metadata, sample);
173
+ }
174
+
175
+ function createConfigFieldCustomGenotypeMaternal(
176
+ config: ConfigJsonFieldComposed,
177
+ metadata: VcfMetadataContainer,
178
+ sample: SampleContainer | null,
179
+ ): ConfigCellCustom<CellValueGenotype> | null {
180
+ if (sample === null) return null;
181
+ const maternalSample = sample.maternalSample;
182
+ if (maternalSample === null) return null;
183
+ return createConfigFieldCustomGenotypeForSample(config, metadata, composeSample(maternalSample));
184
+ }
185
+
186
+ function createConfigFieldCustomGenotypePaternal(
187
+ config: ConfigJsonFieldComposed,
188
+ metadata: VcfMetadataContainer,
189
+ sample: SampleContainer | null,
190
+ ): ConfigCellCustom<CellValueGenotype> | null {
191
+ if (sample === null) return null;
192
+ const paternalSample = sample.paternalSample;
193
+ if (paternalSample === null) return null;
194
+ return createConfigFieldCustomGenotypeForSample(config, metadata, composeSample(paternalSample));
195
+ }
196
+
197
+ function createConfigFieldCustomGenotypeForSample(
198
+ config: ConfigJsonFieldComposed,
199
+ metadata: VcfMetadataContainer,
200
+ sample: SampleContainer,
201
+ ): ConfigCellCustom<CellValueGenotype> | null {
202
+ if (sample === null) return null;
203
+
204
+ const [fieldGt, fieldRepCn, fieldViab] = getSampleFields(metadata, "GT", "REPCN", "VIAB");
205
+ if (fieldGt === undefined) return null; // unlikely, but possible
206
+
207
+ const [fieldSvType, fieldRu, fieldRuMatch, fieldDisplayRu] = getInfoFields(
208
+ metadata,
209
+ "SVTYPE",
210
+ "RU",
211
+ "RUMATCH",
212
+ "DisplayRU",
213
+ );
214
+
215
+ return {
216
+ type: "composed",
217
+ id: "genotype",
218
+ label: () => getLabel(config, getSampleLabel(sample.item)),
219
+ description: () => getDescription(config),
220
+ valueCount: () => 1,
221
+ value: (record: Item<VcfRecord>, valueIndex: number): CellValueGenotype => {
222
+ const [genotype, repeatCount, viab] = getSampleValues(
223
+ sample,
224
+ record,
225
+ valueIndex,
226
+ fieldGt,
227
+ fieldRepCn,
228
+ fieldViab,
229
+ ) as [Genotype, ValueString | undefined, number | null | undefined];
230
+
231
+ const [svType, repeatUnitValue, repeatUnitMatch, displayRepeatUnit] = getInfoValues(
232
+ record,
233
+ valueIndex,
234
+ fieldSvType,
235
+ fieldRu,
236
+ fieldRuMatch,
237
+ fieldDisplayRu,
238
+ ) as [ValueString | undefined, ValueString | undefined, ValueFlag | undefined, ValueString | undefined];
239
+ return {
240
+ refAllele: record.data.r,
241
+ altAlleles: record.data.a,
242
+ genotype,
243
+ repeatCount,
244
+ svType,
245
+ repeatUnitValue,
246
+ repeatUnitMatch,
247
+ displayRepeatUnit,
248
+ viab,
249
+ };
250
+ },
251
+ };
252
+ }
253
+
254
+ function createConfigFieldCustomGnomAd(
255
+ config: ConfigJsonFieldComposed,
256
+ metadata: VcfMetadataContainer,
257
+ ): ConfigCellCustom<CellValueGnomAd> | null {
258
+ const [fieldGnomAdAf, fieldGnomAdCov, fieldGnomAdQc, fieldAlleleNum] = getInfoNestedFields(
259
+ metadata,
260
+ "CSQ",
261
+ "gnomAD_AF",
262
+ "gnomAD_COV",
263
+ "gnomAD_QC",
264
+ "ALLELE_NUM",
265
+ );
266
+ if (fieldGnomAdAf == null) return null;
267
+
268
+ return {
269
+ type: "composed",
270
+ id: "gnomAdAf",
271
+ label: () => getLabel(config, "gnomAD AF"),
272
+ description: () => getDescription(config, "gnomAD allele frequency"),
273
+ valueCount: (record: Item<VcfRecord>) => getInfoValueCount(record, fieldGnomAdAf),
274
+ value: (record: Item<VcfRecord>, valueIndex: number): CellValueGnomAd => {
275
+ const [gnomAdAf, gnomAdCov, gnomAdQcs, alleleNum] = getInfoValues(
276
+ record,
277
+ valueIndex,
278
+ fieldGnomAdAf,
279
+ fieldGnomAdCov,
280
+ fieldGnomAdQc,
281
+ fieldAlleleNum,
282
+ ) as [ValueFloat, ValueFloat | undefined, string[] | undefined, number | undefined];
283
+
284
+ return {
285
+ c: record.data.c,
286
+ p: record.data.p,
287
+ r: record.data.r,
288
+ a: record.data.a,
289
+ gnomAdAf,
290
+ gnomAdCov,
291
+ gnomAdQcs,
292
+ alleleNum,
293
+ };
294
+ },
295
+ };
296
+ }
297
+
298
+ function createConfigFieldCustomHpo(
299
+ config: ConfigJsonFieldComposed,
300
+ metadata: VcfMetadataContainer,
301
+ ): ConfigCellCustom<CellValueHpo> | null {
302
+ const [fieldHpo, fieldGadoPd] = getInfoNestedFields(metadata, "CSQ", "HPO", "GADO_PD");
303
+ if (fieldHpo == null) return null;
304
+
305
+ return {
306
+ type: "composed",
307
+ id: "hpo",
308
+ label: () => getLabel(config, "HPO"),
309
+ description: () => getDescription(config, "Human phenotype ontology matches"),
310
+ valueCount: (record: Item<VcfRecord>) => getInfoValueCount(record, fieldHpo),
311
+ value: (record: Item<VcfRecord>, valueIndex: number): CellValueHpo => {
312
+ const [hpos, gadoPd] = getInfoValues(record, valueIndex, fieldHpo, fieldGadoPd) as [
313
+ ValueCategorical[],
314
+ ValueCategorical | undefined,
315
+ ];
316
+
317
+ return {
318
+ hpos,
319
+ gadoPd,
320
+ };
321
+ },
322
+ };
323
+ }
324
+
325
+ function createConfigFieldCustomInheritancePattern(
326
+ config: ConfigJsonFieldComposed,
327
+ metadata: VcfMetadataContainer,
328
+ sample: SampleContainer | null,
329
+ ): ConfigCellCustom<CellValueInheritanceModes> | null {
330
+ const fieldInhModesGene = getInfoNestedField(metadata, "CSQ", "InheritanceModesGene");
331
+ if (fieldInhModesGene == null) return null;
332
+ const fieldVic = sample ? getSampleField(metadata, "VIC") : undefined;
333
+
334
+ return {
335
+ type: "composed",
336
+ id: "inheritancePattern",
337
+ label: () => getLabel(config, "Inh.Pat."),
338
+ description: () => getDescription(config, "Inheritance pattern"),
339
+ valueCount: (record: Item<VcfRecord>) => getInfoValueCount(record, fieldInhModesGene),
340
+ value: (record: Item<VcfRecord>, valueIndex: number): CellValueInheritanceModes => {
341
+ const inhModesGene = getInfoValue(record, valueIndex, fieldInhModesGene) as ValueCategorical[];
342
+ const vic = sample ? (getSampleValue(sample, record, valueIndex, fieldVic) as ValueFlag | undefined) : undefined;
343
+
344
+ return {
345
+ fieldInheritanceModesGene: fieldInhModesGene as InfoMetadata,
346
+ inheritanceModesGene: inhModesGene,
347
+ isPossibleCompound: vic,
348
+ };
349
+ },
350
+ };
351
+ }
352
+
353
+ function createConfigFieldCustomLocus(
354
+ config: ConfigJsonFieldComposed,
355
+ sample: SampleContainer | null,
356
+ variantType: VariantType,
357
+ ): ConfigCellCustom<CellValueLocus> {
358
+ const components = sample ? ["samples", sample.item.id] : [];
359
+ return {
360
+ type: "composed",
361
+ id: "locus",
362
+ label: () => getLabel(config, "Position"),
363
+ description: () => getDescription(config),
364
+ valueCount: () => 1,
365
+ value: (record: Item<VcfRecord>): CellValueLocus => ({
366
+ c: record.data.c,
367
+ p: record.data.p,
368
+ href: href([...components, "variants", variantType.id, "variant", record.id]),
369
+ }),
370
+ };
371
+ }
372
+
373
+ function createConfigFieldCustomVipC(
374
+ config: ConfigJsonFieldComposed,
375
+ metadata: VcfMetadataContainer,
376
+ sample: SampleContainer | null,
377
+ variantType: VariantType,
378
+ ): ConfigCellCustom<CellValueVipC> | null {
379
+ const [fieldVipC, fieldVipP] = getInfoNestedFields(metadata, "CSQ", "VIPC", "VIPP");
380
+ if (fieldVipC == null) return null;
381
+
382
+ const components = sample ? ["samples", sample.item.id] : [];
383
+
384
+ return {
385
+ type: "composed",
386
+ id: "vipC",
387
+ label: () => getLabel(config, "VIP"),
388
+ description: () => getDescription(config, "VIP classification"),
389
+ valueCount: (record: Item<VcfRecord>) => getInfoValueCount(record, fieldVipC),
390
+ value: (record: Item<VcfRecord>, valueIndex: number): CellValueVipC => {
391
+ const [vipC, vipP] = getInfoValues(record, valueIndex, fieldVipC, fieldVipP) as [
392
+ ValueCategorical,
393
+ string[] | undefined,
394
+ ];
395
+
396
+ return {
397
+ href: href([...components, "variants", variantType.id, "variant", record.id, "consequences", valueIndex]),
398
+ vipC,
399
+ vipP,
400
+ };
401
+ },
402
+ };
403
+ }
404
+
405
+ function createConfigFieldCustomVipCS(
406
+ config: ConfigJsonFieldComposed,
407
+ metadata: VcfMetadataContainer,
408
+ sample: SampleContainer | null,
409
+ ): ConfigCellCustom<CellValueVipCS> | null {
410
+ if (sample === null) return null;
411
+
412
+ const [fieldVipCS, fieldVipPS] = getSampleFields(metadata, "VIPC_S", "VIPP_S");
413
+ if (fieldVipCS == null) return null;
414
+
415
+ return {
416
+ type: "composed",
417
+ id: "vipCS",
418
+ label: () => getLabel(config, "VIP sample"),
419
+ description: () => getDescription(config, "VIP sample classification"),
420
+ valueCount: (record: Item<VcfRecord>) => (getSampleValue(sample, record, 0, fieldVipCS) as string[]).length,
421
+ value: (record: Item<VcfRecord>, valueIndex: number): CellValueVipCS => {
422
+ const [vipCS, vipPS] = getSampleValues(sample, record, 0, fieldVipCS, fieldVipPS) as [
423
+ ValueCategorical[],
424
+ string[] | undefined,
425
+ ];
426
+ return {
427
+ vipCS: vipCS[valueIndex]!,
428
+ vipPS: vipPS && vipPS[valueIndex]!.split("&"),
429
+ };
430
+ },
431
+ };
432
+ }
433
+
434
+ function createConfigFieldCustomVkgl(
435
+ config: ConfigJsonFieldComposed,
436
+ metadata: VcfMetadataContainer,
437
+ ): ConfigCellCustom<CellValueVkgl> | null {
438
+ const [
439
+ fieldVkglCl,
440
+ fieldVkglAmc,
441
+ fieldVkglErasmus,
442
+ fieldVkglLumc,
443
+ fieldVkglNki,
444
+ fieldVkglRadboud,
445
+ fieldVkglUmcg,
446
+ fieldVkglUmcu,
447
+ fieldVkglVumc,
448
+ ] = getInfoNestedFields(
449
+ metadata,
450
+ "CSQ",
451
+ "VKGL_CL",
452
+ "VKGL_AMC",
453
+ "VKGL_ERASMUS",
454
+ "VKGL_LUMC",
455
+ "VKGL_NKI",
456
+ "VKGL_RADBOUD_MUMC",
457
+ "VKGL_UMCG",
458
+ "VKGL_UMCU",
459
+ "VKGL_VUMC",
460
+ );
461
+ if (fieldVkglCl == null) return null;
462
+
463
+ return {
464
+ type: "composed",
465
+ id: "vkgl",
466
+ label: () => getLabel(config, "VKGL"),
467
+ description: () => getDescription(config, "VKGL consensus classification"),
468
+ valueCount: (record: Item<VcfRecord>) => getInfoValueCount(record, fieldVkglCl),
469
+ value: (record: Item<VcfRecord>, valueIndex: number): CellValueVkgl => {
470
+ const [vkglCl, vkglAmc, vkglErasmus, vkglLumc, vkglNki, vkglRadboudMumc, vkglUmcg, vkglUmcu, vkglVumc] =
471
+ getInfoValues(
472
+ record,
473
+ valueIndex,
474
+ fieldVkglCl,
475
+ fieldVkglAmc,
476
+ fieldVkglErasmus,
477
+ fieldVkglLumc,
478
+ fieldVkglNki,
479
+ fieldVkglRadboud,
480
+ fieldVkglUmcg,
481
+ fieldVkglUmcu,
482
+ fieldVkglVumc,
483
+ ) as [
484
+ ValueCategorical,
485
+ ValueCategorical | undefined,
486
+ ValueCategorical | undefined,
487
+ ValueCategorical | undefined,
488
+ ValueCategorical | undefined,
489
+ ValueCategorical | undefined,
490
+ ValueCategorical | undefined,
491
+ ValueCategorical | undefined,
492
+ ValueCategorical | undefined,
493
+ ];
494
+
495
+ return {
496
+ vkglCl,
497
+ vkglAmc,
498
+ vkglErasmus,
499
+ vkglLumc,
500
+ vkglNki,
501
+ vkglRadboudMumc,
502
+ vkglUmcg,
503
+ vkglUmcu,
504
+ vkglVumc,
505
+ };
506
+ },
507
+ };
508
+ }
@@ -0,0 +1,61 @@
1
+ import { ConfigJsonFieldGenotype, ConfigJsonFieldInfo } from "../../types/config";
2
+ import { CellValueGenotype, CellValueInfo, ConfigCellGenotype, ConfigCellInfo } from "../../types/configCells";
3
+ import { VcfRecord } from "@molgenis/vip-report-vcf";
4
+ import {
5
+ FieldMetadataWrapper,
6
+ getInfoFieldsRegex,
7
+ getInfoValue,
8
+ getInfoValueCount,
9
+ getSampleFieldsRegex,
10
+ getSampleValue,
11
+ getSampleValueCount,
12
+ } from "../vcf.ts";
13
+ import { Item } from "@molgenis/vip-report-api";
14
+ import { SampleContainer, VcfMetadataContainer } from "../api.ts";
15
+ import { getDescription, getLabel } from "./config.ts";
16
+
17
+ export function initConfigCellInfo(
18
+ configStatic: ConfigJsonFieldInfo,
19
+ metadata: VcfMetadataContainer,
20
+ ): ConfigCellInfo[] {
21
+ return getInfoFieldsRegex(metadata, new RegExp(`^${configStatic.name}$`))
22
+ .filter((field) => !field.nested)
23
+ .map((field) => createConfigFieldInfo(configStatic, field));
24
+ }
25
+
26
+ function createConfigFieldInfo(configStatic: ConfigJsonFieldInfo, field: FieldMetadataWrapper): ConfigCellInfo {
27
+ return {
28
+ type: "info",
29
+ field,
30
+ label: () => getLabel(configStatic, field.label || field.id),
31
+ description: () => getDescription(configStatic, field.description),
32
+ valueCount: (record: Item<VcfRecord>) => getInfoValueCount(record, field),
33
+ value: (record: Item<VcfRecord>, valueIndex: number): CellValueInfo => getInfoValue(record, valueIndex, field),
34
+ };
35
+ }
36
+
37
+ export function initConfigCellGenotype(
38
+ configStatic: ConfigJsonFieldGenotype,
39
+ metadata: VcfMetadataContainer,
40
+ sample: SampleContainer,
41
+ ): ConfigCellGenotype[] {
42
+ return getSampleFieldsRegex(metadata, new RegExp(`^${configStatic.name}$`))
43
+ .filter((field) => !field.nested)
44
+ .map((field) => createConfigFieldGenotype(configStatic, field, sample));
45
+ }
46
+
47
+ function createConfigFieldGenotype(
48
+ configStatic: ConfigJsonFieldGenotype,
49
+ field: FieldMetadataWrapper,
50
+ sample: SampleContainer,
51
+ ): ConfigCellGenotype {
52
+ return {
53
+ type: "genotype",
54
+ field,
55
+ label: () => getLabel(configStatic, field.label || field.id),
56
+ description: () => getDescription(configStatic, field.description),
57
+ valueCount: (record: Item<VcfRecord>) => getSampleValueCount(sample, record, field),
58
+ value: (record: Item<VcfRecord>, valueIndex: number): CellValueGenotype =>
59
+ getSampleValue(sample, record, valueIndex, field),
60
+ };
61
+ }
@@ -0,0 +1,126 @@
1
+ import { ConfigJsonFieldFixed } from "../../types/config";
2
+ import {
3
+ CellValueAlt,
4
+ CellValueChrom,
5
+ CellValueFilter,
6
+ CellValueId,
7
+ CellValuePos,
8
+ CellValueQual,
9
+ CellValueRef,
10
+ ConfigCellAlt,
11
+ ConfigCellChrom,
12
+ ConfigCellFilter,
13
+ ConfigCellFixed,
14
+ ConfigCellId,
15
+ ConfigCellPos,
16
+ ConfigCellQual,
17
+ ConfigCellRef,
18
+ } from "../../types/configCells";
19
+ import { Item } from "@molgenis/vip-report-api";
20
+ import { VcfRecord } from "@molgenis/vip-report-vcf";
21
+ import { UnexpectedEnumValueException } from "../error.ts";
22
+ import { getDescription, getLabel } from "./config.ts";
23
+
24
+ export function initConfigCellFixed(config: ConfigJsonFieldFixed): ConfigCellFixed {
25
+ let configField: ConfigCellFixed;
26
+ switch (config.name) {
27
+ case "chrom":
28
+ configField = createConfigFieldChrom(config);
29
+ break;
30
+ case "pos":
31
+ configField = createConfigFieldPos(config);
32
+ break;
33
+ case "id":
34
+ configField = createConfigFieldId(config);
35
+ break;
36
+ case "ref":
37
+ configField = createConfigFieldRef(config);
38
+ break;
39
+ case "alt":
40
+ configField = createConfigFieldAlt(config);
41
+ break;
42
+ case "qual":
43
+ configField = createConfigFieldQual(config);
44
+ break;
45
+ case "filter":
46
+ configField = createConfigFieldFilter(config);
47
+ break;
48
+ default:
49
+ throw new UnexpectedEnumValueException(config["name"]);
50
+ }
51
+ return configField;
52
+ }
53
+
54
+ function createConfigFieldChrom(config: ConfigJsonFieldFixed): ConfigCellChrom {
55
+ return {
56
+ type: "chrom",
57
+ label: () => getLabel(config, "Chromosome"),
58
+ description: () => getDescription(config),
59
+ value: (record: Item<VcfRecord>): CellValueChrom => record.data.c,
60
+ valueCount: () => 1,
61
+ };
62
+ }
63
+
64
+ function createConfigFieldPos(config: ConfigJsonFieldFixed): ConfigCellPos {
65
+ return {
66
+ type: "pos",
67
+ label: () => getLabel(config, "Position"),
68
+ description: () => getDescription(config),
69
+ value: (record: Item<VcfRecord>): CellValuePos => record.data.p,
70
+ valueCount: () => 1,
71
+ };
72
+ }
73
+
74
+ function createConfigFieldId(config: ConfigJsonFieldFixed): ConfigCellId {
75
+ return {
76
+ type: "id",
77
+ label: () => getLabel(config, "Ids"),
78
+ description: () => getDescription(config),
79
+ value: (record: Item<VcfRecord>): CellValueId => record.data.i,
80
+ valueCount: () => 1, // one list value
81
+ };
82
+ }
83
+
84
+ function createConfigFieldRef(config: ConfigJsonFieldFixed): ConfigCellRef {
85
+ return {
86
+ type: "ref",
87
+ label: () => getLabel(config, "Reference"),
88
+ description: () => getDescription(config, "Reference base(s)"),
89
+ value: (record: Item<VcfRecord>): CellValueRef => record.data.r,
90
+ valueCount: () => 1,
91
+ };
92
+ }
93
+
94
+ function createConfigFieldAlt(config: ConfigJsonFieldFixed): ConfigCellAlt {
95
+ return {
96
+ type: "alt",
97
+ label: () => getLabel(config, "Alternate(s)"),
98
+ description: () => getDescription(config, "Alternate base(s): list of alternate non-reference alleles"),
99
+ value: (record: Item<VcfRecord>): CellValueAlt => record.data.a,
100
+ valueCount: () => 1, // one list value
101
+ };
102
+ }
103
+
104
+ function createConfigFieldQual(config: ConfigJsonFieldFixed): ConfigCellQual {
105
+ return {
106
+ type: "qual",
107
+ label: () => getLabel(config, "Qual"),
108
+ description: () => getDescription(config, "Quality: phred-scaled quality score for the 'Alt' assertions"),
109
+ value: (record: Item<VcfRecord>): CellValueQual => record.data.q,
110
+ valueCount: () => 1,
111
+ };
112
+ }
113
+
114
+ function createConfigFieldFilter(config: ConfigJsonFieldFixed): ConfigCellFilter {
115
+ return {
116
+ type: "filter",
117
+ label: () => getLabel(config, "Filters"),
118
+ description: () =>
119
+ getDescription(
120
+ config,
121
+ "Filter status: PASS if this position has passed all filter, otherwise a list of codes for filters that fail",
122
+ ),
123
+ value: (record: Item<VcfRecord>): CellValueFilter => record.data.f,
124
+ valueCount: () => 1, // one list value
125
+ };
126
+ }