@fishka/seqio 0.5.0 → 0.6.0

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.
@@ -404,6 +404,55 @@ declare function upsertEntry(file: AbifFile, name: string, number: number, paylo
404
404
  elementCount: number;
405
405
  }): void;
406
406
 
407
+ /**
408
+ * Domain-layer operation: crop an ABIF file to a sample range.
409
+ *
410
+ * `{ start, end }` is a half-open sample range in the DATA9..12 (processed/analyzed)
411
+ * domain — the only domain PLOC maps into (see AGENTS.md's "raw vs processed" note).
412
+ * DATA9..12 are sliced exactly by that range. DATA1..4/5..8 (raw dye trace and
413
+ * instrument telemetry) have no honest sample-for-sample correspondence to the
414
+ * processed domain (the mapping is non-linear mobility correction, not stored in the
415
+ * file), so they are never approximated: `rawTrace` keeps them whole and untouched,
416
+ * or omits them, never a proportional slice.
417
+ *
418
+ * Every basecall version the file carries (PBAS1/PCON1/PLOC1 "edited",
419
+ * PBAS2/PCON2/PLOC2 "called", or any vendor version) is cropped independently by its
420
+ * OWN PLOC — two versions are not guaranteed to share base positions or even length
421
+ * (edits insert/delete bases), so there is no shared coordinate to crop them together
422
+ * by. A version with no PLOC of its own cannot be cropped and is rejected rather than
423
+ * silently dropped or left un-cropped.
424
+ *
425
+ * Everything else (metadata, FWO_, SPAC, ...) is carried over untouched — this is a
426
+ * structural crop, not a re-derivation of run metadata for the new region.
427
+ *
428
+ * Reverse-complement is out of scope here; this function has no RC option.
429
+ *
430
+ * Returns a new, independently mutable AbifFile — the input is not mutated, and
431
+ * neither is the output if the input is later touched. Untouched entries are
432
+ * shallow-copied (a new AbifEntry object; the underlying payload bytes are shared,
433
+ * which is safe since nothing ever mutates payload bytes in place — only replaces
434
+ * them wholesale), so a later upsertEntry() on either file's copy of a shared tag
435
+ * can't reach into the other file's entries.
436
+ */
437
+
438
+ interface CropAbifRange {
439
+ /** Inclusive start sample index into DATA9..12. */
440
+ start: number;
441
+ /** Exclusive end sample index into DATA9..12. */
442
+ end: number;
443
+ }
444
+ interface CropAbifOptions {
445
+ /**
446
+ * DATA1..4 (raw dye trace) and DATA5..8 (telemetry): 'full' keeps them whole and
447
+ * untouched (the exported file's raw trace no longer lines up sample-for-sample
448
+ * with the cropped DATA9..12/PLOC, by design — see the module doc comment);
449
+ * 'omit' drops them from the output entirely. Default 'omit'.
450
+ */
451
+ rawTrace?: 'full' | 'omit';
452
+ }
453
+ /** Crop an AbifFile to a DATA9..12 sample range. See the module doc comment for the model. */
454
+ declare function cropAbif(file: AbifFile, range: CropAbifRange, options?: CropAbifOptions): AbifFile;
455
+
407
456
  /**
408
457
  * High-level "parse everything" wrapper around the raw + view layers.
409
458
  *
@@ -544,6 +593,12 @@ declare function getReverseComplemented(file: AbifFile): boolean | undefined;
544
593
  declare function getChannelMap(file: AbifFile): Record<'A' | 'C' | 'G' | 'T', number>;
545
594
  /** Get PBAS sequence (prefer PBAS2 over PBAS1). undefined if neither present. */
546
595
  declare function getSequence(file: AbifFile): string | undefined;
596
+ /**
597
+ * Get PBAS<version> exactly as stored — no called/edited preference, unlike
598
+ * {@link getSequence}. Used where each basecall version must be handled on its
599
+ * own (e.g. cropping every version a file carries, not just the preferred one).
600
+ */
601
+ declare function getSequenceForVersion(file: AbifFile, version: number): string | undefined;
547
602
  /**
548
603
  * Get per-base Phred-like quality scores (0..255 byte values, typically 0..60
549
604
  * for Sanger). Prefers PCON2 over PCON1.
@@ -552,6 +607,11 @@ declare function getSequence(file: AbifFile): string | undefined;
552
607
  * values ARE the Q-scores — we read raw bytes regardless of declared type.
553
608
  */
554
609
  declare function getConfidences(file: AbifFile): number[] | undefined;
610
+ /**
611
+ * Get PCON<version> exactly as stored — no called/edited preference, unlike
612
+ * {@link getConfidences}. See {@link getSequenceForVersion} for why this exists.
613
+ */
614
+ declare function getConfidencesForVersion(file: AbifFile, version: number): number[] | undefined;
555
615
  /**
556
616
  * Get peak scan positions (one per base). Prefers PLOC2 over PLOC1.
557
617
  *
@@ -560,6 +620,11 @@ declare function getConfidences(file: AbifFile): number[] | undefined;
560
620
  * if interpreted as signed.
561
621
  */
562
622
  declare function getPositions(file: AbifFile): number[] | undefined;
623
+ /**
624
+ * Get PLOC<version> exactly as stored — no called/edited preference, unlike
625
+ * {@link getPositions}. See {@link getSequenceForVersion} for why this exists.
626
+ */
627
+ declare function getPositionsForVersion(file: AbifFile, version: number): number[] | undefined;
563
628
  /**
564
629
  * Get average peak spacing (samples per base), from SPAC/1.
565
630
  *
@@ -571,4 +636,4 @@ declare function getPositions(file: AbifFile): number[] | undefined;
571
636
  */
572
637
  declare function getSamplingRate(file: AbifFile): number | undefined;
573
638
 
574
- export { type AbifBaseCallRole, type AbifBaseCallVariant, type AbifBaseCalls, type AbifByteRange, type AbifChromatogramBundle, type AbifDataChannelRole, type AbifDecodedValue, type AbifDirEntry, type AbifDirectory, type AbifEntry, type AbifEntryRaw, type AbifFile, type AbifMetadata, type ChannelSignals, type Chromatogram, ENTRY_SIZE, HEADER_SIZE, type ParsedAbif, averagePeakSpacing, channelMaxLength, dataChannelRole, ensureRawDataChannels, findEntries, findEntry, getChannelMap, getConfidences, getDataChannel, getFwo, getPositions, getReverseComplemented, getSamplingRate, getSequence, hasData9To12Block, hasSignals, isFwoPermutation, parseAbif, readAbif, setAveragePeakSpacing, setConfidences, setPositions, setSequence, tagNameFromInt32, upsertEntry, writeAbif };
639
+ export { type AbifBaseCallRole, type AbifBaseCallVariant, type AbifBaseCalls, type AbifByteRange, type AbifChromatogramBundle, type AbifDataChannelRole, type AbifDecodedValue, type AbifDirEntry, type AbifDirectory, type AbifEntry, type AbifEntryRaw, type AbifFile, type AbifMetadata, type ChannelSignals, type Chromatogram, type CropAbifOptions, type CropAbifRange, ENTRY_SIZE, HEADER_SIZE, type ParsedAbif, averagePeakSpacing, channelMaxLength, cropAbif, dataChannelRole, ensureRawDataChannels, findEntries, findEntry, getChannelMap, getConfidences, getConfidencesForVersion, getDataChannel, getFwo, getPositions, getPositionsForVersion, getReverseComplemented, getSamplingRate, getSequence, getSequenceForVersion, hasData9To12Block, hasSignals, isFwoPermutation, parseAbif, readAbif, setAveragePeakSpacing, setConfidences, setPositions, setSequence, tagNameFromInt32, upsertEntry, writeAbif };
@@ -404,6 +404,55 @@ declare function upsertEntry(file: AbifFile, name: string, number: number, paylo
404
404
  elementCount: number;
405
405
  }): void;
