@sjcrh/proteinpaint-server 2.44.0 → 2.46.1

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 (82) hide show
  1. package/dataset/clinvar.hg19.js +53 -52
  2. package/dataset/clinvar.hg38.js +74 -73
  3. package/dataset/clinvar.js +164 -47
  4. package/dataset/termdb.test.js +257 -0
  5. package/genome/CriGri.js +1859 -27
  6. package/genome/cgc.js +743 -7
  7. package/genome/danRer10.js +1108 -46
  8. package/genome/dm3.js +71 -44
  9. package/genome/dm6.js +1926 -45
  10. package/genome/galGal5.js +23522 -46
  11. package/genome/galGal6.js +512 -46
  12. package/genome/hg19.js +293 -198
  13. package/genome/hg38.js +472 -105
  14. package/genome/hg38.test.js +406 -40
  15. package/genome/hgvirus.js +45 -20
  16. package/genome/mm10.js +135 -67
  17. package/genome/mm9.js +116 -79
  18. package/genome/rn6.js +1002 -47
  19. package/package.json +31 -35
  20. package/routes/_template_.js +30 -0
  21. package/routes/burden.js +149 -0
  22. package/routes/dataset.js +266 -0
  23. package/routes/dsdata.js +127 -0
  24. package/routes/gdc.maf.js +120 -0
  25. package/routes/gdc.mafBuild.js +106 -0
  26. package/routes/gdc.topMutatedGenes.js +465 -0
  27. package/routes/gene2canonicalisoform.js +41 -0
  28. package/routes/genelookup.js +52 -0
  29. package/routes/genomes.js +144 -0
  30. package/routes/healthcheck.js +30 -0
  31. package/routes/hicdata.js +98 -0
  32. package/routes/hicstat.js +55 -0
  33. package/routes/isoformlst.js +57 -0
  34. package/routes/ntseq.js +43 -0
  35. package/routes/pdomain.js +61 -0
  36. package/routes/snp.js +107 -0
  37. package/routes/termdb.categories.js +209 -0
  38. package/routes/termdb.cluster.js +228 -0
  39. package/routes/termdb.cohort.summary.js +38 -0
  40. package/routes/termdb.cohorts.js +49 -0
  41. package/routes/termdb.config.js +202 -0
  42. package/routes/termdb.getdescrstats.js +102 -0
  43. package/routes/termdb.getnumericcategories.js +92 -0
  44. package/routes/termdb.getpercentile.js +108 -0
  45. package/routes/termdb.getrootterm.js +65 -0
  46. package/routes/termdb.gettermchildren.js +67 -0
  47. package/routes/termdb.singleSampleMutation.js +80 -0
  48. package/routes/termdb.singlecellData.js +46 -0
  49. package/routes/termdb.singlecellSamples.js +160 -0
  50. package/routes/termdb.termsbyids.js +59 -0
  51. package/routes/termdb.topVariablyExpressedGenes.js +171 -0
  52. package/routes/termdb.violin.js +77 -0
  53. package/src/app.js +41500 -0
  54. package/src/serverconfig.js +14 -8
  55. package/start.js +3 -3
  56. package/routes/README.md +0 -84
  57. package/routes/burden.ts +0 -143
  58. package/routes/gdc.maf.ts +0 -195
  59. package/routes/gdc.mafBuild.ts +0 -114
  60. package/routes/gdc.topMutatedGenes.ts +0 -586
  61. package/routes/genelookup.ts +0 -50
  62. package/routes/healthcheck.ts +0 -29
  63. package/routes/hicdata.ts +0 -111
  64. package/routes/hicstat.ts +0 -55
  65. package/routes/termdb.categories.ts +0 -245
  66. package/routes/termdb.cluster.ts +0 -248
  67. package/routes/termdb.getdescrstats.ts +0 -102
  68. package/routes/termdb.getnumericcategories.ts +0 -99
  69. package/routes/termdb.getpercentile.ts +0 -118
  70. package/routes/termdb.getrootterm.ts +0 -73
  71. package/routes/termdb.gettermchildren.ts +0 -82
  72. package/routes/termdb.singleSampleMutation.ts +0 -87
  73. package/routes/termdb.singlecellData.ts +0 -49
  74. package/routes/termdb.singlecellSamples.ts +0 -175
  75. package/routes/termdb.termsbyids.ts +0 -63
  76. package/routes/termdb.topVariablyExpressedGenes.ts +0 -214
  77. package/routes/termdb.violin.ts +0 -77
  78. package/server.js +0 -2
  79. package/server.js.map +0 -1
  80. package/shared/common.js +0 -1080
  81. package/shared/termdb.initbinconfig.js +0 -96
  82. package/shared/vcf.js +0 -629
