@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.
- package/esm/BedAdapter/BedAdapter.d.ts +4 -19
- package/esm/BedAdapter/BedAdapter.js +31 -88
- package/esm/BedAdapter/configSchema.d.ts +89 -40
- package/esm/BedAdapter/configSchema.js +65 -13
- package/esm/BedAdapter/index.js +4 -2
- package/esm/BedGraphAdapter/BedGraphAdapter.d.ts +4 -9
- package/esm/BedGraphAdapter/BedGraphAdapter.js +31 -85
- package/esm/BedGraphAdapter/configSchema.d.ts +35 -9
- package/esm/BedGraphAdapter/configSchema.js +47 -12
- package/esm/BedGraphAdapter/index.js +3 -2
- package/esm/BedGraphTabixAdapter/BedGraphTabixAdapter.d.ts +5 -5
- package/esm/BedGraphTabixAdapter/BedGraphTabixAdapter.js +62 -57
- package/esm/BedGraphTabixAdapter/configSchema.d.ts +48 -19
- package/esm/BedGraphTabixAdapter/configSchema.js +42 -34
- package/esm/BedGraphTabixAdapter/index.js +3 -2
- package/esm/BedTabixAdapter/BedTabixAdapter.d.ts +34 -38
- package/esm/BedTabixAdapter/BedTabixAdapter.js +82 -71
- package/esm/BedTabixAdapter/configSchema.d.ts +68 -31
- package/esm/BedTabixAdapter/configSchema.js +51 -35
- package/esm/BedTabixAdapter/index.js +4 -2
- package/esm/BedpeAdapter/BedpeAdapter.d.ts +4 -10
- package/esm/BedpeAdapter/BedpeAdapter.js +28 -69
- package/esm/BedpeAdapter/configSchema.d.ts +33 -10
- package/esm/BedpeAdapter/configSchema.js +45 -12
- package/esm/BedpeAdapter/index.js +4 -2
- package/esm/BedpeAdapter/util.js +22 -23
- package/esm/BigBedAdapter/BigBedAdapter.d.ts +8 -7
- package/esm/BigBedAdapter/BigBedAdapter.js +100 -107
- package/esm/BigBedAdapter/configSchema.d.ts +47 -17
- package/esm/BigBedAdapter/configSchema.js +51 -12
- package/esm/BigBedAdapter/index.js +3 -2
- package/esm/StarFusionAdapter/StarFusionAdapter.d.ts +15 -0
- package/esm/StarFusionAdapter/StarFusionAdapter.js +121 -0
- package/esm/StarFusionAdapter/configSchema.d.ts +31 -0
- package/esm/StarFusionAdapter/configSchema.js +52 -0
- package/esm/StarFusionAdapter/index.d.ts +2 -0
- package/esm/StarFusionAdapter/index.js +12 -0
- package/esm/adapterUtil.d.ts +5 -0
- package/esm/adapterUtil.js +28 -0
- package/esm/bedGraphUtil.d.ts +10 -0
- package/esm/bedGraphUtil.js +18 -0
- package/esm/generateBedMethylFeature.d.ts +1 -1
- package/esm/generateBedMethylFeature.js +19 -6
- package/esm/generateRastairMethylFeature.d.ts +28 -0
- package/esm/generateRastairMethylFeature.js +38 -0
- package/esm/generateRepeatMaskerFeature.d.ts +4 -51
- package/esm/generateRepeatMaskerFeature.js +28 -41
- package/esm/generateUcscTranscript.d.ts +15 -7
- package/esm/generateUcscTranscript.js +58 -28
- package/esm/index.d.ts +2 -0
- package/esm/index.js +10 -8
- package/esm/util.d.ts +32 -27
- package/esm/util.js +127 -97
- package/package.json +9 -13
- package/esm/GuessAdapter/index.d.ts +0 -2
- package/esm/GuessAdapter/index.js +0 -71
|
@@ -1,35 +1,52 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
|
|
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
|
|
22
|
-
|
|
23
|
-
|
|
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 } =
|
|
46
|
+
const { cdsEndStat, cdsStartStat } = rest;
|
|
30
47
|
if (cdsStartStat === 'none' && cdsEndStat === 'none') {
|
|
31
48
|
return {
|
|
32
|
-
...
|
|
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
|
-
|
|
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
|
|
59
|
-
|
|
60
|
-
|
|
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 <=
|
|
64
|
-
|
|
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
|
-
|
|
68
|
-
|
|
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(
|
|
71
|
-
const cdsEnd = Math.min(
|
|
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 (
|
|
90
|
-
subfeatures.push({
|
|
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
|
-
...
|
|
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
|
|
3
|
-
import BedGraphAdapterF from
|
|
4
|
-
import BedGraphTabixAdapterF from
|
|
5
|
-
import BedTabixAdapterF from
|
|
6
|
-
import BedpeAdapterF from
|
|
7
|
-
import BigBedAdapterF from
|
|
8
|
-
import
|
|
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
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
export declare function
|
|
19
|
-
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
names,
|
|
62
|
-
disableGeneHeuristic,
|
|
63
|
-
});
|
|
85
|
+
end: hasEndColumn
|
|
86
|
+
? +splitLine[colEnd] + (colStart === colEnd && !oneBased ? 1 : 0)
|
|
87
|
+
: start + 1,
|
|
88
|
+
};
|
|
64
89
|
}
|
|
65
|
-
|
|
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
|
|
75
|
-
|
|
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
|
-
|
|
102
|
-
|
|
103
|
-
return
|
|
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
|
-
|
|
134
|
+
...repeat,
|
|
106
135
|
uniqueId,
|
|
107
136
|
score,
|
|
108
137
|
start,
|
|
109
138
|
end,
|
|
110
139
|
strand,
|
|
111
140
|
refName,
|
|
112
|
-
|
|
113
|
-
});
|
|
141
|
+
};
|
|
114
142
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
143
|
+
const subfeatures = rest.blockCount
|
|
144
|
+
? makeBlocks({
|
|
145
|
+
start,
|
|
146
|
+
uniqueId,
|
|
147
|
+
refName,
|
|
148
|
+
chromStarts: rest.chromStarts,
|
|
119
149
|
blockCount: rest.blockCount,
|
|
120
|
-
|
|
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:
|
|
132
|
-
thickEnd:
|
|
172
|
+
thickStart: transcriptCheck.thickStart,
|
|
173
|
+
thickEnd: transcriptCheck.thickEnd,
|
|
133
174
|
});
|
|
134
175
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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": "
|
|
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
|
-
"@
|
|
25
|
-
"@gmod/
|
|
26
|
-
"@gmod/
|
|
27
|
-
"@
|
|
28
|
-
"
|
|
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": "^
|
|
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
|
|
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,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
|
-
}
|