index.ts 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import { spawn } from 'child_process';
  2. import { cpus } from 'os';
  3. import fs from 'fs'
  4. import path from 'path';
  5. const async_exec = (prog: string, args: string[], onData: Function) => {
  6. return new Promise((resolve, reject) => {
  7. const child = spawn(prog, args, {shell: true})
  8. child.stdout.on('data', data => onData(data.toString().trim()))
  9. child.stderr.on('data', data => onData(data.toString().trim()))
  10. child.on('error', err => reject(err))
  11. child.on('exit', code => resolve(code))
  12. })
  13. }
  14. const asyncBwaMem = (
  15. refPath : string,
  16. R1 : string | Array<string>,
  17. R2 : string | Array<string>,
  18. runName : string,
  19. libName : string,
  20. output_dir: string,
  21. onData : Function,
  22. options? : any,
  23. ) => {
  24. if (typeof options === 'undefined') options = {}
  25. const refName = path.parse(refPath).name
  26. const bwa = 'bwa'
  27. const samblaster = 'samblaster'
  28. const samtools = 'samtools'
  29. const sambamba = 'sambamba'
  30. const R1_arr = Array.isArray(R1) ? R1.join(' ') : R1
  31. const R2_arr = Array.isArray(R2) ? R2.join(' ') : R2
  32. const R1_kitty = R1_arr.slice(-2) === 'gz' ? 'zcat' : 'cat'
  33. const R2_kitty = R2_arr.slice(-2) === 'gz' ? 'zcat' : 'cat'
  34. const R1_in = `'< ${R1_kitty} ${R1_arr}'`
  35. const R2_in = `'< ${R2_kitty} ${R2_arr}'`
  36. const discordantFile = path.join(output_dir, `bwa_mem_discordants_on_${refName}.sam`)
  37. const splitterFile = path.join(output_dir, `bwa_mem_splitters_on_${refName}.sam`)
  38. const unmappedFile = path.join(output_dir, `bwa_mem_unmapped_on_${refName}.fq`)
  39. const bam = path.join(output_dir, `bwa_mem_properly_on_${refName}.bam`)
  40. const bamSorted = path.join(output_dir, `bwa_mem_properly_on_${refName}.sorted.bam`)
  41. return new Promise<string[]>(async (resolve, reject) => {
  42. try {
  43. const code = await async_exec(
  44. bwa, ['mem',
  45. '-t', String(cpus().length),
  46. '-R', `"@RG\\tPL:Illumina\\tID:${+(new Date)}\\tSM:${runName}\\tLB:${libName}"`,
  47. refPath, R1_in, R2_in,
  48. '|',
  49. samblaster,
  50. '--addMateTags', // https://github.com/GregoryFaust/samblaster
  51. '-a', // Accept duplicate marks already in input file
  52. '-e', // Exclude reads marked as duplicates from discordant, splitter, and/or unmapped
  53. '-d', discordantFile,
  54. '-s', splitterFile,
  55. '-u', unmappedFile,
  56. '|',
  57. samtools,
  58. 'view',
  59. '-b',
  60. '-',
  61. '>',
  62. bam
  63. ], (message: string) => onData('[BWA-MEM] ' + message))
  64. onData('[BWA-MEM][EXIT CODE] ' + code)
  65. const code_sort = await async_exec(
  66. sambamba, ['sort',
  67. '-t', String(require('os').cpus().length),
  68. bam
  69. ], (message: string) => onData('[SAMBAMBA-SORT] ' + message))
  70. onData('[SAMBAMBA-SORT][EXIT CODE] ' + code_sort)
  71. fs.unlinkSync(bam)
  72. resolve([bamSorted, discordantFile, splitterFile, unmappedFile])
  73. } catch (err) {
  74. reject(err)
  75. }
  76. })
  77. }
  78. export { asyncBwaMem }