@fishka/seqio 0.5.0 → 0.6.1

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.
@@ -390,8 +390,23 @@ declare function findEntry(file: AbifFile, name: string, number: number): AbifEn
390
390
  /** Find all entries with the given tag name. */
391
391
  declare function findEntries(file: AbifFile, name: string): AbifEntry[];
392
392
  /**
393
- * Replace the payload of an existing entry, or append a new one.
394
- * elementType/elementSize/elementCount must be supplied for new entries.
393
+ * Insert a new entry at the slot that keeps the directory sorted by
394
+ * (tagName, tagNumber) the order genuine ABI instruments emit and the ABIF
395
+ * spec prescribes. Readers that binary-search the directory (e.g. Chromas)
396
+ * silently miss a tag appended out of order — a re-basecalled file loses its
397
+ * quality bars because PCON2 is not found. Existing entries are never reordered,
398
+ * so an unmodified file still round-trips byte-exact; only the freshly added tag
399
+ * lands in its sorted place.
400
+ *
401
+ * Prefer {@link upsertEntry}; use this directly only to add an entry whose
402
+ * payload intentionally desyncs from `elementCount * elementSize` (e.g. copying
403
+ * a tolerated malformed record verbatim), which upsertEntry rejects.
404
+ */
405
+ declare function insertEntrySorted(entries: AbifEntry[], entry: AbifEntry): void;
406
+ /**
407
+ * Replace the payload of an existing entry, or insert a new one in sorted
408
+ * directory order. elementType/elementSize/elementCount must be supplied for
409
+ * new entries.
395
410
  *
396
411
  * This is the required way to mutate an entry read from a file — it clears `.raw`
397
412
  * on replacement so writeAbif() never reuses a now-stale on-disk shape. Setting
@@ -404,6 +419,55 @@ declare function upsertEntry(file: AbifFile, name: string, number: number, paylo
404
419
  elementCount: number;
405
420
  }): void;
406
421
 
422
+ /**
423
+ * Domain-layer operation: crop an ABIF file to a sample range.
424
+ *
425
+ * `{ start, end }` is a half-open sample range in the DATA9..12 (processed/analyzed)
426
+ * domain — the only domain PLOC maps into (see AGENTS.md's "raw vs processed" note).
427
+ * DATA9..12 are sliced exactly by that range. DATA1..4/5..8 (raw dye trace and
428
+ * instrument telemetry) have no honest sample-for-sample correspondence to the
429
+ * processed domain (the mapping is non-linear mobility correction, not stored in the
430
+ * file), so they are never approximated: `rawTrace` keeps them whole and untouched,
431
+ * or omits them, never a proportional slice.
432
+ *
433
+ * Every basecall version the file carries (PBAS1/PCON1/PLOC1 "edited",
434
+ * PBAS2/PCON2/PLOC2 "called", or any vendor version) is cropped independently by its
435
+ * OWN PLOC — two versions are not guaranteed to share base positions or even length
436
+ * (edits insert/delete bases), so there is no shared coordinate to crop them together
437
+ * by. A version with no PLOC of its own cannot be cropped and is rejected rather than
438
+ * silently dropped or left un-cropped.
439
+ *
440
+ * Everything else (metadata, FWO_, SPAC, ...) is carried over untouched — this is a
441
+ * structural crop, not a re-derivation of run metadata for the new region.
442
+ *
443
+ * Reverse-complement is out of scope here; this function has no RC option.
444
+ *
445
+ * Returns a new, independently mutable AbifFile — the input is not mutated, and
446
+ * neither is the output if the input is later touched. Untouched entries are
447
+ * shallow-copied (a new AbifEntry object; the underlying payload bytes are shared,
448
+ * which is safe since nothing ever mutates payload bytes in place — only replaces
449
+ * them wholesale), so a later upsertEntry() on either file's copy of a shared tag
450
+ * can't reach into the other file's entries.
451
+ */
452
+
453
+ interface CropAbifRange {
454
+ /** Inclusive start sample index into DATA9..12. */
455
+ start: number;
456
+ /** Exclusive end sample index into DATA9..12. */
457
+ end: number;
458
+ }
459
+ interface CropAbifOptions {
460
+ /**
461
+ * DATA1..4 (raw dye trace) and DATA5..8 (telemetry): 'full' keeps them whole and
462
+ * untouched (the exported file's raw trace no longer lines up sample-for-sample
463
+ * with the cropped DATA9..12/PLOC, by design — see the module doc comment);
464
+ * 'omit' drops them from the output entirely. Default 'omit'.
465
+ */
466
+ rawTrace?: 'full' | 'omit';
467
+ }
468
+ /** Crop an AbifFile to a DATA9..12 sample range. See the module doc comment for the model. */
469
+ declare function cropAbif(file: AbifFile, range: CropAbifRange, options?: CropAbifOptions): AbifFile;
470
+
407
471
  /**
408
472
  * High-level "parse everything" wrapper around the raw + view layers.
409
473
  *
@@ -544,6 +608,12 @@ declare function getReverseComplemented(file: AbifFile): boolean | undefined;
544
608
  declare function getChannelMap(file: AbifFile): Record<'A' | 'C' | 'G' | 'T', number>;
545
609
  /** Get PBAS sequence (prefer PBAS2 over PBAS1). undefined if neither present. */
