@jbrowse/plugin-bed 4.3.0 → 5.0.0-beta.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.
Files changed (56) hide show
  1. package/esm/BedAdapter/BedAdapter.d.ts +4 -19
  2. package/esm/BedAdapter/BedAdapter.js +31 -88
  3. package/esm/BedAdapter/configSchema.d.ts +89 -40
  4. package/esm/BedAdapter/configSchema.js +65 -13
  5. package/esm/BedAdapter/index.js +4 -2
  6. package/esm/BedGraphAdapter/BedGraphAdapter.d.ts +4 -9
  7. package/esm/BedGraphAdapter/BedGraphAdapter.js +31 -85
  8. package/esm/BedGraphAdapter/configSchema.d.ts +35 -9
  9. package/esm/BedGraphAdapter/configSchema.js +47 -12
  10. package/esm/BedGraphAdapter/index.js +3 -2
  11. package/esm/BedGraphTabixAdapter/BedGraphTabixAdapter.d.ts +5 -5
  12. package/esm/BedGraphTabixAdapter/BedGraphTabixAdapter.js +62 -57
  13. package/esm/BedGraphTabixAdapter/configSchema.d.ts +48 -19
  14. package/esm/BedGraphTabixAdapter/configSchema.js +42 -34
  15. package/esm/BedGraphTabixAdapter/index.js +3 -2
  16. package/esm/BedTabixAdapter/BedTabixAdapter.d.ts +34 -38
  17. package/esm/BedTabixAdapter/BedTabixAdapter.js +82 -71
  18. package/esm/BedTabixAdapter/configSchema.d.ts +68 -31
  19. package/esm/BedTabixAdapter/configSchema.js +51 -35
  20. package/esm/BedTabixAdapter/index.js +4 -2
  21. package/esm/BedpeAdapter/BedpeAdapter.d.ts +4 -10
  22. package/esm/BedpeAdapter/BedpeAdapter.js +28 -69
  23. package/esm/BedpeAdapter/configSchema.d.ts +33 -10
  24. package/esm/BedpeAdapter/configSchema.js +45 -12
  25. package/esm/BedpeAdapter/index.js +4 -2
  26. package/esm/BedpeAdapter/util.js +22 -23
  27. package/esm/BigBedAdapter/BigBedAdapter.d.ts +8 -7
  28. package/esm/BigBedAdapter/BigBedAdapter.js +100 -107
  29. package/esm/BigBedAdapter/configSchema.d.ts +47 -17
  30. package/esm/BigBedAdapter/configSchema.js +51 -12
  31. package/esm/BigBedAdapter/index.js +3 -2
  32. package/esm/StarFusionAdapter/StarFusionAdapter.d.ts +15 -0
  33. package/esm/StarFusionAdapter/StarFusionAdapter.js +121 -0
  34. package/esm/StarFusionAdapter/configSchema.d.ts +31 -0
  35. package/esm/StarFusionAdapter/configSchema.js +52 -0
  36. package/esm/StarFusionAdapter/index.d.ts +2 -0
  37. package/esm/StarFusionAdapter/index.js +12 -0
  38. package/esm/adapterUtil.d.ts +5 -0
  39. package/esm/adapterUtil.js +28 -0
  40. package/esm/bedGraphUtil.d.ts +10 -0
  41. package/esm/bedGraphUtil.js +18 -0
  42. package/esm/generateBedMethylFeature.d.ts +1 -1
  43. package/esm/generateBedMethylFeature.js +19 -6
  44. package/esm/generateRastairMethylFeature.d.ts +28 -0
  45. package/esm/generateRastairMethylFeature.js +38 -0
  46. package/esm/generateRepeatMaskerFeature.d.ts +4 -51
  47. package/esm/generateRepeatMaskerFeature.js +28 -41
  48. package/esm/generateUcscTranscript.d.ts +15 -7
  49. package/esm/generateUcscTranscript.js +58 -28
  50. package/esm/index.d.ts +2 -0
  51. package/esm/index.js +10 -8
  52. package/esm/util.d.ts +32 -27
  53. package/esm/util.js +127 -97
  54. package/package.json +9 -13
  55. package/esm/GuessAdapter/index.d.ts +0 -2
  56. package/esm/GuessAdapter/index.js +0 -71