406
406
 
407
+ /**
408
+ * Domain-layer operation: crop an ABIF file to a sample range.
409
+ *
410
+ * `{ start, end }` is a half-open sample range in the DATA9..12 (processed/analyzed)
411
+ * domain — the only domain PLOC maps into (see AGENTS.md's "raw vs processed" note).
412
+ * DATA9..12 are sliced exactly by that range. DATA1..4/5..8 (raw dye trace and
413
+ * instrument telemetry) have no honest sample-for-sample correspondence to the
414
+ * processed domain (the mapping is non-linear mobility correction, not stored in the
415
+ * file), so they are never approximated: `rawTrace` keeps them whole and untouched,
416
+ * or omits them, never a proportional slice.
417
+ *
418
+ * Every basecall version the file carries (PBAS1/PCON1/PLOC1 "edited",
419
+ * PBAS2/PCON2/PLOC2 "called", or any vendor version) is cropped independently by its
420
+ * OWN PLOC — two versions are not guaranteed to share base positions or even length
421
+ * (edits insert/delete bases), so there is no shared coordinate to crop them together
422
+ * by. A version with no PLOC of its own cannot be cropped and is rejected rather than
423
+ * silently dropped or left un-cropped.
424
+ *
425
+ * Everything else (metadata, FWO_, SPAC, ...) is carried over untouched — this is a
426
+ * structural crop, not a re-derivation of run metadata for the new region.
427
+ *
428
+ * Reverse-complement is out of scope here; this function has no RC option.
429
+ *
430
+ * Returns a new, independently mutable AbifFile — the input is not mutated, and
431
+ * neither is the output if the input is later touched. Untouched entries are
432
+ * shallow-copied (a new AbifEntry object; the underlying payload bytes are shared,
433
+ * which is safe since nothing ever mutates payload bytes in place — only replaces
434
+ * them wholesale), so a later upsertEntry() on either file's copy of a shared tag
435
+ * can't reach into the other file's entries.
436
+ */
437
+
438
+ interface CropAbifRange {
439
+ /** Inclusive start sample index into DATA9..12. */
440
+ start: number;
441
+ /** Exclusive end sample index into DATA9..12. */
442
+ end: number;
443
+ }
444
+ interface CropAbifOptions {
445
+ /**
446
+ * DATA1..4 (raw dye trace) and DATA5..8 (telemetry): 'full' keeps them whole and
447
+ * untouched (the exported file's raw trace no longer lines up sample-for-sample
448
+ * with the cropped DATA9..12/PLOC, by design — see the module doc comment);
449
+ * 'omit' drops them from the output entirely. Default 'omit'.
450
+ */
451
+ rawTrace?: 'full' | 'omit';
452
+ }
453
+ /** Crop an AbifFile to a DATA9..12 sample range. See the module doc comment for the model. */
454
+ declare function cropAbif(file: AbifFile, range: CropAbifRange, options?: CropAbifOptions): AbifFile;
455
+
407
456
  /**
408
457
  * High-level "parse everything" wrapper around the raw + view layers.
409
458
  *
@@ -544,6 +593,12 @@ declare function getReverseComplemented(file: AbifFile): boolean | undefined;
544
593
  declare function getChannelMap(file: AbifFile): Record<'A' | 'C' | 'G' | 'T', number>;
545
594
  /** Get PBAS sequence (prefer PBAS2 over PBAS1). undefined if neither present. */
546
595
  declare function getSequence(file: AbifFile): string | undefined;
596
+ /**
597
+ * Get PBAS<version> exactly as stored — no called/edited preference, unlike
598
+ * {@link getSequence}. Used where each basecall version must be handled on its
599
+ * own (e.g. cropping every version a file carries, not just the preferred one).
600
+ */
601
+ declare function getSequenceForVersion(file: AbifFile, version: number): string | undefined;
547
602
  /**
548
603
  * Get per-base Phred-like quality scores (0..255 byte values, typically 0..60
549
604
  * for Sanger). Prefers PCON2 over PCON1.
@@ -552,6 +607,11 @@ declare function getSequence(file: AbifFile): string | undefined;
552
607
  * values ARE the Q-scores — we read raw bytes regardless of declared type.
553
608
  */
554
609
  declare function getConfidences(file: AbifFile): number[] | undefined;
610
+ /**
611
+ * Get PCON<version> exactly as stored — no called/edited preference, unlike
612
+ * {@link getConfidences}. See {@link getSequenceForVersion} for why this exists.
613
+ */
614
+ declare function getConfidencesForVersion(file: AbifFile, version: number): number[] | undefined;
555
615
  /**
556
616
  * Get peak scan positions (one per base). Prefers PLOC2 over PLOC1.
557
617
  *
@@ -560,6 +620,11 @@ declare function getConfidences(file: AbifFile): number[] | undefined;
560
620
  * if interpreted as signed.
561
621
  */
562
622
  declare function getPositions(file: AbifFile): number[] | undefined;
623
+ /**
624
+ * Get PLOC<version> exactly as stored — no called/edited preference, unlike
625
+ * {@link getPositions}. See {@link getSequenceForVersion} for why this exists.
626
+ */
627
+ declare function getPositionsForVersion(file: AbifFile, version: number): number[] | undefined;
563
628
  /**
564
629
  * Get average peak spacing (samples per base), from SPAC/1.
565
630
  *
@@ -571,4 +636,4 @@ declare function getPositions(file: AbifFile): number[] | undefined;
571
636
  */
572
637
  declare function getSamplingRate(file: AbifFile): number | undefined;
573
638
 
