Thomas 3 years ago
parent
commit
94bb0d6f20
6 changed files with 584 additions and 46 deletions
  1. 116 39
      index.js
  2. 85 5
      index.ts
  3. 48 0
      test.js
  4. 39 0
      test.ts
  5. 273 0
      yarn-error.log
  6. 23 2
      yarn.lock

+ 116 - 39
index.js

@@ -12,6 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
     return (mod && mod.__esModule) ? mod : { "default": mod };
 };
 Object.defineProperty(exports, "__esModule", { value: true });
+exports.openSam = exports.analysisTranscript = void 0;
 const child_process_1 = require("child_process");
 const gbffparser_1 = require("gbffparser");
 const fs_1 = __importDefault(require("fs"));
@@ -21,7 +22,7 @@ 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 => console.log(data.toString().trim()));
+        // child.stderr.on('data', data => console.log(data.toString().trim()))
         child.on('error', err => reject(err));
         child.on('exit', code => resolve(code));
     });
@@ -53,13 +54,16 @@ const openSam = (filePaths, restraintTo, count) => __awaiter(void 0, void 0, voi
             args = [...args, '-f', 'json'];
         }
         else {
-            if (restraintTo) {
-                args.push('-c');
-            }
+            //if(restraintTo) {
+            args.push('-c');
+            //}
         }
         args.push(filePath);
         if (restraintTo)
             args.push(restraintTo);
+        const threads = os_1.default.cpus().length - 2 > 0 ? os_1.default.cpus().length - 2 : 1;
+        args.push('-t');
+        args.push(String(threads));
         console.log(['sambamba', ...args].join(' '));
         yield async_exec('sambamba', args, (m) => {
             accum += m;
@@ -94,45 +98,46 @@ const openSam = (filePaths, restraintTo, count) => __awaiter(void 0, void 0, voi
     }
     return jsonLines;
 });
