@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.
- package/dist/abif/index.d.mts +83 -3
- package/dist/abif/index.d.ts +83 -3
- package/dist/abif/index.js +1 -1
- package/dist/abif/index.js.map +1 -1
- package/dist/abif/index.mjs +1 -1
- package/dist/abif/index.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +7 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +7 -7
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/abif/index.d.mts
CHANGED
|
@@ -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
|
-
*
|
|
394
|
-
*
|
|
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 };
|
package/dist/abif/index.d.ts
CHANGED
|
@@ -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
|
-
*
|
|
394
|
-
*
|
|
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 };
|
package/dist/abif/index.js
CHANGED
|
@@ -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
|