546
610
  declare function getSequence(file: AbifFile): string | undefined;
611
+ /**
612
+ * Get PBAS<version> exactly as stored — no called/edited preference, unlike
613
+ * {@link getSequence}. Used where each basecall version must be handled on its
614
+ * own (e.g. cropping every version a file carries, not just the preferred one).
615
+ */
616
+ declare function getSequenceForVersion(file: AbifFile, version: number): string | undefined;
547
617
  /**
548
618
  * Get per-base Phred-like quality scores (0..255 byte values, typically 0..60
549
619
  * for Sanger). Prefers PCON2 over PCON1.
@@ -552,6 +622,11 @@ declare function getSequence(file: AbifFile): string | undefined;
552
622
  * values ARE the Q-scores — we read raw bytes regardless of declared type.
553
623
  */
554
624
  declare function getConfidences(file: AbifFile): number[] | undefined;
625
+ /**
626
+ * Get PCON<version> exactly as stored — no called/edited preference, unlike
627
+ * {@link getConfidences}. See {@link getSequenceForVersion} for why this exists.
628
+ */
629
+ declare function getConfidencesForVersion(file: AbifFile, version: number): number[] | undefined;
555
630
  /**
556
631
  * Get peak scan positions (one per base). Prefers PLOC2 over PLOC1.
557
632
  *
@@ -560,6 +635,11 @@ declare function getConfidences(file: AbifFile): number[] | undefined;
560
635
  * if interpreted as signed.
561
636
  */
562
637
  declare function getPositions(file: AbifFile): number[] | undefined;
638
+ /**
639
+ * Get PLOC<version> exactly as stored — no called/edited preference, unlike
640
+ * {@link getPositions}. See {@link getSequenceForVersion} for why this exists.
641
+ */
642
+ declare function getPositionsForVersion(file: AbifFile, version: number): number[] | undefined;
563
643
  /**
564
644
  * Get average peak spacing (samples per base), from SPAC/1.
565
645
  *
@@ -571,4 +651,4 @@ declare function getPositions(file: AbifFile): number[] | undefined;
571
651
  */
572
652
  declare function getSamplingRate(file: AbifFile): number | undefined;
573
653
 
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 };
654
+ 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, insertEntrySorted, isFwoPermutation, parseAbif, readAbif, setAveragePeakSpacing, setConfidences, setPositions, setSequence, tagNameFromInt32, upsertEntry, writeAbif };
@@ -390,8 +390,23 @@ declare function findEntry(file: AbifFile, name: string, number: number): AbifEn
390
390
  /** Find all entries with the given tag name. */
391
391
  declare function findEntries(file: AbifFile, name: string): AbifEntry[];