-(() => __awaiter(void 0, void 0, void 0, function* () {
-    // await asyncBwaMem('/home/thomas/NGS/ref/ncbi/RNA/human_NM.fa', 
-    // ['/Turbine-pool/LAL-T_RNAseq/fastq_fastp/58_MAS/R1.fq.gz','/Turbine-pool/LAL-T_RNAseq/fastq_fastp/58_MAS/R2.fq.gz'],
-    // 'TEST', 'TEST', 'test/', console.log)
-    const symbol = 'NOTCH1';
-    const LRGPath = '/home/thomas/NGS/ref/ncbi/LRG_RefSeqGene';
-    const tablePath = '/home/thomas/NGS/ref/ncbi/GCF_000001405.39_GRCh38.p13_feature_table.txt';
-    const rnaDBPath = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(n => '/home/thomas/NGS/ref/ncbi/RNA/human.' + n + '.rna.gbff');
-    const geneDBPath = [1, 2, 3, 4, 5, 6, 7].map(n => '/home/thomas/NGS/ref/ncbi/GENES/refseqgene.' + n + '.genomic.gbff');
-    const geneInfo = yield (0, gbffparser_1.getSymbol)(symbol, LRGPath, tablePath, geneDBPath, rnaDBPath);
-    yield fs_1.default.promises.writeFile('test/geneInfo.json', JSON.stringify(geneInfo.filter((entry) => entry.feature === 'mRNA'), null, 4));
-    const transcripts = geneInfo.filter((entry) => entry.feature === 'mRNA')
-        .map((entry) => (Object.assign(Object.assign({}, entry), { sequence: entry.data.sequence, data: entry.data.features.filter((feature) => feature.type === 'exon') })))
-        .map((entry) => ({
-        accession: entry.product_accession,
-        genomic_accession: entry.genomic_accession,
-        start: entry.start,
-        end: entry.end,
-        sequence: entry.sequence,
-        exons: [...entry.data.map((d) => ({ start: d.start, end: d.end }))]
-    }))
-        .map((entry) => (Object.assign(Object.assign({}, entry), { exons: entry.exons.map((exon) => (Object.assign(Object.assign({}, exon), { sequence: entry.sequence.substring(exon.start - 1, exon.end) }))) })));
-    yield fs_1.default.promises.writeFile('test/sub.json', JSON.stringify(transcripts, null, 4));
-    for (let index = 0; index < transcripts.length; index++) {
-        const transcript = transcripts[index];
-        transcripts[index].count = {
-            all: yield openSam('test/bwa_mem_properly_on_human_NM.sorted.bam', transcript.accession, true),
-            splitters: yield openSam('test/bwa_mem_splitters_on_human_NM.sam', transcript.accession, true),
-            discordants: yield openSam('test/bwa_mem_discordants_on_human_NM.sam', transcript.accession, true),
-        };
+exports.openSam = openSam;
+const extractReads = (reads, fastqPaths) => {
+    fastqPaths = Array.isArray(fastqPaths) ? fastqPaths : [fastqPaths];
+};
+const analysisTranscript = (accession, properBam, splittersSam, disordantsSam, rnaDBPath) => __awaiter(void 0, void 0, void 0, function* () {
+    const accessionWoVersion = accession.split(/\.[0-9]{1,3}/)[0];
+    const accJson = yield (0, gbffparser_1.getFromAcc)(accessionWoVersion, rnaDBPath);
+    let json = {
+        sequence: (accJson === null || accJson === void 0 ? void 0 : accJson.sequence) || '',
+        version: accJson === null || accJson === void 0 ? void 0 : accJson.version,
+        exons: (accJson === null || accJson === void 0 ? void 0 : accJson.features.filter(entry => entry.type === 'exon').map((exon, i) => ({
+            n: i + 1,
+            start: exon.start,
+            end: exon.end,
+            strand: exon.strand,
+            sequence: accJson.sequence.substring(exon.start - 1, exon.end),
+            counts: {},
+        }))) || [],
+        counts: {},
+        altTranscripts: {}
+    };
+    json.counts.all = yield openSam(properBam, accession, true);
+    json.counts.splitters = yield openSam(splittersSam, accession, true);
+    json.counts.discordants = yield openSam(disordantsSam, accession, true);
+    for (let index = 0; index < json.exons.length; index++) {
+        const exon = json.exons[index];
+        json.exons[index].counts.all = yield openSam(properBam, accession + ':' + exon.start + '-' + exon.end, true);
+        json.exons[index].counts.splitters = yield openSam(splittersSam, accession + ':' + exon.start + '-' + exon.end, true);
+        json.exons[index].counts.discordants = yield openSam(disordantsSam, accession + ':' + exon.start + '-' + exon.end, true);
+    }
+    if (typeof json.exons !== 'undefined') {
         const samJSON = yield openSam([
             'test/bwa_mem_splitters_on_human_NM.sam',
             'test/bwa_mem_discordants_on_human_NM.sam'
-        ], transcript.accession);
+        ], accession);
         const byRead = {};
         samJSON.map((entry) => ({
             qname: entry.qname.split('_')[0],
             pos: entry.pos,
-            exon: transcript.exons.flatMap((exon, i) => (exon.start <= entry.pos && exon.end >= entry.pos) ? i + 1 : [])[0]
+            exon: json.exons.flatMap((exon, i) => (exon.start <= entry.pos && exon.end >= entry.pos) ? i + 1 : [])[0]
         }))
             .map((entry) => {
             if (typeof byRead[entry.qname] === 'undefined')
@@ -149,9 +154,81 @@ const openSam = (filePaths, restraintTo, count) => __awaiter(void 0, void 0, voi
                 byAltern[bridge].push(qname);
             }
         });
-        transcripts[index].altTranscripts = Object.keys(byAltern)
+        json.altTranscripts = Object.keys(byAltern)
             .map(bridge => ({ bridge, reads: byAltern[bridge] }))
             .sort((a, b) => b.reads.length - a.reads.length);
-        yield fs_1.default.promises.writeFile('test/altTranscripts-' + transcript.accession + '.json', JSON.stringify(transcripts[index], null, 4));
     }
-}))();
+    return json;
+});
+exports.analysisTranscript = analysisTranscript;
+/*(async()=>{
+    // await asyncBwaMem('/home/thomas/NGS/ref/ncbi/RNA/human_NM.fa',
+    // ['/Turbine-pool/LAL-T_RNAseq/fastq_fastp/58_MAS/R1.fq.gz','/Turbine-pool/LAL-T_RNAseq/fastq_fastp/58_MAS/R2.fq.gz'],
+    // 'TEST', 'TEST', 'test/', console.log)
+    
+    const symbol = 'NOTCH1'
+
+    const LRGPath = '/home/thomas/NGS/ref/ncbi/LRG_RefSeqGene'
+    const tablePath = '/home/thomas/NGS/ref/ncbi/GCF_000001405.39_GRCh38.p13_feature_table.txt'
+
+    const rnaDBPath  = [1,2,3,4,5,6,7,8,9,10].map(n => '/home/thomas/NGS/ref/ncbi/RNA/human.' + n + '.rna.gbff')
+    const geneDBPath = [1,2,3,4,5,6,7].map(n => '/home/thomas/NGS/ref/ncbi/GENES/refseqgene.' + n + '.genomic.gbff')
+    
+    const geneInfo = await getSymbol(symbol, LRGPath, tablePath, geneDBPath, rnaDBPath)
+    await fs.promises.writeFile('test/geneInfo.json', JSON.stringify(geneInfo.filter((entry:any) => entry.feature === 'mRNA'), null, 4))
+    const transcripts = geneInfo.filter((entry:any) => entry.feature === 'mRNA')
+    .map((entry:any) => ({...entry, sequence: entry.data.sequence, data:entry.data.features.filter((feature:any) => feature.type === 'exon')}))
+    .map((entry:any) => ({
+        accession: entry.product_accession,
+        genomic_accession: entry.genomic_accession,
+        start: entry.start,
+        end: entry.end,
+        sequence: entry.sequence,
+        exons: [...entry.data.map((d:any) => ({start: d.start, end: d.end}))]
+    }))
+    .map((entry:any) => ({...entry, exons: entry.exons.map((exon:any) => ({...exon, sequence: entry.sequence.substring(exon.start-1,exon.end)}))}))
+    await fs.promises.writeFile('test/sub.json', JSON.stringify(transcripts, null, 4))
+    
+    for (let index = 0; index < transcripts.length; index++) {
+        const transcript = transcripts[index]
+        
+        transcripts[index].count = {
+            all        : await openSam('test/bwa_mem_properly_on_human_NM.sorted.bam', transcript.accession, true),
+            splitters  : await openSam('test/bwa_mem_splitters_on_human_NM.sam', transcript.accession, true),
+            discordants: await openSam('test/bwa_mem_discordants_on_human_NM.sam', transcript.accession, true),
+        }
+
+        const samJSON = await openSam([
+            'test/bwa_mem_splitters_on_human_NM.sam',
+            'test/bwa_mem_discordants_on_human_NM.sam'],
+            transcript.accession)
+
+        const byRead = {} as {[key:string]: number[]}
+        samJSON.map((entry:any) => ({
+            qname: entry.qname.split('_')[0],
+            pos: entry.pos,
+            exon: transcript.exons.flatMap((exon:any, i:any) => (exon.start <= entry.pos && exon.end >= entry.pos) ? i + 1 : [])[0]
+        }))
+        .map((entry:any) => {
+            if(typeof byRead[entry.qname] === 'undefined') byRead[entry.qname] = []
+            byRead[entry.qname] = [...new Set([...byRead[entry.qname], entry.exon])].sort((a,b) => a - b)
+        })
+
+        const byAltern = {} as {[key:string]: string[]}
+        Object.keys(byRead).map(qname => {
+            const bridges = byRead[qname].flatMap((e,i) => byRead[qname]
+            .flatMap((ee,ii) => i === ii || i >= ii ? []: e + '-' + ee))
+            for (const bridge of bridges) {
+                if(typeof byAltern[bridge] === 'undefined') byAltern[bridge] = []
+                byAltern[bridge].push(qname)
+            }
+        })
+
+        transcripts[index].altTranscripts = Object.keys(byAltern)
+        .map(bridge => ({bridge, reads: byAltern[bridge]}))
+        .sort((a,b) => b.reads.length - a.reads.length)
+
+        await fs.promises.writeFile('test/altTranscripts-' + transcript.accession + '.json', JSON.stringify(transcripts[index], null, 4))
+    }
+})()
+*/ 

