@apollo-annotation/shared 0.3.9 → 0.3.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/Changes/AddFeatureChange.js +13 -2
  2. package/dist/Changes/AddFeatureChange.js.map +1 -1
  3. package/dist/Changes/DeleteFeatureChange.js +19 -0
  4. package/dist/Changes/DeleteFeatureChange.js.map +1 -1
  5. package/dist/Changes/FeatureAttributeChange.js +11 -0
  6. package/dist/Changes/FeatureAttributeChange.js.map +1 -1
  7. package/dist/Changes/FromFileBaseChange.d.ts +2 -0
  8. package/dist/Changes/FromFileBaseChange.js +20 -5
  9. package/dist/Changes/FromFileBaseChange.js.map +1 -1
  10. package/dist/GFF3/annotationFeatureToGFF3.test.js +19 -5
  11. package/dist/GFF3/annotationFeatureToGFF3.test.js.map +1 -1
  12. package/dist/GFF3/gff3ToAnnotationFeature.d.ts +1 -1
  13. package/dist/GFF3/gff3ToAnnotationFeature.js +8 -11
  14. package/dist/GFF3/gff3ToAnnotationFeature.js.map +1 -1
  15. package/dist/GFF3/gff3ToAnnotationFeature.test.d.ts +1 -2
  16. package/dist/GFF3/gff3ToAnnotationFeature.test.js +23 -96
  17. package/dist/GFF3/gff3ToAnnotationFeature.test.js.map +1 -1
  18. package/dist/GFF3/testUtil.d.ts +6 -0
  19. package/dist/GFF3/testUtil.js +24 -0
  20. package/dist/GFF3/testUtil.js.map +1 -0
  21. package/dist/tsconfig.tsbuildinfo +1 -1
  22. package/package.json +4 -4
  23. package/src/Changes/AddFeatureChange.ts +14 -2
  24. package/src/Changes/DeleteFeatureChange.ts +18 -0
  25. package/src/Changes/FeatureAttributeChange.ts +13 -0
  26. package/src/Changes/FromFileBaseChange.ts +22 -10
  27. package/src/GFF3/annotationFeatureToGFF3.test.ts +24 -2
  28. package/src/GFF3/gff3ToAnnotationFeature.test.ts +24 -95
  29. package/src/GFF3/gff3ToAnnotationFeature.ts +6 -15
  30. package/src/GFF3/testUtil.ts +25 -0
  31. package/test_data/gene_with_two_cds.gff3 +6 -0
  32. package/test_data/gene_with_two_cds.json +69 -0
  33. package/test_data/single_feature_no_children.gff3 +1 -0
  34. package/test_data/single_feature_no_children.json +14 -0
  35. package/test_data/single_feature_two_children.gff3 +3 -0
  36. package/test_data/single_feature_two_children.json +44 -0
  37. package/test_data/two_cds.gff3 +0 -9
  38. package/test_data/two_cds.json +0 -67
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apollo-annotation/shared",
3
- "version": "0.3.9",
3
+ "version": "0.3.11",
4
4
  "main": "./dist/index.js",
5
5
  "scripts": {
6
6
  "build": "yarn clean && tsc --build",
@@ -10,9 +10,9 @@
10
10
  "test:ci": "NODE_V8_COVERAGE=./coverage glob -c \"tsx --test --test-reporter spec --experimental-test-coverage \" \"**/*.test.ts\""
11
11
  },
