@jbrowse/plugin-alignments 2.0.0 → 2.1.2
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/dist/AlignmentsFeatureDetail/AlignmentsFeatureDetail.js +61 -90
- package/dist/AlignmentsFeatureDetail/AlignmentsFeatureDetail.js.map +1 -1
- package/dist/AlignmentsFeatureDetail/index.js +14 -16
- package/dist/AlignmentsFeatureDetail/index.js.map +1 -1
- package/dist/AlignmentsTrack/index.js +8 -8
- package/dist/AlignmentsTrack/index.js.map +1 -1
- package/dist/BamAdapter/BamAdapter.d.ts +6 -1
- package/dist/BamAdapter/BamAdapter.js +157 -336
- package/dist/BamAdapter/BamAdapter.js.map +1 -1
- package/dist/BamAdapter/BamSlightlyLazyFeature.js +68 -103
- package/dist/BamAdapter/BamSlightlyLazyFeature.js.map +1 -1
- package/dist/BamAdapter/MismatchParser.d.ts +1 -1
- package/dist/BamAdapter/MismatchParser.js +97 -162
- package/dist/BamAdapter/MismatchParser.js.map +1 -1
- package/dist/BamAdapter/configSchema.js +27 -29
- package/dist/BamAdapter/configSchema.js.map +1 -1
- package/dist/BamAdapter/index.js +9 -11
- package/dist/BamAdapter/index.js.map +1 -1
- package/dist/CramAdapter/CramAdapter.js +193 -351
- package/dist/CramAdapter/CramAdapter.js.map +1 -1
- package/dist/CramAdapter/CramSlightlyLazyFeature.js +119 -154
- package/dist/CramAdapter/CramSlightlyLazyFeature.js.map +1 -1
- package/dist/CramAdapter/CramTestAdapters.js +51 -148
- package/dist/CramAdapter/CramTestAdapters.js.map +1 -1
- package/dist/CramAdapter/configSchema.js +23 -25
- package/dist/CramAdapter/configSchema.js.map +1 -1
- package/dist/CramAdapter/index.js +9 -11
- package/dist/CramAdapter/index.js.map +1 -1
- package/dist/HtsgetBamAdapter/HtsgetBamAdapter.js +25 -87
- package/dist/HtsgetBamAdapter/HtsgetBamAdapter.js.map +1 -1
- package/dist/HtsgetBamAdapter/configSchema.js +16 -18
- package/dist/HtsgetBamAdapter/configSchema.js.map +1 -1
- package/dist/HtsgetBamAdapter/index.js +15 -19
- package/dist/HtsgetBamAdapter/index.js.map +1 -1
- package/dist/LinearAlignmentsDisplay/components/AlignmentsDisplay.js +14 -15
- package/dist/LinearAlignmentsDisplay/components/AlignmentsDisplay.js.map +1 -1
- package/dist/LinearAlignmentsDisplay/index.js +7 -7
- package/dist/LinearAlignmentsDisplay/index.js.map +1 -1
- package/dist/LinearAlignmentsDisplay/models/configSchema.js +5 -5
- package/dist/LinearAlignmentsDisplay/models/configSchema.js.map +1 -1
- package/dist/LinearAlignmentsDisplay/models/model.js +64 -140
- package/dist/LinearAlignmentsDisplay/models/model.js.map +1 -1
- package/dist/LinearPileupDisplay/components/ColorByModifications.js +24 -53
- package/dist/LinearPileupDisplay/components/ColorByModifications.js.map +1 -1
- package/dist/LinearPileupDisplay/components/ColorByTag.js +14 -30
- package/dist/LinearPileupDisplay/components/ColorByTag.js.map +1 -1
- package/dist/LinearPileupDisplay/components/FilterByTag.js +33 -49
- package/dist/LinearPileupDisplay/components/FilterByTag.js.map +1 -1
- package/dist/LinearPileupDisplay/components/LinearPileupDisplayBlurb.js +7 -7
- package/dist/LinearPileupDisplay/components/LinearPileupDisplayBlurb.js.map +1 -1
- package/dist/LinearPileupDisplay/components/SetFeatureHeight.js +17 -33
- package/dist/LinearPileupDisplay/components/SetFeatureHeight.js.map +1 -1
- package/dist/LinearPileupDisplay/components/SetMaxHeight.js +14 -30
- package/dist/LinearPileupDisplay/components/SetMaxHeight.js.map +1 -1
- package/dist/LinearPileupDisplay/components/SortByTag.js +14 -30
- package/dist/LinearPileupDisplay/components/SortByTag.js.map +1 -1
- package/dist/LinearPileupDisplay/configSchema.js +4 -4
- package/dist/LinearPileupDisplay/configSchema.js.map +1 -1
- package/dist/LinearPileupDisplay/index.js +7 -7
- package/dist/LinearPileupDisplay/index.js.map +1 -1
- package/dist/LinearPileupDisplay/model.js +534 -645
- package/dist/LinearPileupDisplay/model.js.map +1 -1
- package/dist/LinearSNPCoverageDisplay/components/Tooltip.d.ts +5 -2
- package/dist/LinearSNPCoverageDisplay/components/Tooltip.js +30 -79
- package/dist/LinearSNPCoverageDisplay/components/Tooltip.js.map +1 -1
- package/dist/LinearSNPCoverageDisplay/index.js +7 -7
- package/dist/LinearSNPCoverageDisplay/index.js.map +1 -1
- package/dist/LinearSNPCoverageDisplay/models/configSchema.js +4 -4
- package/dist/LinearSNPCoverageDisplay/models/configSchema.js.map +1 -1
- package/dist/LinearSNPCoverageDisplay/models/model.d.ts +27 -5
- package/dist/LinearSNPCoverageDisplay/models/model.js +171 -244
- package/dist/LinearSNPCoverageDisplay/models/model.js.map +1 -1
- package/dist/NestedFrequencyTable.js +27 -40
- package/dist/NestedFrequencyTable.js.map +1 -1
- package/dist/PileupRPC/rpcMethods.js +63 -191
- package/dist/PileupRPC/rpcMethods.js.map +1 -1
- package/dist/PileupRenderer/PileupLayoutSession.js +25 -47
- package/dist/PileupRenderer/PileupLayoutSession.js.map +1 -1
- package/dist/PileupRenderer/PileupRenderer.d.ts +0 -4
- package/dist/PileupRenderer/PileupRenderer.js +395 -529
- package/dist/PileupRenderer/PileupRenderer.js.map +1 -1
- package/dist/PileupRenderer/components/PileupRendering.js +41 -68
- package/dist/PileupRenderer/components/PileupRendering.js.map +1 -1
- package/dist/PileupRenderer/configSchema.js +2 -2
- package/dist/PileupRenderer/configSchema.js.map +1 -1
- package/dist/PileupRenderer/index.js +9 -11
- package/dist/PileupRenderer/index.js.map +1 -1
- package/dist/PileupRenderer/sortUtil.js +36 -40
- package/dist/PileupRenderer/sortUtil.js.map +1 -1
- package/dist/SNPCoverageAdapter/SNPCoverageAdapter.js +229 -414
- package/dist/SNPCoverageAdapter/SNPCoverageAdapter.js.map +1 -1
- package/dist/SNPCoverageAdapter/configSchema.js +5 -9
- package/dist/SNPCoverageAdapter/configSchema.js.map +1 -1
- package/dist/SNPCoverageAdapter/index.js +17 -21
- package/dist/SNPCoverageAdapter/index.js.map +1 -1
- package/dist/SNPCoverageRenderer/SNPCoverageRenderer.d.ts +1 -1
- package/dist/SNPCoverageRenderer/SNPCoverageRenderer.js +175 -259
- package/dist/SNPCoverageRenderer/SNPCoverageRenderer.js.map +1 -1
- package/dist/SNPCoverageRenderer/configSchema.js +1 -1
- package/dist/SNPCoverageRenderer/configSchema.js.map +1 -1
- package/dist/SNPCoverageRenderer/index.js +10 -12
- package/dist/SNPCoverageRenderer/index.js.map +1 -1
- package/dist/index.js +40 -58
- package/dist/index.js.map +1 -1
- package/dist/shared.js +23 -78
- package/dist/shared.js.map +1 -1
- package/dist/util.js +13 -66
- package/dist/util.js.map +1 -1
- package/esm/BamAdapter/BamAdapter.d.ts +6 -1
- package/esm/BamAdapter/BamAdapter.js.map +1 -1
- package/esm/BamAdapter/MismatchParser.d.ts +1 -1
- package/esm/BamAdapter/MismatchParser.js +2 -2
- package/esm/BamAdapter/MismatchParser.js.map +1 -1
- package/esm/LinearPileupDisplay/model.js +0 -1
- package/esm/LinearPileupDisplay/model.js.map +1 -1
- package/esm/LinearSNPCoverageDisplay/components/Tooltip.d.ts +4 -1
- package/esm/LinearSNPCoverageDisplay/components/Tooltip.js +0 -1
- package/esm/LinearSNPCoverageDisplay/components/Tooltip.js.map +1 -1
- package/esm/LinearSNPCoverageDisplay/models/model.d.ts +27 -5
- package/esm/LinearSNPCoverageDisplay/models/model.js +1 -0
- package/esm/LinearSNPCoverageDisplay/models/model.js.map +1 -1
- package/esm/PileupRenderer/PileupRenderer.d.ts +0 -4
- package/esm/PileupRenderer/PileupRenderer.js +1 -3
- package/esm/PileupRenderer/PileupRenderer.js.map +1 -1
- package/esm/SNPCoverageAdapter/SNPCoverageAdapter.js +4 -3
- package/esm/SNPCoverageAdapter/SNPCoverageAdapter.js.map +1 -1
- package/esm/SNPCoverageRenderer/SNPCoverageRenderer.d.ts +1 -1
- package/esm/SNPCoverageRenderer/SNPCoverageRenderer.js +0 -1
- package/esm/SNPCoverageRenderer/SNPCoverageRenderer.js.map +1 -1
- package/package.json +6 -7
- package/src/AlignmentsFeatureDetail/__snapshots__/index.test.js.snap +12 -12
- package/src/BamAdapter/BamAdapter.ts +1 -1
- package/src/BamAdapter/MismatchParser.ts +2 -2
- package/src/LinearPileupDisplay/model.ts +2 -2
- package/src/LinearSNPCoverageDisplay/components/Tooltip.tsx +3 -4
- package/src/LinearSNPCoverageDisplay/models/model.ts +3 -1
- package/src/PileupRenderer/PileupRenderer.tsx +13 -19
- package/src/SNPCoverageAdapter/SNPCoverageAdapter.ts +4 -3
- package/src/SNPCoverageRenderer/SNPCoverageRenderer.ts +1 -3
|
@@ -1,145 +1,110 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __assign = (this && this.__assign) || function () {
|
|
3
|
-
__assign = Object.assign || function(t) {
|
|
4
|
-
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
-
s = arguments[i];
|
|
6
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
-
t[p] = s[p];
|
|
8
|
-
}
|
|
9
|
-
return t;
|
|
10
|
-
};
|
|
11
|
-
return __assign.apply(this, arguments);
|
|
12
|
-
};
|
|
13
|
-
var __read = (this && this.__read) || function (o, n) {
|
|
14
|
-
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
15
|
-
if (!m) return o;
|
|
16
|
-
var i = m.call(o), r, ar = [], e;
|
|
17
|
-
try {
|
|
18
|
-
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
19
|
-
}
|
|
20
|
-
catch (error) { e = { error: error }; }
|
|
21
|
-
finally {
|
|
22
|
-
try {
|
|
23
|
-
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
24
|
-
}
|
|
25
|
-
finally { if (e) throw e.error; }
|
|
26
|
-
}
|
|
27
|
-
return ar;
|
|
28
|
-
};
|
|
29
|
-
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
30
|
-
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
31
|
-
if (ar || !(i in from)) {
|
|
32
|
-
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
33
|
-
ar[i] = from[i];
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return to.concat(ar || Array.prototype.slice.call(from));
|
|
37
|
-
};
|
|
38
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
|
|
40
|
-
|
|
3
|
+
const MismatchParser_1 = require("./MismatchParser");
|
|
4
|
+
class BamSlightlyLazyFeature {
|
|
41
5
|
// uses parameter properties to automatically create fields on the class
|
|
42
6
|
// https://www.typescriptlang.org/docs/handbook/classes.html#parameter-properties
|
|
43
|
-
|
|
7
|
+
constructor(record, adapter, ref) {
|
|
44
8
|
this.record = record;
|
|
45
9
|
this.adapter = adapter;
|
|
46
10
|
this.ref = ref;
|
|
47
11
|
}
|
|
48
|
-
|
|
12
|
+
_get_name() {
|
|
49
13
|
return this.record.get('name');
|
|
50
|
-
}
|
|
51
|
-
|
|
14
|
+
}
|
|
15
|
+
_get_type() {
|
|
52
16
|
return 'match';
|
|
53
|
-
}
|
|
54
|
-
|
|
17
|
+
}
|
|
18
|
+
_get_score() {
|
|
55
19
|
return this.record.get('mq');
|
|
56
|
-
}
|
|
57
|
-
|
|
20
|
+
}
|
|
21
|
+
_get_flags() {
|
|
58
22
|
return this.record.flags;
|
|
59
|
-
}
|
|
60
|
-
|
|
23
|
+
}
|
|
24
|
+
_get_strand() {
|
|
61
25
|
return this.record.isReverseComplemented() ? -1 : 1;
|
|
62
|
-
}
|
|
63
|
-
|
|
26
|
+
}
|
|
27
|
+
_get_pair_orientation() {
|
|
64
28
|
return this.record.isPaired() ? this.record.getPairOrientation() : undefined;
|
|
65
|
-
}
|
|
66
|
-
|
|
29
|
+
}
|
|
30
|
+
_get_next_seq_id() {
|
|
67
31
|
return this.record._next_refid();
|
|
68
|
-
}
|
|
69
|
-
|
|
32
|
+
}
|
|
33
|
+
_get_seq_id() {
|
|
70
34
|
// @ts-ignore
|
|
71
35
|
return this.record._refID;
|
|
72
|
-
}
|
|
73
|
-
|
|
36
|
+
}
|
|
37
|
+
_get_next_refName() {
|
|
74
38
|
return this.adapter.refIdToName(this.record._next_refid());
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
|
|
39
|
+
}
|
|
40
|
+
_get_next_segment_position() {
|
|
41
|
+
const { record, adapter } = this;
|
|
78
42
|
return record.isPaired()
|
|
79
|
-
?
|
|
43
|
+
? `${adapter.refIdToName(record._next_refid())}:${record._next_pos() + 1}`
|
|
80
44
|
: undefined;
|
|
81
|
-
}
|
|
82
|
-
|
|
45
|
+
}
|
|
46
|
+
_get_seq() {
|
|
83
47
|
return this.record.getReadBases();
|
|
84
|
-
}
|
|
85
|
-
|
|
48
|
+
}
|
|
49
|
+
qualRaw() {
|
|
86
50
|
return this.record.qualRaw();
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
return
|
|
92
|
-
|
|
93
|
-
|
|
51
|
+
}
|
|
52
|
+
set() { }
|
|
53
|
+
tags() {
|
|
54
|
+
const properties = Object.getOwnPropertyNames(BamSlightlyLazyFeature.prototype);
|
|
55
|
+
return [
|
|
56
|
+
...new Set(properties
|
|
57
|
+
.filter(prop => prop.startsWith('_get_') &&
|
|
94
58
|
prop !== '_get_mismatches' &&
|
|
95
59
|
prop !== '_get_tags' &&
|
|
96
60
|
prop !== '_get_next_seq_id' &&
|
|
97
|
-
prop !== '_get_seq_id'
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return
|
|
104
|
-
}
|
|
61
|
+
prop !== '_get_seq_id')
|
|
62
|
+
.map(methodName => methodName.replace('_get_', ''))
|
|
63
|
+
.concat(this.record._tags())),
|
|
64
|
+
];
|
|
65
|
+
}
|
|
66
|
+
id() {
|
|
67
|
+
return `${this.adapter.id}-${this.record.id()}`;
|
|
68
|
+
}
|
|
105
69
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
106
|
-
|
|
107
|
-
|
|
70
|
+
get(field) {
|
|
71
|
+
const methodName = `_get_${field}`;
|
|
108
72
|
// @ts-ignore
|
|
109
73
|
if (this[methodName]) {
|
|
110
74
|
// @ts-ignore
|
|
111
75
|
return this[methodName]();
|
|
112
76
|
}
|
|
113
77
|
return this.record.get(field);
|
|
114
|
-
}
|
|
115
|
-
|
|
78
|
+
}
|
|
79
|
+
_get_refName() {
|
|
116
80
|
return this.adapter.refIdToName(this.record.seq_id());
|
|
117
|
-
}
|
|
118
|
-
|
|
81
|
+
}
|
|
82
|
+
parent() {
|
|
119
83
|
return undefined;
|
|
120
|
-
}
|
|
121
|
-
|
|
84
|
+
}
|
|
85
|
+
children() {
|
|
122
86
|
return undefined;
|
|
123
|
-
}
|
|
124
|
-
|
|
87
|
+
}
|
|
88
|
+
pairedFeature() {
|
|
125
89
|
return false;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
90
|
+
}
|
|
91
|
+
toJSON() {
|
|
92
|
+
return {
|
|
93
|
+
...Object.fromEntries(this.tags()
|
|
94
|
+
.map(t => [t, this.get(t)])
|
|
95
|
+
.filter(elt => elt[1] !== undefined)),
|
|
96
|
+
uniqueId: this.id(),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
_get_mismatches() {
|
|
134
100
|
return (0, MismatchParser_1.getMismatches)(this.get('CIGAR'), this.get('MD'), this.get('seq'), this.ref, this.qualRaw());
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
|
|
101
|
+
}
|
|
102
|
+
_get_clipPos() {
|
|
103
|
+
const cigar = this.get('CIGAR') || '';
|
|
138
104
|
return this.get('strand') === -1
|
|
139
105
|
? +(cigar.match(/(\d+)[SH]$/) || [])[1] || 0
|
|
140
106
|
: +(cigar.match(/^(\d+)([SH])/) || [])[1] || 0;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
}());
|
|
107
|
+
}
|
|
108
|
+
}
|
|
144
109
|
exports.default = BamSlightlyLazyFeature;
|
|
145
110
|
//# sourceMappingURL=BamSlightlyLazyFeature.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BamSlightlyLazyFeature.js","sourceRoot":"","sources":["../../src/BamAdapter/BamSlightlyLazyFeature.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"BamSlightlyLazyFeature.js","sourceRoot":"","sources":["../../src/BamAdapter/BamSlightlyLazyFeature.ts"],"names":[],"mappings":";;AAMA,qDAAgD;AAIhD,MAAqB,sBAAsB;IACzC,wEAAwE;IACxE,iFAAiF;IACjF,YACU,MAAiB,EACjB,OAAmB,EACnB,GAAY;QAFZ,WAAM,GAAN,MAAM,CAAW;QACjB,YAAO,GAAP,OAAO,CAAY;QACnB,QAAG,GAAH,GAAG,CAAS;IACnB,CAAC;IAEJ,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IAChC,CAAC;IAED,SAAS;QACP,OAAO,OAAO,CAAA;IAChB,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC9B,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAA;IAC1B,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,MAAM,CAAC,qBAAqB,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACrD,CAAC;IAED,qBAAqB;QACnB,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;IAC9E,CAAC;IAED,gBAAgB;QACd,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAA;IAClC,CAAC;IAED,WAAW;QACT,aAAa;QACb,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAA;IAC3B,CAAC;IAED,iBAAiB;QACf,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAA;IAC5D,CAAC;IAED,0BAA0B;QACxB,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;QAChC,OAAO,MAAM,CAAC,QAAQ,EAAE;YACtB,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,IAAI,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE;YAC1E,CAAC,CAAC,SAAS,CAAA;IACf,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAA;IACnC,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAA;IAC9B,CAAC;IAED,GAAG,KAAI,CAAC;IAER,IAAI;QACF,MAAM,UAAU,GAAG,MAAM,CAAC,mBAAmB,CAC3C,sBAAsB,CAAC,SAAS,CACjC,CAAA;QAED,OAAO;YACL,GAAG,IAAI,GAAG,CACR,UAAU;iBACP,MAAM,CACL,IAAI,CAAC,EAAE,CACL,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;gBACxB,IAAI,KAAK,iBAAiB;gBAC1B,IAAI,KAAK,WAAW;gBACpB,IAAI,KAAK,kBAAkB;gBAC3B,IAAI,KAAK,aAAa,CACzB;iBACA,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;iBAClD,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAC/B;SACF,CAAA;IACH,CAAC;IAED,EAAE;QACA,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAA;IACjD,CAAC;IAED,8DAA8D;IAC9D,GAAG,CAAC,KAAa;QACf,MAAM,UAAU,GAAG,QAAQ,KAAK,EAAE,CAAA;QAClC,aAAa;QACb,IAAI,IAAI,CAAC,UAAU,CAAC,EAAE;YACpB,aAAa;YACb,OAAO,IAAI,CAAC,UAAU,CAAC,EAAE,CAAA;SAC1B;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IAC/B,CAAC;IAED,YAAY;QACV,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAA;IACvD,CAAC;IAED,MAAM;QACJ,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,QAAQ;QACN,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,aAAa;QACX,OAAO,KAAK,CAAA;IACd,CAAC;IAED,MAAM;QACJ,OAAO;YACL,GAAG,MAAM,CAAC,WAAW,CACnB,IAAI,CAAC,IAAI,EAAE;iBACR,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;iBAC1B,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CACvC;YACD,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE;SACpB,CAAA;IACH,CAAC;IAED,eAAe;QACb,OAAO,IAAA,8BAAa,EAClB,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EACjB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EACd,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EACf,IAAI,CAAC,GAAG,EACR,IAAI,CAAC,OAAO,EAAE,CACf,CAAA;IACH,CAAC;IAED,YAAY;QACV,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;QACrC,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YAC9B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAC5C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;IAClD,CAAC;CACF;AA/ID,yCA+IC"}
|
|
@@ -9,7 +9,7 @@ export interface Mismatch {
|
|
|
9
9
|
seq?: string;
|
|
10
10
|
cliplen?: number;
|
|
11
11
|
}
|
|
12
|
-
export declare function parseCigar(cigar
|
|
12
|
+
export declare function parseCigar(cigar?: string): string[];
|
|
13
13
|
export declare function cigarToMismatches(ops: string[], seq: string, ref?: string, qual?: Buffer): Mismatch[];
|
|
14
14
|
/**
|
|
15
15
|
* parse a SAM MD tag to find mismatching bases of the template versus the reference
|
|
@@ -1,67 +1,24 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
3
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
4
|
-
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
5
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
6
|
-
function step(op) {
|
|
7
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
8
|
-
while (_) try {
|
|
9
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
10
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
11
|
-
switch (op[0]) {
|
|
12
|
-
case 0: case 1: t = op; break;
|
|
13
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
14
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
15
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
16
|
-
default:
|
|
17
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
18
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
19
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
20
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
21
|
-
if (t[2]) _.ops.pop();
|
|
22
|
-
_.trys.pop(); continue;
|
|
23
|
-
}
|
|
24
|
-
op = body.call(thisArg, _);
|
|
25
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
26
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
var __read = (this && this.__read) || function (o, n) {
|
|
30
|
-
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
31
|
-
if (!m) return o;
|
|
32
|
-
var i = m.call(o), r, ar = [], e;
|
|
33
|
-
try {
|
|
34
|
-
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
35
|
-
}
|
|
36
|
-
catch (error) { e = { error: error }; }
|
|
37
|
-
finally {
|
|
38
|
-
try {
|
|
39
|
-
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
40
|
-
}
|
|
41
|
-
finally { if (e) throw e.error; }
|
|
42
|
-
}
|
|
43
|
-
return ar;
|
|
44
|
-
};
|
|
45
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
3
|
exports.getModificationTypes = exports.getModificationPositions = exports.getNextRefPos = exports.getMismatches = exports.mdToMismatches = exports.cigarToMismatches = exports.parseCigar = void 0;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
function parseCigar(cigar) {
|
|
51
|
-
return
|
|
4
|
+
const util_1 = require("@jbrowse/core/util");
|
|
5
|
+
const mdRegex = new RegExp(/(\d+|\^[a-z]+|[a-z])/gi);
|
|
6
|
+
const modificationRegex = new RegExp(/([A-Z])([-+])([^,.?]+)([.?])?/);
|
|
7
|
+
function parseCigar(cigar = '') {
|
|
8
|
+
return cigar.split(/([MIDNSHPX=])/).slice(0, -1);
|
|
52
9
|
}
|
|
53
10
|
exports.parseCigar = parseCigar;
|
|
54
11
|
function cigarToMismatches(ops, seq, ref, qual) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
for (
|
|
60
|
-
|
|
61
|
-
|
|
12
|
+
let roffset = 0; // reference offset
|
|
13
|
+
let soffset = 0; // seq offset
|
|
14
|
+
const mismatches = [];
|
|
15
|
+
const hasRefAndSeq = ref && seq;
|
|
16
|
+
for (let i = 0; i < ops.length; i += 2) {
|
|
17
|
+
const len = +ops[i];
|
|
18
|
+
const op = ops[i + 1];
|
|
62
19
|
if (op === 'M' || op === '=' || op === 'E') {
|
|
63
20
|
if (hasRefAndSeq) {
|
|
64
|
-
for (
|
|
21
|
+
for (let j = 0; j < len; j++) {
|
|
65
22
|
if (
|
|
66
23
|
// @ts-ignore in the full yarn build of the repo, this says that object is possibly undefined for some reason, ignored
|
|
67
24
|
seq[soffset + j].toUpperCase() !== ref[roffset + j].toUpperCase()) {
|
|
@@ -81,7 +38,7 @@ function cigarToMismatches(ops, seq, ref, qual) {
|
|
|
81
38
|
mismatches.push({
|
|
82
39
|
start: roffset,
|
|
83
40
|
type: 'insertion',
|
|
84
|
-
base:
|
|
41
|
+
base: `${len}`,
|
|
85
42
|
length: 0,
|
|
86
43
|
});
|
|
87
44
|
soffset += len;
|
|
@@ -103,9 +60,9 @@ function cigarToMismatches(ops, seq, ref, qual) {
|
|
|
103
60
|
});
|
|
104
61
|
}
|
|
105
62
|
else if (op === 'X') {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
for (
|
|
63
|
+
const r = seq.slice(soffset, soffset + len);
|
|
64
|
+
const q = (qual === null || qual === void 0 ? void 0 : qual.slice(soffset, soffset + len)) || [];
|
|
65
|
+
for (let j = 0; j < len; j++) {
|
|
109
66
|
mismatches.push({
|
|
110
67
|
start: roffset + j,
|
|
111
68
|
type: 'mismatch',
|
|
@@ -120,7 +77,7 @@ function cigarToMismatches(ops, seq, ref, qual) {
|
|
|
120
77
|
mismatches.push({
|
|
121
78
|
start: roffset,
|
|
122
79
|
type: 'hardclip',
|
|
123
|
-
base:
|
|
80
|
+
base: `H${len}`,
|
|
124
81
|
cliplen: len,
|
|
125
82
|
length: 1,
|
|
126
83
|
});
|
|
@@ -129,7 +86,7 @@ function cigarToMismatches(ops, seq, ref, qual) {
|
|
|
129
86
|
mismatches.push({
|
|
130
87
|
start: roffset,
|
|
131
88
|
type: 'softclip',
|
|
132
|
-
base:
|
|
89
|
+
base: `S${len}`,
|
|
133
90
|
cliplen: len,
|
|
134
91
|
length: 1,
|
|
135
92
|
});
|
|
@@ -147,13 +104,13 @@ exports.cigarToMismatches = cigarToMismatches;
|
|
|
147
104
|
* @returns array of mismatches and their positions
|
|
148
105
|
*/
|
|
149
106
|
function mdToMismatches(mdstring, ops, cigarMismatches, seq, qual) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
107
|
+
const mismatchRecords = [];
|
|
108
|
+
let curr = { start: 0, base: '', length: 0, type: 'mismatch' };
|
|
109
|
+
const skips = cigarMismatches.filter(cigar => cigar.type === 'skip');
|
|
110
|
+
let lastCigar = 0;
|
|
111
|
+
let lastTemplateOffset = 0;
|
|
112
|
+
let lastRefOffset = 0;
|
|
113
|
+
let lastSkipPos = 0;
|
|
157
114
|
// convert a position on the reference sequence to a position
|
|
158
115
|
// on the template sequence, taking into account hard and soft
|
|
159
116
|
// clipping of reads
|
|
@@ -168,11 +125,11 @@ function mdToMismatches(mdstring, ops, cigarMismatches, seq, qual) {
|
|
|
168
125
|
};
|
|
169
126
|
}
|
|
170
127
|
function getTemplateCoordLocal(refCoord) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
for (
|
|
174
|
-
|
|
175
|
-
|
|
128
|
+
let templateOffset = lastTemplateOffset;
|
|
129
|
+
let refOffset = lastRefOffset;
|
|
130
|
+
for (let i = lastCigar; i < ops.length && refOffset <= refCoord; i += 2, lastCigar = i) {
|
|
131
|
+
const len = +ops[i];
|
|
132
|
+
const op = ops[i + 1];
|
|
176
133
|
if (op === 'S' || op === 'I') {
|
|
177
134
|
templateOffset += len;
|
|
178
135
|
}
|
|
@@ -189,10 +146,10 @@ function mdToMismatches(mdstring, ops, cigarMismatches, seq, qual) {
|
|
|
189
146
|
return templateOffset - (refOffset - refCoord);
|
|
190
147
|
}
|
|
191
148
|
// now actually parse the MD string
|
|
192
|
-
|
|
193
|
-
for (
|
|
194
|
-
|
|
195
|
-
|
|
149
|
+
const md = mdstring.match(mdRegex) || [];
|
|
150
|
+
for (let i = 0; i < md.length; i++) {
|
|
151
|
+
const token = md[i];
|
|
152
|
+
const num = +token;
|
|
196
153
|
if (!Number.isNaN(num)) {
|
|
197
154
|
curr.start += num;
|
|
198
155
|
}
|
|
@@ -201,10 +158,10 @@ function mdToMismatches(mdstring, ops, cigarMismatches, seq, qual) {
|
|
|
201
158
|
}
|
|
202
159
|
else {
|
|
203
160
|
// mismatch
|
|
204
|
-
for (
|
|
161
|
+
for (let j = 0; j < token.length; j += 1) {
|
|
205
162
|
curr.length = 1;
|
|
206
163
|
while (lastSkipPos < skips.length) {
|
|
207
|
-
|
|
164
|
+
const mismatch = skips[lastSkipPos];
|
|
208
165
|
if (curr.start >= mismatch.start) {
|
|
209
166
|
curr.start += mismatch.length;
|
|
210
167
|
lastSkipPos++;
|
|
@@ -213,9 +170,9 @@ function mdToMismatches(mdstring, ops, cigarMismatches, seq, qual) {
|
|
|
213
170
|
break;
|
|
214
171
|
}
|
|
215
172
|
}
|
|
216
|
-
|
|
173
|
+
const s = getTemplateCoordLocal(curr.start);
|
|
217
174
|
curr.base = seq[s] || 'X';
|
|
218
|
-
|
|
175
|
+
const qualScore = qual === null || qual === void 0 ? void 0 : qual[s];
|
|
219
176
|
if (qualScore) {
|
|
220
177
|
curr.qual = qualScore;
|
|
221
178
|
}
|
|
@@ -228,8 +185,8 @@ function mdToMismatches(mdstring, ops, cigarMismatches, seq, qual) {
|
|
|
228
185
|
}
|
|
229
186
|
exports.mdToMismatches = mdToMismatches;
|
|
230
187
|
function getMismatches(cigar, md, seq, ref, qual) {
|
|
231
|
-
|
|
232
|
-
|
|
188
|
+
let mismatches = [];
|
|
189
|
+
const ops = parseCigar(cigar);
|
|
233
190
|
// parse the CIGAR tag if it has one
|
|
234
191
|
if (cigar) {
|
|
235
192
|
mismatches = mismatches.concat(cigarToMismatches(ops, seq, ref, qual));
|
|
@@ -243,75 +200,53 @@ function getMismatches(cigar, md, seq, ref, qual) {
|
|
|
243
200
|
exports.getMismatches = getMismatches;
|
|
244
201
|
// get relative reference sequence positions for positions given relative to
|
|
245
202
|
// the read sequence
|
|
246
|
-
function getNextRefPos(cigarOps, positions) {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
if (!(i < cigarOps.length && currPos < positions.length)) return [3 /*break*/, 9];
|
|
258
|
-
len = +cigarOps[i];
|
|
259
|
-
op = cigarOps[i + 1];
|
|
260
|
-
if (!(op === 'S' || op === 'I')) return [3 /*break*/, 2];
|
|
261
|
-
for (i_1 = 0; i_1 < len && currPos < positions.length; i_1++) {
|
|
262
|
-
if (positions[currPos] === readPos + i_1) {
|
|
263
|
-
currPos++;
|
|
264
|
-
}
|
|
203
|
+
function* getNextRefPos(cigarOps, positions) {
|
|
204
|
+
let readPos = 0;
|
|
205
|
+
let refPos = 0;
|
|
206
|
+
let currPos = 0;
|
|
207
|
+
for (let i = 0; i < cigarOps.length && currPos < positions.length; i += 2) {
|
|
208
|
+
const len = +cigarOps[i];
|
|
209
|
+
const op = cigarOps[i + 1];
|
|
210
|
+
if (op === 'S' || op === 'I') {
|
|
211
|
+
for (let i = 0; i < len && currPos < positions.length; i++) {
|
|
212
|
+
if (positions[currPos] === readPos + i) {
|
|
213
|
+
currPos++;
|
|
265
214
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
_a.sent();
|
|
282
|
-
currPos++;
|
|
283
|
-
_a.label = 6;
|
|
284
|
-
case 6:
|
|
285
|
-
i_2++;
|
|
286
|
-
return [3 /*break*/, 4];
|
|
287
|
-
case 7:
|
|
288
|
-
readPos += len;
|
|
289
|
-
refPos += len;
|
|
290
|
-
_a.label = 8;
|
|
291
|
-
case 8:
|
|
292
|
-
i += 2;
|
|
293
|
-
return [3 /*break*/, 1];
|
|
294
|
-
case 9: return [2 /*return*/];
|
|
215
|
+
}
|
|
216
|
+
readPos += len;
|
|
217
|
+
}
|
|
218
|
+
else if (op === 'D' || op === 'N') {
|
|
219
|
+
refPos += len;
|
|
220
|
+
}
|
|
221
|
+
else if (op === 'M' || op === 'X' || op === '=') {
|
|
222
|
+
for (let i = 0; i < len && currPos < positions.length; i++) {
|
|
223
|
+
if (positions[currPos] === readPos + i) {
|
|
224
|
+
yield refPos + i;
|
|
225
|
+
currPos++;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
readPos += len;
|
|
229
|
+
refPos += len;
|
|
295
230
|
}
|
|
296
|
-
}
|
|
231
|
+
}
|
|
297
232
|
}
|
|
298
233
|
exports.getNextRefPos = getNextRefPos;
|
|
299
234
|
function getModificationPositions(mm, fseq, fstrand) {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
for (
|
|
304
|
-
|
|
305
|
-
|
|
235
|
+
const seq = fstrand === -1 ? (0, util_1.revcom)(fseq) : fseq;
|
|
236
|
+
const mods = mm.split(';').filter(mod => !!mod);
|
|
237
|
+
const result = [];
|
|
238
|
+
for (let i = 0; i < mods.length; i++) {
|
|
239
|
+
const mod = mods[i];
|
|
240
|
+
const [basemod, ...skips] = mod.split(',');
|
|
306
241
|
// regexes based on parse_mm.pl from hts-specs
|
|
307
|
-
|
|
242
|
+
const matches = basemod.match(modificationRegex);
|
|
308
243
|
if (!matches) {
|
|
309
244
|
throw new Error('bad format for MM tag');
|
|
310
245
|
}
|
|
311
|
-
|
|
246
|
+
const [, base, strand, typestr] = matches;
|
|
312
247
|
// can be a multi e.g. C+mh for both meth (m) and hydroxymeth (h) so
|
|
313
248
|
// split, and they can also be chemical codes (ChEBI) e.g. C+16061
|
|
314
|
-
|
|
249
|
+
const types = typestr.split(/(\d+|.)/).filter(f => !!f);
|
|
315
250
|
if (strand === '-') {
|
|
316
251
|
console.warn('unsupported negative strand modifications');
|
|
317
252
|
// make sure to return a somewhat matching type even in this case
|
|
@@ -321,27 +256,27 @@ function getModificationPositions(mm, fseq, fstrand) {
|
|
|
321
256
|
// sequence of the read, if we have a modification type e.g. C+m;2 and a
|
|
322
257
|
// sequence ACGTACGTAC we skip the two instances of C and go to the last
|
|
323
258
|
// C
|
|
324
|
-
for (
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
for (
|
|
329
|
-
|
|
259
|
+
for (let j = 0; j < types.length; j++) {
|
|
260
|
+
const type = types[j];
|
|
261
|
+
let i = 0;
|
|
262
|
+
const positions = [];
|
|
263
|
+
for (let k = 0; k < skips.length; k++) {
|
|
264
|
+
let delta = +skips[k];
|
|
330
265
|
do {
|
|
331
|
-
if (base === 'N' || base === seq[
|
|
266
|
+
if (base === 'N' || base === seq[i]) {
|
|
332
267
|
delta--;
|
|
333
268
|
}
|
|
334
|
-
|
|
335
|
-
} while (delta >= 0 &&
|
|
336
|
-
|
|
269
|
+
i++;
|
|
270
|
+
} while (delta >= 0 && i < seq.length);
|
|
271
|
+
const temp = i - 1;
|
|
337
272
|
positions.push(fstrand === -1 ? seq.length - 1 - temp : temp);
|
|
338
273
|
}
|
|
339
274
|
if (fstrand === -1) {
|
|
340
|
-
positions.sort(
|
|
275
|
+
positions.sort((a, b) => a - b);
|
|
341
276
|
}
|
|
342
277
|
result.push({
|
|
343
|
-
type
|
|
344
|
-
positions
|
|
278
|
+
type,
|
|
279
|
+
positions,
|
|
345
280
|
});
|
|
346
281
|
}
|
|
347
282
|
}
|
|
@@ -349,19 +284,19 @@ function getModificationPositions(mm, fseq, fstrand) {
|
|
|
349
284
|
}
|
|
350
285
|
exports.getModificationPositions = getModificationPositions;
|
|
351
286
|
function getModificationTypes(mm) {
|
|
352
|
-
|
|
287
|
+
const mods = mm.split(';');
|
|
353
288
|
return mods
|
|
354
|
-
.filter(
|
|
355
|
-
.map(
|
|
356
|
-
|
|
357
|
-
|
|
289
|
+
.filter(mod => !!mod)
|
|
290
|
+
.map(mod => {
|
|
291
|
+
const [basemod] = mod.split(',');
|
|
292
|
+
const matches = basemod.match(modificationRegex);
|
|
358
293
|
if (!matches) {
|
|
359
294
|
throw new Error('bad format for MM tag');
|
|
360
295
|
}
|
|
361
|
-
|
|
296
|
+
const [, , , typestr] = matches;
|
|
362
297
|
// can be a multi e.g. C+mh for both meth (m) and hydroxymeth (h) so
|
|
363
298
|
// split, and they can also be chemical codes (ChEBI) e.g. C+16061
|
|
364
|
-
return typestr.split(/(\d+|.)/).filter(
|
|
299
|
+
return typestr.split(/(\d+|.)/).filter(f => !!f);
|
|
365
300
|
})
|
|
366
301
|
.flat();
|
|
367
302
|
}
|