392
392
  /**
393
- * Replace the payload of an existing entry, or append a new one.
394
- * elementType/elementSize/elementCount must be supplied for new entries.
393
+ * Insert a new entry at the slot that keeps the directory sorted by
394
+ * (tagName, tagNumber) the order genuine ABI instruments emit and the ABIF
395
+ * spec prescribes. Readers that binary-search the directory (e.g. Chromas)
396
+ * silently miss a tag appended out of order — a re-basecalled file loses its
397
+ * quality bars because PCON2 is not found. Existing entries are never reordered,
398
+ * so an unmodified file still round-trips byte-exact; only the freshly added tag
399
+ * lands in its sorted place.
400
+ *
401
+ * Prefer {@link upsertEntry}; use this directly only to add an entry whose
402
+ * payload intentionally desyncs from `elementCount * elementSize` (e.g. copying
403
+ * a tolerated malformed record verbatim), which upsertEntry rejects.
404
+ */
405
+ declare function insertEntrySorted(entries: AbifEntry[], entry: AbifEntry): void;
406
+ /**
407
+ * Replace the payload of an existing entry, or insert a new one in sorted
408
+ * directory order. elementType/elementSize/elementCount must be supplied for
409
+ * new entries.
395
410
  *
396
411
  * This is the required way to mutate an entry read from a file — it clears `.raw`
397
412
  * on replacement so writeAbif() never reuses a now-stale on-disk shape. Setting
@@ -404,6 +419,55 @@ declare function upsertEntry(file: AbifFile, name: string, number: number, paylo
404
419
  elementCount: number;
405
420
  }): void;
406
421
 
422
+ /**
423
+ * Domain-layer operation: crop an ABIF file to a sample range.
424
+ *
425
+ * `{ start, end }` is a half-open sample range in the DATA9..12 (processed/analyzed)
426
+ * domain — the only domain PLOC maps into (see AGENTS.md's "raw vs processed" note).
427
+ * DATA9..12 are sliced exactly by that range. DATA1..4/5..8 (raw dye trace and
428
+ * instrument telemetry) have no honest sample-for-sample correspondence to the
429
+ * processed domain (the mapping is non-linear mobility correction, not stored in the
430
+ * file), so they are never approximated: `rawTrace` keeps them whole and untouched,
431
+ * or omits them, never a proportional slice.
432
+ *
433
+ * Every basecall version the file carries (PBAS1/PCON1/PLOC1 "edited",
434
+ * PBAS2/PCON2/PLOC2 "called", or any vendor version) is cropped independently by its
435
+ * OWN PLOC — two versions are not guaranteed to share base positions or even length
436
+ * (edits insert/delete bases), so there is no shared coordinate to crop them together
437
+ * by. A version with no PLOC of its own cannot be cropped and is rejected rather than
438
+ * silently dropped or left un-cropped.
439
+ *
440
+ * Everything else (metadata, FWO_, SPAC, ...) is carried over untouched — this is a
441
+ * structural crop, not a re-derivation of run metadata for the new region.
442
+ *
443
+ * Reverse-complement is out of scope here; this function has no RC option.
444
+ *
445
+ * Returns a new, independently mutable AbifFile — the input is not mutated, and
446
+ * neither is the output if the input is later touched. Untouched entries are
447
+ * shallow-copied (a new AbifEntry object; the underlying payload bytes are shared,
448
+ * which is safe since nothing ever mutates payload bytes in place — only replaces
449
+ * them wholesale), so a later upsertEntry() on either file's copy of a shared tag
450
+ * can't reach into the other file's entries.
451
+ */
452
+
453
+ interface CropAbifRange {
454
+ /** Inclusive start sample index into DATA9..12. */
455
+ start: number;
456
+ /** Exclusive end sample index into DATA9..12. */
457
+ end: number;
458
+ }
459
+ interface CropAbifOptions {
460
+ /**
461
+ * DATA1..4 (raw dye trace) and DATA5..8 (telemetry): 'full' keeps them whole and
462
+ * untouched (the exported file's raw trace no longer lines up sample-for-sample
463
+ * with the cropped DATA9..12/PLOC, by design — see the module doc comment);
464
+ * 'omit' drops them from the output entirely. Default 'omit'.
465
+ */
466
+ rawTrace?: 'full' | 'omit';
467
+ }
468
+ /** Crop an AbifFile to a DATA9..12 sample range. See the module doc comment for the model. */
469
+ declare function cropAbif(file: AbifFile, range: CropAbifRange, options?: CropAbifOptions): AbifFile;
470
+
407
471
  /**
408
472
  * High-level "parse everything" wrapper around the raw + view layers.
409
473
  *
@@ -544,6 +608,12 @@ declare function getReverseComplemented(file: AbifFile): boolean | undefined;
544
608
  declare function getChannelMap(file: AbifFile): Record<'A' | 'C' | 'G' | 'T', number>;
545
609
  /** Get PBAS sequence (prefer PBAS2 over PBAS1). undefined if neither present. */
