@fishka/seqio 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -39
- package/dist/abif/index.d.mts +192 -97
- package/dist/abif/index.d.ts +192 -97
- 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 +3 -3
package/README.md
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
# @fishka/seqio
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Part of [fishka.bio](https://fishka.bio) — free browser-based bioinformatics tools.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Browser- and Node-compatible sequencing file I/O.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- **FASTA / FASTQ / .qual** — text writers (Phred+33), pure and format-agnostic.
|
|
7
|
+
Current API:
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
- **ABIF** (`.ab1` / `.abi`) parser, typed chromatogram view, raw reader/writer,
|
|
10
|
+
and mutation helpers.
|
|
11
|
+
- **FASTA / FASTQ / .qual** text writers with Phred+33 quality encoding.
|
|
12
|
+
|
|
13
|
+
Planned: SCF and FASTA/FASTQ readers.
|
|
11
14
|
|
|
12
15
|
## Install
|
|
13
16
|
|
|
@@ -15,71 +18,79 @@ Planned: SCF; FASTA/FASTQ reading.
|
|
|
15
18
|
npm install @fishka/seqio
|
|
16
19
|
```
|
|
17
20
|
|
|
18
|
-
##
|
|
21
|
+
## ABIF
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
Use `parseAbif()` when you want a ready-to-render chromatogram, base calls, and
|
|
24
|
+
metadata from an `.ab1` file.
|
|
21
25
|
|
|
22
26
|
```ts
|
|
23
27
|
import { parseAbif } from '@fishka/seqio/abif';
|
|
24
|
-
// or: import { parseAbif } from '@fishka/seqio';
|
|
25
28
|
|
|
26
29
|
const result = parseAbif(uint8ArrayOrArrayBuffer, 'sample.ab1');
|
|
27
30
|
|
|
28
|
-
result.baseCalls?.sequence; //
|
|
29
|
-
result.baseCalls?.confidences; //
|
|
30
|
-
result.baseCalls?.positions; //
|
|
31
|
-
result.baseCallVariants; //
|
|
32
|
-
result.chromatogram.data9To12.A; // A
|
|
33
|
-
result.
|
|
34
|
-
result.metadata.sampleName; // SMPL tag
|
|
35
|
-
result.metadata.samplingRate; // SPAC tag (falls back to PLOC-derived spacing)
|
|
31
|
+
result.baseCalls?.sequence; // preferred called sequence, upper-cased
|
|
32
|
+
result.baseCalls?.confidences; // PCON quality scores
|
|
33
|
+
result.baseCalls?.positions; // PLOC peak positions
|
|
34
|
+
result.baseCallVariants; // all PBAS/PCON/PLOC versions found
|
|
35
|
+
result.chromatogram.data9To12.A; // A trace mapped through FWO_
|
|
36
|
+
result.metadata.sampleName;
|
|
36
37
|
```
|
|
37
38
|
|
|
38
|
-
|
|
39
|
+
Use `readAbif()` / `writeAbif()` when you need entry-level access or want to
|
|
40
|
+
preserve unknown vendor tags during a round trip.
|
|
39
41
|
|
|
40
42
|
```ts
|
|
41
43
|
import { readAbif, writeAbif, findEntry, upsertEntry } from '@fishka/seqio/abif';
|
|
42
|
-
import {
|
|
44
|
+
import { setAveragePeakSpacing, setConfidences, setPositions, setSequence } from '@fishka/seqio/abif';
|
|
43
45
|
|
|
44
46
|
const file = readAbif(bytes);
|
|
47
|
+
|
|
48
|
+
findEntry(file, 'SMPL', 1);
|
|
49
|
+
const commentPayload = new TextEncoder().encode('basecalled');
|
|
50
|
+
upsertEntry(file, 'CMNT', 1, commentPayload, {
|
|
51
|
+
elementType: 2,
|
|
52
|
+
elementSize: 1,
|
|
53
|
+
elementCount: commentPayload.byteLength,
|
|
54
|
+
});
|
|
55
|
+
|
|
45
56
|
setSequence(file, 'ACGT...');
|
|
46
|
-
setConfidences(file, [40, 38, 41
|
|
47
|
-
setPositions(file, [13, 25, 38
|
|
57
|
+
setConfidences(file, [40, 38, 41]);
|
|
58
|
+
setPositions(file, [13, 25, 38]);
|
|
48
59
|
setAveragePeakSpacing(file, 12.5, 'my-basecaller');
|
|
60
|
+
|
|
49
61
|
const out = writeAbif(file);
|
|
50
62
|
```
|
|
51
63
|
|
|
52
|
-
|
|
64
|
+
## FASTA / FASTQ / .qual
|
|
53
65
|
|
|
54
66
|
```ts
|
|
55
67
|
import { formatFasta, formatFastq, formatQual, hasUsableQuality } from '@fishka/seqio';
|
|
56
68
|
|
|
57
69
|
const record = { id: 'sample.ab1', sequence, qualities };
|
|
58
70
|
|
|
59
|
-
formatFasta(record); //
|
|
71
|
+
formatFasta(record); // wrapped at 60 residues by default
|
|
60
72
|
formatFasta(record, { lineWidth: 0 }); // single sequence line
|
|
61
73
|
|
|
62
|
-
// Phred+33; scores clamped to [0, 93]. Only emit quality when it exists —
|
|
63
|
-
// missing/all-255 PCON should stay FASTA-only rather than invent perfect Q.
|
|
64
74
|
if (hasUsableQuality(qualities)) {
|
|
65
|
-
formatFastq(record); //
|
|
66
|
-
formatQual(record);
|
|
75
|
+
formatFastq(record); // Phred+33, scores clamped to [0, 93]
|
|
76
|
+
formatQual(record);
|
|
67
77
|
}
|
|
68
78
|
```
|
|
69
79
|
|
|
70
|
-
##
|
|
71
|
-
|
|
72
|
-
-
|
|
73
|
-
-
|
|
74
|
-
`
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
-
|
|
78
|
-
|
|
79
|
-
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
-
|
|
80
|
+
## API
|
|
81
|
+
|
|
82
|
+
- `parseAbif(input, fileName?)`
|
|
83
|
+
- `readAbif(bytes)`, `writeAbif(file)`, `findEntry()`, `findEntries()`,
|
|
84
|
+
`upsertEntry()`
|
|
85
|
+
- `getSequence()`, `getConfidences()`, `getPositions()`, `getDataChannel()`,
|
|
86
|
+
`getChannelMap()`, `getSamplingRate()`
|
|
87
|
+
- `setSequence()`, `setConfidences()`, `setPositions()`,
|
|
88
|
+
`setAveragePeakSpacing()`, `ensureRawDataChannels()`
|
|
89
|
+
- `formatFasta()`, `formatFastq()`, `formatQual()`, `hasUsableQuality()`
|
|
90
|
+
|
|
91
|
+
The library uses `Uint8Array` and `DataView`, with no Node `Buffer` dependency.
|
|
92
|
+
ABIF writing is meaning-lossless rather than byte-for-byte layout preserving:
|
|
93
|
+
unknown entries are kept, but payloads may be repacked and padding normalized.
|
|
83
94
|
|
|
84
95
|
## License
|
|
85
96
|
|
package/dist/abif/index.d.mts
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,135 @@ declare function upsertEntry(file: AbifFile, name: string, number: number, paylo
|
|
|
374
404
|
elementCount: number;
|
|
375
405
|
}): void;
|
|
376
406
|
|
|
407
|
+
/**
|
|
408
|
+
* Domain-layer operation: crop an ABIF file to a sample range.
|
|
409
|
+
*
|
|
410
|
+
* `{ start, end }` is a half-open sample range in the DATA9..12 (processed/analyzed)
|
|
411
|
+
* domain — the only domain PLOC maps into (see AGENTS.md's "raw vs processed" note).
|
|
412
|
+
* DATA9..12 are sliced exactly by that range. DATA1..4/5..8 (raw dye trace and
|
|
413
|
+
* instrument telemetry) have no honest sample-for-sample correspondence to the
|
|
414
|
+
* processed domain (the mapping is non-linear mobility correction, not stored in the
|
|
415
|
+
* file), so they are never approximated: `rawTrace` keeps them whole and untouched,
|
|
416
|
+
* or omits them, never a proportional slice.
|
|
417
|
+
*
|
|
418
|
+
* Every basecall version the file carries (PBAS1/PCON1/PLOC1 "edited",
|
|
419
|
+
* PBAS2/PCON2/PLOC2 "called", or any vendor version) is cropped independently by its
|
|
420
|
+
* OWN PLOC — two versions are not guaranteed to share base positions or even length
|
|
421
|
+
* (edits insert/delete bases), so there is no shared coordinate to crop them together
|
|
422
|
+
* by. A version with no PLOC of its own cannot be cropped and is rejected rather than
|
|
423
|
+
* silently dropped or left un-cropped.
|
|
424
|
+
*
|
|
425
|
+
* Everything else (metadata, FWO_, SPAC, ...) is carried over untouched — this is a
|
|
426
|
+
* structural crop, not a re-derivation of run metadata for the new region.
|
|
427
|
+
*
|
|
428
|
+
* Reverse-complement is out of scope here; this function has no RC option.
|
|
429
|
+
*
|
|
430
|
+
* Returns a new, independently mutable AbifFile — the input is not mutated, and
|
|
431
|
+
* neither is the output if the input is later touched. Untouched entries are
|
|
432
|
+
* shallow-copied (a new AbifEntry object; the underlying payload bytes are shared,
|
|
433
|
+
* which is safe since nothing ever mutates payload bytes in place — only replaces
|
|
434
|
+
* them wholesale), so a later upsertEntry() on either file's copy of a shared tag
|
|
435
|
+
* can't reach into the other file's entries.
|
|
436
|
+
*/
|
|
437
|
+
|
|
438
|
+
interface CropAbifRange {
|
|
439
|
+
/** Inclusive start sample index into DATA9..12. */
|
|
440
|
+
start: number;
|
|
441
|
+
/** Exclusive end sample index into DATA9..12. */
|
|
442
|
+
end: number;
|
|
443
|
+
}
|
|
444
|
+
interface CropAbifOptions {
|
|
445
|
+
/**
|
|
446
|
+
* DATA1..4 (raw dye trace) and DATA5..8 (telemetry): 'full' keeps them whole and
|
|
447
|
+
* untouched (the exported file's raw trace no longer lines up sample-for-sample
|
|
448
|
+
* with the cropped DATA9..12/PLOC, by design — see the module doc comment);
|
|
449
|
+
* 'omit' drops them from the output entirely. Default 'omit'.
|
|
450
|
+
*/
|
|
451
|
+
rawTrace?: 'full' | 'omit';
|
|
452
|
+
}
|
|
453
|
+
/** Crop an AbifFile to a DATA9..12 sample range. See the module doc comment for the model. */
|
|
454
|
+
declare function cropAbif(file: AbifFile, range: CropAbifRange, options?: CropAbifOptions): AbifFile;
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* High-level "parse everything" wrapper around the raw + view layers.
|
|
458
|
+
*
|
|
459
|
+
* Returns a single ParsedAbif object with metadata, the FWO_-aware
|
|
460
|
+
* DATA1..4 / DATA9..12 channel split, basecalls, and decoded directory entries
|
|
461
|
+
* for diagnostics. Mirrors what typical viewers (chromatogram UIs, sample
|
|
462
|
+
* inspectors) need from a single file.
|
|
463
|
+
*
|
|
464
|
+
* For round-trip authoring (basecallers), prefer {@link readAbif} +
|
|
465
|
+
* setters from ./setters which operate directly on the raw AbifFile.
|
|
466
|
+
*/
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Parse an ABIF file into a high-level view: metadata, channels, basecalls,
|
|
470
|
+
* and decoded directory entries.
|
|
471
|
+
*
|
|
472
|
+
* This is the INTERPRETING layer — it makes convenience choices (FWO_ → "GATC"
|
|
473
|
+
* fallback, derived samplingRate, preferred/upper-cased PBAS2 baseCalls). It is
|
|
474
|
+
* not the raw structural truth: for that use {@link readAbif}, which reads the
|
|
475
|
+
* directory verbatim (raw dataSize/offset/counts, tdir, inline bytes) and makes
|
|
476
|
+
* no interpretation. `parseAbif` builds on top of it.
|
|
477
|
+
*
|
|
478
|
+
* Accepts ArrayBuffer or Uint8Array (Buffer in Node works too — it extends
|
|
479
|
+
* Uint8Array). The `fileName` argument is informational only; it's preserved
|
|
480
|
+
* in the result.
|
|
481
|
+
*/
|
|
482
|
+
declare function parseAbif(input: ArrayBuffer | Uint8Array, fileName?: string): ParsedAbif;
|
|
483
|
+
/** True when any channel has at least one signal value. */
|
|
484
|
+
declare function hasSignals(s: ChannelSignals): boolean;
|
|
485
|
+
/** Length of the longest channel in a ChannelSignals bundle. */
|
|
486
|
+
declare function channelMaxLength(s: ChannelSignals): number;
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Mutation helpers for AbifFile: write PBAS/PCON/PLOC/SPAC and ensure DATA9..12
|
|
490
|
+
* are present. Used by basecallers to author ABIF output.
|
|
491
|
+
*/
|
|
492
|
+
|
|
493
|
+
/** Set PBAS2 (replaces if present). */
|
|
494
|
+
declare function setSequence(file: AbifFile, sequence: string): void;
|
|
495
|
+
/** Set PCON2 (replaces if present). Values clamped to [0, 255]. */
|
|
496
|
+
declare function setConfidences(file: AbifFile, q: ArrayLike<number>): void;
|
|
497
|
+
/**
|
|
498
|
+
* Set PLOC2 (replaces if present).
|
|
499
|
+
*
|
|
500
|
+
* Written as UNSIGNED int16 so positions up to 65535 are preserved on disk
|
|
501
|
+
* (signed int16 would wrap on traces with > 32k scans).
|
|
502
|
+
*/
|
|
503
|
+
declare function setPositions(file: AbifFile, positions: ArrayLike<number>): void;
|
|
504
|
+
/**
|
|
505
|
+
* Set SPAC/1, SPAC/2, SPAC/3 — the standard ABIF "average peak spacing" trio
|
|
506
|
+
* that KB-basecaller writes and downstream tools (BioPython, Sequencher,
|
|
507
|
+
* KB-aware viewers) expect:
|
|
508
|
+
*
|
|
509
|
+
* - SPAC/1 (float32) — average peak spacing used in last analysis.
|
|
510
|
+
* - SPAC/2 (pString) — basecaller name / identifier.
|
|
511
|
+
* - SPAC/3 (float32) — average peak spacing computed by the basecaller.
|
|
512
|
+
*
|
|
513
|
+
* Both float fields are written with the same value.
|
|
514
|
+
*/
|
|
515
|
+
declare function setAveragePeakSpacing(file: AbifFile, spacing: number, basecallerName: string): void;
|
|
516
|
+
/**
|
|
517
|
+
* Mean consecutive peak-to-peak distance in scans, from a positions array.
|
|
518
|
+
* Returns 0 when fewer than 2 positions are present.
|
|
519
|
+
*/
|
|
520
|
+
declare function averagePeakSpacing(positions: ArrayLike<number>): number;
|
|
521
|
+
/**
|
|
522
|
+
* Ensure DATA9..12 are present in the file. Many downstream consumers
|
|
523
|
+
* (BioPython-style readers, viewers) read the chromatogram signal from
|
|
524
|
+
* DATA9..12 by convention — these tags are the raw fluorescence on newer
|
|
525
|
+
* instruments. Older files that only carry DATA1..8 break those consumers
|
|
526
|
+
* with a "no signal" error after re-basecalling.
|
|
527
|
+
*
|
|
528
|
+
* We populate DATA9..12 by copying DATA1..4 (which on DATA1..8-only files IS
|
|
529
|
+
* the raw signal). The DATA1..4 tags are left untouched so any tool that
|
|
530
|
+
* reads them keeps working.
|
|
531
|
+
*
|
|
532
|
+
* No-op when DATA9..12 already exist.
|
|
533
|
+
*/
|
|
534
|
+
declare function ensureRawDataChannels(file: AbifFile): void;
|
|
535
|
+
|
|
377
536
|
/**
|
|
378
537
|
* High-level typed view over an AbifFile.
|
|
379
538
|
*
|
|
@@ -434,6 +593,12 @@ declare function getReverseComplemented(file: AbifFile): boolean | undefined;
|
|
|
434
593
|
declare function getChannelMap(file: AbifFile): Record<'A' | 'C' | 'G' | 'T', number>;
|
|
435
594
|
/** Get PBAS sequence (prefer PBAS2 over PBAS1). undefined if neither present. */
|
|
436
595
|
declare function getSequence(file: AbifFile): string | undefined;
|
|
596
|
+
/**
|
|
597
|
+
* Get PBAS<version> exactly as stored — no called/edited preference, unlike
|
|
598
|
+
* {@link getSequence}. Used where each basecall version must be handled on its
|
|
599
|
+
* own (e.g. cropping every version a file carries, not just the preferred one).
|
|
600
|
+
*/
|
|
601
|
+
declare function getSequenceForVersion(file: AbifFile, version: number): string | undefined;
|
|
437
602
|
/**
|
|
438
603
|
* Get per-base Phred-like quality scores (0..255 byte values, typically 0..60
|
|
439
604
|
* for Sanger). Prefers PCON2 over PCON1.
|
|
@@ -442,6 +607,11 @@ declare function getSequence(file: AbifFile): string | undefined;
|
|
|
442
607
|
* values ARE the Q-scores — we read raw bytes regardless of declared type.
|
|
443
608
|
*/
|
|
444
609
|
declare function getConfidences(file: AbifFile): number[] | undefined;
|
|
610
|
+
/**
|
|
611
|
+
* Get PCON<version> exactly as stored — no called/edited preference, unlike
|
|
612
|
+
* {@link getConfidences}. See {@link getSequenceForVersion} for why this exists.
|
|
613
|
+
*/
|
|
614
|
+
declare function getConfidencesForVersion(file: AbifFile, version: number): number[] | undefined;
|
|
445
615
|
/**
|
|
446
616
|
* Get peak scan positions (one per base). Prefers PLOC2 over PLOC1.
|
|
447
617
|
*
|
|
@@ -450,6 +620,11 @@ declare function getConfidences(file: AbifFile): number[] | undefined;
|
|
|
450
620
|
* if interpreted as signed.
|
|
451
621
|
*/
|
|
452
622
|
declare function getPositions(file: AbifFile): number[] | undefined;
|
|
623
|
+
/**
|
|
624
|
+
* Get PLOC<version> exactly as stored — no called/edited preference, unlike
|
|
625
|
+
* {@link getPositions}. See {@link getSequenceForVersion} for why this exists.
|
|
626
|
+
*/
|
|
627
|
+
declare function getPositionsForVersion(file: AbifFile, version: number): number[] | undefined;
|
|
453
628
|
/**
|
|
454
629
|
* Get average peak spacing (samples per base), from SPAC/1.
|
|
455
630
|
*
|
|
@@ -461,84 +636,4 @@ declare function getPositions(file: AbifFile): number[] | undefined;
|
|
|
461
636
|
*/
|
|
462
637
|
declare function getSamplingRate(file: AbifFile): number | undefined;
|
|
463
638
|
|
|
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
|
-
export { type AbifBaseCallRole, type AbifBaseCallVariant, type AbifBaseCalls, type AbifByteRange, type AbifChromatogramBundle, type AbifDataChannelRole, type AbifDecodedValue, type AbifDirEntry, type AbifDirectory, type AbifEntry, type AbifEntryRaw, type AbifFile, type AbifMetadata, type ChannelSignals, type Chromatogram, ENTRY_SIZE, HEADER_SIZE, type ParsedAbif, averagePeakSpacing, channelMaxLength, dataChannelRole, ensureRawDataChannels, findEntries, findEntry, getChannelMap, getConfidences, getDataChannel, getFwo, getPositions, getReverseComplemented, getSamplingRate, getSequence, hasData9To12Block, hasSignals, isFwoPermutation, parseAbif, readAbif, setAveragePeakSpacing, setConfidences, setPositions, setSequence, tagNameFromInt32, upsertEntry, writeAbif };
|
|
639
|
+
export { type AbifBaseCallRole, type AbifBaseCallVariant, type AbifBaseCalls, type AbifByteRange, type AbifChromatogramBundle, type AbifDataChannelRole, type AbifDecodedValue, type AbifDirEntry, type AbifDirectory, type AbifEntry, type AbifEntryRaw, type AbifFile, type AbifMetadata, type ChannelSignals, type Chromatogram, type CropAbifOptions, type CropAbifRange, ENTRY_SIZE, HEADER_SIZE, type ParsedAbif, averagePeakSpacing, channelMaxLength, cropAbif, dataChannelRole, ensureRawDataChannels, findEntries, findEntry, getChannelMap, getConfidences, getConfidencesForVersion, getDataChannel, getFwo, getPositions, getPositionsForVersion, getReverseComplemented, getSamplingRate, getSequence, getSequenceForVersion, hasData9To12Block, hasSignals, isFwoPermutation, parseAbif, readAbif, setAveragePeakSpacing, setConfidences, setPositions, setSequence, tagNameFromInt32, upsertEntry, writeAbif };
|