gff-nostream 3.0.8 → 3.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/api.d.ts +13 -7
- package/dist/api.js +58 -34
- package/dist/api.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/esm/api.d.ts +13 -7
- package/esm/api.js +57 -34
- package/esm/api.js.map +1 -1
- package/esm/index.d.ts +1 -1
- package/esm/index.js +1 -1
- package/esm/index.js.map +1 -1
- package/package.json +1 -1
- package/src/api.ts +73 -44
- package/src/index.ts +1 -0
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# gff-nostream
|
|
2
2
|
|
|
3
3
|
[](https://npmjs.org/package/gff-nostream)
|
|
4
|
-
|
|
4
|
+

|
|
5
5
|
|
|
6
6
|
Parse GFF3 data. A simplified version of
|
|
7
7
|
[@gmod/gff](https://github.com/GMOD/gff-js) with no Node.js stream dependency.
|
package/dist/api.d.ts
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import type { GFF3Feature, JBrowseFeature } from './util.ts';
|
|
2
|
-
|
|
2
|
+
interface ParseInput {
|
|
3
3
|
line: string;
|
|
4
4
|
lineHash?: string | number;
|
|
5
|
-
/** Optional passthrough byte offsets — not used by the parser */
|
|
6
|
-
start?: number;
|
|
7
|
-
/** Optional passthrough byte offsets — not used by the parser */
|
|
8
|
-
end?: number;
|
|
9
5
|
hasEscapes: boolean;
|
|
10
6
|
}
|
|
7
|
+
export interface LineRecord extends ParseInput {
|
|
8
|
+
/** Genomic start coordinate from the tabix index (1-based) */
|
|
9
|
+
start: number;
|
|
10
|
+
/** Genomic end coordinate from the tabix index */
|
|
11
|
+
end: number;
|
|
12
|
+
/** GFF3 feature type (column 3) */
|
|
13
|
+
type: string;
|
|
14
|
+
}
|
|
15
|
+
/** Extract the GFF3 feature type (column 3) from a raw line without a full split. */
|
|
16
|
+
export declare function extractType(line: string): string;
|
|
11
17
|
/**
|
|
12
18
|
* Synchronously parse a string containing GFF3 and return an array of the
|
|
13
19
|
* parsed items.
|
|
@@ -30,7 +36,7 @@ export declare function parseStringSyncJBrowse(str: string): JBrowseFeature[];
|
|
|
30
36
|
* @param records - Array of LineRecord objects with raw line and metadata
|
|
31
37
|
* @returns array of parsed features
|
|
32
38
|
*/
|
|
33
|
-
export declare function parseRecords(records:
|
|
39
|
+
export declare function parseRecords(records: ParseInput[]): GFF3Feature[];
|
|
34
40
|
/**
|
|
35
41
|
* Parse an array of LineRecord objects directly into JBrowse feature format.
|
|
36
42
|
* Supports parent/child relationships via subfeatures.
|
|
@@ -38,5 +44,5 @@ export declare function parseRecords(records: LineRecord[]): GFF3Feature[];
|
|
|
38
44
|
* @param records - Array of LineRecord objects with raw line and metadata
|
|
39
45
|
* @returns array of JBrowse-format features
|
|
40
46
|
*/
|
|
41
|
-
export declare function parseRecordsJBrowse(records:
|
|
47
|
+
export declare function parseRecordsJBrowse(records: ParseInput[]): JBrowseFeature[];
|
|
42
48
|
export type { GFF3Comment, GFF3Directive, GFF3Feature, GFF3FeatureLine, GFF3FeatureLineWithRefs, GFF3Item, GFF3Sequence, JBrowseFeature, } from './util.ts';
|
package/dist/api.js
CHANGED
|
@@ -1,10 +1,43 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractType = extractType;
|
|
3
4
|
exports.parseStringSync = parseStringSync;
|
|
4
5
|
exports.parseStringSyncJBrowse = parseStringSyncJBrowse;
|
|
5
6
|
exports.parseRecords = parseRecords;
|
|
6
7
|
exports.parseRecordsJBrowse = parseRecordsJBrowse;
|
|
7
8
|
const util_ts_1 = require("./util.js");
|
|
9
|
+
/** Extract the GFF3 feature type (column 3) from a raw line without a full split. */
|
|
10
|
+
function extractType(line) {
|
|
11
|
+
const t1 = line.indexOf('\t');
|
|
12
|
+
const t2 = line.indexOf('\t', t1 + 1);
|
|
13
|
+
const t3 = line.indexOf('\t', t2 + 1);
|
|
14
|
+
return line.slice(t2 + 1, t3);
|
|
15
|
+
}
|
|
16
|
+
/** Append a value to the array stored under key, creating the array if absent. */
|
|
17
|
+
function appendOrphan(orphans, key, value) {
|
|
18
|
+
const arr = orphans.get(key);
|
|
19
|
+
if (arr) {
|
|
20
|
+
arr.push(value);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
orphans.set(key, [value]);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The JBrowse parser collapses single-element attribute arrays to scalars, so a
|
|
28
|
+
* raw ID/Parent value can be a string, a string array, or absent. These coerce
|
|
29
|
+
* those `unknown` values without typecasts.
|
|
30
|
+
*/
|
|
31
|
+
function firstString(value) {
|
|
32
|
+
const v = Array.isArray(value) ? value[0] : value;
|
|
33
|
+
return typeof v === 'string' ? v : undefined;
|
|
34
|
+
}
|
|
35
|
+
function toStringArray(value) {
|
|
36
|
+
if (Array.isArray(value)) {
|
|
37
|
+
return value.filter((v) => typeof v === 'string');
|
|
38
|
+
}
|
|
39
|
+
return typeof value === 'string' ? [value] : [];
|
|
40
|
+
}
|
|
8
41
|
/**
|
|
9
42
|
* Synchronously parse a string containing GFF3 and return an array of the
|
|
10
43
|
* parsed items.
|
|
@@ -53,11 +86,14 @@ function parseRecords(records) {
|
|
|
53
86
|
const byId = new Map();
|
|
54
87
|
const orphans = new Map();
|
|
55
88
|
for (const record of records) {
|
|
56
|
-
const
|
|
89
|
+
const parsed = record.hasEscapes
|
|
57
90
|
? (0, util_ts_1.parseFeature)(record.line)
|
|
58
|
-
: (0, util_ts_1.parseFeatureNoUnescape)(record.line)
|
|
59
|
-
featureLine
|
|
60
|
-
|
|
91
|
+
: (0, util_ts_1.parseFeatureNoUnescape)(record.line);
|
|
92
|
+
const featureLine = {
|
|
93
|
+
...parsed,
|
|
94
|
+
child_features: [],
|
|
95
|
+
derived_features: [],
|
|
96
|
+
};
|
|
61
97
|
if (record.lineHash !== undefined) {
|
|
62
98
|
featureLine.attributes ??= {};
|
|
63
99
|
featureLine.attributes._lineHash = [String(record.lineHash)];
|
|
@@ -109,12 +145,7 @@ function parseRecords(records) {
|
|
|
109
145
|
parent[0].child_features.push(feature);
|
|
110
146
|
}
|
|
111
147
|
else {
|
|
112
|
-
|
|
113
|
-
if (!arr) {
|
|
114
|
-
arr = [];
|
|
115
|
-
orphans.set(parentId, arr);
|
|
116
|
-
}
|
|
117
|
-
arr.push(feature);
|
|
148
|
+
appendOrphan(orphans, parentId, feature);
|
|
118
149
|
}
|
|
119
150
|
}
|
|
120
151
|
}
|
|
@@ -140,17 +171,18 @@ function parseRecordsJBrowse(records) {
|
|
|
140
171
|
if (record.lineHash !== undefined) {
|
|
141
172
|
feature._lineHash = String(record.lineHash);
|
|
142
173
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const id = Array.isArray(rawId) ? rawId[0] : rawId;
|
|
147
|
-
const parent = feature.parent;
|
|
148
|
-
if (!id && !parent) {
|
|
174
|
+
const id = firstString(feature.id);
|
|
175
|
+
const parents = toStringArray(feature.parent);
|
|
176
|
+
if (!id && parents.length === 0) {
|
|
149
177
|
items.push(feature);
|
|
150
178
|
}
|
|
151
|
-
else
|
|
152
|
-
|
|
153
|
-
|
|
179
|
+
else {
|
|
180
|
+
// Register the id only the first time it is seen. Continuation lines
|
|
181
|
+
// (multi-location features such as a CDS spanning several segments share
|
|
182
|
+
// one ID across lines) skip registration but must still be attached to
|
|
183
|
+
// their parent below, so this is independent of the parent handling.
|
|
184
|
+
if (id && !byId.has(id)) {
|
|
185
|
+
if (parents.length === 0) {
|
|
154
186
|
items.push(feature);
|
|
155
187
|
}
|
|
156
188
|
byId.set(id, feature);
|
|
@@ -162,21 +194,13 @@ function parseRecordsJBrowse(records) {
|
|
|
162
194
|
orphans.delete(id);
|
|
163
195
|
}
|
|
164
196
|
}
|
|
165
|
-
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
else {
|
|
173
|
-
let arr = orphans.get(parentId);
|
|
174
|
-
if (!arr) {
|
|
175
|
-
arr = [];
|
|
176
|
-
orphans.set(parentId, arr);
|
|
177
|
-
}
|
|
178
|
-
arr.push(feature);
|
|
179
|
-
}
|
|
197
|
+
for (const parentId of parents) {
|
|
198
|
+
const parentFeature = byId.get(parentId);
|
|
199
|
+
if (parentFeature) {
|
|
200
|
+
parentFeature.subfeatures.push(feature);
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
appendOrphan(orphans, parentId, feature);
|
|
180
204
|
}
|
|
181
205
|
}
|
|
182
206
|
}
|
package/dist/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { parseRecords, parseRecordsJBrowse, parseStringSync, parseStringSyncJBrowse, } from './api.ts';
|
|
1
|
+
export { extractType, parseRecords, parseRecordsJBrowse, parseStringSync, parseStringSyncJBrowse, } from './api.ts';
|
|
2
2
|
export type { GFF3Comment, GFF3Directive, GFF3Feature, GFF3FeatureLine, GFF3FeatureLineWithRefs, GFF3Item, GFF3Sequence, JBrowseFeature, LineRecord, } from './api.ts';
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseStringSyncJBrowse = exports.parseStringSync = exports.parseRecordsJBrowse = exports.parseRecords = void 0;
|
|
3
|
+
exports.parseStringSyncJBrowse = exports.parseStringSync = exports.parseRecordsJBrowse = exports.parseRecords = exports.extractType = void 0;
|
|
4
4
|
var api_ts_1 = require("./api.js");
|
|
5
|
+
Object.defineProperty(exports, "extractType", { enumerable: true, get: function () { return api_ts_1.extractType; } });
|
|
5
6
|
Object.defineProperty(exports, "parseRecords", { enumerable: true, get: function () { return api_ts_1.parseRecords; } });
|
|
6
7
|
Object.defineProperty(exports, "parseRecordsJBrowse", { enumerable: true, get: function () { return api_ts_1.parseRecordsJBrowse; } });
|
|
7
8
|
Object.defineProperty(exports, "parseStringSync", { enumerable: true, get: function () { return api_ts_1.parseStringSync; } });
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,mCAMiB;AALf,qGAAA,WAAW,OAAA;AACX,sGAAA,YAAY,OAAA;AACZ,6GAAA,mBAAmB,OAAA;AACnB,yGAAA,eAAe,OAAA;AACf,gHAAA,sBAAsB,OAAA"}
|
package/esm/api.d.ts
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import type { GFF3Feature, JBrowseFeature } from './util.ts';
|
|
2
|
-
|
|
2
|
+
interface ParseInput {
|
|
3
3
|
line: string;
|
|
4
4
|
lineHash?: string | number;
|
|
5
|
-
/** Optional passthrough byte offsets — not used by the parser */
|
|
6
|
-
start?: number;
|
|
7
|
-
/** Optional passthrough byte offsets — not used by the parser */
|
|
8
|
-
end?: number;
|
|
9
5
|
hasEscapes: boolean;
|
|
10
6
|
}
|
|
7
|
+
export interface LineRecord extends ParseInput {
|
|
8
|
+
/** Genomic start coordinate from the tabix index (1-based) */
|
|
9
|
+
start: number;
|
|
10
|
+
/** Genomic end coordinate from the tabix index */
|
|
11
|
+
end: number;
|
|
12
|
+
/** GFF3 feature type (column 3) */
|
|
13
|
+
type: string;
|
|
14
|
+
}
|
|
15
|
+
/** Extract the GFF3 feature type (column 3) from a raw line without a full split. */
|
|
16
|
+
export declare function extractType(line: string): string;
|
|
11
17
|
/**
|
|
12
18
|
* Synchronously parse a string containing GFF3 and return an array of the
|
|
13
19
|
* parsed items.
|
|
@@ -30,7 +36,7 @@ export declare function parseStringSyncJBrowse(str: string): JBrowseFeature[];
|
|
|
30
36
|
* @param records - Array of LineRecord objects with raw line and metadata
|
|
31
37
|
* @returns array of parsed features
|
|
32
38
|
*/
|
|
33
|
-
export declare function parseRecords(records:
|
|
39
|
+
export declare function parseRecords(records: ParseInput[]): GFF3Feature[];
|
|
34
40
|
/**
|
|
35
41
|
* Parse an array of LineRecord objects directly into JBrowse feature format.
|
|
36
42
|
* Supports parent/child relationships via subfeatures.
|
|
@@ -38,5 +44,5 @@ export declare function parseRecords(records: LineRecord[]): GFF3Feature[];
|
|
|
38
44
|
* @param records - Array of LineRecord objects with raw line and metadata
|
|
39
45
|
* @returns array of JBrowse-format features
|
|
40
46
|
*/
|
|
41
|
-
export declare function parseRecordsJBrowse(records:
|
|
47
|
+
export declare function parseRecordsJBrowse(records: ParseInput[]): JBrowseFeature[];
|
|
42
48
|
export type { GFF3Comment, GFF3Directive, GFF3Feature, GFF3FeatureLine, GFF3FeatureLineWithRefs, GFF3Item, GFF3Sequence, JBrowseFeature, } from './util.ts';
|
package/esm/api.js
CHANGED
|
@@ -1,4 +1,36 @@
|
|
|
1
1
|
import { parseFeature, parseFeatureJBrowse, parseFeatureJBrowseNoUnescape, parseFeatureNoUnescape, } from "./util.js";
|
|
2
|
+
/** Extract the GFF3 feature type (column 3) from a raw line without a full split. */
|
|
3
|
+
export function extractType(line) {
|
|
4
|
+
const t1 = line.indexOf('\t');
|
|
5
|
+
const t2 = line.indexOf('\t', t1 + 1);
|
|
6
|
+
const t3 = line.indexOf('\t', t2 + 1);
|
|
7
|
+
return line.slice(t2 + 1, t3);
|
|
8
|
+
}
|
|
9
|
+
/** Append a value to the array stored under key, creating the array if absent. */
|
|
10
|
+
function appendOrphan(orphans, key, value) {
|
|
11
|
+
const arr = orphans.get(key);
|
|
12
|
+
if (arr) {
|
|
13
|
+
arr.push(value);
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
orphans.set(key, [value]);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The JBrowse parser collapses single-element attribute arrays to scalars, so a
|
|
21
|
+
* raw ID/Parent value can be a string, a string array, or absent. These coerce
|
|
22
|
+
* those `unknown` values without typecasts.
|
|
23
|
+
*/
|
|
24
|
+
function firstString(value) {
|
|
25
|
+
const v = Array.isArray(value) ? value[0] : value;
|
|
26
|
+
return typeof v === 'string' ? v : undefined;
|
|
27
|
+
}
|
|
28
|
+
function toStringArray(value) {
|
|
29
|
+
if (Array.isArray(value)) {
|
|
30
|
+
return value.filter((v) => typeof v === 'string');
|
|
31
|
+
}
|
|
32
|
+
return typeof value === 'string' ? [value] : [];
|
|
33
|
+
}
|
|
2
34
|
/**
|
|
3
35
|
* Synchronously parse a string containing GFF3 and return an array of the
|
|
4
36
|
* parsed items.
|
|
@@ -47,11 +79,14 @@ export function parseRecords(records) {
|
|
|
47
79
|
const byId = new Map();
|
|
48
80
|
const orphans = new Map();
|
|
49
81
|
for (const record of records) {
|
|
50
|
-
const
|
|
82
|
+
const parsed = record.hasEscapes
|
|
51
83
|
? parseFeature(record.line)
|
|
52
|
-
: parseFeatureNoUnescape(record.line)
|
|
53
|
-
featureLine
|
|
54
|
-
|
|
84
|
+
: parseFeatureNoUnescape(record.line);
|
|
85
|
+
const featureLine = {
|
|
86
|
+
...parsed,
|
|
87
|
+
child_features: [],
|
|
88
|
+
derived_features: [],
|
|
89
|
+
};
|
|
55
90
|
if (record.lineHash !== undefined) {
|
|
56
91
|
featureLine.attributes ??= {};
|
|
57
92
|
featureLine.attributes._lineHash = [String(record.lineHash)];
|
|
@@ -103,12 +138,7 @@ export function parseRecords(records) {
|
|
|
103
138
|
parent[0].child_features.push(feature);
|
|
104
139
|
}
|
|
105
140
|
else {
|
|
106
|
-
|
|
107
|
-
if (!arr) {
|
|
108
|
-
arr = [];
|
|
109
|
-
orphans.set(parentId, arr);
|
|
110
|
-
}
|
|
111
|
-
arr.push(feature);
|
|
141
|
+
appendOrphan(orphans, parentId, feature);
|
|
112
142
|
}
|
|
113
143
|
}
|
|
114
144
|
}
|
|
@@ -134,17 +164,18 @@ export function parseRecordsJBrowse(records) {
|
|
|
134
164
|
if (record.lineHash !== undefined) {
|
|
135
165
|
feature._lineHash = String(record.lineHash);
|
|
136
166
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const id = Array.isArray(rawId) ? rawId[0] : rawId;
|
|
141
|
-
const parent = feature.parent;
|
|
142
|
-
if (!id && !parent) {
|
|
167
|
+
const id = firstString(feature.id);
|
|
168
|
+
const parents = toStringArray(feature.parent);
|
|
169
|
+
if (!id && parents.length === 0) {
|
|
143
170
|
items.push(feature);
|
|
144
171
|
}
|
|
145
|
-
else
|
|
146
|
-
|
|
147
|
-
|
|
172
|
+
else {
|
|
173
|
+
// Register the id only the first time it is seen. Continuation lines
|
|
174
|
+
// (multi-location features such as a CDS spanning several segments share
|
|
175
|
+
// one ID across lines) skip registration but must still be attached to
|
|
176
|
+
// their parent below, so this is independent of the parent handling.
|
|
177
|
+
if (id && !byId.has(id)) {
|
|
178
|
+
if (parents.length === 0) {
|
|
148
179
|
items.push(feature);
|
|
149
180
|
}
|
|
150
181
|
byId.set(id, feature);
|
|
@@ -156,21 +187,13 @@ export function parseRecordsJBrowse(records) {
|
|
|
156
187
|
orphans.delete(id);
|
|
157
188
|
}
|
|
158
189
|
}
|
|
159
|
-
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
else {
|
|
167
|
-
let arr = orphans.get(parentId);
|
|
168
|
-
if (!arr) {
|
|
169
|
-
arr = [];
|
|
170
|
-
orphans.set(parentId, arr);
|
|
171
|
-
}
|
|
172
|
-
arr.push(feature);
|
|
173
|
-
}
|
|
190
|
+
for (const parentId of parents) {
|
|
191
|
+
const parentFeature = byId.get(parentId);
|
|
192
|
+
if (parentFeature) {
|
|
193
|
+
parentFeature.subfeatures.push(feature);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
appendOrphan(orphans, parentId, feature);
|
|
174
197
|
}
|
|
175
198
|
}
|
|
176
199
|
}
|
package/esm/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,6BAA6B,EAC7B,sBAAsB,GACvB,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/esm/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { parseRecords, parseRecordsJBrowse, parseStringSync, parseStringSyncJBrowse, } from './api.ts';
|
|
1
|
+
export { extractType, parseRecords, parseRecordsJBrowse, parseStringSync, parseStringSyncJBrowse, } from './api.ts';
|
|
2
2
|
export type { GFF3Comment, GFF3Directive, GFF3Feature, GFF3FeatureLine, GFF3FeatureLineWithRefs, GFF3Item, GFF3Sequence, JBrowseFeature, LineRecord, } from './api.ts';
|
package/esm/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { parseRecords, parseRecordsJBrowse, parseStringSync, parseStringSyncJBrowse, } from "./api.js";
|
|
1
|
+
export { extractType, parseRecords, parseRecordsJBrowse, parseStringSync, parseStringSyncJBrowse, } from "./api.js";
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,sBAAsB,GACvB,MAAM,UAAU,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,sBAAsB,GACvB,MAAM,UAAU,CAAA"}
|
package/package.json
CHANGED
package/src/api.ts
CHANGED
|
@@ -11,16 +11,56 @@ import type {
|
|
|
11
11
|
JBrowseFeature,
|
|
12
12
|
} from './util.ts'
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
interface ParseInput {
|
|
15
15
|
line: string
|
|
16
16
|
lineHash?: string | number
|
|
17
|
-
/** Optional passthrough byte offsets — not used by the parser */
|
|
18
|
-
start?: number
|
|
19
|
-
/** Optional passthrough byte offsets — not used by the parser */
|
|
20
|
-
end?: number
|
|
21
17
|
hasEscapes: boolean
|
|
22
18
|
}
|
|
23
19
|
|
|
20
|
+
export interface LineRecord extends ParseInput {
|
|
21
|
+
/** Genomic start coordinate from the tabix index (1-based) */
|
|
22
|
+
start: number
|
|
23
|
+
/** Genomic end coordinate from the tabix index */
|
|
24
|
+
end: number
|
|
25
|
+
/** GFF3 feature type (column 3) */
|
|
26
|
+
type: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Extract the GFF3 feature type (column 3) from a raw line without a full split. */
|
|
30
|
+
export function extractType(line: string): string {
|
|
31
|
+
const t1 = line.indexOf('\t')
|
|
32
|
+
const t2 = line.indexOf('\t', t1 + 1)
|
|
33
|
+
const t3 = line.indexOf('\t', t2 + 1)
|
|
34
|
+
return line.slice(t2 + 1, t3)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Append a value to the array stored under key, creating the array if absent. */
|
|
38
|
+
function appendOrphan<T>(orphans: Map<string, T[]>, key: string, value: T) {
|
|
39
|
+
const arr = orphans.get(key)
|
|
40
|
+
if (arr) {
|
|
41
|
+
arr.push(value)
|
|
42
|
+
} else {
|
|
43
|
+
orphans.set(key, [value])
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The JBrowse parser collapses single-element attribute arrays to scalars, so a
|
|
49
|
+
* raw ID/Parent value can be a string, a string array, or absent. These coerce
|
|
50
|
+
* those `unknown` values without typecasts.
|
|
51
|
+
*/
|
|
52
|
+
function firstString(value: unknown): string | undefined {
|
|
53
|
+
const v: unknown = Array.isArray(value) ? value[0] : value
|
|
54
|
+
return typeof v === 'string' ? v : undefined
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function toStringArray(value: unknown): string[] {
|
|
58
|
+
if (Array.isArray(value)) {
|
|
59
|
+
return value.filter((v): v is string => typeof v === 'string')
|
|
60
|
+
}
|
|
61
|
+
return typeof value === 'string' ? [value] : []
|
|
62
|
+
}
|
|
63
|
+
|
|
24
64
|
/**
|
|
25
65
|
* Synchronously parse a string containing GFF3 and return an array of the
|
|
26
66
|
* parsed items.
|
|
@@ -44,7 +84,7 @@ export function parseStringSyncJBrowse(str: string): JBrowseFeature[] {
|
|
|
44
84
|
|
|
45
85
|
function stringToRecords(str: string) {
|
|
46
86
|
const lines = str.split(/\r?\n/)
|
|
47
|
-
const records:
|
|
87
|
+
const records: ParseInput[] = []
|
|
48
88
|
for (const line of lines) {
|
|
49
89
|
if (line.startsWith('##FASTA') || line.startsWith('>')) {
|
|
50
90
|
break
|
|
@@ -67,19 +107,20 @@ function stringToRecords(str: string) {
|
|
|
67
107
|
* @param records - Array of LineRecord objects with raw line and metadata
|
|
68
108
|
* @returns array of parsed features
|
|
69
109
|
*/
|
|
70
|
-
export function parseRecords(records:
|
|
110
|
+
export function parseRecords(records: ParseInput[]): GFF3Feature[] {
|
|
71
111
|
const items: GFF3Feature[] = []
|
|
72
112
|
const byId = new Map<string, GFF3Feature>()
|
|
73
113
|
const orphans = new Map<string, GFF3Feature[]>()
|
|
74
114
|
|
|
75
115
|
for (const record of records) {
|
|
76
|
-
const
|
|
77
|
-
record.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
116
|
+
const parsed = record.hasEscapes
|
|
117
|
+
? parseFeature(record.line)
|
|
118
|
+
: parseFeatureNoUnescape(record.line)
|
|
119
|
+
const featureLine: GFF3FeatureLineWithRefs = {
|
|
120
|
+
...parsed,
|
|
121
|
+
child_features: [],
|
|
122
|
+
derived_features: [],
|
|
123
|
+
}
|
|
83
124
|
|
|
84
125
|
if (record.lineHash !== undefined) {
|
|
85
126
|
featureLine.attributes ??= {}
|
|
@@ -131,12 +172,7 @@ export function parseRecords(records: LineRecord[]): GFF3Feature[] {
|
|
|
131
172
|
// so push once via the first line.
|
|
132
173
|
parent[0]!.child_features.push(feature)
|
|
133
174
|
} else {
|
|
134
|
-
|
|
135
|
-
if (!arr) {
|
|
136
|
-
arr = []
|
|
137
|
-
orphans.set(parentId, arr)
|
|
138
|
-
}
|
|
139
|
-
arr.push(feature)
|
|
175
|
+
appendOrphan(orphans, parentId, feature)
|
|
140
176
|
}
|
|
141
177
|
}
|
|
142
178
|
}
|
|
@@ -153,7 +189,7 @@ export function parseRecords(records: LineRecord[]): GFF3Feature[] {
|
|
|
153
189
|
* @param records - Array of LineRecord objects with raw line and metadata
|
|
154
190
|
* @returns array of JBrowse-format features
|
|
155
191
|
*/
|
|
156
|
-
export function parseRecordsJBrowse(records:
|
|
192
|
+
export function parseRecordsJBrowse(records: ParseInput[]): JBrowseFeature[] {
|
|
157
193
|
const items: JBrowseFeature[] = []
|
|
158
194
|
const byId = new Map<string, JBrowseFeature>()
|
|
159
195
|
const orphans = new Map<string, JBrowseFeature[]>()
|
|
@@ -167,17 +203,18 @@ export function parseRecordsJBrowse(records: LineRecord[]): JBrowseFeature[] {
|
|
|
167
203
|
feature._lineHash = String(record.lineHash)
|
|
168
204
|
}
|
|
169
205
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
const rawId = feature.id as string | string[] | undefined
|
|
173
|
-
const id = Array.isArray(rawId) ? rawId[0] : rawId
|
|
174
|
-
const parent = feature.parent as string | string[] | undefined
|
|
206
|
+
const id = firstString(feature.id)
|
|
207
|
+
const parents = toStringArray(feature.parent)
|
|
175
208
|
|
|
176
|
-
if (!id &&
|
|
209
|
+
if (!id && parents.length === 0) {
|
|
177
210
|
items.push(feature)
|
|
178
|
-
} else
|
|
179
|
-
|
|
180
|
-
|
|
211
|
+
} else {
|
|
212
|
+
// Register the id only the first time it is seen. Continuation lines
|
|
213
|
+
// (multi-location features such as a CDS spanning several segments share
|
|
214
|
+
// one ID across lines) skip registration but must still be attached to
|
|
215
|
+
// their parent below, so this is independent of the parent handling.
|
|
216
|
+
if (id && !byId.has(id)) {
|
|
217
|
+
if (parents.length === 0) {
|
|
181
218
|
items.push(feature)
|
|
182
219
|
}
|
|
183
220
|
byId.set(id, feature)
|
|
@@ -190,20 +227,12 @@ export function parseRecordsJBrowse(records: LineRecord[]): JBrowseFeature[] {
|
|
|
190
227
|
}
|
|
191
228
|
}
|
|
192
229
|
|
|
193
|
-
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
} else {
|
|
200
|
-
let arr = orphans.get(parentId)
|
|
201
|
-
if (!arr) {
|
|
202
|
-
arr = []
|
|
203
|
-
orphans.set(parentId, arr)
|
|
204
|
-
}
|
|
205
|
-
arr.push(feature)
|
|
206
|
-
}
|
|
230
|
+
for (const parentId of parents) {
|
|
231
|
+
const parentFeature = byId.get(parentId)
|
|
232
|
+
if (parentFeature) {
|
|
233
|
+
parentFeature.subfeatures.push(feature)
|
|
234
|
+
} else {
|
|
235
|
+
appendOrphan(orphans, parentId, feature)
|
|
207
236
|
}
|
|
208
237
|
}
|
|
209
238
|
}
|