index.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. "use strict";
  2. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
  3. function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  4. return new (P || (P = Promise))(function (resolve, reject) {
  5. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  6. function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  7. function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  8. step((generator = generator.apply(thisArg, _arguments || [])).next());
  9. });
  10. };
  11. Object.defineProperty(exports, "__esModule", { value: true });
  12. exports.getBlastRepr = void 0;
  13. const child_process_1 = require("child_process");
  14. const async_exec = (prog, args, onData, onErr) => {
  15. return new Promise((resolve, reject) => {
  16. const child = (0, child_process_1.spawn)(prog, args, { shell: true });
  17. child.stdout.on('data', data => onData(data.toString().trim()));
  18. child.stderr.on('data', data => onErr(data.toString().trim()));
  19. child.on('error', err => reject(err));
  20. child.on('exit', code => resolve(code));
  21. });
  22. };
  23. const diversitySeq = (Seq) => {
  24. return Seq.split('').reduce((prev, _curr, id, array) => {
  25. if (id != 0 && array[id] !== array[id - 1]) {
  26. return prev + (1 / array.length);
  27. }
  28. else {
  29. return prev;
  30. }
  31. }, 0);
  32. };
  33. const annotateSeq = (seq, blastDB, maxBlast = 100, minDiversity = 0.1, blastnPath = 'blastn') => __awaiter(void 0, void 0, void 0, function* () {
  34. return new Promise((resolve, reject) => __awaiter(void 0, void 0, void 0, function* () {
  35. try {
  36. let results = '';
  37. let sequence = { sequence: seq };
  38. if (sequence.sequence) {
  39. if (diversitySeq(sequence.sequence) > minDiversity) {
  40. const sequenceStr = '\'>GG\\n' + sequence.sequence + '\'';
  41. yield async_exec('echo', [sequenceStr, '|',
  42. blastnPath, '-db', blastDB, '-query', '-', '-outfmt', '6', '-max_target_seqs', '100'], (m) => results += m, console.log);
  43. if (results !== '') {
  44. //https://www.metagenomics.wiki/tools/blast/blastn-output-format-6
  45. const keys = [/*'qseqid',*/ 'sseqid', 'pident', 'length', 'mismatch', 'gapopen', 'qstart', 'qend', 'sstart', 'send', 'evalue', 'bitscore'];
  46. results.split('\n')
  47. .map((it, index) => sequence.blastn = [
  48. ...(sequence.blastn || []),
  49. Object.assign({ index }, it.split('\t')
  50. .slice(1)
  51. .reduce((a, v, i) => (Object.assign(Object.assign({}, a), { [keys[i]]: isNaN(parseInt(v)) ? v : parseInt(v) })), {}))
  52. ].splice(0, maxBlast));
  53. if (sequence.blastn.length === 0) {
  54. throw 'Blastn results parsing failed';
  55. }
  56. }
  57. else {
  58. // console.log('WARNING NO BLASTN RESULT', ['echo', '-e', ,'\'' + sequenceStr + '\'', '|',
  59. // blastn, '-db', blastDB, '-query', '-', '-outfmt', '6', '-max_target_seqs', '100'].join(' '))
  60. throw 'No blastn hit';
  61. }
  62. }
  63. else {
  64. throw 'Sequence diversity < ' + minDiversity;
  65. }
  66. }
  67. else {
  68. throw 'No sequence';
  69. }
  70. resolve(sequence);
  71. }
  72. catch (error) {
  73. reject(error);
  74. }
  75. }));
  76. });
  77. const transpose = (matrix) => matrix.reduce(($, row) => row.map((_, i) => [...($[i] || []), row[i]]), []);
  78. const whichMax = (arr) => arr.flatMap((v, i) => v === Math.max(...arr) ? i : []);
  79. const getBlastRepr = (args) => __awaiter(void 0, void 0, void 0, function* () {
  80. const { sequence, dbs } = args;
  81. try {
  82. let all_blastn = [];
  83. for (const cdb of dbs) {
  84. let res = [];
  85. try {
  86. res = yield annotateSeq(sequence, cdb);
  87. if (res.blastn.length > 0)
  88. all_blastn = [...all_blastn, ...res.blastn].map((v, i) => { return Object.assign(Object.assign({}, v), { index: i + 1 }); });
  89. }
  90. catch (e) { }
  91. }
  92. if (all_blastn.length > 0) {
  93. const indiv_match = all_blastn.map((blastn) => {
  94. const { start, end } = blastn.qstart <= blastn.qend ? { start: blastn.qstart, end: blastn.qend } : { end: blastn.qstart, start: blastn.qend };
  95. return sequence.split('').map((_, i) => ((i + 1) >= start && (i + 1) <= end) ? '|' : '_').join('');
  96. });
  97. const bestRepr = transpose(indiv_match.map((v) => v.split(''))).map((v) => {
  98. const tmp = v.map((c, i) => {
  99. if (c === '|') {
  100. return all_blastn[i].length;
  101. }
  102. else {
  103. return 0;
  104. }
  105. });
  106. if (Math.max(...tmp) === 0) {
  107. return 0;
  108. }
  109. else {
  110. return whichMax(tmp)[0] + 1;
  111. }
  112. });
  113. let bestReprRed = [];
  114. let n = 0;
  115. let start = 0;
  116. bestRepr.reduce((p, c, i) => {
  117. if (p !== c) {
  118. const name = p === 0 ? 'unknown' : all_blastn.filter((v) => v.index === p)[0].sseqid + ":" + all_blastn.filter((v) => v.index === p)[0].sstart + '-' + all_blastn.filter((v) => v.index === p)[0].send;
  119. bestReprRed.push({ name, n, start, end: i });
  120. start = (i + 1);
  121. n = 0;
  122. }
  123. n++;
  124. if (i === (bestRepr.length - 1)) {
  125. const name = c === 0 ? 'unknown' : all_blastn.filter((v) => v.index === c)[0].sseqid + ":" + all_blastn.filter((v) => v.index === c)[0].sstart + '-' + all_blastn.filter((v) => v.index === c)[0].send;
  126. bestReprRed.push({ name, n, start, end: i + 1 });
  127. }
  128. return c;
  129. });
  130. const sup = [sequence, ...indiv_match, bestRepr.join('')];
  131. return { short: bestReprRed.flatMap((ee) => ee.name + "{" + ee.n + "}").join("<>"), all_blastn, sup, bestReprRed };
  132. }
  133. else {
  134. return {};
  135. }
  136. }
  137. catch (error) {
  138. console.log(error);
  139. return 1;
  140. }
  141. });
  142. exports.getBlastRepr = getBlastRepr;
  143. /*
  144. (async()=>{
  145. const sequence = 'TGTTAAAAGTAAGAGACAGCTGAACCCTCGTGGAGCCATTCATACAGGTCCCTATT'
  146. const dbs = ['/home/thomas/NGS/ref/RNA/human_rna.fna']
  147. console.log(await getBlastRepr({sequence, dbs}));
  148. })()*/