+ 85 - 5
index.ts

@@ -1,5 +1,5 @@
 import { spawn } from 'child_process';
-import { getSymbol } from "gbffparser"
+import { getSymbol, getFromAcc } from "gbffparser"
 import { asyncBwaMem, makeReference } from 'aligner'
 import fs from 'fs'
 import os from 'os'
@@ -10,7 +10,7 @@ const async_exec = (prog: string, args: string[], onData: Function) => {
         const child = spawn(prog, args, {shell: true})
 
         child.stdout.on('data', data => onData(data.toString().trim()))
-        child.stderr.on('data', data => console.log(data.toString().trim()))
+        // child.stderr.on('data', data => console.log(data.toString().trim()))
 
         child.on('error', err => reject(err))
         child.on('exit', code => resolve(code))
@@ -46,12 +46,18 @@ const openSam = async (
         if(!count) {
             args = [...args, '-f', 'json']
         } else {
-            if(restraintTo) {
+            //if(restraintTo) {
                 args.push('-c')
-            }
+            //}
         }
+
         args.push(filePath)
         if(restraintTo) args.push(restraintTo)
+
+        const threads = os.cpus().length - 2 > 0 ? os.cpus().length - 2 : 1
+        args.push('-t')
+        args.push(String(threads))
+
         console.log(['sambamba', ...args].join(' '));
         
         await async_exec('sambamba', args, (m: string) => {
@@ -93,7 +99,80 @@ const extractReads = (
 
 }
 
-(async()=>{
+const analysisTranscript = async (
+    accession: string,
+    properBam:string,
+    splittersSam: string,
+    disordantsSam: string,
+    rnaDBPath: string[]
+) => {
+    const accessionWoVersion = accession.split(/\.[0-9]{1,3}/)[0]
+    const accJson = await getFromAcc(accessionWoVersion, rnaDBPath)
+
+    let json: any = {
+        sequence : accJson?.sequence || '',
+        version: accJson?.version,
+        exons: accJson?.features.filter(entry => entry.type === 'exon').map((exon,i) => ({
+            n: i + 1,
+            start: exon.start,
+            end: exon.end,
+            strand: exon.strand,
+            sequence: accJson.sequence.substring(exon.start-1,exon.end),
+            counts: {},
+        })) || [],
+        counts: {},
+        altTranscripts: {}
+    }
+
+
+    json.counts.all         = await openSam(properBam, accession, true)
+    json.counts.splitters   = await openSam(splittersSam, accession, true)
+    json.counts.discordants = await openSam(disordantsSam, accession, true)
+
+    for (let index = 0; index < json.exons.length; index++) {
+        const exon = json.exons[index];
+        json.exons[index].counts.all         = await openSam(properBam, accession + ':' + exon.start + '-' + exon.end, true)
+        json.exons[index].counts.splitters   = await openSam(splittersSam, accession + ':' + exon.start + '-' + exon.end, true)
+        json.exons[index].counts.discordants = await openSam(disordantsSam, accession + ':' + exon.start + '-' + exon.end, true)
+    }
+
+    if(typeof json.exons !== 'undefined') {
+        const samJSON = await openSam([
+            'test/bwa_mem_splitters_on_human_NM.sam', 
+            'test/bwa_mem_discordants_on_human_NM.sam'],
+            accession)
+    
+        const byRead = {} as {[key:string]: number[]}
+        samJSON.map((entry:any) => ({
+            qname: entry.qname.split('_')[0],
+            pos: entry.pos,
+            exon: json.exons.flatMap((exon:any, i:any) => (exon.start <= entry.pos && exon.end >= entry.pos) ? i + 1 : [])[0]
+        }))
+        .map((entry:any) => {
+            if(typeof byRead[entry.qname] === 'undefined') byRead[entry.qname] = []
+            byRead[entry.qname] = [...new Set([...byRead[entry.qname], entry.exon])].sort((a,b) => a - b)
+        })
+    
+        const byAltern = {} as {[key:string]: string[]}
+        Object.keys(byRead).map(qname => {
+            const bridges = byRead[qname].flatMap((e,i) => byRead[qname]
+            .flatMap((ee,ii) => i === ii || i >= ii ? []: e + '-' + ee))
+            for (const bridge of bridges) {
+                if(typeof byAltern[bridge] === 'undefined') byAltern[bridge] = []
+                byAltern[bridge].push(qname)
+            }
+        })
+    
+        json.altTranscripts = Object.keys(byAltern)
+        .map(bridge => ({bridge, reads: byAltern[bridge]}))
+        .sort((a,b) => b.reads.length - a.reads.length)
+    }
+    return json
+}
+
+export { analysisTranscript, openSam }
+
+/*(async()=>{
     // await asyncBwaMem('/home/thomas/NGS/ref/ncbi/RNA/human_NM.fa', 
     // ['/Turbine-pool/LAL-T_RNAseq/fastq_fastp/58_MAS/R1.fq.gz','/Turbine-pool/LAL-T_RNAseq/fastq_fastp/58_MAS/R2.fq.gz'],
     // 'TEST', 'TEST', 'test/', console.log)
@@ -163,3 +242,4 @@ const extractReads = (
         await fs.promises.writeFile('test/altTranscripts-' + transcript.accession + '.json', JSON.stringify(transcripts[index], null, 4))
     }    
 })()
+*/

+ 48 - 0
test.js

@@ -0,0 +1,48 @@
+"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());
+    });
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const fs_1 = __importDefault(require("fs"));
+const _1 = require(".");
+(() => __awaiter(void 0, void 0, void 0, function* () {
+    const baseDir = '/home/thomas/Turbine-B/Data_2/RNAseqBWA/';
+    const rnaDBPath = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(n => '/home/thomas/NGS/ref/ncbi/RNA/human.' + n + '.rna.gbff');
+    const dirs = fs_1.default.readdirSync(baseDir);
+    /*const allResults = []
+    for (const dir of dirs) {
+        console.log(dir)
+        const caseDir = baseDir + dir + '/'
+        const proper = caseDir + 'bwa_mem_properly_on_human_NM.sorted.bam'
+        const splitters = caseDir + 'bwa_mem_splitters_on_human_NM.sam'
+        const discordants = caseDir + 'bwa_mem_discordants_on_human_NM.sam'
+
+        const res = await analysisTranscript('NM_017617.5', proper, splitters, discordants, rnaDBPath)
+        allResults.push({dir,res})
+    }
+    await fs.promises.writeFile('test/frommAcc.json', JSON.stringify(allResults, null, 4))*/
+    const allCounts = [];
+    for (const dir of dirs) {
+        const r = yield (0, _1.openSam)(baseDir + dir + '/' + 'bwa_mem_properly_on_human_NM.sorted.bam', '', true);
+        allCounts.push([dir, ...r].join('\t'));
+    }
+    console.log(allCounts);
+    yield fs_1.default.promises.writeFile('test/allCounts.tsv', allCounts.join('\n'));
+    /*const res = JSON.parse((await fs.promises.readFile('test/frommAcc.json')).toString())
+    const lines = []
+
+    console.log(res[0].dir);
+    
+    const txt = res.map((entry:any) => ([entry.dir,...entry.res.exons.reduce((p:any,c:any) => [...p, c.counts.all[0]],[])].join('\t'))).join('\n')
+    
+    await fs.promises.writeFile('test/CountsByExon.tsv', txt)*/
+}))();

+ 39 - 0
test.ts

@@ -0,0 +1,39 @@
+import fs from 'fs'
+import { analysisTranscript, openSam } from '.'
+
+(async()=>{
+    const baseDir = '/home/thomas/Turbine-B/Data_2/RNAseqBWA/'
+    const rnaDBPath  = [1,2,3,4,5,6,7,8,9,10].map(n => '/home/thomas/NGS/ref/ncbi/RNA/human.' + n + '.rna.gbff')
+
+    const dirs = fs.readdirSync(baseDir)
+    /*const allResults = []
+    for (const dir of dirs) {
+        console.log(dir)
+        const caseDir = baseDir + dir + '/'
+        const proper = caseDir + 'bwa_mem_properly_on_human_NM.sorted.bam'
+        const splitters = caseDir + 'bwa_mem_splitters_on_human_NM.sam'
+        const discordants = caseDir + 'bwa_mem_discordants_on_human_NM.sam'
+
+        const res = await analysisTranscript('NM_017617.5', proper, splitters, discordants, rnaDBPath)
+        allResults.push({dir,res})
+    }
+    await fs.promises.writeFile('test/frommAcc.json', JSON.stringify(allResults, null, 4))*/
+
+    const allCounts = []
+
+    for (const dir of dirs) {
+        const r = await openSam(baseDir + dir + '/' + 'bwa_mem_properly_on_human_NM.sorted.bam', '' , true)
+        allCounts.push([dir, ...r].join('\t'))
+    }
+    console.log(allCounts);
+    
+    await fs.promises.writeFile('test/allCounts.tsv', allCounts.join('\n'))
+    /*const res = JSON.parse((await fs.promises.readFile('test/frommAcc.json')).toString())
+    const lines = []
+
+    console.log(res[0].dir);
+    
+    const txt = res.map((entry:any) => ([entry.dir,...entry.res.exons.reduce((p:any,c:any) => [...p, c.counts.all[0]],[])].join('\t'))).join('\n')
+    
+    await fs.promises.writeFile('test/CountsByExon.tsv', txt)*/
+})()

+ 273 - 0
yarn-error.log

@@ -0,0 +1,273 @@
+Arguments: 
+  /usr/local/bin/node /usr/local/bin/yarn add -D accJson
+
+PATH: 
+  /usr/bin:/home/thomas/perl5/bin:/home/thomas/.local/bin:/home/thomas/.local/bin:/usr/bin:/home/thomas/perl5/bin:/home/thomas/miniconda3/bin:/home/thomas/miniconda3/condabin:/home/thomas/.local/bin:/home/thomas/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin:/usr/local/go/bin:/opt/spark/bin:/opt/spark/sbin:/home/thomas/miniconda3/bin:/home/thomas/miniconda3/condabin:/home/thomas/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/bin:/sbin:/usr/local/go/bin:/home/thomas/go/bin:/usr/local/go/bin:/opt/spark/bin:/opt/spark/sbin:/home/thomas/miniconda3/bin:/home/thomas/miniconda3/condabin:/opt/spark/bin:/opt/spark/sbin:/home/thomas/miniconda3/bin:/home/thomas/miniconda3/condabin:/home/thomas/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/bin:/sbin:/usr/local/go/bin:/home/thomas/go/bin:/opt/spark/bin:/opt/spark/sbin:/home/thomas/miniconda3/bin:/home/thomas/miniconda3/condabin
+
+Yarn version: 
+  1.22.17
+
+Node version: 
+  16.13.1
+
+Platform: 
+  linux x64
+
+Trace: 
+  Error: https://registry.yarnpkg.com/accJson: Not found
+      at Request.params.callback [as _callback] (/usr/local/lib/node_modules/yarn/lib/cli.js:67029:18)
+      at Request.self.callback (/usr/local/lib/node_modules/yarn/lib/cli.js:140883:22)
+      at Request.emit (node:events:390:28)
+      at Request.<anonymous> (/usr/local/lib/node_modules/yarn/lib/cli.js:141855:10)
+      at Request.emit (node:events:390:28)
+      at IncomingMessage.<anonymous> (/usr/local/lib/node_modules/yarn/lib/cli.js:141777:12)
+      at Object.onceWrapper (node:events:509:28)
+      at IncomingMessage.emit (node:events:402:35)
+      at endReadableNT (node:internal/streams/readable:1343:12)
+      at processTicksAndRejections (node:internal/process/task_queues:83:21)
+
+npm manifest: 
+  {
+    "name": "alttranscripts",
+    "version": "1.0.0",
+    "description": "",
+    "main": "index.js",
+    "scripts": {
+      "build": "tsc",
+      "test": "echo \"Error: no test specified\" && exit 1"
+    },
+    "keywords": [],
+    "author": "",
+    "license": "ISC",
+    "devDependencies": {
+      "@types/node": "^17.0.21",
+      "typescript": "^4.6.2"
+    },
+    "dependencies": {
+      "aligner": "http://git.t0m4.fr/Thomas/aligner.git",
+      "gbffparser": "http://git.t0m4.fr/Thomas/gbffParser.git",
+      "glob": "^7.2.0"
+    }
+  }
+
+yarn manifest: 
+  No manifest
+
+Lockfile: 
+  # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+  # yarn lockfile v1
+  
+  
+  "@gmod/bgzf-filehandle@^1.4.2":
+    version "1.4.2"
+    resolved "https://registry.yarnpkg.com/@gmod/bgzf-filehandle/-/bgzf-filehandle-1.4.2.tgz#2523e50cebedfdcb49c7c040365bcb22de3ad964"
+    integrity sha512-eJBFPvH4fqIjVtJtFXw2DKiJYqL/9bOz/cLu5Xn+nGGve2avQ62Bl5aa20SNHSZyoL1QsgY5tGzJwH0IKUtvHg==
+    dependencies:
+      es6-promisify "^7.0.0"
+      generic-filehandle "^2.2.1"
+      long "^5.1.0"
+      pako "^1.0.11"
+  
+  "@types/node@^17.0.21":
+    version "17.0.21"
+    resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.21.tgz#864b987c0c68d07b4345845c3e63b75edd143644"
+    integrity sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==
+  
+  "aligner@http://git.t0m4.fr/Thomas/aligner.git":
+    version "1.0.0"
+    resolved "http://git.t0m4.fr/Thomas/aligner.git#ad3d55803c69f61822b4ec3eb61cf1795cd01115"
+    dependencies:
+      fastq "^1.13.0"
+  
+  ansi-styles@^4.1.0:
+    version "4.3.0"
+    resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+    integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
+    dependencies:
+      color-convert "^2.0.1"
+  
+  balanced-match@^1.0.0:
+    version "1.0.2"
+    resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+    integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+  
+  blessed@^0.1.81:
+    version "0.1.81"
+    resolved "https://registry.yarnpkg.com/blessed/-/blessed-0.1.81.tgz#f962d687ec2c369570ae71af843256e6d0ca1129"
+    integrity sha1-+WLWh+wsNpVwrnGvhDJW5tDKESk=
+  
+  brace-expansion@^1.1.7:
+    version "1.1.11"
+    resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+    integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+    dependencies:
+      balanced-match "^1.0.0"
+      concat-map "0.0.1"
+  
+  chalk@^4.1.2:
+    version "4.1.2"
+    resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
+    integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
+    dependencies:
+      ansi-styles "^4.1.0"
+      supports-color "^7.1.0"
+  
+  color-convert@^2.0.1:
+    version "2.0.1"
+    resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+    integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
+    dependencies:
+      color-name "~1.1.4"
+  
+  color-name@~1.1.4:
+    version "1.1.4"
+    resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+    integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+  
+  concat-map@0.0.1:
+    version "0.0.1"
+    resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+    integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
+  
+  es6-promisify@^6.1.1:
+    version "6.1.1"
+    resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.1.1.tgz#46837651b7b06bf6fff893d03f29393668d01621"
+    integrity sha512-HBL8I3mIki5C1Cc9QjKUenHtnG0A5/xA8Q/AllRcfiwl2CZFXGK7ddBiCoRwAix4i2KxcQfjtIVcrVbB3vbmwg==
+  
+  es6-promisify@^7.0.0:
+    version "7.0.0"
+    resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-7.0.0.tgz#9a710008dd6a4ab75a89e280bad787bfb749927b"
+    integrity sha512-ginqzK3J90Rd4/Yz7qRrqUeIpe3TwSXTPPZtPne7tGBPeAaQiU8qt4fpKApnxHcq1AwtUdHVg5P77x/yrggG8Q==
+  
+  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"
+  
+  figlet@^1.5.2:
+    version "1.5.2"
+    resolved "https://registry.yarnpkg.com/figlet/-/figlet-1.5.2.tgz#dda34ff233c9a48e36fcff6741aeb5bafe49b634"
+    integrity sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ==
+  
+  file-uri-to-path@^2.0.0:
+    version "2.0.0"
+    resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz#7b415aeba227d575851e0a5b0c640d7656403fba"
+    integrity sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==
+  
+  fs.realpath@^1.0.0:
+    version "1.0.0"
+    resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+    integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
+  
+  "gbffparser@http://git.t0m4.fr/Thomas/gbffParser.git":
+    version "1.0.0"
+    resolved "http://git.t0m4.fr/Thomas/gbffParser.git#ca352e37ced3e5cd61e1b369b78104b13d7a762e"
+    dependencies:
+      "@gmod/bgzf-filehandle" "^1.4.2"
+      aligner "http://git.t0m4.fr/Thomas/aligner.git"
+      blessed "^0.1.81"
+      chalk "^4.1.2"
+      figlet "^1.5.2"
+      genbank-parser "^1.2.4"
+      jsonata "^1.8.6"
+  
+  genbank-parser@^1.2.4:
+    version "1.2.4"
+    resolved "https://registry.yarnpkg.com/genbank-parser/-/genbank-parser-1.2.4.tgz#ee2f9c32f66875024af0c09ee0ec5e10fb231802"
+    integrity sha512-r3pTgKHZx/rol90v2cezrNhfMhq3yHWCnBYyETNIJkvnJk+cwx/D/ZVgAy1SX8zwtnfvYQmFbqlpbh2f4t0h2w==
+  
+  generic-filehandle@^2.2.1:
+    version "2.2.2"
+    resolved "https://registry.yarnpkg.com/generic-filehandle/-/generic-filehandle-2.2.2.tgz#6493f4e8c0f9fc26d4086fbfa5d51879d0046f40"
+    integrity sha512-/YRwruMy53YNTNISJa7YWYVCKqSUzx1v+17xi/bYFX9TjBKNm4otuXZ8eXXeaf4S48ncufU8ihmsvHoi0RzJHA==
+    dependencies:
+      es6-promisify "^6.1.1"
+      file-uri-to-path "^2.0.0"
+  
+  glob@^7.2.0:
+    version "7.2.0"
+    resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
+    integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
+    dependencies:
+      fs.realpath "^1.0.0"
+      inflight "^1.0.4"
+      inherits "2"
+      minimatch "^3.0.4"
+      once "^1.3.0"
+      path-is-absolute "^1.0.0"
+  
+  has-flag@^4.0.0:
+    version "4.0.0"
+    resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
+    integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
+  
+  inflight@^1.0.4:
+    version "1.0.6"
+    resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+    integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
+    dependencies:
+      once "^1.3.0"
+      wrappy "1"
+  
+  inherits@2:
+    version "2.0.4"
+    resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+    integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+  
+  jsonata@^1.8.6:
+    version "1.8.6"
+    resolved "https://registry.yarnpkg.com/jsonata/-/jsonata-1.8.6.tgz#e5f0e6ace870a34bac881a182ca2b31227122791"
+    integrity sha512-ZH2TPYdNP2JecOl/HvrH47Xc+9imibEMQ4YqKy/F/FrM+2a6vfbGxeCX23dB9Fr6uvGwv+ghf1KxWB3iZk09wA==
+  
+  long@^5.1.0:
+    version "5.2.0"
+    resolved "https://registry.yarnpkg.com/long/-/long-5.2.0.tgz#2696dadf4b4da2ce3f6f6b89186085d94d52fd61"
+    integrity sha512-9RTUNjK60eJbx3uz+TEGF7fUr29ZDxR5QzXcyDpeSfeH28S9ycINflOgOlppit5U+4kNTe83KQnMEerw7GmE8w==
+  
+  minimatch@^3.0.4:
+    version "3.1.2"
+    resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
+    integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
+    dependencies:
+      brace-expansion "^1.1.7"
+  
+  once@^1.3.0:
+    version "1.4.0"
+    resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+    integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
+    dependencies:
+      wrappy "1"
+  
+  pako@^1.0.11:
+    version "1.0.11"
+    resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
+    integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
+  
+  path-is-absolute@^1.0.0:
+    version "1.0.1"
+    resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+    integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
+  
+  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==
+  
+  supports-color@^7.1.0:
+    version "7.2.0"
+    resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
+    integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
+    dependencies:
+      has-flag "^4.0.0"
+  
+  typescript@^4.6.2:
+    version "4.6.2"
+    resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.2.tgz#fe12d2727b708f4eef40f51598b3398baa9611d4"
+    integrity sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==
+  
+  wrappy@1:
+    version "1.0.2"
+    resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+    integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=

+ 23 - 2
yarn.lock

@@ -19,7 +19,9 @@
 
 "aligner@http://git.t0m4.fr/Thomas/aligner.git":
   version "1.0.0"
-  resolved "http://git.t0m4.fr/Thomas/aligner.git#9cb0ddd203ae903b6d1efdbe3c166c979aefefa6"
+  resolved "http://git.t0m4.fr/Thomas/aligner.git#ad3d55803c69f61822b4ec3eb61cf1795cd01115"
+  dependencies:
+    fastq "^1.13.0"
 
 ansi-styles@^4.1.0:
   version "4.3.0"
@@ -63,6 +65,13 @@ es6-promisify@^7.0.0:
   resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-7.0.0.tgz#9a710008dd6a4ab75a89e280bad787bfb749927b"
   integrity sha512-ginqzK3J90Rd4/Yz7qRrqUeIpe3TwSXTPPZtPne7tGBPeAaQiU8qt4fpKApnxHcq1AwtUdHVg5P77x/yrggG8Q==
 
+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"
+
 figlet@^1.5.2:
   version "1.5.2"
   resolved "https://registry.yarnpkg.com/figlet/-/figlet-1.5.2.tgz#dda34ff233c9a48e36fcff6741aeb5bafe49b634"
@@ -75,13 +84,15 @@ file-uri-to-path@^2.0.0:
 
 "gbffparser@http://git.t0m4.fr/Thomas/gbffParser.git":
   version "1.0.0"
-  resolved "http://git.t0m4.fr/Thomas/gbffParser.git#377cecaa854c8857c700a6a93cfd36d51786ef98"
+  resolved "http://git.t0m4.fr/Thomas/gbffParser.git#ca352e37ced3e5cd61e1b369b78104b13d7a762e"
   dependencies:
     "@gmod/bgzf-filehandle" "^1.4.2"
+    aligner "http://git.t0m4.fr/Thomas/aligner.git"
     blessed "^0.1.81"
     chalk "^4.1.2"
     figlet "^1.5.2"
     genbank-parser "^1.2.4"
+    jsonata "^1.8.6"
 
 genbank-parser@^1.2.4:
   version "1.2.4"
@@ -101,6 +112,11 @@ has-flag@^4.0.0:
   resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
   integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
 
+jsonata@^1.8.6:
+  version "1.8.6"
+  resolved "https://registry.yarnpkg.com/jsonata/-/jsonata-1.8.6.tgz#e5f0e6ace870a34bac881a182ca2b31227122791"
+  integrity sha512-ZH2TPYdNP2JecOl/HvrH47Xc+9imibEMQ4YqKy/F/FrM+2a6vfbGxeCX23dB9Fr6uvGwv+ghf1KxWB3iZk09wA==
+
 long@^5.1.0:
   version "5.2.0"
   resolved "https://registry.yarnpkg.com/long/-/long-5.2.0.tgz#2696dadf4b4da2ce3f6f6b89186085d94d52fd61"
@@ -111,6 +127,11 @@ pako@^1.0.11:
   resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
   integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
 
+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==
+
 supports-color@^7.1.0:
   version "7.2.0"
   resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"