@@ -1,10 +1,11 @@
1
1
  import AdapterType from '@jbrowse/core/pluggableElementTypes/AdapterType';
2
- import configSchema from "./configSchema.js";
2
+ import configSchema, { normalizeSnapshot } from './configSchema.js';
3
3
  export default function BigBedAdapterF(pluginManager) {
4
4
  pluginManager.addAdapterType(() => new AdapterType({
5
5
  name: 'BigBedAdapter',
6
6
  displayName: 'BigBed adapter',
7
+ normalizeSnapshot,
7
8
  configSchema,
8
- getAdapterClass: () => import("./BigBedAdapter.js").then(r => r.default),
9
+ getAdapterClass: () => import('./BigBedAdapter.js').then(r => r.default),
9
10
  }));
10
11
  }
@@ -0,0 +1,15 @@
1
+ import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
2
+ import type { StarFusionAdapterConfig } from './configSchema.ts';
3
+ import type { BaseOptions } from '@jbrowse/core/data_adapters/BaseAdapter';
4
+ import type { Feature, IntervalTree, Region } from '@jbrowse/core/util';
5
+ export default class StarFusionAdapter extends BaseFeatureDataAdapter<StarFusionAdapterConfig> {
6
+ private loadData;
7
+ protected intervalTrees: Record<string, Promise<IntervalTree<Feature> | undefined> | undefined>;
8
+ static capabilities: string[];
9
+ private loadDataP;
10
+ getRefNames(opts?: BaseOptions): Promise<string[]>;
11
+ private featureFromLine;
12
+ private loadFeatureTreeP;
13
+ private loadFeatureTree;
14
+ getFeatures(query: Region, opts?: BaseOptions): import("rxjs").Observable<Feature>;
15
+ }
@@ -0,0 +1,121 @@
1
+ import { BaseFeatureDataAdapter, cachedSetup, } from '@jbrowse/core/data_adapters/BaseAdapter';
2
+ import { SimpleFeature, fetchAndMaybeUnzip } from '@jbrowse/core/util';
3
+ import { openLocation } from '@jbrowse/core/util/io';
4
+ import { parseLineByLine } from '@jbrowse/core/util/parseLineByLine';
5
+ import { buildPairedIntervalTree, intervalTreeFeatures, } from '../adapterUtil.js';
6
+ /**
7
+ * A STAR-Fusion `refName:pos:strand` breakpoint, read from the RIGHT: a refName
8
+ * may contain colons. GRCh38's full analysis set names its HLA contigs
9
+ * `HLA-A*01:01:01:01`, so a breakpoint on one arrives as
10
+ * `HLA-A*01:01:01:01:5000:+` and splitting at the first colon read the contig as
11
+ * `HLA-A*01`, the position as 1 and the strand as absent. Same rule
12
+ * `parseSvAlt` applies to a BND mate locstring, one field further along.
13
+ *
14
+ * A string with fewer than three fields keeps what it always parsed to, so a
15
+ * truncated or strandless row is no worse off than before.
16
+ */
17
+ function parseBreakpoint(str) {
18
+ const parts = str.split(':');
19
+ const strandStr = parts.length >= 3 ? parts.pop() : undefined;
20
+ const pos = parts.length >= 2 ? +parts.pop() : Number.NaN;
21
+ return {
22
+ refName: parts.join(':'),
23
+ start: pos,
24
+ end: pos + 1,
25
+ strand: strandStr === '+' ? 1 : strandStr === '-' ? -1 : undefined,
26
+ };
27
+ }
28
+ /**
29
+ * Which way the sequence a breakpoint keeps runs from it, as the paired-arc
30
+ * display's mate-direction tick (1 = right, -1 = left, 0 = unknown). A
31
+ * breakpoint's strand in STAR-Fusion is its gene's transcription strand, and the
32
+ * fusion transcript keeps the donor's sequence 5' of the junction and the
33
+ * acceptor's 3' of it: so on a + strand donor the retained side is at lower
34
+ * coordinates and on a + strand acceptor it is at higher ones.
35
+ */
36
+ function tickDirection(strand, isDonor) {
37
+ return strand === undefined ? 0 : isDonor ? -strand : strand;
38
+ }
39
+ export default class StarFusionAdapter extends BaseFeatureDataAdapter {
40
+ // No `label`: `fetchAndMaybeUnzip` narrates the download from inside.
41
+ loadData = cachedSetup({ setup: opts => this.loadDataP(opts) });
42
+ intervalTrees = {};
43
+ static capabilities = ['getFeatures', 'getRefNames'];
44
+ async loadDataP(opts) {
45
+ const buffer = await fetchAndMaybeUnzip(openLocation(this.getConf('starFusionLocation'), this.pluginManager), opts);
46
+ let columnNames = [];
47
+ let leftIdx = -1;
48
+ let rightIdx = -1;
49
+ const feats1 = {};
50
+ const feats2 = {};
51
+ parseLineByLine(buffer, line => {
52
+ if (line.startsWith('#')) {
53
+ columnNames = line.slice(1).split('\t');
54
+ leftIdx = columnNames.indexOf('LeftBreakpoint');
55
+ rightIdx = columnNames.indexOf('RightBreakpoint');
56
+ }
57
+ else if (leftIdx >= 0 && rightIdx >= 0) {
58
+ const cols = line.split('\t');
59
+ const left = cols[leftIdx];
60
+ const right = cols[rightIdx];
61
+ // through parseBreakpoint, so the bucket a row is filed under is the
62
+ // refName its feature will report -- a colon-bearing contig split two
63
+ // ways puts the row in a bucket no query can reach
64
+ const leftRef = left ? parseBreakpoint(left).refName : undefined;
65
+ const rightRef = right ? parseBreakpoint(right).refName : undefined;
66
+ if (leftRef && rightRef) {
67
+ ;
68
+ (feats1[leftRef] ??= []).push(line);
69
+ (feats2[rightRef] ??= []).push(line);
70
+ }
71
+ }
72
+ return true;
73
+ }, opts?.statusCallback);
74
+ return { columnNames, feats1, feats2 };
75
+ }
76
+ async getRefNames(opts = {}) {
77
+ const { feats1, feats2 } = await this.loadData(opts);
78
+ return [...new Set([...Object.keys(feats1), ...Object.keys(feats2)])];
79
+ }
80
+ featureFromLine(line, columnNames, uniqueId, flip) {
81
+ const cols = line.split('\t');
82
+ const row = Object.fromEntries(columnNames.map((name, i) => [name, cols[i]]));
83
+ const primaryBp = parseBreakpoint((flip ? row.RightBreakpoint : row.LeftBreakpoint));
84
+ const mateBp = parseBreakpoint((flip ? row.LeftBreakpoint : row.RightBreakpoint));
85
+ // the LeftBreakpoint is the donor, so this feature is the donor end of the
86
+ // junction whenever it is not flipped, and the mate is the other end
87
+ return new SimpleFeature({
88
+ uniqueId,
89
+ refName: primaryBp.refName,
90
+ start: primaryBp.start,
91
+ end: primaryBp.end,
92
+ strand: primaryBp.strand,
93
+ mateDirection: tickDirection(primaryBp.strand, !flip),
94
+ name: row.FusionName,
95
+ score: row.JunctionReadCount ? +row.JunctionReadCount : undefined,
96
+ type: 'fusion',
97
+ mate: {
98
+ refName: mateBp.refName,
99
+ start: mateBp.start,
100
+ end: mateBp.end,
101
+ strand: mateBp.strand,
102
+ mateDirection: tickDirection(mateBp.strand, flip),
103
+ },
104
+ ...row,
105
+ });
106
+ }
107
+ async loadFeatureTreeP(refName) {
108
+ const { columnNames, feats1, feats2 } = await this.loadData();
109
+ return buildPairedIntervalTree(feats1, feats2, refName, this.id, (line, uniqueId, flip) => this.featureFromLine(line, columnNames, uniqueId, flip));
110
+ }
111
+ async loadFeatureTree(refName) {
112
+ this.intervalTrees[refName] ??= this.loadFeatureTreeP(refName).catch((e) => {
113
+ this.intervalTrees[refName] = undefined;
114
+ throw e;
115
+ });
116
+ return this.intervalTrees[refName];
117
+ }
118
+ getFeatures(query, opts = {}) {
119
+ return intervalTreeFeatures(query, opts, refName => this.loadFeatureTree(refName));
120
+ }
121
+ }
@@ -0,0 +1,31 @@
1
+ import type { Instance } from '@jbrowse/mobx-state-tree';
2
+ export declare function normalizeSnapshot(snap: Record<string, unknown>): Record<string, unknown>;
3
+ /**
4
+ * #config StarFusionAdapter
5
+ * #trackType VariantTrack
6
+ * #fileFormat variants | STAR-Fusion
7
+ * used to load STAR-Fusion `star-fusion.fusion_predictions.tsv` output
8
+ *
9
+ * #example
10
+ * ```js
11
+ * {
12
+ * type: 'StarFusionAdapter',
13
+ * uri: 'https://example.com/star-fusion.fusion_predictions.tsv',
14
+ * }
15
+ * ```
16
+ */
17
+ declare const StarFusionAdapter: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
18
+ /**
19
+ * #slot
20
+ */
21
+ readonly starFusionLocation: {
22
+ readonly type: "fileLocation";
23
+ readonly description: "STAR-Fusion TSV output file (plain text or gzipped)";
24
+ readonly defaultValue: {
25
+ readonly uri: "/path/to/star-fusion.fusion_predictions.tsv";
26
+ readonly locationType: "UriLocation";
27
+ };
28
+ };
29
+ }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
30
+ export type StarFusionAdapterConfig = Instance<typeof StarFusionAdapter>;
31
+ export default StarFusionAdapter;
@@ -0,0 +1,52 @@
1
+ import { ConfigurationSchema } from '@jbrowse/core/configuration';
2
+ export function normalizeSnapshot(snap) {
3
+ return snap.uri
4
+ ? {
5
+ ...snap,
6
+ starFusionLocation: {
7
+ uri: snap.uri,
8
+ baseUri: snap.baseUri,
9
+ locationType: 'UriLocation',
10
+ },
11
+ }
12
+ : snap;
13
+ }
14
+ /**
15
+ * #config StarFusionAdapter
16
+ * #trackType VariantTrack
17
+ * #fileFormat variants | STAR-Fusion
18
+ * used to load STAR-Fusion `star-fusion.fusion_predictions.tsv` output
19
+ *
20
+ * #example
21
+ * ```js
22
+ * {
23
+ * type: 'StarFusionAdapter',
24
+ * uri: 'https://example.com/star-fusion.fusion_predictions.tsv',
25
+ * }
26
+ * ```
27
+ */
28
+ const StarFusionAdapter = ConfigurationSchema('StarFusionAdapter', {
29
+ /**
30
+ * #slot
31
+ */
32
+ starFusionLocation: {
33
+ type: 'fileLocation',
34
+ description: 'STAR-Fusion TSV output file (plain text or gzipped)',
35
+ defaultValue: {
36
+ uri: '/path/to/star-fusion.fusion_predictions.tsv',
37
+ locationType: 'UriLocation',
38
+ },
39
+ },
40
+ }, {
41
+ explicitlyTyped: true,
42
+ /**
43
+ * #preProcessSnapshot
44
+ *
45
+ * Allows minimal config:
46
+ * ```json
47
+ * { "type": "StarFusionAdapter", "uri": "star-fusion.tsv" }
48
+ * ```
49
+ */
50
+ preProcessSnapshot: normalizeSnapshot,
51
+ });
52
+ export default StarFusionAdapter;
@@ -0,0 +1,2 @@
1
+ import type PluginManager from '@jbrowse/core/PluginManager';
2
+ export default function StarFusionAdapterF(pluginManager: PluginManager): void;
@@ -0,0 +1,12 @@
1
+ import AdapterType from '@jbrowse/core/pluggableElementTypes/AdapterType';
2
+ import configSchema, { normalizeSnapshot } from './configSchema.js';
3
+ export default function StarFusionAdapterF(pluginManager) {
4
+ pluginManager.addAdapterType(() => new AdapterType({
5
+ name: 'StarFusionAdapter',
6
+ displayName: 'STAR-Fusion adapter',
7
+ configSchema,
8
+ getAdapterClass: () => import('./StarFusionAdapter.js').then(r => r.default),
9
+ locationKey: 'starFusionLocation',
10
+ normalizeSnapshot,
11
+ }));
12
+ }
@@ -0,0 +1,5 @@
1
+ import { IntervalTree } from '@jbrowse/core/util';
2
+ import type { BaseOptions } from '@jbrowse/core/data_adapters/BaseAdapter';
3
+ import type { Feature, Region } from '@jbrowse/core/util';
4
+ export declare function intervalTreeFeatures(query: Region, opts: BaseOptions, loadTree: (refName: string) => Promise<IntervalTree<Feature> | undefined>): import("rxjs").Observable<Feature>;
5
+ export declare function buildPairedIntervalTree(feats1: Record<string, string[]>, feats2: Record<string, string[]>, refName: string, idPrefix: string, makeFeature: (line: string, uniqueId: string, flip: boolean) => Feature): IntervalTree<Feature>;
@@ -0,0 +1,28 @@
1
+ import { IntervalTree } from '@jbrowse/core/util';
2
+ import { ObservableCreate } from '@jbrowse/core/util/rxjs';
3
+ // Emit the features of a per-refName interval tree that intersect the query.
4
+ // Shared by the in-memory interval-tree adapters.
5
+ export function intervalTreeFeatures(query, opts, loadTree) {
6
+ return ObservableCreate(async (observer) => {
7
+ const tree = await loadTree(query.refName);
8
+ for (const f of tree?.search([query.start, query.end]) ?? []) {
9
+ observer.next(f);
10
+ }
11
+ observer.complete();
12
+ }, opts.stopToken);
13
+ }
14
+ // Build one interval tree for a refName from paired-feature buckets, inserting
15
+ // the records that start on this ref (feats1, flip=false) and those whose mate
16
+ // starts here (feats2, flip=true). Shared by BedpeAdapter and StarFusionAdapter.
17
+ export function buildPairedIntervalTree(feats1, feats2, refName, idPrefix, makeFeature) {
18
+ const tree = new IntervalTree();
19
+ for (const [i, line] of (feats1[refName] ?? []).entries()) {
20
+ const f = makeFeature(line, `${idPrefix}-${refName}-${i}-r1`, false);
21
+ tree.insert([f.get('start'), f.get('end')], f);
22
+ }
23
+ for (const [i, line] of (feats2[refName] ?? []).entries()) {
24
+ const f = makeFeature(line, `${idPrefix}-${refName}-${i}-r2`, true);
25
+ tree.insert([f.get('start'), f.get('end')], f);
26
+ }
27
+ return tree;
28
+ }
@@ -0,0 +1,10 @@
1
+ import type { Feature } from '@jbrowse/core/util';
2
+ export declare function makeBedGraphFeature({ uniqueId, refName, start, end, names, j, value, }: {
3
+ uniqueId: string;
4
+ refName: string;
5
+ start: number;
6
+ end: number;
7
+ names: string[];
8
+ j: number;
9
+ value: string;
10
+ }): Feature | undefined;
@@ -0,0 +1,18 @@
1
+ import { SimpleFeature } from '@jbrowse/core/util';
2
+ // Build a single-score bedGraph feature for value column j, or undefined when
3
+ // the value is not numeric. Shared by BedGraphAdapter and BedGraphTabixAdapter.
4
+ export function makeBedGraphFeature({ uniqueId, refName, start, end, names, j, value, }) {
5
+ const score = +value;
6
+ return Number.isNaN(score)
7
+ ? undefined
8
+ : new SimpleFeature({
9
+ id: uniqueId,
10
+ data: {
11
+ refName,
12
+ start,
13
+ end,
14
+ score,
15
+ source: names[j] || `col${j}`,
16
+ },
17
+ });
18
+ }
@@ -16,7 +16,7 @@ export declare function generateBedMethylFeature({ splitLine, uniqueId, refName,
16
16
  end: number;
17
17
  code: string | undefined;
18
18
  score: number;
19
- strand: string | undefined;
19
+ strand: number;
20
20
  color: string | undefined;
21
21
  source: string | undefined;
22
22
  n_valid_cov: string | undefined;
@@ -1,19 +1,32 @@
1
+ import { parseStrand } from './util.js';
2
+ // this uses modkit bedMethyl. unclear how to reliably detect minimal 9+2 bedMethyl
1
3
  export function isBedMethylFeature({ splitLine, start, end, }) {
2
- return (+(splitLine[6] || 0) === start &&
3
- +(splitLine[7] || 0) === end &&
4
- [9, 10, 11, 12, 13, 14, 15, 16, 17].every(r => splitLine[r] && !Number.isNaN(+splitLine[r])));
4
+ // columns 9-17 are the nine numeric methylation stats
5
+ const nums = splitLine.slice(9, 18);
6
+ return (splitLine[6] !== undefined &&
7
+ +splitLine[6] === start &&
8
+ splitLine[7] !== undefined &&
9
+ +splitLine[7] === end &&
10
+ nums.length === 9 &&
11
+ nums.every(x => x && !Number.isNaN(+x)));
5
12
  }
6
13
  export function generateBedMethylFeature({ splitLine, uniqueId, refName, start, end, }) {
7
- const [, , , code, , strand, , , color, n_valid_cov, fraction_modified, n_mod, n_canonical, n_other_mod, n_delete, n_fail, n_diff, n_nocall,] = splitLine;
14
+ // see
15
+ // https://github.com/nanoporetech/modkit?tab=readme-ov-file#description-of-bedmethyl-output
16
+ const code = splitLine[3];
17
+ const strandRaw = splitLine[5];
18
+ const color = splitLine[8];
19
+ const [n_valid_cov, fraction_modified, n_mod, n_canonical, n_other_mod, n_delete, n_fail, n_diff, n_nocall,] = splitLine.slice(9);
8
20
  return {
9
21
  uniqueId,
10
22
  refName,
11
23
  start,
12
24
  end,
13
25
  code,
14
- score: +fraction_modified || 0,
15
- strand,
26
+ score: +fraction_modified,
27
+ strand: parseStrand(strandRaw),
16
28
  color,
29
+ // source mirrors code so MultiQuantitativeTrack groups by modification code
17
30
  source: code,
18
31
  n_valid_cov,
19
32
  fraction_modified,
@@ -0,0 +1,28 @@
1
+ export declare function isRastairMethylFeature(names: string[]): boolean;
2
+ export declare function generateRastairMethylFeature({ splitLine, names, uniqueId, refName, start, end, }: {
3
+ splitLine: string[];
4
+ names: string[];
5
+ uniqueId: string;
6
+ refName: string;
7
+ start: number;
8
+ end: number;
9
+ }): {
10
+ uniqueId: string;
11
+ refName: string;
12
+ start: number;
13
+ end: number;
14
+ code: string;
15
+ source: string;
16
+ score: number;
17
+ fraction_modified: number;
18
+ strand: number;
19
+ n_valid_cov: string | undefined;
20
+ n_mod: string | undefined;
21
+ n_canonical: string | undefined;
22
+ beta_est: string | undefined;
23
+ no_snp: string | undefined;
24
+ snp: string | undefined;
25
+ coverage: string | undefined;
26
+ genotype: string | undefined;
27
+ gt_conf_score: string | undefined;
28
+ };
@@ -0,0 +1,38 @@
1
+ import { parseStrand } from './util.js';
2
+ // Rastair (https://www.rastair.com) emits a headered BED/TSV of per-CpG
3
+ // methylation calls from TAPS / mod-C→T data. Its layout differs from modkit
4
+ // bedMethyl, so it's identified by the header column names rather than
5
+ // positionally: #chr start end name beta_est strand unmod mod no_snp snp
6
+ // coverage genotype gt_p_score gt_conf_score
7
+ const RASTAIR_COLUMNS = ['beta_est', 'unmod', 'mod', 'coverage'];
8
+ export function isRastairMethylFeature(names) {
9
+ return RASTAIR_COLUMNS.every(col => names.includes(col));
10
+ }
11
+ export function generateRastairMethylFeature({ splitLine, names, uniqueId, refName, start, end, }) {
12
+ const col = (name) => splitLine[names.indexOf(name)];
13
+ // beta_est is a 0-1 fraction; the shared bedMethyl display path expects a
14
+ // 0-100 percentage (modkit fraction_modified), so scale to match
15
+ const fraction_modified = Number(col('beta_est')) * 100;
16
+ return {
17
+ uniqueId,
18
+ refName,
19
+ start,
20
+ end,
21
+ // rastair reports modified C (5mC); use modkit's 'm' code so it groups and
22
+ // colors as 5mC methylation in the shared bedMethyl display path
23
+ code: 'm',
24
+ source: 'm',
25
+ score: fraction_modified,
26
+ fraction_modified,
27
+ strand: parseStrand(col('strand')),
28
+ n_valid_cov: col('coverage'),
29
+ n_mod: col('mod'),
30
+ n_canonical: col('unmod'),
31
+ beta_est: col('beta_est'),
32
+ no_snp: col('no_snp'),
33
+ snp: col('snp'),
34
+ coverage: col('coverage'),
35
+ genotype: col('genotype'),
36
+ gt_conf_score: col('gt_conf_score'),
37
+ };
38
+ }
@@ -1,51 +1,4 @@
1
- export declare function isRepeatMaskerDescriptionField(desc?: unknown): desc is string;
2
- export declare function generateRepeatMaskerFeature({ uniqueId, refName, start, end, description, ...rest }: {
3
- uniqueId: string;
4
- refName: string;
5
- start: number;
6
- end: number;
7
- description: string;
8
- [key: string]: unknown;
9
- }): {
10
- uniqueId: string;
11
- refName: string;
12
- start: number;
13
- end: number;
14
- bitsw_score: string | undefined;
15
- percent_div: string | undefined;
16
- percent_del: string | undefined;
17
- percent_ins: string | undefined;
18
- query_chr: string | undefined;
19
- query_begin: string | undefined;
20
- query_end: string | undefined;
21
- query_remaining: string | undefined;
22
- orientation: string | undefined;
23
- matching_repeat_name: string | undefined;
24
- matching_repeat_class: string | undefined;
25
- matching_repeat_begin: string | undefined;
26
- matching_repeat_end: string | undefined;
27
- matching_repeat_remaining: string | undefined;
28
- repeat_id: string | undefined;
29
- description?: undefined;
30
- } | {
31
- uniqueId: string;
32
- refName: string;
33
- start: number;
34
- end: number;
35
- description: undefined;
36
- bitsw_score?: undefined;
37
- percent_div?: undefined;
38
- percent_del?: undefined;
39
- percent_ins?: undefined;
40
- query_chr?: undefined;
41
- query_begin?: undefined;
42
- query_end?: undefined;
43
- query_remaining?: undefined;
44
- orientation?: undefined;
45
- matching_repeat_name?: undefined;
46
- matching_repeat_class?: undefined;
47
- matching_repeat_begin?: undefined;
48
- matching_repeat_end?: undefined;
49
- matching_repeat_remaining?: undefined;
50
- repeat_id?: undefined;
51
- };
1
+ declare const FIELDS: readonly ['bitsw_score', 'percent_div', 'percent_del', 'percent_ins', 'query_chr', 'query_begin', 'query_end', 'query_remaining', 'orientation', 'matching_repeat_name', 'matching_repeat_class', 'matching_repeat_begin', 'matching_repeat_end', 'matching_repeat_remaining', 'repeat_id'];
2
+ export type RepeatMaskerFields = Record<(typeof FIELDS)[number], string>;
3
+ export declare function parseRepeatMaskerDescription(desc: unknown): RepeatMaskerFields | undefined;
4
+ export {};
@@ -1,43 +1,30 @@
1
- export function isRepeatMaskerDescriptionField(desc) {
2
- if (typeof desc !== 'string') {
3
- return false;
1
+ const FIELDS = [
2
+ 'bitsw_score',
3
+ 'percent_div',
4
+ 'percent_del',
5
+ 'percent_ins',
6
+ 'query_chr',
7
+ 'query_begin',
8
+ 'query_end',
9
+ 'query_remaining',
10
+ 'orientation',
11
+ 'matching_repeat_name',
12
+ 'matching_repeat_class',
13
+ 'matching_repeat_begin',
14
+ 'matching_repeat_end',
15
+ 'matching_repeat_remaining',
16
+ 'repeat_id',
17
+ ];
18
+ // RepeatMasker .out-derived description: 15 space-separated fields with numeric
19
+ // values at positions 0,1,2,3,5,6. Returns parsed fields or undefined if the
20
+ // description doesn't match the format.
21
+ export function parseRepeatMaskerDescription(desc) {
22
+ if (typeof desc === 'string') {
23
+ const parts = desc.trim().split(' ');
24
+ const looksRight = [0, 1, 2, 3, 5, 6].every(i => parts[i] !== undefined && !Number.isNaN(+parts[i]));
25
+ if (looksRight) {
26
+ return Object.fromEntries(FIELDS.map((f, i) => [f, parts[i] ?? '']));
27
+ }
4
28
  }
5
- else {
6
- const ret = desc.trim().split(' ');
7
- return [0, 1, 2, 3, 5, 6].every(s => ret[s] !== undefined ? !Number.isNaN(+ret[s]) : false);
8
- }
9
- }
10
- function makeRepeatTrackDescription(description) {
11
- if (isRepeatMaskerDescriptionField(description)) {
12
- const [bitsw_score, percent_div, percent_del, percent_ins, query_chr, query_begin, query_end, query_remaining, orientation, matching_repeat_name, matching_repeat_class, matching_repeat_begin, matching_repeat_end, matching_repeat_remaining, repeat_id,] = description.trim().split(' ');
13
- return {
14
- bitsw_score,
15
- percent_div,
16
- percent_del,
17
- percent_ins,
18
- query_chr,
19
- query_begin,
20
- query_end,
21
- query_remaining,
22
- orientation,
23
- matching_repeat_name,
24
- matching_repeat_class,
25
- matching_repeat_begin,
26
- matching_repeat_end,
27
- matching_repeat_remaining,
28
- repeat_id,
29
- };
30
- }
31
- return { description };
32
- }
33
- export function generateRepeatMaskerFeature({ uniqueId, refName, start, end, description, ...rest }) {
34
- const { subfeatures, ...rest2 } = rest;
35
- return {
36
- ...rest2,
37
- ...makeRepeatTrackDescription(description),
38
- uniqueId,
39
- refName,
40
- start,
41
- end,
42
- };
29
+ return undefined;
43
30
  }
@@ -1,12 +1,20 @@
1
1
  import type { MinimalFeature } from './types.ts';
2
- export declare function isUcscTranscript({ thickStart, blockCount, strand, }: {
3
- thickStart?: unknown;
4
- blockCount?: unknown;
2
+ interface UcscTranscriptCheck {
3
+ thickStart?: number;
4
+ thickEnd?: number;
5
+ blockCount?: number;
5
6
  strand?: number;
6
- }): boolean;
7
+ }
8
+ interface ValidUcscTranscriptCheck {
9
+ thickStart: number;
10
+ thickEnd: number;
11
+ blockCount: number;
12
+ strand: number;
13
+ }
14
+ export declare function isUcscTranscript(input: UcscTranscriptCheck): input is ValidUcscTranscriptCheck;
7
15
  interface UcscTranscriptInput {
8
16
  uniqueId: string;
9
- strand?: number;
17
+ strand: number;
10
18
  thickStart: number;
11
19
  thickEnd: number;
12
20
  refName: string;
@@ -15,10 +23,10 @@ interface UcscTranscriptInput {
15
23
  subfeatures: MinimalFeature[];
16
24
  [key: string]: unknown;
17
25
  }
18
- interface UcscTranscriptOutput {
26
+ interface UcscTranscriptOutput extends MinimalFeature {
19
27
  uniqueId: string;
20
28
  strand: number;
21
- type: string;
29
+ type: 'mRNA' | 'transcript';
22
30
  refName: string;
23
31
  start: number;
24
32
  end: number;