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 CHANGED
@@ -1,7 +1,7 @@
1
1
  # gff-nostream
2
2
 
3
3
  [![NPM version](https://img.shields.io/npm/v/gff-nostream.svg?style=flat-square)](https://npmjs.org/package/gff-nostream)
4
- [![Build Status](https://img.shields.io/github/actions/workflow/status/GMOD/gff-nostream/push.yml?branch=main)](https://github.com/GMOD/gff-nostream/actions?query=branch%3Amain+workflow%3APush+)
4
+ ![Build Status](https://img.shields.io/github/actions/workflow/status/GMOD/gff-nostream/publish.yml?branch=main)
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
- export interface LineRecord {
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: LineRecord[]): GFF3Feature[];
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: LineRecord[]): JBrowseFeature[];
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 featureLine = (record.hasEscapes
89
+ const parsed = record.hasEscapes
57
90
  ? (0, util_ts_1.parseFeature)(record.line)
58
- : (0, util_ts_1.parseFeatureNoUnescape)(record.line));
59
- featureLine.child_features = [];
60
- featureLine.derived_features = [];
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
- let arr = orphans.get(parentId);
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
- // attribute parsing collapses single-element arrays to scalars, so id can
144
- // be string | string[]; defensively take the first if multi-valued.
145
- const rawId = feature.id;
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 if (!id || !byId.has(id)) {
152
- if (id) {
153
- if (!parent) {
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
- if (parent) {
166
- const parents = Array.isArray(parent) ? parent : [parent];
167
- for (const parentId of parents) {
168
- const parentFeature = byId.get(parentId);
169
- if (parentFeature) {
170
- parentFeature.subfeatures.push(feature);
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":";;AA8BA,0CAEC;AAQD,wDAEC;AA2BD,oCA6EC;AASD,kDAyDC;AApND,uCAKkB;AAkBlB;;;;;;GAMG;AACH,SAAgB,eAAe,CAAC,GAAW;IACzC,OAAO,YAAY,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAA;AAC3C,CAAC;AAED;;;;;GAKG;AACH,SAAgB,sBAAsB,CAAC,GAAW;IAChD,OAAO,mBAAmB,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAA;AAClD,CAAC;AAED,SAAS,eAAe,CAAC,GAAW;IAClC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IAChC,MAAM,OAAO,GAAiB,EAAE,CAAA;IAChC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACvD,MAAK;QACP,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9C,SAAQ;QACV,CAAC;QACD,OAAO,CAAC,IAAI,CAAC;YACX,IAAI;YACJ,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;SAC/B,CAAC,CAAA;IACJ,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,YAAY,CAAC,OAAqB;IAChD,MAAM,KAAK,GAAkB,EAAE,CAAA;IAC/B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAuB,CAAA;IAC3C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAyB,CAAA;IAEhD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,WAAW,GAAG,CAClB,MAAM,CAAC,UAAU;YACf,CAAC,CAAC,IAAA,sBAAY,EAAC,MAAM,CAAC,IAAI,CAAC;YAC3B,CAAC,CAAC,IAAA,gCAAsB,EAAC,MAAM,CAAC,IAAI,CAAC,CACb,CAAA;QAC5B,WAAW,CAAC,cAAc,GAAG,EAAE,CAAA;QAC/B,WAAW,CAAC,gBAAgB,GAAG,EAAE,CAAA;QAEjC,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YAClC,WAAW,CAAC,UAAU,KAAK,EAAE,CAAA;YAC7B,WAAW,CAAC,UAAU,CAAC,SAAS,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAA;QAC9D,CAAC;QAED,MAAM,KAAK,GAAG,WAAW,CAAC,UAAU,CAAA;QACpC,MAAM,GAAG,GAAG,KAAK,EAAE,EAAE,CAAA;QACrB,MAAM,OAAO,GAAG,KAAK,EAAE,MAAM,CAAA;QAE7B,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;YACrB,KAAK,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,CAAC,CAAA;QAC3B,CAAC;aAAM,CAAC;YACN,IAAI,OAAoB,CAAA;YACxB,IAAI,GAAG,EAAE,CAAC;gBACR,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAE,CAAA;gBAClB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;gBAC7B,IAAI,QAAQ,EAAE,CAAC;oBACb,qEAAqE;oBACrE,kEAAkE;oBAClE,+BAA+B;oBAC/B,WAAW,CAAC,cAAc,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC,cAAc,CAAA;oBACxD,WAAW,CAAC,gBAAgB,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC,gBAAgB,CAAA;oBAC5D,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;oBAC1B,OAAO,GAAG,QAAQ,CAAA;gBACpB,CAAC;qBAAM,CAAC;oBACN,OAAO,GAAG,CAAC,WAAW,CAAC,CAAA;oBACvB,IAAI,CAAC,OAAO,EAAE,CAAC;wBACb,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;oBACrB,CAAC;oBACD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;oBACrB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;oBAC/B,IAAI,OAAO,EAAE,CAAC;wBACZ,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;4BACxB,WAAW,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;wBACpC,CAAC;wBACD,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;oBACpB,CAAC;gBACH,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,OAAO,GAAG,CAAC,WAAW,CAAC,CAAA;YACzB,CAAC;YAED,IAAI,OAAO,EAAE,CAAC;gBACZ,KAAK,MAAM,QAAQ,IAAI,OAAO,EAAE,CAAC;oBAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;oBACjC,IAAI,MAAM,EAAE,CAAC;wBACX,4DAA4D;wBAC5D,mCAAmC;wBACnC,MAAM,CAAC,CAAC,CAAE,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;oBACzC,CAAC;yBAAM,CAAC;wBACN,IAAI,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;wBAC/B,IAAI,CAAC,GAAG,EAAE,CAAC;4BACT,GAAG,GAAG,EAAE,CAAA;4BACR,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;wBAC5B,CAAC;wBACD,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;oBACnB,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,mBAAmB,CAAC,OAAqB;IACvD,MAAM,KAAK,GAAqB,EAAE,CAAA;IAClC,MAAM,IAAI,GAAG,IAAI,GAAG,EAA0B,CAAA;IAC9C,MAAM,OAAO,GAAG,IAAI,GAAG,EAA4B,CAAA;IAEnD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU;YAC/B,CAAC,CAAC,IAAA,6BAAmB,EAAC,MAAM,CAAC,IAAI,CAAC;YAClC,CAAC,CAAC,IAAA,uCAA6B,EAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QAE9C,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YAClC,OAAO,CAAC,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QAC7C,CAAC;QAED,0EAA0E;QAC1E,oEAAoE;QACpE,MAAM,KAAK,GAAG,OAAO,CAAC,EAAmC,CAAA;QACzD,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;QAClD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAuC,CAAA;QAE9D,IAAI,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;YACnB,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACrB,CAAC;aAAM,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YAChC,IAAI,EAAE,EAAE,CAAC;gBACP,IAAI,CAAC,MAAM,EAAE,CAAC;oBACZ,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;gBACrB,CAAC;gBACD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;gBACrB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;gBAC/B,IAAI,OAAO,EAAE,CAAC;oBACZ,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;wBACxB,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;oBAC7B,CAAC;oBACD,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;gBACpB,CAAC;YACH,CAAC;YAED,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;gBACzD,KAAK,MAAM,QAAQ,IAAI,OAAO,EAAE,CAAC;oBAC/B,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;oBACxC,IAAI,aAAa,EAAE,CAAC;wBAClB,aAAa,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;oBACzC,CAAC;yBAAM,CAAC;wBACN,IAAI,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;wBAC/B,IAAI,CAAC,GAAG,EAAE,CAAC;4BACT,GAAG,GAAG,EAAE,CAAA;4BACR,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;wBAC5B,CAAC;wBACD,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;oBACnB,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAA;AACd,CAAC"}
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,mCAKiB;AAJf,sGAAA,YAAY,OAAA;AACZ,6GAAA,mBAAmB,OAAA;AACnB,yGAAA,eAAe,OAAA;AACf,gHAAA,sBAAsB,OAAA"}
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
- export interface LineRecord {
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: LineRecord[]): GFF3Feature[];
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: LineRecord[]): JBrowseFeature[];
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 featureLine = (record.hasEscapes
82
+ const parsed = record.hasEscapes
51
83
  ? parseFeature(record.line)
52
- : parseFeatureNoUnescape(record.line));
53
- featureLine.child_features = [];
54
- featureLine.derived_features = [];
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
- let arr = orphans.get(parentId);
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
- // attribute parsing collapses single-element arrays to scalars, so id can
138
- // be string | string[]; defensively take the first if multi-valued.
139
- const rawId = feature.id;
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 if (!id || !byId.has(id)) {
146
- if (id) {
147
- if (!parent) {
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
- if (parent) {
160
- const parents = Array.isArray(parent) ? parent : [parent];
161
- for (const parentId of parents) {
162
- const parentFeature = byId.get(parentId);
163
- if (parentFeature) {
164
- parentFeature.subfeatures.push(feature);
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":"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"}
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gff-nostream",
3
- "version": "3.0.8",
3
+ "version": "3.0.10",
4
4
  "description": "utilities to read GFF3 data",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/api.ts CHANGED
@@ -11,16 +11,56 @@ import type {
11
11
  JBrowseFeature,
12
12
  } from './util.ts'
13
13
 
14
- export interface LineRecord {
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: LineRecord[] = []
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: LineRecord[]): GFF3Feature[] {
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 featureLine = (
77
- record.hasEscapes
78
- ? parseFeature(record.line)
79
- : parseFeatureNoUnescape(record.line)
80
- ) as GFF3FeatureLineWithRefs
81
- featureLine.child_features = []
82
- featureLine.derived_features = []
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
- let arr = orphans.get(parentId)
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: LineRecord[]): JBrowseFeature[] {
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
- // attribute parsing collapses single-element arrays to scalars, so id can
171
- // be string | string[]; defensively take the first if multi-valued.
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 && !parent) {
209
+ if (!id && parents.length === 0) {
177
210
  items.push(feature)
178
- } else if (!id || !byId.has(id)) {
179
- if (id) {
180
- if (!parent) {
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
- if (parent) {
194
- const parents = Array.isArray(parent) ? parent : [parent]
195
- for (const parentId of parents) {
196
- const parentFeature = byId.get(parentId)
197
- if (parentFeature) {
198
- parentFeature.subfeatures.push(feature)
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
  }
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export {
2
+ extractType,
2
3
  parseRecords,
3
4
  parseRecordsJBrowse,
4
5
  parseStringSync,