@@ -0,0 +1,41 @@
1
+ const api = {
2
+ endpoint: "gene2canonicalisoform",
3
+ // should rename to simply 'canonicalIsoform' or 'isoform', gene and type: 'canonical' can be part of payload
4
+ methods: {
5
+ get: {
6
+ init,
7
+ request: {
8
+ typeId: "any"
9
+ },
10
+ response: {
11
+ typeId: "any"
12
+ }
13
+ },
14
+ post: {
15
+ alternativeFor: "get",
16
+ init
17
+ }
18
+ }
19
+ };
20
+ function init({ genomes }) {
21
+ return function(req, res) {
22
+ try {
23
+ if (!req.query.gene)
24
+ throw ".gene missing";
25
+ const genome = genomes[req.query.genome];
26
+ if (!genome)
27
+ throw "unknown genome";
28
+ if (!genome.genedb.get_gene2canonicalisoform)
29
+ throw "gene2canonicalisoform not supported on this genome";
30
+ const data = genome.genedb.get_gene2canonicalisoform.get(req.query.gene);
31
+ res.send(data);
32
+ } catch (e) {
33
+ res.send({ error: e.message || e });
34
+ if (e.stack)
35
+ console.log(e.stack);
36
+ }
37
+ };
38
+ }
39
+ export {
40
+ api
41
+ };
@@ -0,0 +1,52 @@
1
+ import { getResult } from "#src/gene.js";
2
+ function init({ genomes }) {
3
+ return (req, res) => {
4
+ try {
5
+ const q = req.query;
6
+ const g = genomes[req.query.genome];
7
+ if (!g)
8
+ throw "invalid genome name";
9
+ const result = getResult(g, req.query);
10
+ res.send(result);
11
+ } catch (e) {
12
+ res.send({ error: e.message || e });
13
+ if (e.stack)
14
+ console.log(e.stack);
15
+ }
16
+ };
17
+ }
18
+ const api = {
19
+ endpoint: "genelookup",
20
+ methods: {
21
+ get: {
22
+ init,
23
+ request: {
24
+ typeId: "GeneLookupRequest"
25
+ //valid: default to type checker
26
+ },
27
+ response: {
28
+ typeId: "GeneLookupResponse"
29
+ // will combine this with type checker
30
+ //valid: (t) => {}
31
+ },
32
+ examples: [
33
+ {
34
+ request: {
35
+ body: { input: "kr", genome: "hg38-test" }
36
+ },
37
+ response: {
38
+ header: { status: 200 },
39
+ body: { hits: ["KRAS"] }
40
+ }
41
+ }
42
+ ]
43
+ },
44
+ post: {
45
+ alternativeFor: "get",
46
+ init
47
+ }
48
+ }
49
+ };
50
+ export {
51
+ api
52
+ };
@@ -0,0 +1,144 @@
1
+ import fs from "fs";
2
+ import serverconfig from "#src/serverconfig.js";
3
+ import { authApi } from "#src/auth.js";
4
+ import { versionInfo } from "#src/health.ts";
5
+ const api = {
6
+ endpoint: "genomes",
7
+ methods: {
8
+ get: {
9
+ init,
10
+ request: {
11
+ typeId: "any"
12
+ },
13
+ response: {
14
+ typeId: "any"
15
+ }
16
+ },
17
+ post: {
18
+ alternativeFor: "get",
19
+ init
20
+ }
21
+ }
22
+ };
23
+ function init({ genomes }) {
24
+ return async function handle_genomes(req, res) {
25
+ try {
26
+ await fs.promises.stat(serverconfig.tpmasterdir);
27
+ } catch (e) {
28
+ let message = "Error with TP directory (" + e.code + ")";
29
+ const m = serverconfig.maintenance || {};
30
+ if ("start" in m && "stop" in m && m.tpMessage) {
31
+ const start = +new Date(m.start);
32
+ const stop = +new Date(m.stop);
33
+ const currTime = +/* @__PURE__ */ new Date();
34
+ if (start <= currTime && currTime <= stop) {
35
+ message = m.tpMessage;
36
+ }
37
+ }
38
+ res.send({ error: message });
39
+ return;
40
+ }
41
+ const hash = {};
42
+ if (req.query && req.query.genome) {
43
+ hash[req.query.genome] = clientcopy_genome(req.query.genome, genomes);
44
+ } else {
45
+ for (const genomename in genomes) {
46
+ hash[genomename] = clientcopy_genome(genomename, genomes);
47
+ }
48
+ }
49
+ let hasblat = false;
50
+ for (const n in genomes) {
51
+ if (genomes[n].blat)
52
+ hasblat = true;
53
+ }
54
+ res.send({
55
+ genomes: hash,
56
+ debugmode: serverconfig.debugmode,
57
+ headermessage: serverconfig.headermessage,
58
+ base_zindex: serverconfig.base_zindex,
59
+ codedate: versionInfo.codedate,
60
+ launchdate: versionInfo.launchdate,
61
+ hasblat,
62
+ features: serverconfig.features,
63
+ dsAuth: authApi.getDsAuth(req),
64
+ commonOverrides: serverconfig.commonOverrides,
65
+ targetPortal: serverconfig.targetPortal,
66
+ //sending target portal to the client
67
+ cardsPath: serverconfig.cards?.path
68
+ });
69
+ };
70
+ }
71
+ function clientcopy_genome(genomename, genomes) {
72
+ const g = genomes[genomename];
73
+ const g2 = {
74
+ species: g.species,
75
+ name: genomename,
76
+ hasSNP: g.snp ? true : false,
77
+ hasIdeogram: g.genedb.hasIdeogram,
78
+ fimo_motif: g.fimo_motif ? true : false,
79
+ blat: g.blat ? true : false,
80
+ geneset: g.geneset,
81
+ defaultcoord: g.defaultcoord,
82
+ isdefault: g.isdefault,
83
+ majorchr: g.majorchr,
84
+ majorchrorder: g.majorchrorder,
85
+ minorchr: g.minorchr,
86
+ tracks: g.tracks,
87
+ hicenzymefragment: g.hicenzymefragment,
88
+ datasets: {}
89
+ };
90
+ if (g.termdbs) {
91
+ g2.termdbs = {};
92
+ for (const k in g.termdbs) {
93
+ g2.termdbs[k] = { label: g.termdbs[k].label };
94
+ }
95
+ }
96
+ for (const dsname in g.datasets) {
97
+ const ds = g.datasets[dsname];
98
+ if (ds.isMds3) {
99
+ g2.datasets[ds.label] = {
100
+ isMds3: true,
101
+ noHandleOnClient: ds.noHandleOnClient,
102
+ label: ds.label
103
+ };
104
+ continue;
105
+ }
106
+ if (ds.isMds) {
107
+ g2.datasets[ds.label] = {
108
+ isMds: true,
109
+ mdsIsUninitiated: true,
110
+ noHandleOnClient: ds.noHandleOnClient,
111
+ label: ds.label
112
+ };
113
+ continue;
114
+ }
115
+ g2.datasets[ds.label] = {
116
+ isofficial: true,
117
+ legacyDsIsUninitiated: true,
118
+ // so client only gets copy_legacyDataset once
119
+ noHandleOnClient: ds.noHandleOnClient,
120
+ label: ds.label
121
+ };
122
+ }
123
+ if (g.hicdomain) {
124
+ g2.hicdomain = { groups: {} };
125
+ for (const s1 in g.hicdomain.groups) {
126
+ const tt = g.hicdomain.groups[s1];
127
+ g2.hicdomain.groups[s1] = {
128
+ name: tt.name,
129
+ reference: tt.reference,
130
+ sets: {}
131
+ };
132
+ for (const s2 in tt.sets) {
133
+ g2.hicdomain.groups[s1].sets[s2] = {
134
+ name: tt.sets[s2].name,
135
+ longname: tt.sets[s2].longname
136
+ };
137
+ }
138
+ }
139
+ }
140
+ return g2;
141
+ }
142
+ export {
143
+ api
144
+ };
@@ -0,0 +1,30 @@
1
+ import { getStat } from "#src/health.ts";
2
+ const api = {
3
+ endpoint: "healthcheck",
4
+ methods: {
5
+ get: {
6
+ init({ genomes }) {
7
+ return async (req, res) => {
8
+ try {
9
+ const health = await getStat(genomes);
10
+ res.send(health);
11
+ } catch (e) {
12
+ res.send({ status: "error", error: e.message || e });
13
+ }
14
+ };
15
+ },
16
+ request: {
17
+ typeId: null
18
+ //valid: default to type checker
19
+ },
20
+ response: {
21
+ typeId: "HealthCheckResponse"
22
+ // will combine this with type checker
23
+ //valid: (t) => {}
24
+ }
25
+ }
26
+ }
27
+ };
28
+ export {
29
+ api
30
+ };
@@ -0,0 +1,98 @@
1
+ import { fileurl } from "#src/utils.js";
2
+ import { spawn } from "child_process";
3
+ import readline from "readline";
4
+ import serverconfig from "#src/serverconfig.js";
5
+ const api = {
6
+ endpoint: "hicdata",
7
+ methods: {
8
+ get: {
9
+ init,
10
+ request: {
11
+ typeId: "HicdataRequest"
12
+ },
13
+ response: {
14
+ typeId: "HicdataResponse"
15
+ }
16
+ /*
17
+ examples: [
18
+ {
19
+ request: {
20
+ body: {
21
+ genome: 'hg38-test',
22
+ dslabel: 'TermdbTest',
23
+ embedder: 'localhost',
24
+ gettermbyid: 'subcohort'
25
+ }
26
+ },
27
+ response: {
28
+ header: { status: 200 }
29
+ }
30
+ }
31
+ ]
32
+ */
33
+ },
34
+ post: {
35
+ alternativeFor: "get",
36
+ init
37
+ }
38
+ }
39
+ };
40
+ function init() {
41
+ return async (req, res) => {
42
+ try {
43
+ const payload = await handle_hicdata(req.query);
44
+ res.send(payload);
45
+ } catch (e) {
46
+ res.send({ error: e?.message || e });
47
+ if (e instanceof Error && e.stack)
48
+ console.log(e);
49
+ }
50
+ };
51
+ }
52
+ function handle_hicdata(q) {
53
+ return new Promise((resolve, reject) => {
54
+ const [e, file, isurl] = fileurl({ query: q });
55
+ if (e)
56
+ reject({ error: "illegal file name" });
57
+ const matrixType = q.matrixType == "log(oe)" ? "oe" : q.matrixType ? q.matrixType : "observed";
58
+ const par = [matrixType, q.nmeth || "NONE", file, q.pos1, q.pos2, q.isfrag ? "FRAG" : "BP", q.resolution];
59
+ const ps = spawn(serverconfig.hicstraw, par);
60
+ const rl = readline.createInterface({ input: ps.stdout });
61
+ const items = [];
62
+ const erroutput = [];
63
+ let linenot3fields = 0;
64
+ let fieldnotnumerical = 0;
65
+ rl.on("line", (line) => {
66
+ const l = line.split(" ");
67
+ if (l.length != 3) {
68
+ linenot3fields++;
69
+ return;
70
+ }
71
+ const n1 = Number.parseInt(l[0]);
72
+ const n2 = Number.parseInt(l[1]);
73
+ const v = q.matrixType == "log(oe)" ? Math.log(Number.parseFloat(l[2])) : Number.parseFloat(l[2]);
74
+ if (Number.isNaN(n1) || Number.isNaN(n2) || Number.isNaN(v)) {
75
+ fieldnotnumerical++;
76
+ return;
77
+ }
78
+ if (q.mincutoff != void 0 && v <= q.mincutoff) {
79
+ return;
80
+ }
81
+ items.push([n1, n2, v]);
82
+ });
83
+ ps.stderr.on("data", (i) => erroutput.push(i));
84
+ ps.on("close", () => {
85
+ const err = erroutput.join("");
86
+ if (err)
87
+ reject({ error: err });
88
+ if (linenot3fields)
89
+ reject({ error: linenot3fields + " lines have other than 3 fields" });
90
+ if (fieldnotnumerical)
91
+ reject({ error: fieldnotnumerical + " lines have non-numerical values in any of the 3 fields" });
92
+ resolve({ items });
93
+ });
94
+ });
95
+ }
96
+ export {
97
+ api
98
+ };
@@ -0,0 +1,55 @@
1
+ import { fileurl, file_is_readable } from "#src/utils.js";
2
+ import { do_hicstat } from "#src/hicstat.ts";
3
+ const api = {
4
+ endpoint: "hicstat",
5
+ methods: {
6
+ get: {
7
+ init,
8
+ request: {
9
+ typeId: "HicstatRequest"
10
+ },
11
+ response: {
12
+ typeId: "HicstatResponse"
13
+ },
14
+ examples: [
15
+ {
16
+ request: {
17
+ body: {
18
+ genome: "hg19",
19
+ file: "proteinpaint_demo/hg19/hic/hic_demo.hic",
20
+ embedder: "localhost"
21
+ }
22
+ },
23
+ response: {
24
+ header: { status: 200 }
25
+ }
26
+ }
27
+ ]
28
+ },
29
+ post: {
30
+ alternativeFor: "get",
31
+ init
32
+ }
33
+ }
34
+ };
35
+ function init() {
36
+ return async (req, res) => {
37
+ try {
38
+ const [e, file, isurl] = fileurl(req);
39
+ if (e)
40
+ throw "illegal file name";
41
+ if (!isurl) {
42
+ await file_is_readable(file);
43
+ }
44
+ const out = await do_hicstat(file, isurl);
45
+ res.send({ out });
46
+ } catch (e) {
47
+ res.send({ error: e?.message || e });
48
+ if (e instanceof Error && e.stack)
49
+ console.log(e);
50
+ }
51
+ };
52
+ }
53
+ export {
54
+ api
55
+ };
@@ -0,0 +1,57 @@
1
+ const api = {
2
+ // route endpoint
3
+ // - no need for trailing slash
4
+ // - should be a noun (method is based on HTTP GET, POST, etc)
5
+ // - don't add 'Data' as response is assumed to be data
6
+ endpoint: "isoformlst",
7
+ methods: {
8
+ get: {
9
+ init,
10
+ request: {
11
+ typeId: "any"
12
+ },
13
+ response: {
14
+ typeId: "any"
15
+ }
16
+ },
17
+ post: {
18
+ alternativeFor: "get",
19
+ init
20
+ }
21
+ }
22
+ };
23
+ function init({ genomes }) {
24
+ return function handle_isoformlst(req, res) {
25
+ try {
26
+ const g = genomes[req.query.genome];
27
+ if (!g)
28
+ throw "invalid genome";
29
+ if (!Array.isArray(req.query.lst))
30
+ throw ".lst missing";
31
+ const lst = [];
32
+ for (const isoform of req.query.lst) {
33
+ if (g.genomicNameRegexp.test(isoform))
34
+ continue;
35
+ const tmp = g.genedb.getjsonbyisoform.all(isoform);
36
+ lst.push(
37
+ tmp.map((i) => {
38
+ const j = JSON.parse(i.genemodel);
39
+ if (i.isdefault)
40
+ j.isdefault = true;
41
+ return j;
42
+ })
43
+ );
44
+ }
45
+ res.send({ lst });
46
+ } catch (e) {
47
+ res.send({ error: e.message || e });
48
+ if (e.stack)
49
+ console.log(e.stack);
50
+ else
51
+ console.trace(e);
52
+ }
53
+ };
54
+ }
55
+ export {
56
+ api
57
+ };
@@ -0,0 +1,43 @@
1
+ import { get_fasta } from "#src/utils.js";
2
+ const api = {
3
+ endpoint: "ntseq",
4
+ methods: {
5
+ get: {
6
+ init,
7
+ request: {
8
+ typeId: "any"
9
+ },
10
+ response: {
11
+ typeId: "any"
12
+ }
13
+ },
14
+ post: {
15
+ alternativeFor: "get",
16
+ init
17
+ }
18
+ }
19
+ };
20
+ function init({ genomes }) {
21
+ return async function handle_ntseq(req, res) {
22
+ try {
23
+ if (!req.query.coord)
24
+ throw "coord missing";
25
+ const g = genomes[req.query.genome];
26
+ if (!g)
27
+ throw "invalid genome";
28
+ if (!g.genomefile)
29
+ throw "no sequence file available";
30
+ const seq = await get_fasta(g, req.query.coord);
31
+ res.send({
32
+ seq: seq.split("\n").slice(1).join("")
33
+ });
34
+ } catch (e) {
35
+ res.send({ error: e.message || e });
36
+ if (e.stack)
37
+ console.log(e.stack);
38
+ }
39
+ };
40
+ }
41
+ export {
42
+ api
43
+ };
@@ -0,0 +1,61 @@
1
+ const api = {
2
+ // route endpoint
3
+ // - no need for trailing slash
4
+ // - should be a noun (method is based on HTTP GET, POST, etc)
5
+ // - don't add 'Data' as response is assumed to be data
6
+ endpoint: "pdomain",
7
+ methods: {
8
+ get: {
9
+ init,
10
+ request: {
11
+ typeId: "any"
12
+ },
13
+ response: {
14
+ typeId: "any"
15
+ }
16
+ },
17
+ post: {
18
+ alternativeFor: "get",
19
+ init
20
+ }
21
+ }
22
+ };
23
+ function init({ genomes }) {
24
+ return function handle_pdomain(req, res) {
25
+ try {
26
+ const gn = req.query.genome;
27
+ if (!gn)
28
+ throw "no genome";
29
+ const g = genomes[gn];
30
+ if (!g)
31
+ throw "invalid genome " + gn;
32
+ if (!g.proteindomain) {
33
+ return res.send({ lst: [] });
34
+ }
35
+ if (!Array.isArray(req.query.isoforms))
36
+ throw "isoforms[] missing";
37
+ const lst = [];
38
+ for (const isoform of req.query.isoforms) {
39
+ if (g.genomicNameRegexp.test(isoform))
40
+ continue;
41
+ const tmp = g.proteindomain.getbyisoform.all(isoform);
42
+ lst.push({
43
+ name: isoform,
44
+ pdomains: tmp.map((i) => {
45
+ const j = JSON.parse(i.data);
46
+ j.refseq = isoform;
47
+ return j;
48
+ })
49
+ });
50
+ }
51
+ res.send({ lst });
52
+ } catch (e) {
53
+ res.send({ error: e.message || e });
54
+ if (e.stack)
55
+ console.log(e.stack);
56
+ }
57
+ };
58
+ }
59
+ export {
60
+ api
61
+ };
package/routes/snp.js ADDED
@@ -0,0 +1,107 @@
1
+ import * as utils from "#src/utils.js";
2
+ const api = {
3
+ // route endpoint
4
+ // - no need for trailing slash
5
+ // - should be a noun (method is based on HTTP GET, POST, etc)
6
+ // - don't add 'Data' as response is assumed to be data
7
+ endpoint: "snp",
8
+ methods: {
9
+ get: {
10
+ init,
11
+ request: {
12
+ typeId: "any"
13
+ },
14
+ response: {
15
+ typeId: "any"
16
+ }
17
+ },
18
+ post: {
19
+ alternativeFor: "get",
20
+ init
21
+ }
22
+ }
23
+ };
24
+ function init({ genomes }) {
25
+ return async function handle_snp(req, res) {
26
+ try {
27
+ const n = req.query.genome;
28
+ if (!n)
29
+ throw "no genome";
30
+ res.send({ results: await searchSNP(req.query, genomes[n]) });
31
+ } catch (e) {
32
+ if (e.stack)
33
+ console.log(e.stack);
34
+ return res.send({ error: e.message || e });
35
+ }
36
+ };
37
+ }
38
+ async function searchSNP(q, genome) {
39
+ if (!genome)
40
+ throw "invalid genome";
41
+ if (!genome.snp)
42
+ throw "snp is not configured for this genome";
43
+ const hits = [];
44
+ if (q.byCoord) {
45
+ if (genome.genomicNameRegexp.test(q.chr))
46
+ throw "invalid chr name";
47
+ if (!Array.isArray(q.ranges))
48
+ throw "ranges not an array";
49
+ for (const r of q.ranges) {
50
+ if (!Number.isInteger(r.start) || !Number.isInteger(r.stop) || r.start < 0 || r.stop < r.start)
51
+ throw "invalid start/stop";
52
+ if (r.stop - r.start >= 100) {
53
+ throw "range too big";
54
+ }
55
+ const snps = await utils.query_bigbed_by_coord(genome.snp.bigbedfile, q.chr, r.start, r.stop);
56
+ for (const snp of snps) {
57
+ const hit = snp2hit(snp);
58
+ if (q.alleleLst) {
59
+ let missing = false;
60
+ for (const i of q.alleleLst) {
61
+ if (i && !hit.alleles.includes(i)) {
62
+ missing = true;
63
+ break;
64
+ }
65
+ }
66
+ if (missing)
67
+ continue;
68
+ }
69
+ hits.push(hit);
70
+ }
71
+ }
72
+ } else if (q.byName) {
73
+ if (!Array.isArray(q.lst))
74
+ throw ".lst[] missing";
75
+ for (const n of q.lst) {
76
+ if (genome.genomicNameRegexp.test(n))
77
+ continue;
78
+ const snps = await utils.query_bigbed_by_name(genome.snp.bigbedfile, n);
79
+ for (const snp of snps) {
80
+ const hit = snp2hit(snp);
81
+ hits.push(hit);
82
+ }
83
+ }
84
+ } else {
85
+ throw "unknown query method";
86
+ }
87
+ return hits;
88
+ }
89
+ function snp2hit(snp) {
90
+ const fields = snp.split(" ");
91
+ const ref = fields[4];
92
+ const alts = fields[6].split(",").filter(Boolean);
93
+ const observed = ref + "/" + alts.join("/");
94
+ const hit = {
95
+ chrom: fields[0],
96
+ chromStart: Number(fields[1]),
97
+ chromEnd: Number(fields[2]),
98
+ name: fields[3],
99
+ observed,
100
+ alleles: [ref, ...alts]
101
+ };
102
+ return hit;
103
+ }
104
+ export {
105
+ api,
106
+ searchSNP
107
+ };