@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,35 +1,52 @@
1
- export function isUcscTranscript({ thickStart, blockCount, strand, }) {
2
- return (typeof thickStart === 'number' &&
3
- typeof blockCount === 'number' &&
4
- strand !== 0);
1
+ // type guard: narrows input fields to required + non-zero when true
2
+ // strand===0 means unstranded — likely not a gene
3
+ export function isUcscTranscript(input) {
4
+ return (input.thickStart !== undefined &&
5
+ input.thickEnd !== undefined &&
6
+ input.thickStart !== input.thickEnd &&
7
+ input.blockCount !== undefined &&
8
+ input.blockCount > 0 &&
9
+ input.strand !== undefined &&
10
+ input.strand !== 0);
5
11
  }
12
+ // phase = (3 - cumulative_cds_width % 3) % 3, computed in transcriptional order
6
13
  function calculatePhasesFromCds(cdsRegions, strand) {
7
14
  const sorted = [...cdsRegions].sort((a, b) => strand > 0 ? a.start - b.start : b.start - a.start);
8
15
  const phaseMap = new Map();
9
16
  let cumulativeWidth = 0;
10
17
  for (const cds of sorted) {
11
- const phase = (3 - (cumulativeWidth % 3)) % 3;
12
- phaseMap.set(cds.start, phase);
18
+ phaseMap.set(cds.start, (3 - (cumulativeWidth % 3)) % 3);
13
19
  cumulativeWidth += cds.end - cds.start;
14
20
  }
15
21
  return phaseMap;
16
22
  }
23
+ // convert UCSC exonFrames (0,1,2) to GFF phase: frame 0→0, frame 1→2, frame 2→1
24
+ // UCSC frame = bases from start of codon; GFF phase = bases to skip to reach next codon
25
+ // https://genome.ucsc.edu/FAQ/FAQformat.html#format1 (bigGenePred exonFrames)
26
+ // https://github.com/The-Sequence-Ontology/Specifications/blob/master/gff3.md (phase)
17
27
  function frameToPhase(frame) {
18
28
  return (3 - frame) % 3;
19
29
  }
30
+ function parseFrames(frames) {
31
+ return typeof frames === 'string'
32
+ ? frames.replace(/,$/, '').split(',').map(Number)
33
+ : frames;
34
+ }
20
35
  export function generateUcscTranscript(data) {
21
- const { strand = 0, uniqueId, start, end, ...rest } = data;
22
- const { subfeatures: oldSubfeatures, thickStart, thickEnd, refName, chrom: _1, chromStart: _2, chromEnd: _3, chromStarts: _4, blockStarts: _5, blockSizes: _6, blockCount: _7, ...rest2 } = rest;
23
- const exonFrames = (rest2.exonFrames ?? rest2._exonFrames);
36
+ const { strand, uniqueId, start, end, thickStart, thickEnd, refName, subfeatures: oldSubfeatures, chrom, chromStart, chromEnd, chromStarts, blockStarts, blockSizes, blockCount, ...rest } = data;
37
+ // exonFrames from bigGenePred - the @gmod/bed parser returns it in genomic order.
38
+ // _exonFrames fallback supports BED files that use the underscore-prefixed column
39
+ // name, which the parser leaves as raw text because it is not a standard column.
40
+ const exonFrames = parseFrames(rest.exonFrames ?? rest._exonFrames);
24
41
  const feats = oldSubfeatures
25
42
  .filter(child => child.type === 'block')
26
43
  .sort((a, b) => a.start - b.start);
27
44
  const fiveUTR = strand > 0 ? 'five_prime_UTR' : 'three_prime_UTR';
28
45
  const threeUTR = strand > 0 ? 'three_prime_UTR' : 'five_prime_UTR';
29
- const { cdsEndStat, cdsStartStat } = rest2;
46
+ const { cdsEndStat, cdsStartStat } = rest;
30
47
  if (cdsStartStat === 'none' && cdsEndStat === 'none') {
31
48
  return {
32
- ...rest2,
49
+ ...rest,
33
50
  uniqueId,
34
51
  strand,
35
52
  type: 'transcript',
@@ -39,15 +56,15 @@ export function generateUcscTranscript(data) {
39
56
  subfeatures: feats.map(e => ({ ...e, type: 'exon' })),
40
57
  };
41
58
  }
59
+ // If exonFrames not available, calculate phases from CDS regions
42
60
  let calculatedPhases;
43
61
  if (!exonFrames) {
44
62
  const cdsRegions = [];
45
63
  for (const block of feats) {
46
- const { start, end } = block;
47
- if (thickStart < end && thickEnd > start) {
64
+ if (thickStart < block.end && thickEnd > block.start) {
48
65
  cdsRegions.push({
49
- start: Math.max(start, thickStart),
50
- end: Math.min(end, thickEnd),
66
+ start: Math.max(block.start, thickStart),
67
+ end: Math.min(block.end, thickEnd),
51
68
  });
52
69
  }
53
70
  }
@@ -55,20 +72,28 @@ export function generateUcscTranscript(data) {
55
72
  }
56
73
  const subfeatures = [];
57
74
  for (const [i, feat] of feats.entries()) {
58
- const block = feat;
59
- const { start, end } = block;
60
- if (thickStart >= end) {
61
- subfeatures.push({ type: fiveUTR, start, end, refName });
75
+ const { start: bStart, end: bEnd } = feat;
76
+ if (thickStart >= bEnd) {
77
+ // entire block is 5' UTR
78
+ subfeatures.push({ type: fiveUTR, start: bStart, end: bEnd, refName });
62
79
  }
63
- else if (thickEnd <= start) {
64
- subfeatures.push({ type: threeUTR, start, end, refName });
80
+ else if (thickEnd <= bStart) {
81
+ // entire block is 3' UTR
82
+ subfeatures.push({ type: threeUTR, start: bStart, end: bEnd, refName });
65
83
  }
66
84
  else {
67
- if (start < thickStart) {
68
- subfeatures.push({ type: fiveUTR, start, end: thickStart, refName });
85
+ // block overlaps CDS region - may have UTR on either side
86
+ if (bStart < thickStart) {
87
+ subfeatures.push({
88
+ type: fiveUTR,
89
+ start: bStart,
90
+ end: thickStart,
91
+ refName,
92
+ });
69
93
  }
70
- const cdsStart = Math.max(start, thickStart);
71
- const cdsEnd = Math.min(end, thickEnd);
94
+ const cdsStart = Math.max(bStart, thickStart);
95
+ const cdsEnd = Math.min(bEnd, thickEnd);
96
+ // Get phase from exonFrames (with conversion) or calculated phases
72
97
  let phase = 0;
73
98
  if (exonFrames) {
74
99
  const frame = exonFrames[i];
@@ -86,13 +111,18 @@ export function generateUcscTranscript(data) {
86
111
  end: cdsEnd,
87
112
  refName,
88
113
  });
89
- if (end > thickEnd) {
90
- subfeatures.push({ type: threeUTR, start: thickEnd, end, refName });
114
+ if (bEnd > thickEnd) {
115
+ subfeatures.push({
116
+ type: threeUTR,
117
+ start: thickEnd,
118
+ end: bEnd,
119
+ refName,
120
+ });
91
121
  }
92
122
  }
93
123
  }
94
124
  return {
95
- ...rest2,
125
+ ...rest,
96
126
  uniqueId,
97
127
  strand,
98
128
  type: 'mRNA',
package/esm/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import Plugin from '@jbrowse/core/Plugin';
2
2
  import type PluginManager from '@jbrowse/core/PluginManager';
3
+ export { default as BedTabixAdapter } from './BedTabixAdapter/BedTabixAdapter.ts';
4
+ export { default as bedTabixConfigSchema } from './BedTabixAdapter/configSchema.ts';
3
5
  export default class BedPlugin extends Plugin {
4
6
  name: string;
5
7
  install(pluginManager: PluginManager): void;
package/esm/index.js CHANGED
@@ -1,20 +1,22 @@
1
1
  import Plugin from '@jbrowse/core/Plugin';
2
- import BedAdapterF from "./BedAdapter/index.js";
3
- import BedGraphAdapterF from "./BedGraphAdapter/index.js";
4
- import BedGraphTabixAdapterF from "./BedGraphTabixAdapter/index.js";
5
- import BedTabixAdapterF from "./BedTabixAdapter/index.js";
6
- import BedpeAdapterF from "./BedpeAdapter/index.js";
7
- import BigBedAdapterF from "./BigBedAdapter/index.js";
8
- import GuessAdapterF from "./GuessAdapter/index.js";
2
+ import BedAdapterF from './BedAdapter/index.js';
3
+ import BedGraphAdapterF from './BedGraphAdapter/index.js';
4
+ import BedGraphTabixAdapterF from './BedGraphTabixAdapter/index.js';
5
+ import BedTabixAdapterF from './BedTabixAdapter/index.js';
6
+ import BedpeAdapterF from './BedpeAdapter/index.js';
7
+ import BigBedAdapterF from './BigBedAdapter/index.js';
8
+ import StarFusionAdapterF from './StarFusionAdapter/index.js';
9
+ export { default as BedTabixAdapter } from './BedTabixAdapter/BedTabixAdapter.js';
10
+ export { default as bedTabixConfigSchema } from './BedTabixAdapter/configSchema.js';
9
11
  export default class BedPlugin extends Plugin {
10
12
  name = 'BedPlugin';
11
13
  install(pluginManager) {
12
14
  BigBedAdapterF(pluginManager);
13
15
  BedAdapterF(pluginManager);
14
16
  BedpeAdapterF(pluginManager);
17
+ StarFusionAdapterF(pluginManager);
15
18
  BedTabixAdapterF(pluginManager);
16
19
  BedGraphAdapterF(pluginManager);
17
20
  BedGraphTabixAdapterF(pluginManager);
18
- GuessAdapterF(pluginManager);
19
21
  }
20
22
  }
package/esm/util.d.ts CHANGED
@@ -1,5 +1,21 @@
1
+ import BED from '@gmod/bed';
1
2
  import type { MinimalFeature } from './types.ts';
2
- import type BED from '@gmod/bed';
3
+ import type { StatusCallback } from '@jbrowse/core/util';
4
+ export interface FeatureData {
5
+ uniqueId: string;
6
+ refName: string;
7
+ start: number;
8
+ end: number;
9
+ strand?: number;
10
+ score?: number;
11
+ type?: string;
12
+ subfeatures?: MinimalFeature[];
13
+ [key: string]: unknown;
14
+ }
15
+ export declare function bucketBedLines(buffer: Uint8Array, statusCallback?: StatusCallback): {
16
+ header: string;
17
+ features: Record<string, string[]>;
18
+ };
3
19
  export declare function makeBlocks({ start, uniqueId, refName, chromStarts, blockCount, blockSizes, blockStarts, }: {
4
20
  blockCount: number;
5
21
  start: number;
@@ -8,36 +24,27 @@ export declare function makeBlocks({ start, uniqueId, refName, chromStarts, bloc
8
24
  chromStarts?: number[];
9
25
  blockSizes?: number[];
10
26
  blockStarts?: number[];
11
- }): {
12
- uniqueId: string;
13
- start: number;
14
- end: number;
15
- refName: string;
16
- type: string;
17
- }[];
18
- export declare function featureData({ line, colRef, colStart, colEnd, scoreColumn, parser, uniqueId, names, disableGeneHeuristic, }: {
19
- line: string;
27
+ }): MinimalFeature[];
28
+ export declare function parseNamesFromHeader(header: string): string[] | undefined;
29
+ export declare function resolveColumnNames(columnNames: string[], getHeader: () => Promise<string>): Promise<string[] | undefined>;
30
+ export declare function makeParser({ autoSql, columnNames, }: {
31
+ autoSql?: string;
32
+ columnNames?: string[];
33
+ }): BED;
34
+ export declare function bedFeatureLocus({ splitLine, colRef, colStart, colEnd, oneBased, hasEndColumn, }: {
35
+ splitLine: string[];
20
36
  colRef: number;
21
37
  colStart: number;
22
38
  colEnd: number;
23
- scoreColumn: string;
24
- parser: BED;
25
- uniqueId: string;
26
- names?: string[];
27
- disableGeneHeuristic?: boolean;
28
- }): FeatureData;
29
- interface FeatureData {
30
- uniqueId: string;
39
+ oneBased?: boolean;
40
+ hasEndColumn?: boolean;
41
+ }): {
31
42
  refName: string;
32
43
  start: number;
33
44
  end: number;
34
- strand?: number | string;
35
- score?: number;
36
- type?: string;
37
- subfeatures?: MinimalFeature[];
38
- [key: string]: unknown;
39
- }
40
- export declare function featureData2({ splitLine, refName, start, end, parser, uniqueId, scoreColumn, names, disableGeneHeuristic, }: {
45
+ };
46
+ export declare function parseStrand(strand: string | number | undefined): number;
47
+ export declare function featureData({ splitLine, refName, start, end, parser, uniqueId, scoreColumn, names, disableGeneHeuristic, }: {
41
48
  splitLine: string[];
42
49
  refName: string;
43
50
  start: number;
@@ -48,5 +55,3 @@ export declare function featureData2({ splitLine, refName, start, end, parser, u
48
55
  names?: string[];
49
56
  disableGeneHeuristic?: boolean;
50
57
  }): FeatureData;
51
- export declare function arrayify(f?: string | number[]): number[] | undefined;
52
- export {};
package/esm/util.js CHANGED
@@ -1,31 +1,28 @@
1
- import { generateBedMethylFeature, isBedMethylFeature, } from "./generateBedMethylFeature.js";
2
- import { generateRepeatMaskerFeature, isRepeatMaskerDescriptionField, } from "./generateRepeatMaskerFeature.js";
3
- import { generateUcscTranscript, isUcscTranscript, } from "./generateUcscTranscript.js";
4
- function defaultParser(fields, splitLine) {
5
- const obj = {};
6
- let hasBlockCount = false;
7
- for (const [i, element] of splitLine.entries()) {
8
- const field = fields[i];
9
- if (field) {
10
- obj[field] = element;
11
- if (field === 'blockCount') {
12
- hasBlockCount = true;
13
- }
1
+ import BED from '@gmod/bed';
2
+ import { parseLineByLine } from '@jbrowse/core/util/parseLineByLine';
3
+ import { generateBedMethylFeature, isBedMethylFeature, } from './generateBedMethylFeature.js';
4
+ import { generateRastairMethylFeature, isRastairMethylFeature, } from './generateRastairMethylFeature.js';
5
+ import { parseRepeatMaskerDescription } from './generateRepeatMaskerFeature.js';
6
+ import { generateUcscTranscript, isUcscTranscript, } from './generateUcscTranscript.js';
7
+ // Heuristically split features and header from a buffered BED file, bucketing
8
+ // data lines by the first tab-separated column (refName).
9
+ export function bucketBedLines(buffer, statusCallback) {
10
+ const features = {};
11
+ const headerLines = [];
12
+ parseLineByLine(buffer, line => {
13
+ if (line.startsWith('#')) {
14
+ headerLines.push(line);
14
15
  }
15
- }
16
- if (hasBlockCount) {
17
- const { blockStarts, blockCount, chromStarts, thickEnd, thickStart, blockSizes, ...rest } = obj;
18
- return {
19
- ...rest,
20
- blockStarts: arrayify(blockStarts),
21
- chromStarts: arrayify(chromStarts),
22
- blockSizes: arrayify(blockSizes),
23
- thickStart: thickStart ? +thickStart : undefined,
24
- thickEnd: thickEnd ? +thickEnd : undefined,
25
- blockCount: blockCount ? +blockCount : undefined,
26
- };
27
- }
28
- return obj;
16
+ else if (!line.startsWith('track') && !line.startsWith('browser')) {
17
+ // 'track'/'browser' are UCSC directive lines, not data (matches
18
+ // filterBedHeaderLines in spreadsheet-view)
19
+ const tab = line.indexOf('\t');
20
+ const refName = tab === -1 ? line : line.slice(0, tab);
21
+ (features[refName] ??= []).push(line);
22
+ }
23
+ return true;
24
+ }, statusCallback);
25
+ return { header: headerLines.join('\n'), features };
29
26
  }
30
27
  export function makeBlocks({ start, uniqueId, refName, chromStarts, blockCount, blockSizes, blockStarts, }) {
31
28
  const subfeatures = [];
@@ -45,24 +42,55 @@ export function makeBlocks({ start, uniqueId, refName, chromStarts, blockCount,
45
42
  }
46
43
  return subfeatures;
47
44
  }
48
- export function featureData({ line, colRef, colStart, colEnd, scoreColumn, parser, uniqueId, names, disableGeneHeuristic, }) {
49
- const splitLine = line.split('\t');
50
- const refName = splitLine[colRef];
51
- const start = Number.parseInt(splitLine[colStart], 10);
52
- const end = Number.parseInt(splitLine[colEnd], 10) + (colStart === colEnd ? 1 : 0);
53
- return featureData2({
54
- splitLine,
55
- refName,
45
+ export function parseNamesFromHeader(header) {
46
+ const defs = header.split(/\n|\r\n|\r/).filter(Boolean);
47
+ const defline = defs.at(-1);
48
+ // Strip the comment marker if there is one, rather than assuming it: a
49
+ // header kept for tabix with `-S N` instead of `#` is a bare row, and
50
+ // chopping its first character would rename its first column rather than
51
+ // fail to find one.
52
+ return defline?.includes('\t')
53
+ ? defline
54
+ .replace(/^#/, '')
55
+ .split('\t')
56
+ .map(f => f.trim())
57
+ : undefined;
58
+ }
59
+ // shared by BedAdapter/BedpeAdapter's getNames(): explicit columnNames config
60
+ // wins, else fall back to parsing the file's own header line
61
+ export async function resolveColumnNames(columnNames, getHeader) {
62
+ if (columnNames.length) {
63
+ return columnNames;
64
+ }
65
+ return parseNamesFromHeader(await getHeader());
66
+ }
67
+ // A header names the columns but says nothing about their types, so @gmod/bed
68
+ // takes the types from the standard BED columns of the same name — that is what
69
+ // splits `blockSizes` into numbers and leaves an unrecognized column a string.
70
+ // Names win over a configured autoSql, as they did when this file parsed the
71
+ // named case itself.
72
+ export function makeParser({ autoSql, columnNames, }) {
73
+ return columnNames?.length ? new BED({ columnNames }) : new BED({ autoSql });
74
+ }
75
+ // Decode a BED line's locus (0-based half-open) from its column layout, so the
76
+ // off-by-one rules live in one place instead of being re-derived at each call
77
+ // site. `oneBased` shifts a 1-based-closed start back a base. `hasEndColumn`
78
+ // false (tabix `-b` with no `-e`, e.g. point/GWAS data) means width-1 features.
79
+ // A start/end column collision in a 0-based file is also a point feature (+1).
80
+ export function bedFeatureLocus({ splitLine, colRef, colStart, colEnd, oneBased = false, hasEndColumn = true, }) {
81
+ const start = +splitLine[colStart] - (oneBased ? 1 : 0);
82
+ return {
83
+ refName: splitLine[colRef],
56
84
  start,
57
- end,
58
- parser,
59
- uniqueId,
60
- scoreColumn,
61
- names,
62
- disableGeneHeuristic,
63
- });
85
+ end: hasEndColumn
86
+ ? +splitLine[colEnd] + (colStart === colEnd && !oneBased ? 1 : 0)
87
+ : start + 1,
88
+ };
64
89
  }
65
- function parseStrand(strand) {
90
+ // Takes either form: `@gmod/bed`'s parseLine has already run its own
91
+ // parseStrand and hands over ±1/0, while the methylation and bedpe paths read
92
+ // the raw column. `.` and a missing column are unstranded, i.e. 0.
93
+ export function parseStrand(strand) {
66
94
  if (strand === '-' || strand === -1) {
67
95
  return -1;
68
96
  }
@@ -71,24 +99,8 @@ function parseStrand(strand) {
71
99
  }
72
100
  return 0;
73
101
  }
74
- export function featureData2({ splitLine, refName, start, end, parser, uniqueId, scoreColumn, names, disableGeneHeuristic, }) {
75
- const data = names
76
- ? defaultParser(names, splitLine)
77
- : parser.parseLine(splitLine, { uniqueId });
78
- const { strand: strand2, score: score2, chrom: _1, chromStart: _2, chromEnd: _3, ...rest } = data;
79
- const score = scoreColumn ? +data[scoreColumn] : score2 ? +score2 : undefined;
80
- const strand = parseStrand(strand2);
81
- const subfeatures = rest.blockCount
82
- ? makeBlocks({
83
- start,
84
- uniqueId,
85
- refName,
86
- chromStarts: rest.chromStarts,
87
- blockCount: rest.blockCount,
88
- blockSizes: rest.blockSizes,
89
- blockStarts: rest.blockStarts,
90
- })
91
- : undefined;
102
+ export function featureData({ splitLine, refName, start, end, parser, uniqueId, scoreColumn, names, disableGeneHeuristic, }) {
103
+ // bedMethyl detection runs on raw splitLine before parsing
92
104
  if (isBedMethylFeature({ splitLine, start, end })) {
93
105
  return generateBedMethylFeature({
94
106
  splitLine,
@@ -98,59 +110,77 @@ export function featureData2({ splitLine, refName, start, end, parser, uniqueId,
98
110
  end,
99
111
  });
100
112
  }
101
- else if (isRepeatMaskerDescriptionField(rest.description)) {
102
- const { chromStarts: _4, blockSizes: _5, blockStarts: _6, blockCount: _7, thickStart: _8, thickEnd: _9, description, ...rest2 } = rest;
103
- return generateRepeatMaskerFeature({
113
+ // rastair methylation is identified by its header column names
114
+ if (names !== undefined && isRastairMethylFeature(names)) {
115
+ return generateRastairMethylFeature({
116
+ splitLine,
117
+ names,
118
+ uniqueId,
119
+ refName,
120
+ start,
121
+ end,
122
+ });
123
+ }
124
+ const data = parser.parseLine(splitLine, { uniqueId });
125
+ const { strand: strandRaw, score: scoreRaw, chrom, chromStart, chromEnd, ...rest } = data;
126
+ const strand = parseStrand(strandRaw);
127
+ const rawScore = scoreColumn ? data[scoreColumn] : scoreRaw;
128
+ const score = rawScore === undefined ? undefined : Number(rawScore);
129
+ const repeat = parseRepeatMaskerDescription(rest.description);
130
+ if (repeat) {
131
+ const { description, chromStarts, blockSizes, blockStarts, blockCount, thickStart, thickEnd, ...rest2 } = rest;
132
+ return {
104
133
  ...rest2,
105
- description,
134
+ ...repeat,
106
135
  uniqueId,
107
136
  score,
108
137
  start,
109
138
  end,
110
139
  strand,
111
140
  refName,
112
- subfeatures,
113
- });
141
+ };
114
142
  }
115
- else if (!disableGeneHeuristic &&
116
- subfeatures &&
117
- isUcscTranscript({
118
- strand,
143
+ const subfeatures = rest.blockCount
144
+ ? makeBlocks({
145
+ start,
146
+ uniqueId,
147
+ refName,
148
+ chromStarts: rest.chromStarts,
119
149
  blockCount: rest.blockCount,
120
- thickStart: rest.thickStart,
121
- })) {
150
+ blockSizes: rest.blockSizes,
151
+ blockStarts: rest.blockStarts,
152
+ })
153
+ : undefined;
154
+ const transcriptCheck = {
155
+ strand,
156
+ blockCount: rest.blockCount,
157
+ thickStart: rest.thickStart,
158
+ thickEnd: rest.thickEnd,
159
+ };
160
+ if (!disableGeneHeuristic &&
161
+ subfeatures &&
162
+ isUcscTranscript(transcriptCheck)) {
122
163
  return generateUcscTranscript({
123
164
  ...rest,
124
165
  score,
125
166
  start,
126
167
  end,
127
- strand,
168
+ strand: transcriptCheck.strand,
128
169
  refName,
129
170
  uniqueId,
130
171
  subfeatures,
131
- thickStart: rest.thickStart,
132
- thickEnd: rest.thickEnd,
172
+ thickStart: transcriptCheck.thickStart,
173
+ thickEnd: transcriptCheck.thickEnd,
133
174
  });
134
175
  }
135
- else {
136
- return {
137
- ...rest,
138
- uniqueId,
139
- score,
140
- start,
141
- end,
142
- strand,
143
- refName,
144
- subfeatures,
145
- };
146
- }
147
- }
148
- export function arrayify(f) {
149
- if (f === undefined) {
150
- return undefined;
151
- }
152
- if (typeof f === 'string') {
153
- return f.split(',').map(s => +s);
154
- }
155
- return f;
176
+ return {
177
+ ...rest,
178
+ uniqueId,
179
+ score,
180
+ start,
181
+ end,
182
+ strand,
183
+ refName,
184
+ subfeatures,
185
+ };
156
186
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/plugin-bed",
3
- "version": "4.3.0",
3
+ "version": "5.0.0-beta.1",
4
4
  "type": "module",
5
5
  "description": "JBrowse 2 bed adapters, tracks, etc.",
6
6
  "keywords": [
@@ -21,14 +21,13 @@
21
21
  "esm"
22
22
  ],
23
23
  "dependencies": {
24
- "@flatten-js/interval-tree": "^2.0.3",
25
- "@gmod/bbi": "^9.0.9",
26
- "@gmod/bed": "^2.2.1",
27
- "@gmod/tabix": "^3.3.3",
28
- "@jbrowse/mobx-state-tree": "^5.6.0",
29
- "mobx": "^6.15.3",
24
+ "@gmod/bbi": "^11.2.3",
25
+ "@gmod/bed": "^2.3.0",
26
+ "@gmod/tabix": "^3.8.2",
27
+ "@jbrowse/mobx-state-tree": "^6.5.1",
28
+ "mobx": "^7.0.3",
30
29
  "rxjs": "^7.8.2",
31
- "@jbrowse/core": "^4.3.0"
30
+ "@jbrowse/core": "^5.0.0-beta.1"
32
31
  },
33
32
  "publishConfig": {
34
33
  "access": "public"
@@ -38,14 +37,11 @@
38
37
  "build": "pnpm run /^build:/",
39
38
  "test": "cd ../..; jest --passWithNoTests plugins/bed",
40
39
  "prebuild": "pnpm clean",
41
- "build:esm": "tsc -p tsconfig.build.esm.json",
40
+ "build:esm": "node ../../node_modules/typescript7/bin/tsc --build tsconfig.build.esm.json",
42
41
  "clean": "rimraf esm *.tsbuildinfo"
43
42
  },
44
43
  "types": "esm/index.d.ts",
45
44
  "exports": {
46
- ".": {
47
- "types": "./esm/index.d.ts",
48
- "import": "./esm/index.js"
49
- }
45
+ ".": "./esm/index.js"
50
46
  }
51
47
  }
@@ -1,2 +0,0 @@
1
- import type PluginManager from '@jbrowse/core/PluginManager';
2
- export default function GuessAdapterF(pluginManager: PluginManager): void;
@@ -1,71 +0,0 @@
1
- import { testAdapter } from '@jbrowse/core/util';
2
- import { getFileName, makeIndex, makeIndexType, } from '@jbrowse/core/util/tracks';
3
- export default function GuessAdapterF(pluginManager) {
4
- pluginManager.addToExtensionPoint('Core-guessAdapterForLocation', (adapterGuesser) => {
5
- return (file, index, adapterHint) => {
6
- const fileName = getFileName(file);
7
- const indexName = index && getFileName(index);
8
- if (testAdapter(fileName, /\.bedpe(\.gz)?$/i, adapterHint, 'BedpeAdapter')) {
9
- return {
10
- type: 'BedpeAdapter',
11
- bedpeLocation: file,
12
- };
13
- }
14
- else if (testAdapter(fileName, /\.bb$/i, adapterHint, 'BigBedAdapter') ||
15
- testAdapter(fileName, /\.bigbed$/i, adapterHint, 'BigBedAdapter')) {
16
- return {
17
- type: 'BigBedAdapter',
18
- bigBedLocation: file,
19
- };
20
- }
21
- else if (testAdapter(fileName, /\.bed$/i, adapterHint, 'BedAdapter')) {
22
- return {
23
- type: 'BedAdapter',
24
- bedLocation: file,
25
- };
26
- }
27
- else if (testAdapter(fileName, /\.bg$/i, adapterHint, 'BedGraphAdapter')) {
28
- return {
29
- type: 'BedGraphAdapter',
30
- bedGraphLocation: file,
31
- };
32
- }
33
- else if (testAdapter(fileName, /\.bg(\.gz)?$/i, adapterHint, 'BedGraphTabixAdapter')) {
34
- return {
35
- type: 'BedGraphTabixAdapter',
36
- bedGraphGzLocation: file,
37
- index: {
38
- location: index || makeIndex(file, '.tbi'),
39
- indexType: makeIndexType(indexName, 'CSI', 'TBI'),
40
- },
41
- };
42
- }
43
- else if (testAdapter(fileName, /\.bedmethyl\.gz$/i, adapterHint, 'BedTabixAdapter') ||
44
- testAdapter(fileName, /\.bed\.gz$/i, adapterHint, 'BedTabixAdapter')) {
45
- return {
46
- type: 'BedTabixAdapter',
47
- bedGzLocation: file,
48
- index: {
49
- location: index || makeIndex(file, '.tbi'),
50
- indexType: makeIndexType(indexName, 'CSI', 'TBI'),
51
- },
52
- };
53
- }
54
- else {
55
- return adapterGuesser(file, index, adapterHint);
56
- }
57
- };
58
- });
59
- pluginManager.addToExtensionPoint('Core-guessTrackTypeForLocation', (trackTypeGuesser) => (adapterName, file) => {
60
- if (adapterName === 'BedTabixAdapter' &&
61
- file &&
62
- /\.bedmethyl\.gz$/i.test(getFileName(file))) {
63
- return 'MultiQuantitativeTrack';
64
- }
65
- return ({
66
- BedpeAdapter: 'VariantTrack',
67
- BedGraphAdapter: 'QuantitativeTrack',
68
- BedGraphTabixAdapter: 'QuantitativeTrack',
69
- }[adapterName] || trackTypeGuesser(adapterName, file));
70
- });
71
- }