546
610
  declare function getSequence(file: AbifFile): string | undefined;
611
+ /**
612
+ * Get PBAS<version> exactly as stored — no called/edited preference, unlike
613
+ * {@link getSequence}. Used where each basecall version must be handled on its
614
+ * own (e.g. cropping every version a file carries, not just the preferred one).
615
+ */
616
+ declare function getSequenceForVersion(file: AbifFile, version: number): string | undefined;
547
617
  /**
548
618
  * Get per-base Phred-like quality scores (0..255 byte values, typically 0..60
549
619
  * for Sanger). Prefers PCON2 over PCON1.
@@ -552,6 +622,11 @@ declare function getSequence(file: AbifFile): string | undefined;
552
622
  * values ARE the Q-scores — we read raw bytes regardless of declared type.
553
623
  */
554
624
  declare function getConfidences(file: AbifFile): number[] | undefined;
625
+ /**
626
+ * Get PCON<version> exactly as stored — no called/edited preference, unlike
627
+ * {@link getConfidences}. See {@link getSequenceForVersion} for why this exists.
628
+ */
629
+ declare function getConfidencesForVersion(file: AbifFile, version: number): number[] | undefined;
555
630
  /**
556
631
  * Get peak scan positions (one per base). Prefers PLOC2 over PLOC1.
557
632
  *
@@ -560,6 +635,11 @@ declare function getConfidences(file: AbifFile): number[] | undefined;
560
635
  * if interpreted as signed.
561
636
  */
562
637
  declare function getPositions(file: AbifFile): number[] | undefined;
638
+ /**
639
+ * Get PLOC<version> exactly as stored — no called/edited preference, unlike
640
+ * {@link getPositions}. See {@link getSequenceForVersion} for why this exists.
641
+ */
642
+ declare function getPositionsForVersion(file: AbifFile, version: number): number[] | undefined;
563
643
  /**
564
644
  * Get average peak spacing (samples per base), from SPAC/1.
565
645
  *
@@ -571,4 +651,4 @@ declare function getPositions(file: AbifFile): number[] | undefined;
571
651
  */
572
652
  declare function getSamplingRate(file: AbifFile): number | undefined;
