@sjcrh/proteinpaint-shared 2.78.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.
package/package.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "@sjcrh/proteinpaint-shared",
3
+ "version": "2.78.0-0",
4
+ "description": "ProteinPaint code that is shared between server and client-side workspaces",
5
+ "type": "module",
6
+ "main": "src/index.js",
7
+ "exports": {
8
+ "./*": "./src/*"
9
+ },
10
+ "directories": {
11
+ "test": "test"
12
+ },
13
+ "scripts": {
14
+ "test": "echo \"Error: no test specified\" && exit 1"
15
+ },
16
+ "author": "",
17
+ "license": "ISC"
18
+ }
@@ -0,0 +1,86 @@
1
+ ////////////////////////////////////
2
+ //
3
+ // shared between client and server
4
+ //
5
+ ////////////////////////////////////
6
+
7
+ import * as common from './common.js'
8
+ import * as bulk from './bulk.js'
9
+
10
+ export function parseheader(line, flag) {
11
+ const header = line.toLowerCase().split('\t')
12
+ if (header.length <= 1) return 'invalid file header for CNV'
13
+ const htry = (...lst) => {
14
+ for (const i of lst) {
15
+ const j = header.indexOf(i)
16
+ if (j != -1) return j
17
+ }
18
+ return -1
19
+ }
20
+ let i = htry('gene')
21
+ if (i == -1) return 'gene missing from header'
22
+ header[i] = 'gene'
23
+ i = htry('cnv')
24
+ if (i == -1) return 'CNV missing from header'
25
+ header[i] = 'cnv'
26
+ i = htry('sample', 'sample_name', 'tumor_sample_barcode')
27
+ if (i != -1) header[i] = 'sample'
28
+ i = htry('patient', 'donor', 'target_case_id')
29
+ if (i != -1) header[i] = 'patient'
30
+ i = htry('disease')
31
+ if (i != -1) header[i] = 'disease'
32
+ i = htry('origin')
33
+ if (i != -1) header[i] = 'origin'
34
+ i = htry('sampletype', 'sample type', 'sample_type')
35
+ if (i != -1) header[i] = 'sampletype'
36
+ flag.cnv.header = header
37
+ flag.cnv.loaded = true
38
+ return false
39
+ }
40
+
41
+ export function parseline(i, line, flag) {
42
+ if (line == '' || line[0] == '#') return
43
+ const lst = line.split('\t')
44
+ const m = {}
45
+ for (let j = 0; j < flag.cnv.header.length; j++) {
46
+ m[flag.cnv.header[j]] = lst[j]
47
+ }
48
+ if (!m.gene) {
49
+ flag.cnv.badlines.push([i, 'missing gene', lst])
50
+ return
51
+ }
52
+ if (!m.cnv) {
53
+ flag.cnv.badlines.push([i, 'missing cnv value', lst])
54
+ return
55
+ }
56
+ const value = m.cnv.toLowerCase()
57
+ switch (value) {
58
+ case 'amplification':
59
+ case 'gain':
60
+ m.class = common.mclasscnvgain
61
+ break
62
+ case 'deletion':
63
+ case 'loss':
64
+ m.class = common.mclasscnvloss
65
+ break
66
+ case 'loh':
67
+ m.class = common.mclasscnvloh
68
+ break
69
+ default:
70
+ flag.cnv.badlines.push([i, 'invalid cnv value: ' + m.cnv, lst])
71
+ m.class = null
72
+ }
73
+ if (!m.class) {
74
+ return
75
+ }
76
+ if (bulk.parsesample(m, flag, i, lst, flag.cnv.badlines)) {
77
+ return
78
+ }
79
+ m.dt = common.dtcnv
80
+ flag.good++
81
+ const n = flag.geneToUpper ? m.gene.toUpperCase() : m.gene
82
+ if (!(n in flag.data)) {
83
+ flag.data[n] = []
84
+ }
85
+ flag.data[n].push(m)
86
+ }
@@ -0,0 +1,124 @@
1
+ ////////////////////////////////////
2
+ //
3
+ // shared between client and server
4
+ //
5
+ ////////////////////////////////////
6
+
7
+ import * as common from './common.js'
8
+ import * as bulk from './bulk.js'
9
+
10
+ export function parseheader(line, flag) {
11
+ const header = line.toLowerCase().split('\t')
12
+ if (header.length <= 1) return 'invalid header line for intragenic deletion'
13
+ const htry = (...lst) => {
14
+ for (const i of lst) {
15
+ const j = header.indexOf(i)
16
+ if (j != -1) return j
17
+ }
18
+ return -1
19
+ }
20
+ let i = htry('gene')
21
+ if (i == -1) return 'gene missing from header'
22
+ header[i] = 'gene'
23
+ i = htry(
24
+ 'annovar_isoform',
25
+ 'mrna_accession',
26
+ 'mrna accession',
27
+ 'refseq_mrna_id',
28
+ 'annovar_sj_filter_isoform',
29
+ 'refseq',
30
+ 'isoform'
31
+ )
32
+ if (i == -1) return 'isoform missing from header'
33
+ header[i] = 'isoform'
34
+ i = htry('rnaposition')
35
+ if (i != -1) {
36
+ header[i] = 'rnaposition'
37
+ i = htry('rnadellength')
38
+ if (i == -1) return 'rnadellength is required when rnaPosition is used'
39
+ header[i] = 'rnadellength'
40
+ }
41
+ i = htry('chromosome', 'chr')
42
+ if (i != -1) {
43
+ header[i] = 'chr'
44
+ i = htry('chr_start')
45
+ if (i == -1) return 'chr_start is required when chr is used'
46
+ header[i] = 'chrpos1'
47
+ i = htry('chr_stop')
48
+ if (i == -1) return 'chr_stop is required when chr is used'
49
+ header[i] = 'chrpos2'
50
+ }
51
+
52
+ i = htry('sample', 'sample_name', 'tumor_sample_barcode')
53
+ if (i != -1) header[i] = 'sample'
54
+ i = htry('patient', 'donor', 'target_case_id')
55
+ if (i != -1) header[i] = 'patient'
56
+ i = htry('disease')
57
+ if (i != -1) header[i] = 'disease'
58
+ i = htry('origin')
59
+ if (i != -1) header[i] = 'origin'
60
+ i = htry('sampletype', 'sample type', 'sample_type')
61
+ if (i != -1) header[i] = 'sampletype'
62
+ flag.del.header = header
63
+ flag.del.loaded = true
64
+ return false
65
+ }
66
+
67
+ export function parseline(i, line, flag) {
68
+ if (line == '' || line[0] == '#') return
69
+ const lst = line.split('\t')
70
+ const m = {}
71
+ for (let j = 0; j < flag.del.header.length; j++) {
72
+ if (lst[j] == undefined) break
73
+ m[flag.del.header[j]] = lst[j]
74
+ }
75
+ if (!m.gene) {
76
+ flag.del.badlines.push([i, 'missing gene', lst])
77
+ return
78
+ }
79
+ if (m.rnaposition) {
80
+ let v = Number.parseInt(m.rnaposition)
81
+ if (Number.isNaN(v) || v < 0) {
82
+ flag.del.badlines.push([i, 'invalid rnaPosition value', lst])
83
+ return
84
+ }
85
+ m.rnaposition = v
86
+ if (!m.rnadellength) {
87
+ flag.del.badlines.push([i, 'missing rnaDellength value', lst])
88
+ return
89
+ }
90
+ v = Number.parseInt(m.rnadellength)
91
+ if (Number.isNaN(v) || v < 0) {
92
+ flag.del.badlines.push([i, 'invalid rnaDellength value', lst])
93
+ return
94
+ }
95
+ m.rnadellength = v
96
+ }
97
+ if (m.chr) {
98
+ let v = Number.parseInt(m.chrpos1)
99
+ if (Number.isNaN(v) || v < 0) {
100
+ flag.del.badlines.push([i, 'invalid chr_start value', lst])
101
+ return
102
+ }
103
+ m.chrpos1 = v
104
+ v = Number.parseInt(m.chrpos2)
105
+ if (Number.isNaN(v) || v < 0) {
106
+ flag.del.badlines.push([i, 'invalid chr_stop value', lst])
107
+ return
108
+ }
109
+ m.chrpos2 = v
110
+ }
111
+
112
+ if (bulk.parsesample(m, flag, i, lst, flag.del.badlines)) {
113
+ return
114
+ }
115
+ m.dt = common.dtdel
116
+ m.class = common.mclassdel
117
+ m.mname = 'DEL'
118
+ flag.good++
119
+ var n = flag.geneToUpper ? m.gene.toUpperCase() : m.gene
120
+ if (!(n in flag.data)) {
121
+ flag.data[n] = []
122
+ }
123
+ flag.data[n].push(m)
124
+ }
@@ -0,0 +1,123 @@
1
+ ////////////////////////////////////
2
+ //
3
+ // shared between client and server
4
+ //
5
+ ////////////////////////////////////
6
+
7
+ import * as common from './common.js'
8
+ import * as bulk from './bulk.js'
9
+
10
+ export function parseheader(line, flag) {
11
+ const header = line.toLowerCase().split('\t')
12
+ if (header.length <= 1) return 'invalid header line for ITD'
13
+ const htry = (...lst) => {
14
+ for (const i of lst) {
15
+ const j = header.indexOf(i)
16
+ if (j != -1) return j
17
+ }
18
+ return -1
19
+ }
20
+ let i = htry('gene')
21
+ if (i == -1) return 'gene missing from header'
22
+ header[i] = 'gene'
23
+ i = htry(
24
+ 'annovar_isoform',
25
+ 'mrna_accession',
26
+ 'mrna accession',
27
+ 'refseq_mrna_id',
28
+ 'annovar_sj_filter_isoform',
29
+ 'refseq',
30
+ 'isoform'
31
+ )
32
+ if (i == -1) return 'isoform missing from header'
33
+ header[i] = 'isoform'
34
+ i = htry('rnaposition')
35
+ if (i != -1) {
36
+ header[i] = 'rnaposition'
37
+ i = htry('rnaduplength')
38
+ if (i == -1) return 'rnaduplength is required when rnaposition is present'
39
+ header[i] = 'rnaduplength'
40
+ }
41
+ i = htry('chromosome', 'chr')
42
+ if (i != -1) {
43
+ header[i] = 'chr'
44
+ i = htry('chr_start')
45
+ if (i == -1) return 'chr_start is required when chr is present'
46
+ header[i] = 'chrpos1'
47
+ i = htry('chr_stop')
48
+ if (i == -1) return 'chr_stop is required when chr is present'
49
+ header[i] = 'chrpos2'
50
+ }
51
+
52
+ i = htry('sample', 'sample_name', 'tumor_sample_barcode')
53
+ if (i != -1) header[i] = 'sample'
54
+ i = htry('patient', 'donor', 'target_case_id')
55
+ if (i != -1) header[i] = 'patient'
56
+ i = htry('disease')
57
+ if (i != -1) header[i] = 'disease'
58
+ i = htry('origin')
59
+ if (i != -1) header[i] = 'origin'
60
+ i = htry('sampletype', 'sample type', 'sample_type')
61
+ if (i != -1) header[i] = 'sampletype'
62
+ flag.itd.header = header
63
+ flag.itd.loaded = true
64
+ return false
65
+ }
66
+
67
+ export function parseline(i, line, flag) {
68
+ if (line == '' || line[0] == '#') return
69
+ const lst = line.split('\t')
70
+ const m = {}
71
+ for (let j = 0; j < flag.itd.header.length; j++) {
72
+ if (lst[j] == undefined) break
73
+ m[flag.itd.header[j]] = lst[j]
74
+ }
75
+ if (!m.gene) {
76
+ flag.itd.badlines.push([i, 'missing gene', lst])
77
+ return
78
+ }
79
+ if (m.rnaposition) {
80
+ let v = Number.parseInt(m.rnaposition)
81
+ if (Number.isNaN(v) || v < 0) {
82
+ flag.itd.badlines.push([i, 'invalid rnaPosition value', lst])
83
+ return
84
+ }
85
+ m.rnaposition = v
86
+ if (!m.rnaduplength) {
87
+ flag.itd.badlines.push([i, 'missing rnaDuplength value', lst])
88
+ return
89
+ }
90
+ v = Number.parseInt(m.rnaduplength)
91
+ if (Number.isNaN(v) || v < 0) {
92
+ flag.itd.badlines.push([i, 'invalid rnaDuplength value', lst])
93
+ return
94
+ }
95
+ m.rnaduplength = v
96
+ }
97
+ if (m.chr) {
98
+ let v = Number.parseInt(m.chrpos1)
99
+ if (Number.isNaN(v) || v < 0) {
100
+ flag.itd.badlines.push([i, 'invalid chr_start value', lst])
101
+ return
102
+ }
103
+ m.chrpos1 = v
104
+ v = Number.parseInt(m.chrpos2)
105
+ if (Number.isNaN(v) || v < 0) {
106
+ flag.itd.badlines.push([i, 'invalid chr_stop value', lst])
107
+ return
108
+ }
109
+ m.chrpos2 = v
110
+ }
111
+ if (bulk.parsesample(m, flag, i, lst, flag.itd.badlines)) {
112
+ return
113
+ }
114
+ m.dt = common.dtitd
115
+ m.class = common.mclassitd
116
+ m.mname = 'ITD'
117
+ flag.good++
118
+ var n = flag.geneToUpper ? m.gene.toUpperCase() : m.gene
119
+ if (!(n in flag.data)) {
120
+ flag.data[n] = []
121
+ }
122
+ flag.data[n].push(m)
123
+ }
package/src/bulk.js ADDED
@@ -0,0 +1,197 @@
1
+ ////////////////////////////////////
2
+ //
3
+ // shared between client and server
4
+ //
5
+ ////////////////////////////////////
6
+
7
+ import * as common from './common.js'
8
+
9
+ export default {}
10
+
11
+ export function init_bulk_flag(genome) {
12
+ if (!genome) {
13
+ return null
14
+ }
15
+ const mclasslabel2key = {}
16
+ for (const n in common.mclass) {
17
+ mclasslabel2key[common.mclass[n].label.toUpperCase()] = n
18
+ }
19
+ return {
20
+ genome: genome,
21
+ mclasslabel2key: mclasslabel2key,
22
+ data: {},
23
+ sample2disease: {}, // (proof) k: sample, v: disease
24
+ // will only record this when origin is used
25
+ patient2st: {},
26
+ // k: patient, v: { k: sampletype, v: sample }
27
+ // new sample names always override old
28
+ good: 0,
29
+ geneToUpper: true, // option to not force uppercase on gene names
30
+ snv: {
31
+ loaded: false,
32
+ header: null,
33
+ badlines: [],
34
+ // jinghui: based on missense/silent ratio of entire dataset to decide whether to include silent when importing...
35
+ // hard-coded class codes
36
+ missense: 0,
37
+ silent: 0
38
+ },
39
+ svjson: {
40
+ loaded: false,
41
+ header: null,
42
+ badlines: []
43
+ },
44
+ fusion: {
45
+ loaded: false,
46
+ header: null,
47
+ badlines: [],
48
+ original: []
49
+ },
50
+ sv: {
51
+ loaded: false,
52
+ header: null,
53
+ badlines: [],
54
+ original: []
55
+ },
56
+ cnv: {
57
+ loaded: false,
58
+ header: null,
59
+ badlines: []
60
+ },
61
+ itd: {
62
+ loaded: false,
63
+ header: null,
64
+ badlines: []
65
+ },
66
+ del: {
67
+ loaded: false,
68
+ header: null,
69
+ badlines: []
70
+ },
71
+ truncation: {
72
+ loaded: false,
73
+ header: null,
74
+ badlines: []
75
+ }
76
+ }
77
+ }
78
+
79
+ export function parsesample(m, flag, i, lst, badline) {
80
+ let variantorigin = common.moriginsomatic
81
+ if (m.sampletype) {
82
+ const s = m.sampletype.toLowerCase()
83
+ switch (s) {
84
+ case 'relapse':
85
+ variantorigin = common.moriginrelapse
86
+ break
87
+ case 'germline':
88
+ variantorigin = common.morigingermline
89
+ break
90
+ case 'somatic':
91
+ case 'diagnosis':
92
+ break
93
+ }
94
+ if (m.sample) {
95
+ if (m.patient) {
96
+ // good
97
+ } else {
98
+ m.patient = m.sample + ' ' + m.sampletype
99
+ }
100
+ } else {
101
+ if (m.patient) {
102
+ m.sample = m.patient + ' ' + m.sampletype
103
+ } else {
104
+ // neither sample or patient, will quit later
105
+ }
106
+ }
107
+ } else {
108
+ if (m.patient) {
109
+ if (m.sample) {
110
+ m.sampletype = m.sample
111
+ } else {
112
+ m.sample = m.sampletype = m.patient
113
+ }
114
+ } else {
115
+ if (m.sample) {
116
+ m.sampletype = m.sample
117
+ } else {
118
+ // no patient/sample, will quit later
119
+ }
120
+ }
121
+ }
122
+ if (m.origin) {
123
+ // override existing variantorigin
124
+ const s = m.origin.toLowerCase()
125
+ switch (s) {
126
+ case 'r':
127
+ case 'relapse':
128
+ variantorigin = common.moriginrelapse
129
+ m.isrim2 = true
130
+ break
131
+ case 'g':
132
+ case 'germline':
133
+ variantorigin = common.morigingermline
134
+ m.isrim1 = true
135
+ break
136
+ case 'gp':
137
+ case 'germline pathogenic':
138
+ variantorigin = common.morigingermlinepathogenic
139
+ m.isrim1 = true
140
+ break
141
+ case 'gnp':
142
+ case 'germline nonpathogenic':
143
+ case 'germline non-pathogenic':
144
+ variantorigin = common.morigingermlinenonpathogenic
145
+ m.isrim1 = true
146
+ break
147
+ case 's':
148
+ case 'somatic':
149
+ case 'diagnosis':
150
+ variantorigin = common.moriginsomatic
151
+ break
152
+ }
153
+ }
154
+ m.origin = variantorigin
155
+
156
+ if (!m.sample && !m.patient) {
157
+ // will not go into sample table
158
+ return
159
+ }
160
+
161
+ const nopatientname = 'no patient/individual name'
162
+ let p
163
+ if (m.patient) {
164
+ if (!flag.patient2st[m.patient]) {
165
+ flag.patient2st[m.patient] = {}
166
+ }
167
+ flag.patient2st[m.patient][m.sampletype] = m.sample
168
+ } else {
169
+ if (!flag.patient2st[nopatientname]) {
170
+ flag.patient2st[nopatientname] = {}
171
+ }
172
+ flag.patient2st[nopatientname][m.sampletype] = m.sample
173
+ }
174
+
175
+ if (m.sample) {
176
+ if (m.disease) {
177
+ if (m.sample in flag.sample2disease) {
178
+ if (m.disease != flag.sample2disease[m.sample]) {
179
+ flag.snv.badlines.push([
180
+ i,
181
+ 'conflict of disease types for sample "' +
182
+ m.sample +
183
+ '": ' +
184
+ m.disease +
185
+ ', ' +
186
+ flag.sample2disease[m.sample],
187
+ lst
188
+ ])
189
+ return true
190
+ }
191
+ } else {
192
+ flag.sample2disease[m.sample] = m.disease
193
+ }
194
+ }
195
+ }
196
+ return false
197
+ }