12
12
  "dependencies": {
13
- "@apollo-annotation/common": "^0.3.9",
14
- "@apollo-annotation/mst": "^0.3.9",
15
- "@apollo-annotation/schemas": "^0.3.9",
13
+ "@apollo-annotation/common": "^0.3.11",
14
+ "@apollo-annotation/mst": "^0.3.11",
15
+ "@apollo-annotation/schemas": "^0.3.11",
16
16
  "@gmod/gff": "^2.0.0",
17
17
  "@gmod/indexedfasta": "^2.0.4",
18
18
  "@jbrowse/core": "^3.6.5",
@@ -89,6 +89,12 @@ export class AddFeatureChange extends FeatureChange {
89
89
  let featureCnt = 0
90
90
  logger.debug?.(`changes: ${JSON.stringify(changes)}`)
91
91
 
92
+ const { INDEXED_IDS } = process.env
93
+ let idsToIndex: string[] | undefined
94
+ if (INDEXED_IDS) {
95
+ idsToIndex = INDEXED_IDS.split(',')
96
+ }
97
+
92
98
  // Loop the changes
93
99
  for (const change of changes) {
94
100
  logger.debug?.(`change: ${JSON.stringify(change)}`)
@@ -106,9 +112,10 @@ export class AddFeatureChange extends FeatureChange {
106
112
 
107
113
  // CopyFeature is called from CopyFeature.tsx
108
114
  if (copyFeature) {
115
+ const indexedIds = this.getIndexedIds(addedFeature, idsToIndex)
109
116
  // Add into Mongo
110
117
  const [newFeatureDoc] = await featureModel.create(
111
- [{ ...addedFeature, allIds, status: -1, user }],
118
+ [{ ...addedFeature, allIds, indexedIds, status: -1, user }],
112
119
  { session },
113
120
  )
114
121
  logger.debug?.(
@@ -116,6 +123,7 @@ export class AddFeatureChange extends FeatureChange {
116
123
  )
117
124
  featureCnt++
118
125
  } else {
126
+ const indexedIds = this.getIndexedIds(addedFeature, idsToIndex)
119
127
  // Adding new child feature
120
128
  if (parentFeatureId) {
121
129
  const topLevelFeature = await featureModel
@@ -139,12 +147,16 @@ export class AddFeatureChange extends FeatureChange {
139
147
  this.addChild(parentFeature, addedFeature)
140
148
  const childIds = this.getChildFeatureIds(addedFeature)
141
149
  topLevelFeature.allIds.push(_id, ...childIds)
150
+ if (indexedIds.length > 0 && !topLevelFeature.indexedIds) {
151
+ topLevelFeature.indexedIds = []
152
+ }
153
+ topLevelFeature.indexedIds?.push(...indexedIds)
142
154
  await topLevelFeature.save()
143
155
  } else {
144
156
  const childIds = this.getChildFeatureIds(addedFeature)
145
157
  const allIdsV2 = [_id, ...childIds]
146
158
  const [newFeatureDoc] = await featureModel.create(
147
- [{ allIds: allIdsV2, status: 0, ...addedFeature }],
159
+ [{ allIds: allIdsV2, indexedIds, status: 0, ...addedFeature }],
148
160
  { session },
149
161
  )
150
162
  logger.verbose?.(`Added docId "${newFeatureDoc._id}"`)
@@ -67,6 +67,12 @@ export class DeleteFeatureChange extends FeatureChange {
67
67
  const { featureModel, session } = backend
68
68
  const { changes, logger } = this
69
69
 
70
+ const { INDEXED_IDS } = process.env
71
+ let idsToIndex: string[] | undefined
72
+ if (INDEXED_IDS) {
73
+ idsToIndex = INDEXED_IDS.split(',')
74
+ }
75
+
70
76
  // Loop the changes
71
77
  for (const change of changes) {
72
78
  const { deletedFeature, parentFeatureId } = change
@@ -105,6 +111,18 @@ export class DeleteFeatureChange extends FeatureChange {
105
111
  featureDoc.allIds = featureDoc.allIds.filter(
106
112
  (id) => !deletedIds.includes(id),
107
113
  )
114
+ const indexedIds = this.getIndexedIds(featureDoc, idsToIndex)
115
+ if (featureDoc.indexedIds) {
116
+ if (indexedIds.length > 0) {
117
+ featureDoc.indexedIds = indexedIds
118
+ } else {
119
+ delete featureDoc.indexedIds
120
+ }
121
+ } else {
122
+ if (indexedIds.length > 0) {
123
+ featureDoc.indexedIds = indexedIds
124
+ }
125
+ }
108
126
  // Save updated document in Mongo
109
127
  featureDoc.markModified('children') // Mark as modified. Without this save() -method is not updating data in database
110
128
  try {
@@ -100,11 +100,24 @@ export class FeatureAttributeChange extends FeatureChange {
100
100
  featuresForChanges.push({ feature: foundFeature, topLevelFeature })
101
101
  }
102
102
 
103
+ const { INDEXED_IDS } = process.env
104
+ let idsToIndex: string[] | undefined
105
+ if (INDEXED_IDS) {
106
+ idsToIndex = INDEXED_IDS.split(',')
107
+ }
103
108
  // Let's update objects
104
109
  for (const [idx, change] of changes.entries()) {
105
110
  const { newAttributes } = change
106
111
  const { feature, topLevelFeature } = featuresForChanges[idx]
112
+ const indexedIdsChanged = idsToIndex?.some(
113
+ (id) => id in newAttributes || id in (feature?.attributes ?? {}),
114
+ )
107
115
  feature.attributes = newAttributes
116
+ if (indexedIdsChanged) {
117
+ const indexedIds = this.getIndexedIds(topLevelFeature, idsToIndex)
118
+ topLevelFeature.indexedIds = indexedIds
119
+ topLevelFeature.markModified('indexedIds')
120
+ }
108
121
  if (topLevelFeature._id.equals(feature._id)) {
109
122
  topLevelFeature.markModified('attributes') // Mark as modified. Without this save() -method is not updating data in database
110
123
  } else {
@@ -4,6 +4,7 @@ import {
4
4
  AssemblySpecificChange,
5
5
  type ServerDataStore,
6
6
  } from '@apollo-annotation/common'
7
+ import { type AnnotationFeatureSnapshot } from '@apollo-annotation/mst'
7
8
  import {
8
9
  type FileDocument,
9
10
  type RefSeqDocument,
@@ -183,8 +184,13 @@ export abstract class FromFileBaseChange extends AssemblySpecificChange {
183
184
  }
184
185
 
185
186
  async addFeatureIntoDb(gff3Feature: GFF3Feature, backend: ServerDataStore) {
186
- const { featureModel, refSeqModel, user } = backend
187
+ const { INDEXED_IDS } = process.env
188
+ let idsToIndex: string[] | undefined
189
+ if (INDEXED_IDS) {
190
+ idsToIndex = INDEXED_IDS.split(',')
191
+ }
187
192
  const { assembly, refSeqCache } = this
193
+ const { featureModel, refSeqModel, user } = backend
188
194
 
189
195
  const [{ seq_id: refName }] = gff3Feature
190
196
  if (!refName) {
@@ -206,19 +212,25 @@ export abstract class FromFileBaseChange extends AssemblySpecificChange {
206
212
  `RefSeq was not found by assembly "${assembly}" and seq_id "${refName}" not found`,
207
213
  )
208
214
  }
209
- // Let's add featureId to parent feature
210
- const featureIds: string[] = []
211
-
212
- const newFeature = gff3ToAnnotationFeature(
213
- gff3Feature,
214
- refSeqDoc._id,
215
- featureIds,
216
- )
215
+ const newFeature = gff3ToAnnotationFeature(gff3Feature, refSeqDoc._id)
216
+ const allIds = this.getAllIds(newFeature)
217
+ const indexedIds = this.getIndexedIds(newFeature, idsToIndex)
217
218
 
218
219
  // Add into Mongo
219
220
  // We cannot use Mongo 'session' / transaction here because Mongo has 16 MB limit for transaction
220
221
  await featureModel.create([
221
- { allIds: featureIds, ...newFeature, user, status: -1 },
222
+ { allIds, indexedIds, ...newFeature, user, status: -1 },
222
223
  ])
223
224
  }
225
+
226
+ getAllIds(feature: AnnotationFeatureSnapshot): string[] {
227
+ const allIds = [feature._id]
228
+ if (feature.children) {
229
+ for (const child of Object.values(feature.children)) {
230
+ const childIds = this.getAllIds(child)
231
+ allIds.push(...childIds)
232
+ }
233
+ }
234
+ return allIds
235
+ }
224
236
  }
@@ -1,12 +1,34 @@
1
1
  /* eslint-disable prefer-destructuring */
2
2
  /* eslint-disable @typescript-eslint/no-floating-promises */
3
+ import { readFileSync } from 'node:fs'
3
4
  import { describe, it } from 'node:test'
4
5
 
5
6
  import { type AnnotationFeatureSnapshot } from '@apollo-annotation/mst'
6
- import { assert } from 'chai'
7
+ import { formatSync } from '@gmod/gff'
8
+ import { assert, expect } from 'chai'
7
9
 
8
10
  import { annotationFeatureToGFF3 } from './annotationFeatureToGFF3'
9
- import { readAnnotationFeatureSnapshot } from './gff3ToAnnotationFeature.test'
11
+ import { readAnnotationFeatureSnapshot, testCases } from './testUtil'
12
+
13
+ describe('Converts AnnotationFeatureSnapshot JSON to GFF3 when', () => {
14
+ for (const testCase of testCases) {
15
+ const { filenameStem, description } = testCase
16
+ it(description, () => {
17
+ const annotationFeatures = JSON.parse(
18
+ readFileSync(`test_data/${filenameStem}.json`, 'utf8'),
19
+ ) as AnnotationFeatureSnapshot[]
20
+ const expectedGFF3 = readFileSync(
21
+ `test_data/${filenameStem}.gff3`,
22
+ 'utf8',
23
+ )
24
+ const gffFeatures = annotationFeatures.map((annotationFeature) =>
25
+ annotationFeatureToGFF3(annotationFeature),
26
+ )
27
+ const gff3 = formatSync(gffFeatures)
28
+ expect(gff3).to.equal(expectedGFF3)
29
+ })
30
+ }
31
+ })
10
32
 
11
33
  describe('annotationFeatureToGFF3', () => {
12
34
  it('Test mandatory columns', () => {
@@ -8,77 +8,10 @@ import { assert, use } from 'chai'
8
8
  import chaiExclude from 'chai-exclude'
9
9
 
10
10
  import { gff3ToAnnotationFeature } from './gff3ToAnnotationFeature'
11
+ import { readAnnotationFeatureSnapshot, testCases } from './testUtil'
11
12
 
12
13
  use(chaiExclude)
13
14
 
14
- const testCases: [string, string, AnnotationFeatureSnapshot][] = [
15
- [
16
- 'a feature with no children',
17
- 'ctgA example remark 1000 2000 . . . Name=Remark:hga;Alias=hga\n',
18
- {
19
- _id: '66c51f3e002c683eaf98a223',
20
- refSeq: 'ctgA',
21
- type: 'remark',
22
- min: 999,
23
- max: 2000,
24
- attributes: {
25
- gff_source: ['example'],
26
- gff_name: ['Remark:hga'],
27
- gff_alias: ['hga'],
28
- },
29
- },
30
- ],
31
- [
32
- 'a feature with two children',
33
- `ctgA est EST_match 1050 3202 . + . ID=Match1;Name=agt830.5;Target=agt830.5 1 654
34
- ctgA est match_part 1050 1500 . + . Parent=Match1;Name=agt830.5;Target=agt830.5 1 451
35
- ctgA est match_part 3000 3202 . + . Parent=Match1;Name=agt830.5;Target=agt830.5 452 654
36
- `,
37
- {
38
- _id: '66cf9fbb4e947fa2c27d3d6a',
39
- refSeq: 'ctgA',
40
- type: 'EST_match',
41
- min: 1049,
42
- max: 3202,
43
- strand: 1,
44
- children: {
45
- '66cf9fbb4e947fa2c27d3d68': {
46
- _id: '66cf9fbb4e947fa2c27d3d68',
47
- refSeq: 'ctgA',
48
- type: 'match_part',
49
- min: 1049,
50
- max: 1500,
51
- strand: 1,
52
- attributes: {
53
- gff_source: ['est'],
54
- gff_name: ['agt830.5'],
55
- gff_target: ['agt830.5 1 451'],
56
- },
57
- },
58
- '66cf9fbb4e947fa2c27d3d69': {
59
- _id: '66cf9fbb4e947fa2c27d3d69',
60
- refSeq: 'ctgA',
61
- type: 'match_part',
62
- min: 2999,
63
- max: 3202,
64
- strand: 1,
65
- attributes: {
66
- gff_source: ['est'],
67
- gff_name: ['agt830.5'],
68
- gff_target: ['agt830.5 452 654'],
69
- },
70
- },
71
- },
72
- attributes: {
73
- gff_source: ['est'],
74
- gff_id: ['Match1'],
75
- gff_name: ['agt830.5'],
76
- gff_target: ['agt830.5 1 654'],
77
- },
78
- },
79
- ],
80
- ]
81
-
82
15
  interface AnnotationFeatureSnapshotWithChildrenArray
83
16
  extends Omit<AnnotationFeatureSnapshot, 'children'> {
84
17
  children?: AnnotationFeatureSnapshotWithChildrenArray[]
@@ -108,6 +41,29 @@ function compareFeatures(
108
41
  )
109
42
  }
110
43
 
44
+ describe('Converts GFF3 to AnnotationFeatureSnapshot JSON when', () => {
45
+ for (const testCase of testCases) {
46
+ const { filenameStem, description } = testCase
47
+ it(description, () => {
48
+ const fileText = readFileSync(`test_data/${filenameStem}.gff3`, 'utf8')
49
+ const gffFeatures = parseStringSync(fileText, { parseSequences: false })
50
+ const annotationFeatures = gffFeatures.map((gff3Feature) =>
51
+ gff3ToAnnotationFeature(gff3Feature),
52
+ )
53
+ const annotationFeaturesExpected = JSON.parse(
54
+ readFileSync(`test_data/${filenameStem}.json`, 'utf8'),
55
+ ) as AnnotationFeatureSnapshot[]
56
+ for (const [
57
+ i,
58
+ annotationFeatureExpected,
59
+ ] of annotationFeaturesExpected.entries()) {
60
+ const annotationFeature = annotationFeatures[i]
61
+ compareFeatures(annotationFeature, annotationFeatureExpected)
62
+ }
63
+ })
64
+ }
65
+ })
66
+
111
67
  function readFeatureFile(fn: string): GFF3Feature[] {
112
68
  const lines = readFileSync(fn).toString().split('\n')
113
69
  const feature: string[] = []
@@ -120,13 +76,6 @@ function readFeatureFile(fn: string): GFF3Feature[] {
120
76
  return inGff
121
77
  }
122
78
 
123
- export function readAnnotationFeatureSnapshot(
124
- fn: string,
125
- ): AnnotationFeatureSnapshot {
126
- const lines = readFileSync(fn).toString()
127
- return JSON.parse(lines) as AnnotationFeatureSnapshot
128
- }
129
-
130
79
  const [ex1, , ex2, , ex3, , ex4] = readFeatureFile(
131
80
  'test_data/gene_representations.gff3',
132
81
  )
@@ -139,13 +88,6 @@ describe('gff3ToAnnotationFeature examples', () => {
139
88
  const expected = readAnnotationFeatureSnapshot('test_data/one_cds.json')
140
89
  compareFeatures(actual, expected)
141
90
  })
142
- it('Convert two CDSs', () => {
143
- const actual = gff3ToAnnotationFeature(
144
- readFeatureFile('test_data/two_cds.gff3')[0],
145
- )
146
- const expected = readAnnotationFeatureSnapshot('test_data/two_cds.json')
147
- compareFeatures(actual, expected)
148
- })
149
91
  it('Convert example 1', () => {
150
92
  const actual = gff3ToAnnotationFeature(ex1)
151
93
  const txt = JSON.stringify(actual, null, 2)
@@ -228,19 +170,6 @@ describe('CDS without exons', () => {
228
170
  })
229
171
  })
230
172
 
231
- describe('gff3ToAnnotationFeature', () => {
232
- for (const testCase of testCases) {
233
- const [description, featureLine, convertedFeature] = testCase
234
- it(`converts ${description}`, () => {
235
- const gff3Feature = parseStringSync(featureLine, {
236
- parseSequences: false,
237
- })
238
- const feature = gff3ToAnnotationFeature(gff3Feature[0])
239
- compareFeatures(convertedFeature, feature)
240
- })
241
- }
242
- })
243
-
244
173
  describe('Source and score', () => {
245
174
  it('Convert score and source', () => {
246
175
  const gffFeature: GFF3Feature = [
@@ -8,7 +8,6 @@ import { gffToInternal, isGFFReservedAttribute } from './gffReservedKeys'
8
8
  export function gff3ToAnnotationFeature(
9
9
  gff3Feature: GFF3Feature,
10
10
  refSeq?: string,
11
- featureIds?: string[],
12
11
  ): AnnotationFeatureSnapshot {
13
12
  const [firstFeature] = gff3Feature
14
13
  const { end, seq_id: refName, start, strand, type } = firstFeature
@@ -35,7 +34,7 @@ export function gff3ToAnnotationFeature(
35
34
 
36
35
  const [min, max] = getFeatureMinMax(gff3Feature)
37
36
 
38
- const convertedChildren = convertChildren(gff3Feature, refSeq, featureIds)
37
+ const convertedChildren = convertChildren(gff3Feature, refSeq)
39
38
 
40
39
  const convertedAttributes = convertFeatureAttributes(gff3Feature)
41
40
 
@@ -61,9 +60,6 @@ export function gff3ToAnnotationFeature(
61
60
  if (convertedAttributes) {
62
61
  feature.attributes = convertedAttributes
63
62
  }
64
- if (featureIds) {
65
- featureIds.push(feature._id)
66
- }
67
63
  return feature
68
64
  }
69
65
 
@@ -182,13 +178,13 @@ function convertChildren(
182
178
  if (firstChildFeatureLocation.type === 'CDS') {
183
179
  cdsFeatures.push(childFeature)
184
180
  } else {
185
- const child = gff3ToAnnotationFeature(childFeature, refSeq, featureIds)
181
+ const child = gff3ToAnnotationFeature(childFeature, refSeq)
186
182
  convertedChildren[child._id] = child
187
183
  }
188
184
  }
189
185
 
190
186
  if (cdsFeatures.length > 0) {
191
- const processedCDS = processCDS(cdsFeatures, refSeq, featureIds)
187
+ const processedCDS = processCDS(cdsFeatures, refSeq)
192
188
 
193
189
  for (const cds of processedCDS) {
194
190
  convertedChildren[cds._id] = cds
@@ -372,16 +368,13 @@ function mergeAnnotationFeatures(
372
368
  function processCDS(
373
369
  cdsFeatures: GFF3Feature[],
374
370
  refSeq?: string,
375
- featureIds?: string[],
376
371
  ): AnnotationFeatureSnapshot[] {
377
372
  const locationCounts = cdsFeatures.map((cds) => cds.length)
378
373
  // If any CDS have multiple locations, assume it really is multiple CDS
379
374
  // (e.g. the mRNA has multiple alternative translational start sites)
380
375
  // and process normally.
381
376
  if (locationCounts.some((count) => count > 1)) {
382
- return cdsFeatures.map((cds) =>
383
- gff3ToAnnotationFeature(cds, refSeq, featureIds),
384
- )
377
+ return cdsFeatures.map((cds) => gff3ToAnnotationFeature(cds, refSeq))
385
378
  }
386
379
  // If all CDS have a single location, we guess that this GFF3 represented CDS
387
380
  // as multiple features instead of a single feature with multiple locations.
@@ -402,7 +395,7 @@ function processCDS(
402
395
  })
403
396
  // If no overlaps, assume it's a single CDS feature
404
397
  if (!overlapping) {
405
- return [gff3ToAnnotationFeature(sortedCDSLocations, refSeq, featureIds)]
398
+ return [gff3ToAnnotationFeature(sortedCDSLocations, refSeq)]
406
399
  }
407
400
  // Some CDS locations overlap, the best we can do is use the original order to
408
401
  // guess how to group the locations into features
@@ -430,7 +423,5 @@ function processCDS(
430
423
  lastGroup.push(location)
431
424
  }
432
425
  }
433
- return groupedLocations.map((group) =>
434
- gff3ToAnnotationFeature(group, refSeq, featureIds),
435
- )
426
+ return groupedLocations.map((group) => gff3ToAnnotationFeature(group, refSeq))
436
427
  }
@@ -0,0 +1,25 @@
1
+ import { readFileSync } from 'node:fs'
2
+
3
+ import { type AnnotationFeatureSnapshot } from '@apollo-annotation/mst'
4
+
5
+ export function readAnnotationFeatureSnapshot(
6
+ fn: string,
7
+ ): AnnotationFeatureSnapshot {
8
+ const lines = readFileSync(fn).toString()
9
+ return JSON.parse(lines) as AnnotationFeatureSnapshot
10
+ }
11
+
12
+ export const testCases: { filenameStem: string; description: string }[] = [
13
+ {
14
+ filenameStem: 'single_feature_no_children',
15
+ description: 'there is a single feature with no children',
16
+ },
17
+ {
18
+ filenameStem: 'single_feature_two_children',
19
+ description: 'there is a single feature with two children',
20
+ },
21
+ {
22
+ filenameStem: 'gene_with_two_cds',
23
+ description: 'Gene with two CDS',
24
+ },
25
+ ]
@@ -0,0 +1,6 @@
1
+ chr1 . gene 1000 9000 . + . testid=t003;ID=gene10001;Name=EDEN
2
+ chr1 . mRNA 1050 9000 . + . testid=t004,t001,t004;Parent=gene10001;ID=mRNA10001;Name=EDEN.1
3
+ chr1 . exon 1050 1500 . + . testid=t007;Parent=mRNA10001;ID=exon10001
4
+ chr1 . exon 5000 5500 . + . testid=t010;Parent=mRNA10001;ID=exon10004
5
+ chr1 . CDS 1201 1500 . + 0 testid=t012,t013,t014;Parent=mRNA10001;ID=cds10001;Name=edenprotein.1
6
+ chr1 . CDS 5000 5000 . + 0 testid=t012,t013,t014;Parent=mRNA10001;ID=cds10001;Name=edenprotein.1
@@ -0,0 +1,69 @@
1
+ [
2
+ {
3
+ "_id": "66d70f3b9c7a7460925687a3",
4
+ "refSeq": "chr1",
5
+ "type": "gene",
6
+ "min": 999,
7
+ "max": 9000,
8
+ "strand": 1,
9
+ "children": {
10
+ "66d70f3b9c7a7460925687a2": {
11
+ "_id": "66d70f3b9c7a7460925687a2",
12
+ "refSeq": "chr1",
13
+ "type": "mRNA",
14
+ "min": 1049,
15
+ "max": 9000,
16
+ "strand": 1,
17
+ "children": {
18
+ "66d70f3b9c7a74609256879f": {
19
+ "_id": "66d70f3b9c7a74609256879f",
20
+ "refSeq": "chr1",
21
+ "type": "exon",
22
+ "min": 1049,
23
+ "max": 1500,
24
+ "strand": 1,
25
+ "attributes": {
26
+ "testid": ["t007"],
27
+ "gff_id": ["exon10001"]
28
+ }
29
+ },
30
+ "66d70f3b9c7a7460925687a0": {
31
+ "_id": "66d70f3b9c7a7460925687a0",
32
+ "refSeq": "chr1",
33
+ "type": "exon",
34
+ "min": 4999,
35
+ "max": 5500,
36
+ "strand": 1,
37
+ "attributes": {
38
+ "testid": ["t010"],
39
+ "gff_id": ["exon10004"]
40
+ }
41
+ },
42
+ "66d70f3b9c7a7460925687a1": {
43
+ "_id": "66d70f3b9c7a7460925687a1",
44
+ "refSeq": "chr1",
45
+ "type": "CDS",
46
+ "min": 1200,
47
+ "max": 5000,
48
+ "strand": 1,
49
+ "attributes": {
50
+ "testid": ["t012", "t013", "t014"],
51
+ "gff_id": ["cds10001"],
52
+ "gff_name": ["edenprotein.1"]
53
+ }
54
+ }
55
+ },
56
+ "attributes": {
57
+ "testid": ["t004", "t001", "t004"],
58
+ "gff_id": ["mRNA10001"],
59
+ "gff_name": ["EDEN.1"]
60
+ }
61
+ }
62
+ },
63
+ "attributes": {
64
+ "testid": ["t003"],
65
+ "gff_id": ["gene10001"],
66
+ "gff_name": ["EDEN"]
67
+ }
68
+ }
69
+ ]
@@ -0,0 +1 @@
1
+ ctgA example remark 1000 2000 . . . Name=Remark:hga;Alias=hga
@@ -0,0 +1,14 @@
1
+ [
2
+ {
3
+ "_id": "6931ef3bf5c33f70085c3a7b",
4
+ "refSeq": "ctgA",
5
+ "type": "remark",
6
+ "min": 999,
7
+ "max": 2000,
8
+ "attributes": {
9
+ "gff_source": ["example"],
10
+ "gff_name": ["Remark:hga"],
11
+ "gff_alias": ["hga"]
12
+ }
13
+ }
14
+ ]
@@ -0,0 +1,3 @@
1
+ ctgA est EST_match 1050 3202 . + . ID=Match1;Name=agt830.5;Target=agt830.5 1 654
2
+ ctgA est match_part 1050 1500 . + . Parent=Match1;Name=agt830.5;Target=agt830.5 1 451
3
+ ctgA est match_part 3000 3202 . + . Parent=Match1;Name=agt830.5;Target=agt830.5 452 654
@@ -0,0 +1,44 @@
1
+ [
2
+ {
3
+ "_id": "6931fc4f88722ca882ba334c",
4
+ "refSeq": "ctgA",
5
+ "type": "EST_match",
6
+ "min": 1049,
7
+ "max": 3202,
8
+ "strand": 1,
9
+ "children": {
10
+ "6931fc4f88722ca882ba334a": {
11
+ "_id": "6931fc4f88722ca882ba334a",
12
+ "refSeq": "ctgA",
13
+ "type": "match_part",
14
+ "min": 1049,
15
+ "max": 1500,
16
+ "strand": 1,
17
+ "attributes": {
18
+ "gff_source": ["est"],
19
+ "gff_name": ["agt830.5"],
20
+ "gff_target": ["agt830.5 1 451"]
21
+ }
22
+ },
23
+ "6931fc4f88722ca882ba334b": {
24
+ "_id": "6931fc4f88722ca882ba334b",
25
+ "refSeq": "ctgA",
26
+ "type": "match_part",
27
+ "min": 2999,
28
+ "max": 3202,
29
+ "strand": 1,
30
+ "attributes": {
31
+ "gff_source": ["est"],
32
+ "gff_name": ["agt830.5"],
33
+ "gff_target": ["agt830.5 452 654"]
34
+ }
35
+ }
36
+ },
37
+ "attributes": {
38
+ "gff_source": ["est"],
39
+ "gff_id": ["Match1"],
40
+ "gff_name": ["agt830.5"],
41
+ "gff_target": ["agt830.5 1 654"]
42
+ }
43
+ }
44
+ ]
@@ -1,9 +0,0 @@
1
- ##gff-version 3
2
- ##sequence-region chr1 1000 9000
3
- #example01
4
- chr1 . gene 1000 9000 . + . ID=gene10001;Name=EDEN;testid=t003
5
- chr1 . mRNA 1050 9000 . + . ID=mRNA10001;Parent=gene10001;Name=EDEN.1;testid=t004,t001,t004
6
- chr1 . exon 1050 1500 . + . ID=exon10001;Parent=mRNA10001;testid=t007
7
- chr1 . exon 5000 5500 . + . ID=exon10004;Parent=mRNA10001;testid=t010
8
- chr1 . CDS 1201 1500 . + 0 ID=cds10001;Parent=mRNA10001;Name=edenprotein.1;testid=t012,t013,t014
9
- chr1 . CDS 5000 5000 . + 0 ID=cds10001;Parent=mRNA10001;Name=edenprotein.1;testid=t014