573
653
 
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 };
654
+ 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, insertEntrySorted, 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 E(e){let n="";for(let t=0;t<e.length;t++)n+=String.fromCharCode(e[t]);return n}function z(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 W(e){return String.fromCharCode(e>>>24&255,e>>>16&255,e>>>8&255,e&255)}var v=128,N=28;function j(e){if(e.byteLength<v)throw new Error(`ABIF too small: ${e.byteLength} bytes`);let n=0;if(E(x(e,0,4))!=="ABIF")if(e.byteLength>=132&&E(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<v)throw new Error(`ABIF too small: ${e.byteLength-t} bytes after offset ${t}`);let r=w(e),a=r.getInt16(t+4,false),i=H(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(H(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,v-6-N)),A=n===128?new Uint8Array(x(e,0,128)):void 0,C=Y(e,t,u,y,d,n);return {version:a,tdir:o,entries:d,macBinaryOffset:n,macBinaryHeader:A,headerReserved:g,unreferencedRanges:C}}function Y(e,n,t,r,a,i){let c=e.byteLength,l=[];i===128&&l.push([0,128]),l.push([n,n+v]);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 H(e,n,t,r){let a=E(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 oe(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=v;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(z("ABIF"),0),h.setInt16(4,e.version,false),f.set(e.headerReserved,6+N),G(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;G(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 G(e,n,t,r){if(r.tagName.length!==4)throw new Error(`tagName must be 4 chars: "${r.tagName}"`);if(e.set(z(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 se(e,n){return e.entries.filter(t=>t.tagName===n)}function Z(e,n){return e.tagName!==n.tagName?e.tagName<n.tagName?-1:1:e.tagNumber-n.tagNumber}function O(e,n){let t=e.findIndex(r=>Z(r,n)>0);e.splice(t<0?e.length:t,0,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):O(e.entries,{tagName:n,tagNumber:t,elementType:a.elementType,elementSize:a.elementSize,elementCount:a.elementCount,payload:r,dataHandle:0});}function fe(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 P(e){let n=S(e,"FWO_",1);return n?E(n.payload.subarray(0,n.elementCount)):"GATC"}function R(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 ce(e){return e>=5&&e<=8?"telemetry":e>=1&&e<=4||e>=9&&e<=12||e===105||e===205?"trace":"other"}function de(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 ge(e){let n=P(e);if(!R(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 be(e){return U(e,2)??U(e,1)}function U(e,n){let t=S(e,"PBAS",n);if(t)return E(t.payload.subarray(0,t.elementCount)).replace(/\0+$/g,"")}function he(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 pe(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 ye(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 Ne(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(J(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 K(e))l.push(...Q(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 J(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 K(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 Q(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:z(u),dataHandle:0},{tagName:"PLOC",tagNumber:n,elementType:4,elementSize:2,elementCount:d.length,payload:X(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 X(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 ee={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 V(e){return ee[e]??(e>=1024?`user${e}`:`type${e}`)}function te(e,n=10){return e.length<=n?`[${e.join(", ")}]`:`[${e.slice(0,n).join(", ")}, \u2026 +${e.length-n}] (n=${e.length})`}function ne(e,n=80){return e.length>n?e.slice(0,n)+"\u2026":e}function q(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 I(e){if(e.kind==="numbers")return e.value;if(e.kind==="number")return [e.value]}function F(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 _(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:E(t.subarray(0,n)).replace(/\0+$/g,"")};case 3:return F(t.byteLength,n,2,a=>r.getUint16(a,false));case 4:return F(t.byteLength,n,2,a=>r.getInt16(a,false));case 5:return F(t.byteLength,n,4,a=>r.getInt32(a,false));case 7:return F(t.byteLength,n,4,a=>r.getFloat32(a,false));case 8:return F(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:E(x(t,1,Math.min(a,Math.max(0,n-1))))}}default:return {kind:"unknown",value:t}}}function re(e,n){switch(e.kind){case "number":return String(e.value);case "numbers":return te(e.value);case "string":return ne(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 `${V(n)} ${q(e.value)}`;case "unknown":return `${V(n)} ${q(e.value)}`}}function $e(e,n=""){let t=e instanceof Uint8Array?e:new Uint8Array(e),r=j(t),a=r.entries.map(s=>{let m=s.tagName==="PCON"&&s.elementSize===1?_(1,s.elementCount,s.payload):_(s.elementType,s.elementCount,s.payload);return {tag:s.tagName,tagNumber:s.tagNumber,elementType:s.elementType,elementTypeName:V(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:re(m,s.elementType)}}),i=P(r);R(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=I(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)):I(p);b&&(f[m.tagNumber]=b);}else if(m.tagName==="PLOC"){let b=I(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 ve(e){return e.A.length>0||e.C.length>0||e.G.length>0||e.T.length>0}function Fe(e){return Math.max(e.A.length,e.C.length,e.G.length,e.T.length)}function Le(e,n){$(e,"PBAS",2,z(n),{elementType:2,elementSize:1,elementCount:n.length});}function Me(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 Oe(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 Pe(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=z(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 Re(e){return e.length<2?0:(e[e.length-1]-e[0])/(e.length-1)}function Ie(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)||O(e.entries,{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=v;exports.averagePeakSpacing=Re;exports.channelMaxLength=Fe;exports.cropAbif=Ne;exports.dataChannelRole=ce;exports.ensureRawDataChannels=Ie;exports.findEntries=se;exports.findEntry=S;exports.getChannelMap=ge;exports.getConfidences=he;exports.getConfidencesForVersion=D;exports.getDataChannel=fe;exports.getFwo=P;exports.getPositions=pe;exports.getPositionsForVersion=k;exports.getReverseComplemented=de;exports.getSamplingRate=ye;exports.getSequence=be;exports.getSequenceForVersion=U;exports.hasData9To12Block=B;exports.hasSignals=ve;exports.insertEntrySorted=O;exports.isFwoPermutation=R;exports.parseAbif=$e;exports.readAbif=j;exports.setAveragePeakSpacing=Pe;exports.setConfidences=Me;exports.setPositions=Oe;exports.setSequence=Le;exports.tagNameFromInt32=W;exports.upsertEntry=$;exports.writeAbif=oe;//# sourceMappingURL=index.js.map
2
2
  //# sourceMappingURL=index.js.map