574
- export { type AbifBaseCallRole, type AbifBaseCallVariant, type AbifBaseCalls, type AbifByteRange, type AbifChromatogramBundle, type AbifDataChannelRole, type AbifDecodedValue, type AbifDirEntry, type AbifDirectory, type AbifEntry, type AbifEntryRaw, type AbifFile, type AbifMetadata, type ChannelSignals, type Chromatogram, ENTRY_SIZE, HEADER_SIZE, type ParsedAbif, averagePeakSpacing, channelMaxLength, dataChannelRole, ensureRawDataChannels, findEntries, findEntry, getChannelMap, getConfidences, getDataChannel, getFwo, getPositions, getReverseComplemented, getSamplingRate, getSequence, hasData9To12Block, hasSignals, isFwoPermutation, parseAbif, readAbif, setAveragePeakSpacing, setConfidences, setPositions, setSequence, tagNameFromInt32, upsertEntry, writeAbif };
639
+ export { type AbifBaseCallRole, type AbifBaseCallVariant, type AbifBaseCalls, type AbifByteRange, type AbifChromatogramBundle, type AbifDataChannelRole, type AbifDecodedValue, type AbifDirEntry, type AbifDirectory, type AbifEntry, type AbifEntryRaw, type AbifFile, type AbifMetadata, type ChannelSignals, type Chromatogram, type CropAbifOptions, type CropAbifRange, ENTRY_SIZE, HEADER_SIZE, type ParsedAbif, averagePeakSpacing, channelMaxLength, cropAbif, dataChannelRole, ensureRawDataChannels, findEntries, findEntry, getChannelMap, getConfidences, getConfidencesForVersion, getDataChannel, getFwo, getPositions, getPositionsForVersion, getReverseComplemented, getSamplingRate, getSequence, getSequenceForVersion, hasData9To12Block, hasSignals, isFwoPermutation, parseAbif, readAbif, setAveragePeakSpacing, setConfidences, setPositions, setSequence, tagNameFromInt32, upsertEntry, writeAbif };
@@ -1,2 +1,2 @@
1
- 'use strict';function v(e){let n="";for(let t=0;t<e.length;t++)n+=String.fromCharCode(e[t]);return n}function E(e){let n=new Uint8Array(e.length);for(let t=0;t<e.length;t++)n[t]=e.charCodeAt(t)&255;return n}function w(e){return new DataView(e.buffer,e.byteOffset,e.byteLength)}function x(e,n,t){return e.subarray(n,n+t)}function H(e){return String.fromCharCode(e>>>24&255,e>>>16&255,e>>>8&255,e&255)}var U=128,N=28;function R(e){if(e.byteLength<U)throw new Error(`ABIF too small: ${e.byteLength} bytes`);let n=0;if(v(x(e,0,4))!=="ABIF")if(e.byteLength>=132&&v(x(e,128,4))==="ABIF")n=128;else throw new Error('Not an ABIF file: missing "ABIF" magic.');let t=n;if(e.byteLength-t<U)throw new Error(`ABIF too small: ${e.byteLength-t} bytes after offset ${t}`);let r=w(e),a=r.getInt16(t+4,false),i=B(e,r,t+6,t);if(i.tagName!=="tdir")throw new Error(`Expected "tdir" header entry, got "${i.tagName}"`);if(i.elementSize!==N)throw new Error(`Expected dir element size ${N}, got ${i.elementSize}`);let b=i.raw?.elementCount??i.elementCount,c=Math.max(0,b),y=r.getInt32(t+6+20,false);if(y<0||y+c*N>e.byteLength-t)throw new Error(`Directory out of bounds: offset=${y}, entries=${c}, file=${e.byteLength-t}`);let u=[];for(let z=0;z<c;z++)u.push(B(e,r,t+y+z*N,t));let A=i.raw?.dataSize??c*N,p=t+y+c*N,g=Math.min(Math.max(0,A-c*N),Math.max(0,e.byteLength-p)),o={entryCount:c,rawEntryCount:b,elementType:i.elementType,tagNumber:i.tagNumber,entrySize:i.elementSize,dataSize:A,dataOffset:y,dataOffsetBytes:i.raw?.dataOffsetBytes??new Uint8Array(4),dataHandle:i.dataHandle,paddingBytes:new Uint8Array(x(e,p,g))},m=new Uint8Array(x(e,t+6+N,U-6-N)),h=n===128?new Uint8Array(x(e,0,128)):void 0,C=G(e,t,y,A,u,n);return {version:a,tdir:o,entries:u,macBinaryOffset:n,macBinaryHeader:h,headerReserved:m,unreferencedRanges:C}}function G(e,n,t,r,a,i){let b=e.byteLength,c=[];i===128&&c.push([0,128]),c.push([n,n+U]);let y=Math.max(a.length*N,Math.max(0,r));c.push([n+t,n+t+y]);for(let o of a)if(o.raw&&!o.raw.inline){let m=n+o.raw.dataOffset;c.push([m,m+o.payload.byteLength]);}let u=c.map(([o,m])=>[Math.max(0,Math.min(o,b)),Math.max(0,Math.min(m,b))]).filter(([o,m])=>m>o).sort((o,m)=>o[0]-m[0]),A=[];for(let[o,m]of u){let h=A[A.length-1];h&&o<=h[1]?h[1]=Math.max(h[1],m):A.push([o,m]);}let p=[],g=0;for(let[o,m]of A)o>g&&p.push({offset:g,bytes:new Uint8Array(x(e,g,o-g))}),g=Math.max(g,m);return g<b&&p.push({offset:g,bytes:new Uint8Array(x(e,g,b-g))}),p}function B(e,n,t,r){let a=v(x(e,t,4)),i=n.getInt32(t+4,false),b=n.getInt16(t+8,false),c=n.getInt16(t+10,false),y=n.getInt32(t+12,false),u=n.getInt32(t+16,false),A=n.getInt32(t+24,false),p=Math.max(0,y*Math.max(0,c)),g=u>=0?u:p,o=u>=0?u<=4:p<=4,m=Math.max(0,c>0?Math.min(y,Math.floor(g/c)):Math.min(y,g)),h,C;if(o)C=-1,h=new Uint8Array(x(e,t+20,Math.min(4,g)));else {C=n.getInt32(t+20,false);let s=r+C;if(C<0||s+g>e.byteLength)throw new Error(`Entry ${a}${i}: payload out of bounds (offset=${C}, size=${g})`);h=new Uint8Array(x(e,s,g));}let z=new Uint8Array(x(e,t+20,4));return {tagName:a,tagNumber:i,elementType:b,elementSize:c,elementCount:m,payload:h,dataHandle:A,raw:{elementCount:y,dataSize:u,dataOffset:C,inline:o,dataOffsetBytes:z}}}function J(e){let n=e.macBinaryOffset,t=e.entries.length,r=e.tdir.entryCount,a=e.entries.map(o=>o.raw&&o.payload.byteLength===o.raw.dataSize?o.raw:void 0),i=U;i=Math.max(i,e.tdir.dataOffset+Math.max(e.tdir.dataSize,r*N));for(let o of a)o&&!o.inline&&(i=Math.max(i,o.dataOffset+o.dataSize));for(let o of e.unreferencedRanges)i=Math.max(i,o.offset-n+o.bytes.length);let b=t>r,c=i,y=b?c:e.tdir.dataOffset,u=t===r?e.tdir.dataSize:t*N;b&&(c+=u);let A=new Array(t);for(let o=0;o<t;o++){let m=e.entries[o].payload.byteLength;if(a[o]||m<=4){A[o]=-1;continue}A[o]=c,c+=m;}let p=new Uint8Array(c),g=w(p);p.set(E("ABIF"),0),g.setInt16(4,e.version,false),p.set(e.headerReserved,6+N),O(p,g,6,{tagName:"tdir",tagNumber:e.tdir.tagNumber,elementType:e.tdir.elementType,elementSize:e.tdir.entrySize,elementCount:t,dataSize:u,dataHandle:e.tdir.dataHandle,offsetSlot:{kind:"external",value:y}}),t===r&&e.tdir.paddingBytes.length>0&&p.set(e.tdir.paddingBytes,y+t*N);for(let o=0;o<t;o++){let m=e.entries[o],h=a[o],C=y+o*N,z=m.payload.byteLength;O(p,g,C,{tagName:m.tagName,tagNumber:m.tagNumber,elementType:m.elementType,elementSize:m.elementSize,elementCount:h?h.elementCount:m.elementCount,dataSize:h?h.dataSize:z,dataHandle:m.dataHandle,offsetSlot:z<=4?{kind:"inline",payload:m.payload,dataSize:z,staleTail:h?.dataOffsetBytes}:{kind:"external",value:h?h.dataOffset:A[o]}}),z>4&&p.set(m.payload,h?h.dataOffset:A[o]);}for(let o of e.unreferencedRanges)p.set(o.bytes,o.offset-n);return p}function O(e,n,t,r){if(r.tagName.length!==4)throw new Error(`tagName must be 4 chars: "${r.tagName}"`);if(e.set(E(r.tagName),t),n.setInt32(t+4,r.tagNumber,false),n.setInt16(t+8,r.elementType,false),n.setInt16(t+10,r.elementSize,false),n.setInt32(t+12,r.elementCount,false),n.setInt32(t+16,r.dataSize,false),r.offsetSlot.kind==="external")n.setInt32(t+20,r.offsetSlot.value,false);else {let{payload:a,dataSize:i,staleTail:b}=r.offsetSlot;e.fill(0,t+20,t+24),e.set(a.subarray(0,i),t+20),b&&i<4&&e.set(b.subarray(i,4),t+20+i);}n.setInt32(t+24,r.dataHandle,false);}function S(e,n,t){return e.entries.find(r=>r.tagName===n&&r.tagNumber===t)}function K(e,n){return e.entries.filter(t=>t.tagName===n)}function T(e,n,t,r,a){if(r.byteLength!==a.elementCount*a.elementSize)throw new Error(`upsertEntry ${n}${t}: payload length ${r.byteLength} != count*size`);let i=S(e,n,t);i?(i.elementType=a.elementType,i.elementSize=a.elementSize,i.elementCount=a.elementCount,i.payload=r,i.raw=void 0):e.entries.push({tagName:n,tagNumber:t,elementType:a.elementType,elementSize:a.elementSize,elementCount:a.elementCount,payload:r,dataHandle:0});}function te(e,n){let t=S(e,"DATA",n);if(!t)return;if(t.elementSize!==2)throw new Error(`DATA${n}: expected elementSize=2, got ${t.elementSize}`);let r=new Int16Array(t.elementCount),a=w(t.payload);for(let i=0;i<t.elementCount;i++)r[i]=a.getInt16(i*2,false);return r}function M(e){let n=S(e,"FWO_",1);return n?v(n.payload.subarray(0,n.elementCount)):"GATC"}function D(e){return /^[ACGT]{4}$/.test(e)&&new Set(e).size===4}function I(e){return !!(S(e,"DATA",9)&&S(e,"DATA",10)&&S(e,"DATA",11)&&S(e,"DATA",12))}function ne(e){return e>=5&&e<=8?"telemetry":e>=1&&e<=4||e>=9&&e<=12||e===105||e===205?"trace":"other"}function re(e){let n=S(e,"RevC",1);if(!n)return;let t=w(n.payload);return n.payload.byteLength>=2?t.getInt16(0,false)!==0:n.payload.some(r=>r!==0)}function ae(e){let n=M(e);if(!D(n))throw new Error(`FWO_ is not a permutation of A/C/G/T: "${n}"`);return {[n[0]]:1,[n[1]]:2,[n[2]]:3,[n[3]]:4}}function ie(e){let n=a=>v(a.payload.subarray(0,a.elementCount)).replace(/\0+$/g,""),t=S(e,"PBAS",2);if(t)return n(t);let r=S(e,"PBAS",1);if(r)return n(r)}function oe(e){let n=S(e,"PCON",2)??S(e,"PCON",1);if(!n)return;let t=new Array(n.elementCount);for(let r=0;r<n.elementCount;r++)t[r]=n.payload[r];return t}function se(e){let n=S(e,"PLOC",2)??S(e,"PLOC",1);if(!n)return;if(n.elementSize!==2)throw new Error(`PLOC: expected elementSize=2, got ${n.elementSize}`);let t=w(n.payload),r=new Array(n.elementCount);for(let a=0;a<n.elementCount;a++)r[a]=t.getUint16(a*2,false);return r}function le(e){let n=S(e,"SPAC",1);if(!n||n.elementSize!==4||n.payload.byteLength<4)return;let t=w(n.payload).getFloat32(0,false);return Number.isFinite(t)&&t>0?t:void 0}var j={1:"byte",2:"char",3:"word",4:"short",5:"long",7:"float",8:"double",10:"date",11:"time",12:"thumb",13:"bool",18:"pString",19:"cString",1023:"tdir"};function L(e){return j[e]??(e>=1024?`user${e}`:`type${e}`)}function _(e,n=10){return e.length<=n?`[${e.join(", ")}]`:`[${e.slice(0,n).join(", ")}, \u2026 +${e.length-n}] (n=${e.length})`}function q(e,n=80){return e.length>n?e.slice(0,n)+"\u2026":e}function P(e){let n=e.subarray(0,16),t=Array.from(n,r=>r.toString(16).padStart(2,"0")).join(" ");return `${e.byteLength}B [${t}${e.byteLength>16?" \u2026":""}]`}function F(e){if(e.kind==="numbers")return e.value;if(e.kind==="number")return [e.value]}function k(e,n,t,r){let a=Math.max(0,Math.min(n,Math.floor(e/t))),i=[];for(let b=0;b<a;b++)i.push(r(b*t));return i.length===1?{kind:"number",value:i[0]}:{kind:"numbers",value:i}}function V(e,n,t){let r=w(t);switch(e){case 1:return {kind:"numbers",value:Array.from(t.subarray(0,n))};case 2:case 19:return {kind:"string",value:v(t.subarray(0,n)).replace(/\0+$/g,"")};case 3:return k(t.byteLength,n,2,a=>r.getUint16(a,false));case 4:return k(t.byteLength,n,2,a=>r.getInt16(a,false));case 5:return k(t.byteLength,n,4,a=>r.getInt32(a,false));case 7:return k(t.byteLength,n,4,a=>r.getFloat32(a,false));case 8:return k(t.byteLength,n,8,a=>r.getFloat64(a,false));case 10:{if(t.byteLength<4)return {kind:"unknown",value:t};let a=r.getInt16(0,false),i=r.getUint8(2),b=r.getUint8(3);return {kind:"date",value:{year:a,month:i,day:b}}}case 11:return t.byteLength<4?{kind:"unknown",value:t}:{kind:"time",value:{hour:r.getUint8(0),minute:r.getUint8(1),second:r.getUint8(2),hsec:r.getUint8(3)}};case 13:{let a=[];for(let i=0;i<Math.min(n,t.byteLength);i++)a.push(r.getUint8(i)!==0);return {kind:"bools",value:a}}case 18:{if(t.byteLength<1)return {kind:"string",value:""};let a=r.getUint8(0);return {kind:"string",value:v(x(t,1,Math.min(a,Math.max(0,n-1))))}}default:return {kind:"unknown",value:t}}}function W(e,n){switch(e.kind){case "number":return String(e.value);case "numbers":return _(e.value);case "string":return q(JSON.stringify(e.value));case "bools":return e.value.length===1?String(e.value[0]):`[${e.value.join(", ")}]`;case "date":{let{year:t,month:r,day:a}=e.value;return `${t}-${String(r).padStart(2,"0")}-${String(a).padStart(2,"0")}`}case "time":{let{hour:t,minute:r,second:a}=e.value;return `${String(t).padStart(2,"0")}:${String(r).padStart(2,"0")}:${String(a).padStart(2,"0")}`}case "bytes":return `${L(n)} ${P(e.value)}`;case "unknown":return `${L(n)} ${P(e.value)}`}}function ce(e,n=""){let t=e instanceof Uint8Array?e:new Uint8Array(e),r=R(t),a=r.entries.map(s=>{let l=s.tagName==="PCON"&&s.elementSize===1?V(1,s.elementCount,s.payload):V(s.elementType,s.elementCount,s.payload);return {tag:s.tagName,tagNumber:s.tagNumber,elementType:s.elementType,elementTypeName:L(s.elementType),elementSize:s.elementSize,elementCount:s.elementCount,rawElementCount:s.raw?.elementCount??s.elementCount,dataSize:s.raw?.dataSize??s.elementCount*s.elementSize,dataOffset:s.raw?.dataOffset??-1,inline:s.raw?.inline??s.elementCount*s.elementSize<=4,decoded:l,preview:W(l,s.elementType)}}),i=M(r);D(i)||(i="GATC");let b={},c={A:[],C:[],G:[],T:[]},y={A:[],C:[],G:[],T:[]},u={comments:[]},A={},p={},g={},o=s=>i[s];for(let s=0;s<r.entries.length;s++){let l=r.entries[s],d=a[s].decoded;if(l.tagName==="DATA"){let f=F(d);f&&(b[l.tagNumber]=f,l.tagNumber>=1&&l.tagNumber<=4?c[o(l.tagNumber-1)]=f:l.tagNumber>=9&&l.tagNumber<=12&&(y[o(l.tagNumber-9)]=f));}else if(l.tagName==="PBAS"&&d.kind==="string")A[l.tagNumber]=d.value;else if(l.tagName==="PCON"){let f=l.elementSize===1?Array.from(l.payload.subarray(0,l.elementCount)):F(d);f&&(p[l.tagNumber]=f);}else if(l.tagName==="PLOC"){let f=F(d);f&&(g[l.tagNumber]=f.map($=>$<0?$+65536:$));}else if(l.tagName==="SPAC")if(l.elementSize===4&&l.payload.byteLength>=4){let f=w(l.payload).getFloat32(0,false);Number.isFinite(f)&&f>0&&(u.samplingRate=f);}else d.kind==="number"&&(u.samplingRate=d.value);else if(l.tagName==="SMPL"&&d.kind==="string")u.sampleName=d.value;else if(l.tagName==="LANE"&&d.kind==="number")u.laneNumber=d.value;else if(l.tagName==="TUBE"&&d.kind==="string")u.tube=d.value;else if(l.tagName==="MCHN"&&d.kind==="string")u.machineName=d.value;else if(l.tagName==="MODL"&&d.kind==="string")u.machineModel=d.value;else if(l.tagName==="RUND"&&d.kind==="date"){let f=d.value;u.runDate=`${f.year}-${String(f.month).padStart(2,"0")}-${String(f.day).padStart(2,"0")}`;}else if(l.tagName==="RUNT"&&d.kind==="time"){let f=d.value;u.runTime=`${String(f.hour).padStart(2,"0")}:${String(f.minute).padStart(2,"0")}:${String(f.second).padStart(2,"0")}`;}else l.tagName==="CMNT"&&d.kind==="string"?u.comments.push(d.value):l.tagName==="RevC"&&l.tagNumber===1&&(d.kind==="number"?u.reverseComplemented=d.value!==0:d.kind==="numbers"&&(u.reverseComplemented=d.value.some(f=>f!==0)));}let m=Object.keys(A).map(Number).sort((s,l)=>s-l).map(s=>({version:s,role:s===1?"edited":s===2?"called":"unknown",sequence:A[s],confidences:p[s]??[],positions:g[s]??[]})),h,C=2 in A?2:1 in A?1:Object.keys(A).map(Number)[0];if(C!==void 0&&A[C]!==void 0){let s=A[C].toUpperCase(),l=p[C]??[];l.length!==s.length&&(l=Object.keys(p).map(Number).map(f=>p[f]).find(f=>f.length===s.length)??[]);let d=g[C]??[];d.length!==s.length&&(d=Object.keys(g).map(Number).map(f=>g[f]).find(f=>f.length===s.length)??[]),h={sequence:s,confidences:l,positions:d,pbasVersion:C};}if(!Number.isFinite(u.samplingRate)||(u.samplingRate??0)<=0){let s=h?.positions,l=Math.max(y.A.length,y.C.length,y.G.length,y.T.length);s&&s.length>1?u.samplingRate=(s[s.length-1]-s[0])/(s.length-1):h&&h.sequence.length>0&&l>0&&(u.samplingRate=l/h.sequence.length);}let z={baseOrder:i,dataChannels:b,data1To4:c,data9To12:y};return {fileName:n,fileSize:t.byteLength,abifVersion:r.version,macBinaryOffset:r.macBinaryOffset,dirEntryCount:r.entries.length,metadata:u,chromatogram:z,baseCalls:h,baseCallVariants:m,entries:a}}function ge(e){return e.A.length>0||e.C.length>0||e.G.length>0||e.T.length>0}function be(e){return Math.max(e.A.length,e.C.length,e.G.length,e.T.length)}function Se(e,n){T(e,"PBAS",2,E(n),{elementType:2,elementSize:1,elementCount:n.length});}function Ce(e,n){let t=new Uint8Array(n.length);for(let r=0;r<n.length;r++)t[r]=Math.max(0,Math.min(255,Math.round(n[r])));T(e,"PCON",2,t,{elementType:2,elementSize:1,elementCount:n.length});}function we(e,n){let t=new Uint8Array(n.length*2),r=w(t);for(let a=0;a<n.length;a++)r.setUint16(a*2,Math.max(0,Math.min(65535,n[a])),false);T(e,"PLOC",2,t,{elementType:4,elementSize:2,elementCount:n.length});}function Ne(e,n,t){let r=new Uint8Array(4);w(r).setFloat32(0,n,false),T(e,"SPAC",1,r,{elementType:7,elementSize:4,elementCount:1});let a=E(t),i=Math.min(255,a.length),b=new Uint8Array(1+i);b[0]=i,b.set(a.subarray(0,i),1),T(e,"SPAC",2,b,{elementType:18,elementSize:1,elementCount:1+i});let c=new Uint8Array(4);w(c).setFloat32(0,n,false),T(e,"SPAC",3,c,{elementType:7,elementSize:4,elementCount:1});}function xe(e){return e.length<2?0:(e[e.length-1]-e[0])/(e.length-1)}function ze(e){if(!I(e))for(let n=1;n<=4;n++){let t=S(e,"DATA",n);if(!t)continue;let r=8+n;S(e,"DATA",r)||e.entries.push({tagName:"DATA",tagNumber:r,elementType:t.elementType,elementSize:t.elementSize,elementCount:t.elementCount,payload:new Uint8Array(t.payload),dataHandle:0});}}exports.ENTRY_SIZE=N;exports.HEADER_SIZE=U;exports.averagePeakSpacing=xe;exports.channelMaxLength=be;exports.dataChannelRole=ne;exports.ensureRawDataChannels=ze;exports.findEntries=K;exports.findEntry=S;exports.getChannelMap=ae;exports.getConfidences=oe;exports.getDataChannel=te;exports.getFwo=M;exports.getPositions=se;exports.getReverseComplemented=re;exports.getSamplingRate=le;exports.getSequence=ie;exports.hasData9To12Block=I;exports.hasSignals=ge;exports.isFwoPermutation=D;exports.parseAbif=ce;exports.readAbif=R;exports.setAveragePeakSpacing=Ne;exports.setConfidences=Ce;exports.setPositions=we;exports.setSequence=Se;exports.tagNameFromInt32=H;exports.upsertEntry=T;exports.writeAbif=J;//# sourceMappingURL=index.js.map
1
+ 'use strict';function z(e){let n="";for(let t=0;t<e.length;t++)n+=String.fromCharCode(e[t]);return n}function E(e){let n=new Uint8Array(e.length);for(let t=0;t<e.length;t++)n[t]=e.charCodeAt(t)&255;return n}function w(e){return new DataView(e.buffer,e.byteOffset,e.byteLength)}function x(e,n,t){return e.subarray(n,n+t)}function _(e){return String.fromCharCode(e>>>24&255,e>>>16&255,e>>>8&255,e&255)}var F=128,N=28;function G(e){if(e.byteLength<F)throw new Error(`ABIF too small: ${e.byteLength} bytes`);let n=0;if(z(x(e,0,4))!=="ABIF")if(e.byteLength>=132&&z(x(e,128,4))==="ABIF")n=128;else throw new Error('Not an ABIF file: missing "ABIF" magic.');let t=n;if(e.byteLength-t<F)throw new Error(`ABIF too small: ${e.byteLength-t} bytes after offset ${t}`);let r=w(e),a=r.getInt16(t+4,false),i=V(e,r,t+6,t);if(i.tagName!=="tdir")throw new Error(`Expected "tdir" header entry, got "${i.tagName}"`);if(i.elementSize!==N)throw new Error(`Expected dir element size ${N}, got ${i.elementSize}`);let c=i.raw?.elementCount??i.elementCount,l=Math.max(0,c),u=r.getInt32(t+6+20,false);if(u<0||u+l*N>e.byteLength-t)throw new Error(`Directory out of bounds: offset=${u}, entries=${l}, file=${e.byteLength-t}`);let d=[];for(let T=0;T<l;T++)d.push(V(e,r,t+u+T*N,t));let y=i.raw?.dataSize??l*N,f=t+u+l*N,h=Math.min(Math.max(0,y-l*N),Math.max(0,e.byteLength-f)),o={entryCount:l,rawEntryCount:c,elementType:i.elementType,tagNumber:i.tagNumber,entrySize:i.elementSize,dataSize:y,dataOffset:u,dataOffsetBytes:i.raw?.dataOffsetBytes??new Uint8Array(4),dataHandle:i.dataHandle,paddingBytes:new Uint8Array(x(e,f,h))},g=new Uint8Array(x(e,t+6+N,F-6-N)),A=n===128?new Uint8Array(x(e,0,128)):void 0,C=W(e,t,u,y,d,n);return {version:a,tdir:o,entries:d,macBinaryOffset:n,macBinaryHeader:A,headerReserved:g,unreferencedRanges:C}}function W(e,n,t,r,a,i){let c=e.byteLength,l=[];i===128&&l.push([0,128]),l.push([n,n+F]);let u=Math.max(a.length*N,Math.max(0,r));l.push([n+t,n+t+u]);for(let o of a)if(o.raw&&!o.raw.inline){let g=n+o.raw.dataOffset;l.push([g,g+o.payload.byteLength]);}let d=l.map(([o,g])=>[Math.max(0,Math.min(o,c)),Math.max(0,Math.min(g,c))]).filter(([o,g])=>g>o).sort((o,g)=>o[0]-g[0]),y=[];for(let[o,g]of d){let A=y[y.length-1];A&&o<=A[1]?A[1]=Math.max(A[1],g):y.push([o,g]);}let f=[],h=0;for(let[o,g]of y)o>h&&f.push({offset:h,bytes:new Uint8Array(x(e,h,o-h))}),h=Math.max(h,g);return h<c&&f.push({offset:h,bytes:new Uint8Array(x(e,h,c-h))}),f}function V(e,n,t,r){let a=z(x(e,t,4)),i=n.getInt32(t+4,false),c=n.getInt16(t+8,false),l=n.getInt16(t+10,false),u=n.getInt32(t+12,false),d=n.getInt32(t+16,false),y=n.getInt32(t+24,false),f=Math.max(0,u*Math.max(0,l)),h=d>=0?d:f,o=d>=0?d<=4:f<=4,g=Math.max(0,l>0?Math.min(u,Math.floor(h/l)):Math.min(u,h)),A,C;if(o)C=-1,A=new Uint8Array(x(e,t+20,Math.min(4,h)));else {C=n.getInt32(t+20,false);let s=r+C;if(C<0||s+h>e.byteLength)throw new Error(`Entry ${a}${i}: payload out of bounds (offset=${C}, size=${h})`);A=new Uint8Array(x(e,s,h));}let T=new Uint8Array(x(e,t+20,4));return {tagName:a,tagNumber:i,elementType:c,elementSize:l,elementCount:g,payload:A,dataHandle:y,raw:{elementCount:u,dataSize:d,dataOffset:C,inline:o,dataOffsetBytes:T}}}function ae(e){let n=e.macBinaryOffset,t=e.entries.length,r=e.tdir.entryCount,a=e.entries.map(o=>o.raw&&o.payload.byteLength===o.raw.dataSize?o.raw:void 0),i=F;i=Math.max(i,e.tdir.dataOffset+Math.max(e.tdir.dataSize,r*N));for(let o of a)o&&!o.inline&&(i=Math.max(i,o.dataOffset+o.dataSize));for(let o of e.unreferencedRanges)i=Math.max(i,o.offset-n+o.bytes.length);let c=t>r,l=i,u=c?l:e.tdir.dataOffset,d=t===r?e.tdir.dataSize:t*N;c&&(l+=d);let y=new Array(t);for(let o=0;o<t;o++){let g=e.entries[o].payload.byteLength;if(a[o]||g<=4){y[o]=-1;continue}y[o]=l,l+=g;}let f=new Uint8Array(l),h=w(f);f.set(E("ABIF"),0),h.setInt16(4,e.version,false),f.set(e.headerReserved,6+N),H(f,h,6,{tagName:"tdir",tagNumber:e.tdir.tagNumber,elementType:e.tdir.elementType,elementSize:e.tdir.entrySize,elementCount:t,dataSize:d,dataHandle:e.tdir.dataHandle,offsetSlot:{kind:"external",value:u}}),t===r&&e.tdir.paddingBytes.length>0&&f.set(e.tdir.paddingBytes,u+t*N);for(let o=0;o<t;o++){let g=e.entries[o],A=a[o],C=u+o*N,T=g.payload.byteLength;H(f,h,C,{tagName:g.tagName,tagNumber:g.tagNumber,elementType:g.elementType,elementSize:g.elementSize,elementCount:A?A.elementCount:g.elementCount,dataSize:A?A.dataSize:T,dataHandle:g.dataHandle,offsetSlot:T<=4?{kind:"inline",payload:g.payload,dataSize:T,staleTail:A?.dataOffsetBytes}:{kind:"external",value:A?A.dataOffset:y[o]}}),T>4&&f.set(g.payload,A?A.dataOffset:y[o]);}for(let o of e.unreferencedRanges)f.set(o.bytes,o.offset-n);return f}function H(e,n,t,r){if(r.tagName.length!==4)throw new Error(`tagName must be 4 chars: "${r.tagName}"`);if(e.set(E(r.tagName),t),n.setInt32(t+4,r.tagNumber,false),n.setInt16(t+8,r.elementType,false),n.setInt16(t+10,r.elementSize,false),n.setInt32(t+12,r.elementCount,false),n.setInt32(t+16,r.dataSize,false),r.offsetSlot.kind==="external")n.setInt32(t+20,r.offsetSlot.value,false);else {let{payload:a,dataSize:i,staleTail:c}=r.offsetSlot;e.fill(0,t+20,t+24),e.set(a.subarray(0,i),t+20),c&&i<4&&e.set(c.subarray(i,4),t+20+i);}n.setInt32(t+24,r.dataHandle,false);}function S(e,n,t){return e.entries.find(r=>r.tagName===n&&r.tagNumber===t)}function ie(e,n){return e.entries.filter(t=>t.tagName===n)}function $(e,n,t,r,a){if(r.byteLength!==a.elementCount*a.elementSize)throw new Error(`upsertEntry ${n}${t}: payload length ${r.byteLength} != count*size`);let i=S(e,n,t);i?(i.elementType=a.elementType,i.elementSize=a.elementSize,i.elementCount=a.elementCount,i.payload=r,i.raw=void 0):e.entries.push({tagName:n,tagNumber:t,elementType:a.elementType,elementSize:a.elementSize,elementCount:a.elementCount,payload:r,dataHandle:0});}function me(e,n){let t=S(e,"DATA",n);if(!t)return;if(t.elementSize!==2)throw new Error(`DATA${n}: expected elementSize=2, got ${t.elementSize}`);let r=new Int16Array(t.elementCount),a=w(t.payload);for(let i=0;i<t.elementCount;i++)r[i]=a.getInt16(i*2,false);return r}function O(e){let n=S(e,"FWO_",1);return n?z(n.payload.subarray(0,n.elementCount)):"GATC"}function P(e){return /^[ACGT]{4}$/.test(e)&&new Set(e).size===4}function B(e){return !!(S(e,"DATA",9)&&S(e,"DATA",10)&&S(e,"DATA",11)&&S(e,"DATA",12))}function le(e){return e>=5&&e<=8?"telemetry":e>=1&&e<=4||e>=9&&e<=12||e===105||e===205?"trace":"other"}function fe(e){let n=S(e,"RevC",1);if(!n)return;let t=w(n.payload);return n.payload.byteLength>=2?t.getInt16(0,false)!==0:n.payload.some(r=>r!==0)}function ce(e){let n=O(e);if(!P(n))throw new Error(`FWO_ is not a permutation of A/C/G/T: "${n}"`);return {[n[0]]:1,[n[1]]:2,[n[2]]:3,[n[3]]:4}}function de(e){return U(e,2)??U(e,1)}function U(e,n){let t=S(e,"PBAS",n);if(t)return z(t.payload.subarray(0,t.elementCount)).replace(/\0+$/g,"")}function ge(e){return D(e,2)??D(e,1)}function D(e,n){let t=S(e,"PCON",n);if(!t)return;let r=new Array(t.elementCount);for(let a=0;a<t.elementCount;a++)r[a]=t.payload[a];return r}function be(e){return k(e,2)??k(e,1)}function k(e,n){let t=S(e,"PLOC",n);if(!t)return;if(t.elementSize!==2)throw new Error(`PLOC${n}: expected elementSize=2, got ${t.elementSize}`);let r=w(t.payload),a=new Array(t.elementCount);for(let i=0;i<t.elementCount;i++)a[i]=r.getUint16(i*2,false);return a}function he(e){let n=S(e,"SPAC",1);if(!n||n.elementSize!==4||n.payload.byteLength<4)return;let t=w(n.payload).getFloat32(0,false);return Number.isFinite(t)&&t>0?t:void 0}function Ce(e,n,t={}){let{start:r,end:a}=n;if(!Number.isInteger(r)||!Number.isInteger(a)||r<0||a<=r)throw new Error(`cropAbif: invalid range [${r}, ${a})`);if(!B(e))throw new Error("cropAbif: no DATA9..12 block to crop \u2014 the range has nothing to apply to");let i=Math.min(L(e,9),L(e,10),L(e,11),L(e,12));if(a>i)throw new Error(`cropAbif: range end ${a} exceeds the processed trace length ${i}`);let c=t.rawTrace??"omit",l=[];for(let u of e.entries)u.tagName==="DATA"&&u.tagNumber>=9&&u.tagNumber<=12?l.push(Y(u,r,a)):u.tagName==="DATA"&&u.tagNumber>=1&&u.tagNumber<=8?c==="full"&&l.push({...u}):u.tagName==="PBAS"||u.tagName==="PCON"||u.tagName==="PLOC"||l.push({...u});for(let u of Z(e))l.push(...J(e,u,r,a));return {version:e.version,tdir:e.tdir,entries:l,macBinaryOffset:0,macBinaryHeader:void 0,headerReserved:e.headerReserved,unreferencedRanges:[]}}function L(e,n){return S(e,"DATA",n)?.elementCount??0}function Y(e,n,t){if(e.elementSize!==2)throw new Error(`cropAbif: DATA${e.tagNumber} expected elementSize=2, got ${e.elementSize}`);let r=new Uint8Array(e.payload.subarray(n*2,t*2));return {tagName:"DATA",tagNumber:e.tagNumber,elementType:e.elementType,elementSize:2,elementCount:t-n,payload:r,dataHandle:e.dataHandle}}function Z(e){let n=new Set;for(let t of e.entries)t.tagName==="PBAS"&&n.add(t.tagNumber);return Array.from(n).sort((t,r)=>t-r)}function J(e,n,t,r){let a=U(e,n);if(a===void 0)return [];let i=k(e,n);if(i===void 0)throw new Error(`cropAbif: PBAS${n} has no PLOC${n} to crop by`);if(i.length!==a.length)throw new Error(`cropAbif: PBAS${n}/PLOC${n} length mismatch (${a.length} vs ${i.length})`);let c=D(e,n);if(c!==void 0&&c.length!==a.length)throw new Error(`cropAbif: PBAS${n}/PCON${n} length mismatch`);let l=[];for(let f=0;f<i.length;f++)i[f]>=t&&i[f]<r&&l.push(f);let u=l.map(f=>a[f]).join(""),d=l.map(f=>i[f]-t),y=[{tagName:"PBAS",tagNumber:n,elementType:2,elementSize:1,elementCount:u.length,payload:E(u),dataHandle:0},{tagName:"PLOC",tagNumber:n,elementType:4,elementSize:2,elementCount:d.length,payload:K(d),dataHandle:0}];if(c!==void 0){let f=l.map(h=>c[h]);y.push({tagName:"PCON",tagNumber:n,elementType:2,elementSize:1,elementCount:f.length,payload:Uint8Array.from(f),dataHandle:0});}return y}function K(e){let n=new Uint8Array(e.length*2),t=w(n);for(let r=0;r<e.length;r++)t.setUint16(r*2,Math.max(0,Math.min(65535,e[r])),false);return n}var Q={1:"byte",2:"char",3:"word",4:"short",5:"long",7:"float",8:"double",10:"date",11:"time",12:"thumb",13:"bool",18:"pString",19:"cString",1023:"tdir"};function I(e){return Q[e]??(e>=1024?`user${e}`:`type${e}`)}function X(e,n=10){return e.length<=n?`[${e.join(", ")}]`:`[${e.slice(0,n).join(", ")}, \u2026 +${e.length-n}] (n=${e.length})`}function ee(e,n=80){return e.length>n?e.slice(0,n)+"\u2026":e}function j(e){let n=e.subarray(0,16),t=Array.from(n,r=>r.toString(16).padStart(2,"0")).join(" ");return `${e.byteLength}B [${t}${e.byteLength>16?" \u2026":""}]`}function R(e){if(e.kind==="numbers")return e.value;if(e.kind==="number")return [e.value]}function v(e,n,t,r){let a=Math.max(0,Math.min(n,Math.floor(e/t))),i=[];for(let c=0;c<a;c++)i.push(r(c*t));return i.length===1?{kind:"number",value:i[0]}:{kind:"numbers",value:i}}function q(e,n,t){let r=w(t);switch(e){case 1:return {kind:"numbers",value:Array.from(t.subarray(0,n))};case 2:case 19:return {kind:"string",value:z(t.subarray(0,n)).replace(/\0+$/g,"")};case 3:return v(t.byteLength,n,2,a=>r.getUint16(a,false));case 4:return v(t.byteLength,n,2,a=>r.getInt16(a,false));case 5:return v(t.byteLength,n,4,a=>r.getInt32(a,false));case 7:return v(t.byteLength,n,4,a=>r.getFloat32(a,false));case 8:return v(t.byteLength,n,8,a=>r.getFloat64(a,false));case 10:{if(t.byteLength<4)return {kind:"unknown",value:t};let a=r.getInt16(0,false),i=r.getUint8(2),c=r.getUint8(3);return {kind:"date",value:{year:a,month:i,day:c}}}case 11:return t.byteLength<4?{kind:"unknown",value:t}:{kind:"time",value:{hour:r.getUint8(0),minute:r.getUint8(1),second:r.getUint8(2),hsec:r.getUint8(3)}};case 13:{let a=[];for(let i=0;i<Math.min(n,t.byteLength);i++)a.push(r.getUint8(i)!==0);return {kind:"bools",value:a}}case 18:{if(t.byteLength<1)return {kind:"string",value:""};let a=r.getUint8(0);return {kind:"string",value:z(x(t,1,Math.min(a,Math.max(0,n-1))))}}default:return {kind:"unknown",value:t}}}function te(e,n){switch(e.kind){case "number":return String(e.value);case "numbers":return X(e.value);case "string":return ee(JSON.stringify(e.value));case "bools":return e.value.length===1?String(e.value[0]):`[${e.value.join(", ")}]`;case "date":{let{year:t,month:r,day:a}=e.value;return `${t}-${String(r).padStart(2,"0")}-${String(a).padStart(2,"0")}`}case "time":{let{hour:t,minute:r,second:a}=e.value;return `${String(t).padStart(2,"0")}:${String(r).padStart(2,"0")}:${String(a).padStart(2,"0")}`}case "bytes":return `${I(n)} ${j(e.value)}`;case "unknown":return `${I(n)} ${j(e.value)}`}}function ze(e,n=""){let t=e instanceof Uint8Array?e:new Uint8Array(e),r=G(t),a=r.entries.map(s=>{let m=s.tagName==="PCON"&&s.elementSize===1?q(1,s.elementCount,s.payload):q(s.elementType,s.elementCount,s.payload);return {tag:s.tagName,tagNumber:s.tagNumber,elementType:s.elementType,elementTypeName:I(s.elementType),elementSize:s.elementSize,elementCount:s.elementCount,rawElementCount:s.raw?.elementCount??s.elementCount,dataSize:s.raw?.dataSize??s.elementCount*s.elementSize,dataOffset:s.raw?.dataOffset??-1,inline:s.raw?.inline??s.elementCount*s.elementSize<=4,decoded:m,preview:te(m,s.elementType)}}),i=O(r);P(i)||(i="GATC");let c={},l={A:[],C:[],G:[],T:[]},u={A:[],C:[],G:[],T:[]},d={comments:[]},y={},f={},h={},o=s=>i[s];for(let s=0;s<r.entries.length;s++){let m=r.entries[s],p=a[s].decoded;if(m.tagName==="DATA"){let b=R(p);b&&(c[m.tagNumber]=b,m.tagNumber>=1&&m.tagNumber<=4?l[o(m.tagNumber-1)]=b:m.tagNumber>=9&&m.tagNumber<=12&&(u[o(m.tagNumber-9)]=b));}else if(m.tagName==="PBAS"&&p.kind==="string")y[m.tagNumber]=p.value;else if(m.tagName==="PCON"){let b=m.elementSize===1?Array.from(m.payload.subarray(0,m.elementCount)):R(p);b&&(f[m.tagNumber]=b);}else if(m.tagName==="PLOC"){let b=R(p);b&&(h[m.tagNumber]=b.map(M=>M<0?M+65536:M));}else if(m.tagName==="SPAC")if(m.elementSize===4&&m.payload.byteLength>=4){let b=w(m.payload).getFloat32(0,false);Number.isFinite(b)&&b>0&&(d.samplingRate=b);}else p.kind==="number"&&(d.samplingRate=p.value);else if(m.tagName==="SMPL"&&p.kind==="string")d.sampleName=p.value;else if(m.tagName==="LANE"&&p.kind==="number")d.laneNumber=p.value;else if(m.tagName==="TUBE"&&p.kind==="string")d.tube=p.value;else if(m.tagName==="MCHN"&&p.kind==="string")d.machineName=p.value;else if(m.tagName==="MODL"&&p.kind==="string")d.machineModel=p.value;else if(m.tagName==="RUND"&&p.kind==="date"){let b=p.value;d.runDate=`${b.year}-${String(b.month).padStart(2,"0")}-${String(b.day).padStart(2,"0")}`;}else if(m.tagName==="RUNT"&&p.kind==="time"){let b=p.value;d.runTime=`${String(b.hour).padStart(2,"0")}:${String(b.minute).padStart(2,"0")}:${String(b.second).padStart(2,"0")}`;}else m.tagName==="CMNT"&&p.kind==="string"?d.comments.push(p.value):m.tagName==="RevC"&&m.tagNumber===1&&(p.kind==="number"?d.reverseComplemented=p.value!==0:p.kind==="numbers"&&(d.reverseComplemented=p.value.some(b=>b!==0)));}let g=Object.keys(y).map(Number).sort((s,m)=>s-m).map(s=>({version:s,role:s===1?"edited":s===2?"called":"unknown",sequence:y[s],confidences:f[s]??[],positions:h[s]??[]})),A,C=2 in y?2:1 in y?1:Object.keys(y).map(Number)[0];if(C!==void 0&&y[C]!==void 0){let s=y[C].toUpperCase(),m=f[C]??[];m.length!==s.length&&(m=Object.keys(f).map(Number).map(b=>f[b]).find(b=>b.length===s.length)??[]);let p=h[C]??[];p.length!==s.length&&(p=Object.keys(h).map(Number).map(b=>h[b]).find(b=>b.length===s.length)??[]),A={sequence:s,confidences:m,positions:p,pbasVersion:C};}if(!Number.isFinite(d.samplingRate)||(d.samplingRate??0)<=0){let s=A?.positions,m=Math.max(u.A.length,u.C.length,u.G.length,u.T.length);s&&s.length>1?d.samplingRate=(s[s.length-1]-s[0])/(s.length-1):A&&A.sequence.length>0&&m>0&&(d.samplingRate=m/A.sequence.length);}let T={baseOrder:i,dataChannels:c,data1To4:l,data9To12:u};return {fileName:n,fileSize:t.byteLength,abifVersion:r.version,macBinaryOffset:r.macBinaryOffset,dirEntryCount:r.entries.length,metadata:d,chromatogram:T,baseCalls:A,baseCallVariants:g,entries:a}}function Ee(e){return e.A.length>0||e.C.length>0||e.G.length>0||e.T.length>0}function $e(e){return Math.max(e.A.length,e.C.length,e.G.length,e.T.length)}function ke(e,n){$(e,"PBAS",2,E(n),{elementType:2,elementSize:1,elementCount:n.length});}function Be(e,n){let t=new Uint8Array(n.length);for(let r=0;r<n.length;r++)t[r]=Math.max(0,Math.min(255,Math.round(n[r])));$(e,"PCON",2,t,{elementType:2,elementSize:1,elementCount:n.length});}function Le(e,n){let t=new Uint8Array(n.length*2),r=w(t);for(let a=0;a<n.length;a++)r.setUint16(a*2,Math.max(0,Math.min(65535,n[a])),false);$(e,"PLOC",2,t,{elementType:4,elementSize:2,elementCount:n.length});}function Me(e,n,t){let r=new Uint8Array(4);w(r).setFloat32(0,n,false),$(e,"SPAC",1,r,{elementType:7,elementSize:4,elementCount:1});let a=E(t),i=Math.min(255,a.length),c=new Uint8Array(1+i);c[0]=i,c.set(a.subarray(0,i),1),$(e,"SPAC",2,c,{elementType:18,elementSize:1,elementCount:1+i});let l=new Uint8Array(4);w(l).setFloat32(0,n,false),$(e,"SPAC",3,l,{elementType:7,elementSize:4,elementCount:1});}function Oe(e){return e.length<2?0:(e[e.length-1]-e[0])/(e.length-1)}function Pe(e){if(!B(e))for(let n=1;n<=4;n++){let t=S(e,"DATA",n);if(!t)continue;let r=8+n;S(e,"DATA",r)||e.entries.push({tagName:"DATA",tagNumber:r,elementType:t.elementType,elementSize:t.elementSize,elementCount:t.elementCount,payload:new Uint8Array(t.payload),dataHandle:0});}}exports.ENTRY_SIZE=N;exports.HEADER_SIZE=F;exports.averagePeakSpacing=Oe;exports.channelMaxLength=$e;exports.cropAbif=Ce;exports.dataChannelRole=le;exports.ensureRawDataChannels=Pe;exports.findEntries=ie;exports.findEntry=S;exports.getChannelMap=ce;exports.getConfidences=ge;exports.getConfidencesForVersion=D;exports.getDataChannel=me;exports.getFwo=O;exports.getPositions=be;exports.getPositionsForVersion=k;exports.getReverseComplemented=fe;exports.getSamplingRate=he;exports.getSequence=de;exports.getSequenceForVersion=U;exports.hasData9To12Block=B;exports.hasSignals=Ee;exports.isFwoPermutation=P;exports.parseAbif=ze;exports.readAbif=G;exports.setAveragePeakSpacing=Me;exports.setConfidences=Be;exports.setPositions=Le;exports.setSequence=ke;exports.tagNameFromInt32=_;exports.upsertEntry=$;exports.writeAbif=ae;//# sourceMappingURL=index.js.map
2
2
  //# sourceMappingURL=index.js.map