@fishka/seqio 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -39
- package/dist/abif/index.d.mts +126 -96
- package/dist/abif/index.d.ts +126 -96
- 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.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/abif/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
declare function tagNameFromInt32(n: number): string;
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Low-level ABIF file model: a flat list of directory entries with raw
|
|
3
5
|
* payloads. Lossless round-trip is preserved: every entry (including unknown
|
|
@@ -60,7 +62,10 @@ interface AbifEntry {
|
|
|
60
62
|
/**
|
|
61
63
|
* The directory fields exactly as they were on disk — present only when this entry was read from a
|
|
62
64
|
* file (absent for entries synthesized by setters/writeAbif). Lets consumers inspect the real record
|
|
63
|
-
* without our reconciliation
|
|
65
|
+
* without our reconciliation, and lets writeAbif() reuse this entry's original directory slot/offset
|
|
66
|
+
* verbatim on an unmodified round-trip. Mutate entries only through upsertEntry() — it clears this
|
|
67
|
+
* field, since a hand-edited entry (payload/elementType/elementSize/elementCount set directly) can no
|
|
68
|
+
* longer be reproduced from its stale on-disk shape.
|
|
64
69
|
*/
|
|
65
70
|
raw?: AbifEntryRaw;
|
|
66
71
|
}
|
|
@@ -292,14 +297,13 @@ type AbifDecodedValue = {
|
|
|
292
297
|
value: Uint8Array;
|
|
293
298
|
};
|
|
294
299
|
|
|
295
|
-
declare function tagNameFromInt32(n: number): string;
|
|
296
|
-
|
|
297
300
|
/**
|
|
298
|
-
*
|
|
299
|
-
*
|
|
300
|
-
*
|
|
301
|
-
*
|
|
302
|
-
*
|
|
301
|
+
* Raw layer: the ABIF byte<->struct codec. Every directory entry (including unknown
|
|
302
|
+
* vendor tags) is preserved as a raw payload (Uint8Array), and writeAbif() reproduces
|
|
303
|
+
* the original bytes exactly for an unmodified round-trip (see its own doc comment).
|
|
304
|
+
* The domain layer (view.ts, setters.ts, parser.ts, abif-op-*.ts) provides typed,
|
|
305
|
+
* format-aware access on top of this — this file knows nothing about what any tag
|
|
306
|
+
* means.
|
|
303
307
|
*
|
|
304
308
|
* ABIF file layout:
|
|
305
309
|
* [0..3] "ABIF" magic
|
|
@@ -350,14 +354,35 @@ declare function readAbif(bytes: Uint8Array): AbifFile;
|
|
|
350
354
|
/**
|
|
351
355
|
* Serialize an AbifFile back to a Uint8Array.
|
|
352
356
|
*
|
|
353
|
-
*
|
|
354
|
-
*
|
|
355
|
-
*
|
|
356
|
-
*
|
|
357
|
-
*
|
|
358
|
-
*
|
|
359
|
-
*
|
|
360
|
-
*
|
|
357
|
+
* Byte-exact on an unmodified round-trip for well-formed records and the tolerated
|
|
358
|
+
* count/dataSize desyncs readAbif() accepts: readAbif() followed right back by
|
|
359
|
+
* writeAbif(), with nothing touched in between, reproduces the original bytes
|
|
360
|
+
* exactly (a MacBinary-wrapped input round-trips its ABIF payload byte-exact, but
|
|
361
|
+
* the preamble itself is never re-added — see the AGENTS.md note on why). The one
|
|
362
|
+
* exception is a genuinely invalid negative `dataSize`/`numElements` field (readAbif
|
|
363
|
+
* tolerates these defensively, falling back to a computed size, but never treats them
|
|
364
|
+
* as verbatim-eligible on write — see the byteLength check below) — such an entry
|
|
365
|
+
* round-trips meaning-lossless (correct payload/content) but its declared dataSize
|
|
366
|
+
* field gets normalized to the real payload length rather than reproducing the
|
|
367
|
+
* original garbage value.
|
|
368
|
+
*
|
|
369
|
+
* This works by keeping every entry whose payload size hasn't changed since it was
|
|
370
|
+
* read (`entry.raw` present — upsertEntry() clears it on any mutation — and
|
|
371
|
+
* `payload.byteLength === raw.dataSize`) at its exact original directory slot and
|
|
372
|
+
* file offset, writing the *original* on-disk numElements/dataSize/offset-or-inline-
|
|
373
|
+
* padding instead of the reconciled/current ones. A new or resized entry is appended
|
|
374
|
+
* past the highest byte offset still known to hold preserved content (every verbatim
|
|
375
|
+
* entry's span, the directory, and any unreferenced range); only its own directory
|
|
376
|
+
* record changes, so every other entry's bytes stay untouched. A resized/removed
|
|
377
|
+
* entry's *old* span is not itself reserved — nothing points at it anymore, so it is
|
|
378
|
+
* free to be reused by whatever gets appended next; the output is not padded out to
|
|
379
|
+
* the original file's true end.
|
|
380
|
+
*
|
|
381
|
+
* The directory is kept at its original file offset as long as the entry count
|
|
382
|
+
* didn't grow (removing entries just shortens it in place; the original directory
|
|
383
|
+
* padding is only reused when the count is exactly unchanged, since a shorter
|
|
384
|
+
* directory can't reuse padding sized for more entries). Only a growing entry count
|
|
385
|
+
* relocates the whole directory to freshly appended space.
|
|
361
386
|
*/
|
|
362
387
|
declare function writeAbif(file: AbifFile): Uint8Array;
|
|
363
388
|
/** Find an entry by name+number, or undefined. */
|
|
@@ -367,6 +392,11 @@ declare function findEntries(file: AbifFile, name: string): AbifEntry[];
|
|
|
367
392
|
/**
|
|
368
393
|
* Replace the payload of an existing entry, or append a new one.
|
|
369
394
|
* elementType/elementSize/elementCount must be supplied for new entries.
|
|
395
|
+
*
|
|
396
|
+
* This is the required way to mutate an entry read from a file — it clears `.raw`
|
|
397
|
+
* on replacement so writeAbif() never reuses a now-stale on-disk shape. Setting
|
|
398
|
+
* `entry.payload`/`elementType`/`elementSize`/`elementCount` directly instead
|
|
399
|
+
* leaves `.raw` behind and can corrupt the written directory record.
|
|
370
400
|
*/
|
|
371
401
|
declare function upsertEntry(file: AbifFile, name: string, number: number, payload: Uint8Array, defaults: {
|
|
372
402
|
elementType: number;
|
|
@@ -374,6 +404,86 @@ declare function upsertEntry(file: AbifFile, name: string, number: number, paylo
|
|
|
374
404
|
elementCount: number;
|
|
375
405
|
}): void;
|
|
376
406
|
|
|
407
|
+
/**
|
|
408
|
+
* High-level "parse everything" wrapper around the raw + view layers.
|
|
409
|
+
*
|
|
410
|
+
* Returns a single ParsedAbif object with metadata, the FWO_-aware
|
|
411
|
+
* DATA1..4 / DATA9..12 channel split, basecalls, and decoded directory entries
|
|
412
|
+
* for diagnostics. Mirrors what typical viewers (chromatogram UIs, sample
|
|
413
|
+
* inspectors) need from a single file.
|
|
414
|
+
*
|
|
415
|
+
* For round-trip authoring (basecallers), prefer {@link readAbif} +
|
|
416
|
+
* setters from ./setters which operate directly on the raw AbifFile.
|
|
417
|
+
*/
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Parse an ABIF file into a high-level view: metadata, channels, basecalls,
|
|
421
|
+
* and decoded directory entries.
|
|
422
|
+
*
|
|
423
|
+
* This is the INTERPRETING layer — it makes convenience choices (FWO_ → "GATC"
|
|
424
|
+
* fallback, derived samplingRate, preferred/upper-cased PBAS2 baseCalls). It is
|
|
425
|
+
* not the raw structural truth: for that use {@link readAbif}, which reads the
|
|
426
|
+
* directory verbatim (raw dataSize/offset/counts, tdir, inline bytes) and makes
|
|
427
|
+
* no interpretation. `parseAbif` builds on top of it.
|
|
428
|
+
*
|
|
429
|
+
* Accepts ArrayBuffer or Uint8Array (Buffer in Node works too — it extends
|
|
430
|
+
* Uint8Array). The `fileName` argument is informational only; it's preserved
|
|
431
|
+
* in the result.
|
|
432
|
+
*/
|
|
433
|
+
declare function parseAbif(input: ArrayBuffer | Uint8Array, fileName?: string): ParsedAbif;
|
|
434
|
+
/** True when any channel has at least one signal value. */
|
|
435
|
+
declare function hasSignals(s: ChannelSignals): boolean;
|
|
436
|
+
/** Length of the longest channel in a ChannelSignals bundle. */
|
|
437
|
+
declare function channelMaxLength(s: ChannelSignals): number;
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Mutation helpers for AbifFile: write PBAS/PCON/PLOC/SPAC and ensure DATA9..12
|
|
441
|
+
* are present. Used by basecallers to author ABIF output.
|
|
442
|
+
*/
|
|
443
|
+
|
|
444
|
+
/** Set PBAS2 (replaces if present). */
|
|
445
|
+
declare function setSequence(file: AbifFile, sequence: string): void;
|
|
446
|
+
/** Set PCON2 (replaces if present). Values clamped to [0, 255]. */
|
|
447
|
+
declare function setConfidences(file: AbifFile, q: ArrayLike<number>): void;
|
|
448
|
+
/**
|
|
449
|
+
* Set PLOC2 (replaces if present).
|
|
450
|
+
*
|
|
451
|
+
* Written as UNSIGNED int16 so positions up to 65535 are preserved on disk
|
|
452
|
+
* (signed int16 would wrap on traces with > 32k scans).
|
|
453
|
+
*/
|
|
454
|
+
declare function setPositions(file: AbifFile, positions: ArrayLike<number>): void;
|
|
455
|
+
/**
|
|
456
|
+
* Set SPAC/1, SPAC/2, SPAC/3 — the standard ABIF "average peak spacing" trio
|
|
457
|
+
* that KB-basecaller writes and downstream tools (BioPython, Sequencher,
|
|
458
|
+
* KB-aware viewers) expect:
|
|
459
|
+
*
|
|
460
|
+
* - SPAC/1 (float32) — average peak spacing used in last analysis.
|
|
461
|
+
* - SPAC/2 (pString) — basecaller name / identifier.
|
|
462
|
+
* - SPAC/3 (float32) — average peak spacing computed by the basecaller.
|
|
463
|
+
*
|
|
464
|
+
* Both float fields are written with the same value.
|
|
465
|
+
*/
|
|
466
|
+
declare function setAveragePeakSpacing(file: AbifFile, spacing: number, basecallerName: string): void;
|
|
467
|
+
/**
|
|
468
|
+
* Mean consecutive peak-to-peak distance in scans, from a positions array.
|
|
469
|
+
* Returns 0 when fewer than 2 positions are present.
|
|
470
|
+
*/
|
|
471
|
+
declare function averagePeakSpacing(positions: ArrayLike<number>): number;
|
|
472
|
+
/**
|
|
473
|
+
* Ensure DATA9..12 are present in the file. Many downstream consumers
|
|
474
|
+
* (BioPython-style readers, viewers) read the chromatogram signal from
|
|
475
|
+
* DATA9..12 by convention — these tags are the raw fluorescence on newer
|
|
476
|
+
* instruments. Older files that only carry DATA1..8 break those consumers
|
|
477
|
+
* with a "no signal" error after re-basecalling.
|
|
478
|
+
*
|
|
479
|
+
* We populate DATA9..12 by copying DATA1..4 (which on DATA1..8-only files IS
|
|
480
|
+
* the raw signal). The DATA1..4 tags are left untouched so any tool that
|
|
481
|
+
* reads them keeps working.
|
|
482
|
+
*
|
|
483
|
+
* No-op when DATA9..12 already exist.
|
|
484
|
+
*/
|
|
485
|
+
declare function ensureRawDataChannels(file: AbifFile): void;
|
|
486
|
+
|
|
377
487
|
/**
|
|
378
488
|
* High-level typed view over an AbifFile.
|
|
379
489
|
*
|
|
@@ -461,84 +571,4 @@ declare function getPositions(file: AbifFile): number[] | undefined;
|
|
|
461
571
|
*/
|
|
462
572
|
declare function getSamplingRate(file: AbifFile): number | undefined;
|
|
463
573
|
|
|
464
|
-
/**
|
|
465
|
-
* Mutation helpers for AbifFile: write PBAS/PCON/PLOC/SPAC and ensure DATA9..12
|
|
466
|
-
* are present. Used by basecallers to author ABIF output.
|
|
467
|
-
*/
|
|
468
|
-
|
|
469
|
-
/** Set PBAS2 (replaces if present). */
|
|
470
|
-
declare function setSequence(file: AbifFile, sequence: string): void;
|
|
471
|
-
/** Set PCON2 (replaces if present). Values clamped to [0, 255]. */
|
|
472
|
-
declare function setConfidences(file: AbifFile, q: ArrayLike<number>): void;
|
|
473
|
-
/**
|
|
474
|
-
* Set PLOC2 (replaces if present).
|
|
475
|
-
*
|
|
476
|
-
* Written as UNSIGNED int16 so positions up to 65535 are preserved on disk
|
|
477
|
-
* (signed int16 would wrap on traces with > 32k scans).
|
|
478
|
-
*/
|
|
479
|
-
declare function setPositions(file: AbifFile, positions: ArrayLike<number>): void;
|
|
480
|
-
/**
|
|
481
|
-
* Set SPAC/1, SPAC/2, SPAC/3 — the standard ABIF "average peak spacing" trio
|
|
482
|
-
* that KB-basecaller writes and downstream tools (BioPython, Sequencher,
|
|
483
|
-
* KB-aware viewers) expect:
|
|
484
|
-
*
|
|
485
|
-
* - SPAC/1 (float32) — average peak spacing used in last analysis.
|
|
486
|
-
* - SPAC/2 (pString) — basecaller name / identifier.
|
|
487
|
-
* - SPAC/3 (float32) — average peak spacing computed by the basecaller.
|
|
488
|
-
*
|
|
489
|
-
* Both float fields are written with the same value.
|
|
490
|
-
*/
|
|
491
|
-
declare function setAveragePeakSpacing(file: AbifFile, spacing: number, basecallerName: string): void;
|
|
492
|
-
/**
|
|
493
|
-
* Mean consecutive peak-to-peak distance in scans, from a positions array.
|
|
494
|
-
* Returns 0 when fewer than 2 positions are present.
|
|
495
|
-
*/
|
|
496
|
-
declare function averagePeakSpacing(positions: ArrayLike<number>): number;
|
|
497
|
-
/**
|
|
498
|
-
* Ensure DATA9..12 are present in the file. Many downstream consumers
|
|
499
|
-
* (BioPython-style readers, viewers) read the chromatogram signal from
|
|
500
|
-
* DATA9..12 by convention — these tags are the raw fluorescence on newer
|
|
501
|
-
* instruments. Older files that only carry DATA1..8 break those consumers
|
|
502
|
-
* with a "no signal" error after re-basecalling.
|
|
503
|
-
*
|
|
504
|
-
* We populate DATA9..12 by copying DATA1..4 (which on DATA1..8-only files IS
|
|
505
|
-
* the raw signal). The DATA1..4 tags are left untouched so any tool that
|
|
506
|
-
* reads them keeps working.
|
|
507
|
-
*
|
|
508
|
-
* No-op when DATA9..12 already exist.
|
|
509
|
-
*/
|
|
510
|
-
declare function ensureRawDataChannels(file: AbifFile): void;
|
|
511
|
-
|
|
512
|
-
/**
|
|
513
|
-
* High-level "parse everything" wrapper around the raw + view layers.
|
|
514
|
-
*
|
|
515
|
-
* Returns a single ParsedAbif object with metadata, the FWO_-aware
|
|
516
|
-
* DATA1..4 / DATA9..12 channel split, basecalls, and decoded directory entries
|
|
517
|
-
* for diagnostics. Mirrors what typical viewers (chromatogram UIs, sample
|
|
518
|
-
* inspectors) need from a single file.
|
|
519
|
-
*
|
|
520
|
-
* For round-trip authoring (basecallers), prefer {@link readAbif} +
|
|
521
|
-
* setters from ./setters which operate directly on the raw AbifFile.
|
|
522
|
-
*/
|
|
523
|
-
|
|
524
|
-
/**
|
|
525
|
-
* Parse an ABIF file into a high-level view: metadata, channels, basecalls,
|
|
526
|
-
* and decoded directory entries.
|
|
527
|
-
*
|
|
528
|
-
* This is the INTERPRETING layer — it makes convenience choices (FWO_ → "GATC"
|
|
529
|
-
* fallback, derived samplingRate, preferred/upper-cased PBAS2 baseCalls). It is
|
|
530
|
-
* not the raw structural truth: for that use {@link readAbif}, which reads the
|
|
531
|
-
* directory verbatim (raw dataSize/offset/counts, tdir, inline bytes) and makes
|
|
532
|
-
* no interpretation. `parseAbif` builds on top of it.
|
|
533
|
-
*
|
|
534
|
-
* Accepts ArrayBuffer or Uint8Array (Buffer in Node works too — it extends
|
|
535
|
-
* Uint8Array). The `fileName` argument is informational only; it's preserved
|
|
536
|
-
* in the result.
|
|
537
|
-
*/
|
|
538
|
-
declare function parseAbif(input: ArrayBuffer | Uint8Array, fileName?: string): ParsedAbif;
|
|
539
|
-
/** True when any channel has at least one signal value. */
|
|
540
|
-
declare function hasSignals(s: ChannelSignals): boolean;
|
|
541
|
-
/** Length of the longest channel in a ChannelSignals bundle. */
|
|
542
|
-
declare function channelMaxLength(s: ChannelSignals): number;
|
|
543
|
-
|
|
544
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 };
|
package/dist/abif/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';function v(e){let t="";for(let n=0;n<e.length;n++)t+=String.fromCharCode(e[n]);return t}function z(e){let t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n)&255;return t}function w(e){return new DataView(e.buffer,e.byteOffset,e.byteLength)}function N(e,t,n){return e.subarray(t,t+n)}function G(e){return String.fromCharCode(e>>>24&255,e>>>16&255,e>>>8&255,e&255)}var $=128,x=28;function O(e){if(e.byteLength<$)throw new Error(`ABIF too small: ${e.byteLength} bytes`);let t=0;if(v(N(e,0,4))!=="ABIF")if(e.byteLength>=132&&v(N(e,128,4))==="ABIF")t=128;else throw new Error('Not an ABIF file: missing "ABIF" magic.');let n=t;if(e.byteLength-n<$)throw new Error(`ABIF too small: ${e.byteLength-n} bytes after offset ${n}`);let r=w(e),a=r.getInt16(n+4,false),i=B(e,r,n+6,n);if(i.tagName!=="tdir")throw new Error(`Expected "tdir" header entry, got "${i.tagName}"`);if(i.elementSize!==x)throw new Error(`Expected dir element size ${x}, got ${i.elementSize}`);let c=i.raw?.elementCount??i.elementCount,u=Math.max(0,c),d=r.getInt32(n+6+20,false);if(d<0||d+u*x>e.byteLength-n)throw new Error(`Directory out of bounds: offset=${d}, entries=${u}, file=${e.byteLength-n}`);let s=[];for(let E=0;E<u;E++)s.push(B(e,r,n+d+E*x,n));let g=i.raw?.dataSize??u*x,S=n+d+u*x,b=Math.min(Math.max(0,g-u*x),Math.max(0,e.byteLength-S)),h={entryCount:u,rawEntryCount:c,elementType:i.elementType,tagNumber:i.tagNumber,entrySize:i.elementSize,dataSize:g,dataOffset:d,dataOffsetBytes:i.raw?.dataOffsetBytes??new Uint8Array(4),dataHandle:i.dataHandle,paddingBytes:new Uint8Array(N(e,S,b))},y=new Uint8Array(N(e,n+6+x,$-6-x)),p=t===128?new Uint8Array(N(e,0,128)):void 0,C=H(e,n,d,g,s,t);return {version:a,tdir:h,entries:s,macBinaryOffset:t,macBinaryHeader:p,headerReserved:y,unreferencedRanges:C}}function H(e,t,n,r,a,i){let c=e.byteLength,u=[];i===128&&u.push([0,128]),u.push([t,t+$]);let d=Math.max(a.length*x,Math.max(0,r));u.push([t+n,t+n+d]);for(let h of a)if(h.raw&&!h.raw.inline){let y=t+h.raw.dataOffset;u.push([y,y+h.payload.byteLength]);}let s=u.map(([h,y])=>[Math.max(0,Math.min(h,c)),Math.max(0,Math.min(y,c))]).filter(([h,y])=>y>h).sort((h,y)=>h[0]-y[0]),g=[];for(let[h,y]of s){let p=g[g.length-1];p&&h<=p[1]?p[1]=Math.max(p[1],y):g.push([h,y]);}let S=[],b=0;for(let[h,y]of g)h>b&&S.push({offset:b,bytes:new Uint8Array(N(e,b,h-b))}),b=Math.max(b,y);return b<c&&S.push({offset:b,bytes:new Uint8Array(N(e,b,c-b))}),S}function B(e,t,n,r){let a=v(N(e,n,4)),i=t.getInt32(n+4,false),c=t.getInt16(n+8,false),u=t.getInt16(n+10,false),d=t.getInt32(n+12,false),s=t.getInt32(n+16,false),g=t.getInt32(n+24,false),S=Math.max(0,d*Math.max(0,u)),b=s>=0?s:S,h=s>=0?s<=4:S<=4,y=Math.max(0,u>0?Math.min(d,Math.floor(b/u)):Math.min(d,b)),p,C;if(h)C=-1,p=new Uint8Array(N(e,n+20,Math.min(4,b)));else {C=t.getInt32(n+20,false);let o=r+C;if(C<0||o+b>e.byteLength)throw new Error(`Entry ${a}${i}: payload out of bounds (offset=${C}, size=${b})`);p=new Uint8Array(N(e,o,b));}let E=new Uint8Array(N(e,n+20,4));return {tagName:a,tagNumber:i,elementType:c,elementSize:u,elementCount:y,payload:p,dataHandle:g,raw:{elementCount:d,dataSize:s,dataOffset:C,inline:h,dataOffsetBytes:E}}}function J(e){let t=e.entries.length,n=$,r=t*x,a=n+r,i=new Array(t);for(let s=0;s<t;s++){let g=e.entries[s].payload.byteLength;g>4?(i[s]=a,a+=g):i[s]=-1;}let c=a,u=new Uint8Array(c),d=w(u);u.set(z("ABIF"),0),d.setInt16(4,e.version,false),I({tagName:"tdir",tagNumber:1,elementType:1023,elementSize:x,elementCount:t,payload:new Uint8Array(0),dataHandle:0},u,d,6,-1,r,n);for(let s=0;s<t;s++){let g=e.entries[s];I(g,u,d,n+s*x,i[s]);}for(let s=0;s<t;s++){let g=i[s];g>=0&&u.set(e.entries[s].payload,g);}return u}function I(e,t,n,r,a,i,c){if(e.tagName.length!==4)throw new Error(`tagName must be 4 chars: "${e.tagName}"`);t.set(z(e.tagName),r),n.setInt32(r+4,e.tagNumber,false),n.setInt16(r+8,e.elementType,false),n.setInt16(r+10,e.elementSize,false),n.setInt32(r+12,e.elementCount,false);let u=i??e.payload.byteLength;if(n.setInt32(r+16,u,false),c!==void 0)n.setInt32(r+20,c,false);else if(u<=4)t.fill(0,r+20,r+24),t.set(e.payload.subarray(0,u),r+20);else {if(a<0)throw new Error(`External payload requires offset for ${e.tagName}${e.tagNumber}`);n.setInt32(r+20,a,false);}n.setInt32(r+24,e.dataHandle,false);}function A(e,t,n){return e.entries.find(r=>r.tagName===t&&r.tagNumber===n)}function K(e,t){return e.entries.filter(n=>n.tagName===t)}function T(e,t,n,r,a){if(r.byteLength!==a.elementCount*a.elementSize)throw new Error(`upsertEntry ${t}${n}: payload length ${r.byteLength} != count*size`);let i=A(e,t,n);i?(i.elementType=a.elementType,i.elementSize=a.elementSize,i.elementCount=a.elementCount,i.payload=r):e.entries.push({tagName:t,tagNumber:n,elementType:a.elementType,elementSize:a.elementSize,elementCount:a.elementCount,payload:r,dataHandle:0});}function te(e,t){let n=A(e,"DATA",t);if(!n)return;if(n.elementSize!==2)throw new Error(`DATA${t}: expected elementSize=2, got ${n.elementSize}`);let r=new Int16Array(n.elementCount),a=w(n.payload);for(let i=0;i<n.elementCount;i++)r[i]=a.getInt16(i*2,false);return r}function k(e){let t=A(e,"FWO_",1);return t?v(t.payload.subarray(0,t.elementCount)):"GATC"}function L(e){return /^[ACGT]{4}$/.test(e)&&new Set(e).size===4}function R(e){return !!(A(e,"DATA",9)&&A(e,"DATA",10)&&A(e,"DATA",11)&&A(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 t=A(e,"RevC",1);if(!t)return;let n=w(t.payload);return t.payload.byteLength>=2?n.getInt16(0,false)!==0:t.payload.some(r=>r!==0)}function ae(e){let t=k(e);if(!L(t))throw new Error(`FWO_ is not a permutation of A/C/G/T: "${t}"`);return {[t[0]]:1,[t[1]]:2,[t[2]]:3,[t[3]]:4}}function ie(e){let t=a=>v(a.payload.subarray(0,a.elementCount)).replace(/\0+$/g,""),n=A(e,"PBAS",2);if(n)return t(n);let r=A(e,"PBAS",1);if(r)return t(r)}function oe(e){let t=A(e,"PCON",2)??A(e,"PCON",1);if(!t)return;let n=new Array(t.elementCount);for(let r=0;r<t.elementCount;r++)n[r]=t.payload[r];return n}function se(e){let t=A(e,"PLOC",2)??A(e,"PLOC",1);if(!t)return;if(t.elementSize!==2)throw new Error(`PLOC: expected elementSize=2, got ${t.elementSize}`);let n=w(t.payload),r=new Array(t.elementCount);for(let a=0;a<t.elementCount;a++)r[a]=n.getUint16(a*2,false);return r}function le(e){let t=A(e,"SPAC",1);if(!t||t.elementSize!==4||t.payload.byteLength<4)return;let n=w(t.payload).getFloat32(0,false);return Number.isFinite(n)&&n>0?n:void 0}function ge(e,t){T(e,"PBAS",2,z(t),{elementType:2,elementSize:1,elementCount:t.length});}function de(e,t){let n=new Uint8Array(t.length);for(let r=0;r<t.length;r++)n[r]=Math.max(0,Math.min(255,Math.round(t[r])));T(e,"PCON",2,n,{elementType:2,elementSize:1,elementCount:t.length});}function be(e,t){let n=new Uint8Array(t.length*2),r=w(n);for(let a=0;a<t.length;a++)r.setUint16(a*2,Math.max(0,Math.min(65535,t[a])),false);T(e,"PLOC",2,n,{elementType:4,elementSize:2,elementCount:t.length});}function he(e,t,n){let r=new Uint8Array(4);w(r).setFloat32(0,t,false),T(e,"SPAC",1,r,{elementType:7,elementSize:4,elementCount:1});let a=z(n),i=Math.min(255,a.length),c=new Uint8Array(1+i);c[0]=i,c.set(a.subarray(0,i),1),T(e,"SPAC",2,c,{elementType:18,elementSize:1,elementCount:1+i});let u=new Uint8Array(4);w(u).setFloat32(0,t,false),T(e,"SPAC",3,u,{elementType:7,elementSize:4,elementCount:1});}function ye(e){return e.length<2?0:(e[e.length-1]-e[0])/(e.length-1)}function Ae(e){if(!R(e))for(let t=1;t<=4;t++){let n=A(e,"DATA",t);if(!n)continue;let r=8+t;A(e,"DATA",r)||e.entries.push({tagName:"DATA",tagNumber:r,elementType:n.elementType,elementSize:n.elementSize,elementCount:n.elementCount,payload:new Uint8Array(n.payload),dataHandle: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 M(e){return j[e]??(e>=1024?`user${e}`:`type${e}`)}function _(e,t=10){return e.length<=t?`[${e.join(", ")}]`:`[${e.slice(0,t).join(", ")}, \u2026 +${e.length-t}] (n=${e.length})`}function q(e,t=80){return e.length>t?e.slice(0,t)+"\u2026":e}function P(e){let t=e.subarray(0,16),n=Array.from(t,r=>r.toString(16).padStart(2,"0")).join(" ");return `${e.byteLength}B [${n}${e.byteLength>16?" \u2026":""}]`}function D(e){if(e.kind==="numbers")return e.value;if(e.kind==="number")return [e.value]}function U(e,t,n,r){let a=Math.max(0,Math.min(t,Math.floor(e/n))),i=[];for(let c=0;c<a;c++)i.push(r(c*n));return i.length===1?{kind:"number",value:i[0]}:{kind:"numbers",value:i}}function V(e,t,n){let r=w(n);switch(e){case 1:return {kind:"numbers",value:Array.from(n.subarray(0,t))};case 2:case 19:return {kind:"string",value:v(n.subarray(0,t)).replace(/\0+$/g,"")};case 3:return U(n.byteLength,t,2,a=>r.getUint16(a,false));case 4:return U(n.byteLength,t,2,a=>r.getInt16(a,false));case 5:return U(n.byteLength,t,4,a=>r.getInt32(a,false));case 7:return U(n.byteLength,t,4,a=>r.getFloat32(a,false));case 8:return U(n.byteLength,t,8,a=>r.getFloat64(a,false));case 10:{if(n.byteLength<4)return {kind:"unknown",value:n};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 n.byteLength<4?{kind:"unknown",value:n}:{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(t,n.byteLength);i++)a.push(r.getUint8(i)!==0);return {kind:"bools",value:a}}case 18:{if(n.byteLength<1)return {kind:"string",value:""};let a=r.getUint8(0);return {kind:"string",value:v(N(n,1,Math.min(a,Math.max(0,t-1))))}}default:return {kind:"unknown",value:n}}}function W(e,t){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:n,month:r,day:a}=e.value;return `${n}-${String(r).padStart(2,"0")}-${String(a).padStart(2,"0")}`}case "time":{let{hour:n,minute:r,second:a}=e.value;return `${String(n).padStart(2,"0")}:${String(r).padStart(2,"0")}:${String(a).padStart(2,"0")}`}case "bytes":return `${M(t)} ${P(e.value)}`;case "unknown":return `${M(t)} ${P(e.value)}`}}function Ne(e,t=""){let n=e instanceof Uint8Array?e:new Uint8Array(e),r=O(n),a=r.entries.map(o=>{let l=o.tagName==="PCON"&&o.elementSize===1?V(1,o.elementCount,o.payload):V(o.elementType,o.elementCount,o.payload);return {tag:o.tagName,tagNumber:o.tagNumber,elementType:o.elementType,elementTypeName:M(o.elementType),elementSize:o.elementSize,elementCount:o.elementCount,rawElementCount:o.raw?.elementCount??o.elementCount,dataSize:o.raw?.dataSize??o.elementCount*o.elementSize,dataOffset:o.raw?.dataOffset??-1,inline:o.raw?.inline??o.elementCount*o.elementSize<=4,decoded:l,preview:W(l,o.elementType)}}),i=k(r);L(i)||(i="GATC");let c={},u={A:[],C:[],G:[],T:[]},d={A:[],C:[],G:[],T:[]},s={comments:[]},g={},S={},b={},h=o=>i[o];for(let o=0;o<r.entries.length;o++){let l=r.entries[o],f=a[o].decoded;if(l.tagName==="DATA"){let m=D(f);m&&(c[l.tagNumber]=m,l.tagNumber>=1&&l.tagNumber<=4?u[h(l.tagNumber-1)]=m:l.tagNumber>=9&&l.tagNumber<=12&&(d[h(l.tagNumber-9)]=m));}else if(l.tagName==="PBAS"&&f.kind==="string")g[l.tagNumber]=f.value;else if(l.tagName==="PCON"){let m=l.elementSize===1?Array.from(l.payload.subarray(0,l.elementCount)):D(f);m&&(S[l.tagNumber]=m);}else if(l.tagName==="PLOC"){let m=D(f);m&&(b[l.tagNumber]=m.map(F=>F<0?F+65536:F));}else if(l.tagName==="SPAC")if(l.elementSize===4&&l.payload.byteLength>=4){let m=w(l.payload).getFloat32(0,false);Number.isFinite(m)&&m>0&&(s.samplingRate=m);}else f.kind==="number"&&(s.samplingRate=f.value);else if(l.tagName==="SMPL"&&f.kind==="string")s.sampleName=f.value;else if(l.tagName==="LANE"&&f.kind==="number")s.laneNumber=f.value;else if(l.tagName==="TUBE"&&f.kind==="string")s.tube=f.value;else if(l.tagName==="MCHN"&&f.kind==="string")s.machineName=f.value;else if(l.tagName==="MODL"&&f.kind==="string")s.machineModel=f.value;else if(l.tagName==="RUND"&&f.kind==="date"){let m=f.value;s.runDate=`${m.year}-${String(m.month).padStart(2,"0")}-${String(m.day).padStart(2,"0")}`;}else if(l.tagName==="RUNT"&&f.kind==="time"){let m=f.value;s.runTime=`${String(m.hour).padStart(2,"0")}:${String(m.minute).padStart(2,"0")}:${String(m.second).padStart(2,"0")}`;}else l.tagName==="CMNT"&&f.kind==="string"?s.comments.push(f.value):l.tagName==="RevC"&&l.tagNumber===1&&(f.kind==="number"?s.reverseComplemented=f.value!==0:f.kind==="numbers"&&(s.reverseComplemented=f.value.some(m=>m!==0)));}let y=Object.keys(g).map(Number).sort((o,l)=>o-l).map(o=>({version:o,role:o===1?"edited":o===2?"called":"unknown",sequence:g[o],confidences:S[o]??[],positions:b[o]??[]})),p,C=2 in g?2:1 in g?1:Object.keys(g).map(Number)[0];if(C!==void 0&&g[C]!==void 0){let o=g[C].toUpperCase(),l=S[C]??[];l.length!==o.length&&(l=Object.keys(S).map(Number).map(m=>S[m]).find(m=>m.length===o.length)??[]);let f=b[C]??[];f.length!==o.length&&(f=Object.keys(b).map(Number).map(m=>b[m]).find(m=>m.length===o.length)??[]),p={sequence:o,confidences:l,positions:f,pbasVersion:C};}if(!Number.isFinite(s.samplingRate)||(s.samplingRate??0)<=0){let o=p?.positions,l=Math.max(d.A.length,d.C.length,d.G.length,d.T.length);o&&o.length>1?s.samplingRate=(o[o.length-1]-o[0])/(o.length-1):p&&p.sequence.length>0&&l>0&&(s.samplingRate=l/p.sequence.length);}let E={baseOrder:i,dataChannels:c,data1To4:u,data9To12:d};return {fileName:t,fileSize:n.byteLength,abifVersion:r.version,macBinaryOffset:r.macBinaryOffset,dirEntryCount:r.entries.length,metadata:s,chromatogram:E,baseCalls:p,baseCallVariants:y,entries:a}}function xe(e){return e.A.length>0||e.C.length>0||e.G.length>0||e.T.length>0}function ve(e){return Math.max(e.A.length,e.C.length,e.G.length,e.T.length)}exports.ENTRY_SIZE=x;exports.HEADER_SIZE=$;exports.averagePeakSpacing=ye;exports.channelMaxLength=ve;exports.dataChannelRole=ne;exports.ensureRawDataChannels=Ae;exports.findEntries=K;exports.findEntry=A;exports.getChannelMap=ae;exports.getConfidences=oe;exports.getDataChannel=te;exports.getFwo=k;exports.getPositions=se;exports.getReverseComplemented=re;exports.getSamplingRate=le;exports.getSequence=ie;exports.hasData9To12Block=R;exports.hasSignals=xe;exports.isFwoPermutation=L;exports.parseAbif=Ne;exports.readAbif=O;exports.setAveragePeakSpacing=he;exports.setConfidences=de;exports.setPositions=be;exports.setSequence=ge;exports.tagNameFromInt32=G;exports.upsertEntry=T;exports.writeAbif=J;//# sourceMappingURL=index.js.map
|
|
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
|
|
2
2
|
//# sourceMappingURL=index.js.map
|