Sfoglia il codice sorgente

scheduleAsyncBwaMem

Thomas 3 anni fa
parent
commit
82da480698
9 ha cambiato i file con 373 aggiunte e 285 eliminazioni
  1. 2 1
      .gitignore
  2. 0 4
      dist/index.d.ts
  3. 0 259
      dist/index.js
  4. 198 0
      index.js
  5. 31 4
      index.ts
  6. 15 0
      test.js
  7. 8 0
      test.ts
  8. 99 9
      tsconfig.json
  9. 20 8
      yarn.lock

+ 2 - 1
.gitignore

@@ -1 +1,2 @@
-node_modules
+node_modules
+test

+ 0 - 4
dist/index.d.ts

@@ -1,4 +0,0 @@
-declare const writeSequence: (sequenceName: string, sequence: string, filePath: string, lineN?: number) => Promise<boolean>;
-declare const makeReference: (sequenceName: string, sequence: string, filePath: string, lineN?: number) => Promise<void>;
-declare const asyncBwaMem: (refPath: string, reads: string | Array<string> | Array<Array<string>>, runName: string, libName: string, outputDir: string, onData: Function, options?: any) => Promise<string[]>;
-export { asyncBwaMem, writeSequence, makeReference };

+ 0 - 259
dist/index.js

@@ -1,259 +0,0 @@
-"use strict";
-var __assign = (this && this.__assign) || function () {
-    __assign = Object.assign || function(t) {
-        for (var s, i = 1, n = arguments.length; i < n; i++) {
-            s = arguments[i];
-            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
-                t[p] = s[p];
-        }
-        return t;
-    };
-    return __assign.apply(this, arguments);
-};
-var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
-    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
-    return new (P || (P = Promise))(function (resolve, reject) {
-        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
-        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
-        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
-        step((generator = generator.apply(thisArg, _arguments || [])).next());
-    });
-};
-var __generator = (this && this.__generator) || function (thisArg, body) {
-    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
-    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
-    function verb(n) { return function (v) { return step([n, v]); }; }
-    function step(op) {
-        if (f) throw new TypeError("Generator is already executing.");
-        while (_) try {
-            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
-            if (y = 0, t) op = [op[0] & 2, t.value];
-            switch (op[0]) {
-                case 0: case 1: t = op; break;
-                case 4: _.label++; return { value: op[1], done: false };
-                case 5: _.label++; y = op[1]; op = [0]; continue;
-                case 7: op = _.ops.pop(); _.trys.pop(); continue;
-                default:
-                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
-                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
-                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
-                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
-                    if (t[2]) _.ops.pop();
-                    _.trys.pop(); continue;
-            }
-            op = body.call(thisArg, _);
-        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
-        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
-    }
-};
-var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
-    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
-        if (ar || !(i in from)) {
-            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
-            ar[i] = from[i];
-        }
-    }
-    return to.concat(ar || Array.prototype.slice.call(from));
-};
-var __importDefault = (this && this.__importDefault) || function (mod) {
-    return (mod && mod.__esModule) ? mod : { "default": mod };
-};
-Object.defineProperty(exports, "__esModule", { value: true });
-exports.makeReference = exports.writeSequence = exports.asyncBwaMem = void 0;
-var child_process_1 = require("child_process");
-var os_1 = require("os");
-var fs_1 = __importDefault(require("fs"));
-var path_1 = __importDefault(require("path"));
-var async_exec = function (prog, args, onData) {
-    return new Promise(function (resolve, reject) {
-        var child = (0, child_process_1.spawn)(prog, args, { shell: true });
-        child.stdout.on('data', function (data) { return onData(data.toString().trim()); });
-        child.stderr.on('data', function (data) { return onData(data.toString().trim()); });
-        child.on('error', function (err) { return reject(err); });
-        child.on('exit', function (code) { return resolve(code); });
-    });
-};
-var invReplace = function (regex, string, by) {
-    if (by === void 0) { by = '_'; }
-    return string.split('').map(function (letter) { return letter.match(regex) ? letter : by; }).join('');
-};
-var writeSequence = function (sequenceName, sequence, filePath, lineN) {
-    if (lineN === void 0) { lineN = 80; }
-    return __awaiter(void 0, void 0, void 0, function () {
-        return __generator(this, function (_a) {
-            return [2 /*return*/, new Promise(function (resolve, reject) { return __awaiter(void 0, void 0, void 0, function () {
-                    var r, regex_sam_restriction, nSeqName, error_1;
-                    var _a;
-                    return __generator(this, function (_b) {
-                        switch (_b.label) {
-                            case 0:
-                                _b.trys.push([0, 2, , 3]);
-                                r = new RegExp(".{1," + lineN + "}", "g");
-                                regex_sam_restriction = /[>0-9A-Za-z!#$%&+\./:;?@^_|~-]|[\n\t]/g;
-                                nSeqName = invReplace(regex_sam_restriction, sequenceName);
-                                return [4 /*yield*/, fs_1.default.promises.writeFile(filePath, '>' + nSeqName + '\n' + ((_a = sequence.match(r)) === null || _a === void 0 ? void 0 : _a.join('\n').toUpperCase()))];
-                            case 1:
-                                _b.sent();
-                                resolve(true);
-                                return [3 /*break*/, 3];
-                            case 2:
-                                error_1 = _b.sent();
-                                console.log(error_1);
-                                reject(false);
-                                return [3 /*break*/, 3];
-                            case 3: return [2 /*return*/];
-                        }
-                    });
-                }); })];
-        });
-    });
-};
-exports.writeSequence = writeSequence;
-var makeReference = function (sequenceName, sequence, filePath, lineN) {
-    if (lineN === void 0) { lineN = 80; }
-    return __awaiter(void 0, void 0, void 0, function () {
-        return __generator(this, function (_a) {
-            switch (_a.label) {
-                case 0: return [4 /*yield*/, writeSequence(sequenceName, sequence, filePath, lineN)];
-                case 1:
-                    if (!_a.sent()) return [3 /*break*/, 3];
-                    return [4 /*yield*/, async_exec('bwa', ['index', filePath], function () { return console.log; })];
-                case 2:
-                    _a.sent();
-                    _a.label = 3;
-                case 3: return [2 /*return*/];
-            }
-        });
-    });
-};
-exports.makeReference = makeReference;
-var asyncBwaMem = function (refPath, reads, 
-// R1        : string | Array<string>,
-// R2        : string | Array<string>,
-runName, libName, outputDir, onData, options) {
-    return new Promise(function (resolve, reject) { return __awaiter(void 0, void 0, void 0, function () {
-        var defaultOptions, refName, bwa, samblaster, samtools, sambamba, readsIn, isPairedEnd, R1, R2, R1_arr, R2_arr, R1_kitty, R2_kitty, R1_in, R2_in, bam, bamSorted, retObj, threads, samblasterCmd, discordantFile, splitterFile, unmappedFile, code, code_sort, err_1;
-        return __generator(this, function (_a) {
-            switch (_a.label) {
-                case 0:
-                    _a.trys.push([0, 6, , 7]);
-                    defaultOptions = {
-                        output_discordant: true,
-                        output_splitted: true,
-                        output_unmapped: true
-                    };
-                    if (typeof options === 'undefined') {
-                        options = defaultOptions;
-                    }
-                    else {
-                        options = __assign(__assign({}, defaultOptions), options);
-                    }
-                    refName = path_1.default.parse(refPath).name;
-                    bwa = 'bwa';
-                    samblaster = 'samblaster';
-                    samtools = 'samtools';
-                    sambamba = 'sambamba';
-                    readsIn = void 0;
-                    isPairedEnd = false;
-                    if (Array.isArray(reads)) {
-                        isPairedEnd = true;
-                        console.log('Assuming paired end reads');
-                        R1 = reads[0], R2 = reads[1];
-                        R1_arr = Array.isArray(R1) ? R1.join(' ') : R1;
-                        R2_arr = Array.isArray(R2) ? R2.join(' ') : R2;
-                        R1_kitty = R1_arr.slice(-2) === 'gz' ? 'zcat' : 'cat';
-                        R2_kitty = R2_arr.slice(-2) === 'gz' ? 'zcat' : 'cat';
-                        R1_in = "'< ".concat(R1_kitty, " ").concat(R1_arr, "'");
-                        R2_in = "'< ".concat(R2_kitty, " ").concat(R2_arr, "'");
-                        readsIn = R1_in + ' ' + R2_in;
-                    }
-                    else {
-                        readsIn = reads;
-                    }
-                    bam = path_1.default.join(outputDir, "bwa_mem_properly_on_".concat(refName, ".bam"));
-                    bamSorted = path_1.default.join(outputDir, "bwa_mem_properly_on_".concat(refName, ".sorted.bam"));
-                    retObj = { bamSorted: bamSorted };
-                    if (options === null || options === void 0 ? void 0 : options.remove_mapped) {
-                        bam = '/dev/null';
-                        delete retObj.bamSorted;
-                    }
-                    threads = String((0, os_1.cpus)().length);
-                    samblasterCmd = [];
-                    // https://github.com/GregoryFaust/samblaster
-                    samblasterCmd = ['|', samblaster,
-                        '--addMateTags',
-                        '-a',
-                        '-e', // Exclude reads marked as duplicates from discordant, splitter, and/or unmapped
-                    ];
-                    if ((options === null || options === void 0 ? void 0 : options.output_discordant) || (options === null || options === void 0 ? void 0 : options.output_splitted)) {
-                        console.log('Using samblaster');
-                        if (options === null || options === void 0 ? void 0 : options.output_discordant) {
-                            if (!isPairedEnd) {
-                                console.log('Discordant reads can be found only in paired reads, skipping');
-                            }
-                            else {
-                                discordantFile = path_1.default.join(outputDir, "bwa_mem_discordants_on_".concat(refName, ".sam"));
-                                console.log('Discordant reads file path: ', discordantFile);
-                                samblasterCmd = __spreadArray(__spreadArray([], samblasterCmd, true), ['-d', discordantFile], false);
-                                retObj = __assign(__assign({}, retObj), { discordantFile: discordantFile });
-                            }
-                        }
-                        if (!isPairedEnd) {
-                            samblasterCmd = __spreadArray(__spreadArray([], samblasterCmd, true), ['--ignoreUnmated'], false);
-                        }
-                        if (options === null || options === void 0 ? void 0 : options.output_splitted) {
-                            splitterFile = path_1.default.join(outputDir, "bwa_mem_splitters_on_".concat(refName, ".sam"));
-                            console.log('Splitted reads file path: ', splitterFile);
-                            samblasterCmd = __spreadArray(__spreadArray([], samblasterCmd, true), ['-s', splitterFile], false);
-                            retObj = __assign(__assign({}, retObj), { splitterFile: splitterFile });
-                        }
-                    }
-                    if (options === null || options === void 0 ? void 0 : options.output_unmapped) {
-                        unmappedFile = path_1.default.join(outputDir, "bwa_mem_unmapped_on_".concat(refName, ".fq"));
-                        console.log('Unmapped reads file path: ', unmappedFile);
-                        samblasterCmd = __spreadArray(__spreadArray([], samblasterCmd, true), ['-u', unmappedFile], false);
-                        retObj = __assign(__assign({}, retObj), { unmappedFile: unmappedFile });
-                    }
-                    if (!!fs_1.default.existsSync(refPath + '.amb')) return [3 /*break*/, 2];
-                    return [4 /*yield*/, async_exec(bwa, ['index', refPath], function (message) { return onData('[BWA-INDEX] ' + message); })];
-                case 1:
-                    _a.sent();
-                    _a.label = 2;
-                case 2:
-                    console.log(options, samblasterCmd);
-                    return [4 /*yield*/, async_exec(bwa, __spreadArray(__spreadArray(['mem',
-                            '-t', threads,
-                            '-R', "\"@RG\\tPL:Illumina\\tID:".concat(+(new Date), "\\tSM:").concat(runName, "\\tLB:").concat(libName, "\""), refPath,
-                            readsIn], samblasterCmd, true), ['|',
-                            samtools,
-                            'view',
-                            '-Sb',
-                            '-',
-                            '>',
-                            bam], false), function (message) { return onData('[BWA-MEM] ' + message); })];
-                case 3:
-                    code = _a.sent();
-                    onData('[BWA-MEM][EXIT CODE] ' + code);
-                    if (!retObj.bamSorted) return [3 /*break*/, 5];
-                    return [4 /*yield*/, async_exec(sambamba, ['sort',
-                            '-t', threads,
-                            bam
-                        ], function (message) { return onData('[SAMBAMBA-SORT] ' + message); })];
-                case 4:
-                    code_sort = _a.sent();
-                    onData('[SAMBAMBA-SORT][EXIT CODE] ' + code_sort);
-                    fs_1.default.unlinkSync(bam);
-                    _a.label = 5;
-                case 5:
-                    resolve(retObj);
-                    return [3 /*break*/, 7];
-                case 6:
-                    err_1 = _a.sent();
-                    reject(err_1);
-                    return [3 /*break*/, 7];
-                case 7: return [2 /*return*/];
-            }
-        });
-    }); });
-};
-exports.asyncBwaMem = asyncBwaMem;

+ 198 - 0
index.js

@@ -0,0 +1,198 @@
+"use strict";
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+    if (k2 === undefined) k2 = k;
+    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
+}) : (function(o, m, k, k2) {
+    if (k2 === undefined) k2 = k;
+    o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+    Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+    o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+    if (mod && mod.__esModule) return mod;
+    var result = {};
+    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+    __setModuleDefault(result, mod);
+    return result;
+};
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.scheduleAsyncBwaMem = exports.makeReference = exports.writeSequence = exports.asyncBwaMem = void 0;
+const child_process_1 = require("child_process");
+const os_1 = require("os");
+const fs_1 = __importDefault(require("fs"));
+const path_1 = __importDefault(require("path"));
+const fastq = __importStar(require("fastq"));
+const async_exec = (prog, args, onData) => {
+    return new Promise((resolve, reject) => {
+        const child = (0, child_process_1.spawn)(prog, args, { shell: true });
+        child.stdout.on('data', data => onData(data.toString().trim()));
+        child.stderr.on('data', data => onData(data.toString().trim()));
+        child.on('error', err => reject(err));
+        child.on('exit', code => resolve(code));
+    });
+};
+const invReplace = (regex, string, by = '_') => string.split('').map(letter => letter.match(regex) ? letter : by).join('');
+const writeSequence = (sequenceName, sequence, filePath, lineN = 80) => __awaiter(void 0, void 0, void 0, function* () {
+    return new Promise((resolve, reject) => __awaiter(void 0, void 0, void 0, function* () {
+        var _a;
+        try {
+            const r = new RegExp(".{1," + lineN + "}", "g");
+            const regex_sam_restriction = /[>0-9A-Za-z!#$%&+\./:;?@^_|~-]|[\n\t]/g;
+            const nSeqName = invReplace(regex_sam_restriction, sequenceName);
+            yield fs_1.default.promises.writeFile(filePath, '>' + nSeqName + '\n' + ((_a = sequence.match(r)) === null || _a === void 0 ? void 0 : _a.join('\n').toUpperCase()));
+            resolve(true);
+        }
+        catch (error) {
+            console.log(error);
+            reject(false);
+        }
+    }));
+});
+exports.writeSequence = writeSequence;
+const makeReference = (sequenceName, sequence, filePath, lineN = 80) => __awaiter(void 0, void 0, void 0, function* () {
+    if (yield writeSequence(sequenceName, sequence, filePath, lineN))
+        yield async_exec('bwa', ['index', filePath], () => console.log);
+});
+exports.makeReference = makeReference;
+const asyncBwaMem = (refPath, reads, 
+// R1        : string | Array<string>,
+// R2        : string | Array<string>,
+runName, libName, outputDir, onData, options) => {
+    return new Promise((resolve, reject) => __awaiter(void 0, void 0, void 0, function* () {
+        try {
+            const defaultOptions = {
+                output_discordant: true,
+                output_splitted: true,
+                output_unmapped: true
+            };
+            if (typeof options === 'undefined') {
+                options = defaultOptions;
+            }
+            else {
+                options = Object.assign(Object.assign({}, defaultOptions), options);
+            }
+            const refName = path_1.default.parse(refPath).name;
+            const bwa = 'bwa';
+            const samblaster = 'samblaster';
+            const samtools = 'samtools';
+            const sambamba = 'sambamba';
+            let readsIn;
+            let isPairedEnd = false;
+            if (Array.isArray(reads)) {
+                isPairedEnd = true;
+                console.log('Assuming paired end reads');
+                const [R1, R2] = reads;
+                const R1_arr = Array.isArray(R1) ? R1.join(' ') : R1;
+                const R2_arr = Array.isArray(R2) ? R2.join(' ') : R2;
+                const R1_kitty = R1_arr.slice(-2) === 'gz' ? 'zcat' : 'cat';
+                const R2_kitty = R2_arr.slice(-2) === 'gz' ? 'zcat' : 'cat';
+                const R1_in = `'< ${R1_kitty} ${R1_arr}'`;
+                const R2_in = `'< ${R2_kitty} ${R2_arr}'`;
+                readsIn = R1_in + ' ' + R2_in;
+            }
+            else {
+                readsIn = reads;
+            }
+            let bam = path_1.default.join(outputDir, `bwa_mem_properly_on_${refName}.bam`);
+            let bamSorted = path_1.default.join(outputDir, `bwa_mem_properly_on_${refName}.sorted.bam`);
+            let retObj = { bamSorted };
+            if (options === null || options === void 0 ? void 0 : options.remove_mapped) {
+                bam = '/dev/null';
+                delete retObj.bamSorted;
+            }
+            const threads = String((0, os_1.cpus)().length);
+            let samblasterCmd = [];
+            // https://github.com/GregoryFaust/samblaster
+            samblasterCmd = ['|', samblaster,
+                '--addMateTags',
+                '-a',
+                '-e', // Exclude reads marked as duplicates from discordant, splitter, and/or unmapped
+            ];
+            if ((options === null || options === void 0 ? void 0 : options.output_discordant) || (options === null || options === void 0 ? void 0 : options.output_splitted)) {
+                console.log('Using samblaster');
+                if (options === null || options === void 0 ? void 0 : options.output_discordant) {
+                    if (!isPairedEnd) {
+                        console.log('Discordant reads can be found only in paired reads, skipping');
+                    }
+                    else {
+                        const discordantFile = path_1.default.join(outputDir, `bwa_mem_discordants_on_${refName}.sam`);
+                        console.log('Discordant reads file path: ', discordantFile);
+                        samblasterCmd = [...samblasterCmd, '-d', discordantFile];
+                        retObj = Object.assign(Object.assign({}, retObj), { discordantFile });
+                    }
+                }
+                if (!isPairedEnd) {
+                    samblasterCmd = [...samblasterCmd, '--ignoreUnmated'];
+                }
+                if (options === null || options === void 0 ? void 0 : options.output_splitted) {
+                    const splitterFile = path_1.default.join(outputDir, `bwa_mem_splitters_on_${refName}.sam`);
+                    console.log('Splitted reads file path: ', splitterFile);
+                    samblasterCmd = [...samblasterCmd, '-s', splitterFile];
+                    retObj = Object.assign(Object.assign({}, retObj), { splitterFile });
+                }
+            }
+            if (options === null || options === void 0 ? void 0 : options.output_unmapped) {
+                const unmappedFile = path_1.default.join(outputDir, `bwa_mem_unmapped_on_${refName}.fq`);
+                console.log('Unmapped reads file path: ', unmappedFile);
+                samblasterCmd = [...samblasterCmd, '-u', unmappedFile];
+                retObj = Object.assign(Object.assign({}, retObj), { unmappedFile });
+            }
+            if (!fs_1.default.existsSync(refPath + '.amb')) {
+                yield async_exec(bwa, ['index', refPath], (message) => onData('[BWA-INDEX] ' + message));
+            }
+            console.log(options, samblasterCmd);
+            const code = yield async_exec(bwa, ['mem',
+                '-t', threads,
+                '-R', `"@RG\\tPL:Illumina\\tID:${+(new Date)}\\tSM:${runName}\\tLB:${libName}"`,
+                refPath,
+                readsIn,
+                ...samblasterCmd,
+                '|',
+                samtools,
+                'view',
+                '-Sb',
+                '-',
+                '>',
+                bam
+            ], (message) => onData('[BWA-MEM] ' + message));
+            onData('[BWA-MEM][EXIT CODE] ' + code);
+            if (retObj.bamSorted) {
+                const code_sort = yield async_exec(sambamba, ['sort',
+                    '-t', threads,
+                    bam
+                ], (message) => onData('[SAMBAMBA-SORT] ' + message));
+                onData('[SAMBAMBA-SORT][EXIT CODE] ' + code_sort);
+                fs_1.default.unlinkSync(bam);
+            }
+            resolve(retObj);
+        }
+        catch (err) {
+            reject(err);
+        }
+    }));
+};
+exports.asyncBwaMem = asyncBwaMem;
+const asyncBwaMemWorker = (args) => __awaiter(void 0, void 0, void 0, function* () {
+    const { refPath, reads, runName, libName, outputDir, onData } = args;
+    yield asyncBwaMem(refPath, reads, runName, libName, outputDir, onData);
+});
+const scheduleAsyncBwaMem = (allReads, refPath, runName, libName, outputDir, onData) => __awaiter(void 0, void 0, void 0, function* () {
+    const q = fastq.promise(asyncBwaMemWorker, 1);
+    yield Promise.all(allReads.map(reads => q.push({ refPath, reads, runName, libName, outputDir, onData })));
+});
+exports.scheduleAsyncBwaMem = scheduleAsyncBwaMem;

+ 31 - 4
index.ts

@@ -2,6 +2,8 @@ import { spawn } from 'child_process';
 import { cpus } from 'os';
 import fs from 'fs'
 import path from 'path';
+import * as fastq from "fastq";
+import type { queueAsPromised } from "fastq";
 
 const async_exec = (prog: string, args: string[], onData: Function) => {
     return new Promise((resolve, reject) => {
@@ -45,9 +47,7 @@ const asyncBwaMem = (
     outputDir : string,
     onData    : Function,
     options?  : any,
-  ) => {
-    
-  
+) => {
     return new Promise<string[]>(async (resolve, reject) => {
       try {
         const defaultOptions = {
@@ -183,4 +183,31 @@ const asyncBwaMem = (
     })
 }
 
-export { asyncBwaMem, writeSequence, makeReference }
+type Task = {
+  refPath   : string,
+  reads     : string | Array<string> | Array<Array<string>> ;
+  runName   : string;
+  libName   : string;
+  outputDir : string;
+  onData    : Function
+}
+
+const asyncBwaMemWorker = async (args:any) => {
+  const {refPath, reads, runName, libName, outputDir, onData}  = args
+  await asyncBwaMem(refPath, reads, runName, libName, outputDir, onData)
+}
+
+const scheduleAsyncBwaMem = async (
+  allReads: Array<Array<string>> | Array<Array<Array<string>>>,
+  refPath   : string,
+  runName   : string,
+  libName   : string,
+  outputDir : string,
+  onData    : Function
+) => {
+  const q: queueAsPromised<Task> = fastq.promise(asyncBwaMemWorker, 1)
+  await Promise.all(allReads.map(reads => q.push({refPath, reads, runName, libName, outputDir, onData})))
+}
+
+
+export { asyncBwaMem, writeSequence, makeReference, scheduleAsyncBwaMem }

+ 15 - 0
test.js

@@ -0,0 +1,15 @@
+"use strict";
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const _1 = require(".");
+(() => __awaiter(void 0, void 0, void 0, function* () {
+    yield (0, _1.scheduleAsyncBwaMem)([['/Turbine-pool/LAL-T_RNAseq/fastq_fastp/231_LEB/R1.fq.gz', '/Turbine-pool/LAL-T_RNAseq/fastq_fastp/231_LEB/R2.fq.gz']], '/home/thomas/NGS/ref/ncbi/RNA/human_NM.fa', 'TEST', 'TEST', 'test/', console.log);
+}))();

+ 8 - 0
test.ts

@@ -0,0 +1,8 @@
+import { scheduleAsyncBwaMem } from ".";
+
+(async()=>{
+    await scheduleAsyncBwaMem(
+        [['/Turbine-pool/LAL-T_RNAseq/fastq_fastp/231_LEB/R1.fq.gz','/Turbine-pool/LAL-T_RNAseq/fastq_fastp/231_LEB/R2.fq.gz']],
+        '/home/thomas/NGS/ref/ncbi/RNA/human_NM.fa', 'TEST', 'TEST', 'test/', console.log
+    )
+})()

+ 99 - 9
tsconfig.json

@@ -1,11 +1,101 @@
 {
-    "compilerOptions": {
-      "target": "es5",
-      "module": "commonjs",
-      "declaration": true,
-      "outDir": "./dist",
-      "strict": true,
-      "esModuleInterop": true,
-    },
+  "compilerOptions": {
+    /* Visit https://aka.ms/tsconfig.json to read more about this file */
+
+    /* Projects */
+    // "incremental": true,                              /* Enable incremental compilation */
+    // "composite": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */
+    // "tsBuildInfoFile": "./",                          /* Specify the folder for .tsbuildinfo incremental compilation files. */
+    // "disableSourceOfProjectReferenceRedirect": true,  /* Disable preferring source files instead of declaration files when referencing composite projects */
+    // "disableSolutionSearching": true,                 /* Opt a project out of multi-project reference checking when editing. */
+    // "disableReferencedProjectLoad": true,             /* Reduce the number of projects loaded automatically by TypeScript. */
+
+    /* Language and Environment */
+    "target": "es2016",                                  /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
+    // "lib": [],                                        /* Specify a set of bundled library declaration files that describe the target runtime environment. */
+    // "jsx": "preserve",                                /* Specify what JSX code is generated. */
+    // "experimentalDecorators": true,                   /* Enable experimental support for TC39 stage 2 draft decorators. */
+    // "emitDecoratorMetadata": true,                    /* Emit design-type metadata for decorated declarations in source files. */
+    // "jsxFactory": "",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
+    // "jsxFragmentFactory": "",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
+    // "jsxImportSource": "",                            /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
+    // "reactNamespace": "",                             /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
+    // "noLib": true,                                    /* Disable including any library files, including the default lib.d.ts. */
+    // "useDefineForClassFields": true,                  /* Emit ECMAScript-standard-compliant class fields. */
+
+    /* Modules */
+    "module": "commonjs",                                /* Specify what module code is generated. */
+    // "rootDir": "./",                                  /* Specify the root folder within your source files. */
+    // "moduleResolution": "node",                       /* Specify how TypeScript looks up a file from a given module specifier. */
+    // "baseUrl": "./",                                  /* Specify the base directory to resolve non-relative module names. */
+    // "paths": {},                                      /* Specify a set of entries that re-map imports to additional lookup locations. */
+    // "rootDirs": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */
+    // "typeRoots": [],                                  /* Specify multiple folders that act like `./node_modules/@types`. */
+    // "types": [],                                      /* Specify type package names to be included without being referenced in a source file. */
+    // "allowUmdGlobalAccess": true,                     /* Allow accessing UMD globals from modules. */
+    // "resolveJsonModule": true,                        /* Enable importing .json files */
+    // "noResolve": true,                                /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
+
+    /* JavaScript Support */
+    // "allowJs": true,                                  /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
+    // "checkJs": true,                                  /* Enable error reporting in type-checked JavaScript files. */
+    // "maxNodeModuleJsDepth": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
+
+    /* Emit */
+    // "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
+    // "declarationMap": true,                           /* Create sourcemaps for d.ts files. */
+    // "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */
+    // "sourceMap": true,                                /* Create source map files for emitted JavaScript files. */
+    // "outFile": "./",                                  /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
+    // "outDir": "./",                                   /* Specify an output folder for all emitted files. */
+    // "removeComments": true,                           /* Disable emitting comments. */
+    // "noEmit": true,                                   /* Disable emitting files from a compilation. */
+    // "importHelpers": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
+    // "importsNotUsedAsValues": "remove",               /* Specify emit/checking behavior for imports that are only used for types */
+    // "downlevelIteration": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
+    // "sourceRoot": "",                                 /* Specify the root path for debuggers to find the reference source code. */
+    // "mapRoot": "",                                    /* Specify the location where debugger should locate map files instead of generated locations. */
+    // "inlineSourceMap": true,                          /* Include sourcemap files inside the emitted JavaScript. */
+    // "inlineSources": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */
+    // "emitBOM": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
+    // "newLine": "crlf",                                /* Set the newline character for emitting files. */
+    // "stripInternal": true,                            /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
+    // "noEmitHelpers": true,                            /* Disable generating custom helper functions like `__extends` in compiled output. */
+    // "noEmitOnError": true,                            /* Disable emitting files if any type checking errors are reported. */
+    // "preserveConstEnums": true,                       /* Disable erasing `const enum` declarations in generated code. */
+    // "declarationDir": "./",                           /* Specify the output directory for generated declaration files. */
+    // "preserveValueImports": true,                     /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
+
+    /* Interop Constraints */
+    // "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */
+    // "allowSyntheticDefaultImports": true,             /* Allow 'import x from y' when a module doesn't have a default export. */
+    "esModuleInterop": true,                             /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
+    // "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
+    "forceConsistentCasingInFileNames": true,            /* Ensure that casing is correct in imports. */
+
+    /* Type Checking */
+    "strict": true,                                      /* Enable all strict type-checking options. */
+    // "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied `any` type.. */
+    // "strictNullChecks": true,                         /* When type checking, take into account `null` and `undefined`. */
+    // "strictFunctionTypes": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
+    // "strictBindCallApply": true,                      /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
+    // "strictPropertyInitialization": true,             /* Check for class properties that are declared but not set in the constructor. */
+    // "noImplicitThis": true,                           /* Enable error reporting when `this` is given the type `any`. */
+    // "useUnknownInCatchVariables": true,               /* Type catch clause variables as 'unknown' instead of 'any'. */
+    // "alwaysStrict": true,                             /* Ensure 'use strict' is always emitted. */
+    // "noUnusedLocals": true,                           /* Enable error reporting when a local variables aren't read. */
+    // "noUnusedParameters": true,                       /* Raise an error when a function parameter isn't read */
+    // "exactOptionalPropertyTypes": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */
+    // "noImplicitReturns": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */
+    // "noFallthroughCasesInSwitch": true,               /* Enable error reporting for fallthrough cases in switch statements. */
+    // "noUncheckedIndexedAccess": true,                 /* Include 'undefined' in index signature results */
+    // "noImplicitOverride": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */
+    // "noPropertyAccessFromIndexSignature": true,       /* Enforces using indexed accessors for keys declared using an indexed type */
+    // "allowUnusedLabels": true,                        /* Disable error reporting for unused labels. */
+    // "allowUnreachableCode": true,                     /* Disable error reporting for unreachable code. */
+
+    /* Completeness */
+    // "skipDefaultLibCheck": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */
+    "skipLibCheck": true                                 /* Skip type checking all .d.ts files. */
   }
-  
+}

+ 20 - 8
yarn.lock

@@ -3,11 +3,23 @@
 
 
 "@types/node@^17.0.17":
-  "integrity" "sha512-e8PUNQy1HgJGV3iU/Bp2+D/DXh3PYeyli8LgIwsQcs1Ar1LoaWHSIT6Rw+H2rNJmiq6SNWiDytfx8+gYj7wDHw=="
-  "resolved" "https://registry.npmjs.org/@types/node/-/node-17.0.17.tgz"
-  "version" "17.0.17"
-
-"typescript@^4.5.5":
-  "integrity" "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA=="
-  "resolved" "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz"
-  "version" "4.5.5"
+  version "17.0.17"
+  resolved "https://registry.npmjs.org/@types/node/-/node-17.0.17.tgz"
+  integrity sha512-e8PUNQy1HgJGV3iU/Bp2+D/DXh3PYeyli8LgIwsQcs1Ar1LoaWHSIT6Rw+H2rNJmiq6SNWiDytfx8+gYj7wDHw==
+
+fastq@^1.13.0:
+  version "1.13.0"
+  resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
+  integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==
+  dependencies:
+    reusify "^1.0.4"
+
+reusify@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
+  integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
+
+typescript@^4.5.5:
+  version "4.5.5"
+  resolved "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz"
+  integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==