@apollo-annotation/shared 0.3.6 → 0.3.8
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/Changes/AddAssemblyAliasesChange.d.ts +16 -0
- package/dist/Changes/AddAssemblyAliasesChange.js +50 -0
- package/dist/Changes/AddAssemblyAliasesChange.js.map +1 -0
- package/dist/Changes/AddAssemblyAndFeaturesFromFileChange.js +1 -1
- package/dist/Changes/AddAssemblyAndFeaturesFromFileChange.js.map +1 -1
- package/dist/Changes/AddAssemblyFromFileChange.js +1 -1
- package/dist/Changes/AddAssemblyFromFileChange.js.map +1 -1
- package/dist/Changes/AddFeatureChange.d.ts +1 -0
- package/dist/Changes/AddFeatureChange.js +5 -25
- package/dist/Changes/AddFeatureChange.js.map +1 -1
- package/dist/Changes/AddRefSeqAliasesChange.js +2 -4
- package/dist/Changes/AddRefSeqAliasesChange.js.map +1 -1
- package/dist/Changes/DeleteFeatureChange.d.ts +9 -8
- package/dist/Changes/DeleteFeatureChange.js +37 -32
- package/dist/Changes/DeleteFeatureChange.js.map +1 -1
- package/dist/Changes/FeatureAttributeChange.d.ts +2 -1
- package/dist/Changes/FeatureAttributeChange.js +14 -6
- package/dist/Changes/FeatureAttributeChange.js.map +1 -1
- package/dist/Changes/ImportJBrowseConfigChange.d.ts +3 -0
- package/dist/Changes/ImportJBrowseConfigChange.js +17 -13
- package/dist/Changes/ImportJBrowseConfigChange.js.map +1 -1
- package/dist/Changes/LocationEndChange.js +40 -37
- package/dist/Changes/LocationEndChange.js.map +1 -1
- package/dist/Changes/LocationStartChange.js +40 -37
- package/dist/Changes/LocationStartChange.js.map +1 -1
- package/dist/Changes/MergeExonsChange.d.ts +29 -0
- package/dist/Changes/MergeExonsChange.js +114 -0
- package/dist/Changes/MergeExonsChange.js.map +1 -0
- package/dist/Changes/MergeTranscriptsChange.d.ts +34 -0
- package/dist/Changes/MergeTranscriptsChange.js +245 -0
- package/dist/Changes/MergeTranscriptsChange.js.map +1 -0
- package/dist/Changes/SplitExonChange.d.ts +33 -0
- package/dist/Changes/SplitExonChange.js +142 -0
- package/dist/Changes/SplitExonChange.js.map +1 -0
- package/dist/Changes/UndoMergeExonsChange.d.ts +27 -0
- package/dist/Changes/UndoMergeExonsChange.js +104 -0
- package/dist/Changes/UndoMergeExonsChange.js.map +1 -0
- package/dist/Changes/UndoMergeTranscriptsChange.d.ts +27 -0
- package/dist/Changes/UndoMergeTranscriptsChange.js +104 -0
- package/dist/Changes/UndoMergeTranscriptsChange.js.map +1 -0
- package/dist/Changes/UndoSplitExonChange.d.ts +32 -0
- package/dist/Changes/UndoSplitExonChange.js +111 -0
- package/dist/Changes/UndoSplitExonChange.js.map +1 -0
- package/dist/Changes/index.d.ts +21 -0
- package/dist/Changes/index.js +21 -0
- package/dist/Changes/index.js.map +1 -1
- package/dist/Checks/CDSCheck.d.ts +1 -1
- package/dist/Checks/CDSCheck.js +8 -9
- package/dist/Checks/CDSCheck.js.map +1 -1
- package/dist/Checks/TranscriptCheck.d.ts +9 -0
- package/dist/Checks/TranscriptCheck.js +109 -0
- package/dist/Checks/TranscriptCheck.js.map +1 -0
- package/dist/Checks/index.d.ts +1 -0
- package/dist/Checks/index.js +1 -0
- package/dist/Checks/index.js.map +1 -1
- package/dist/GFF3/annotationFeatureToGFF3.js +7 -1
- package/dist/GFF3/annotationFeatureToGFF3.js.map +1 -1
- package/dist/GFF3/gff3ToAnnotationFeature.test.js +1 -1
- package/dist/GFF3/gff3ToAnnotationFeature.test.js.map +1 -1
- package/dist/Validations/ParentChildValidation.js +3 -1
- package/dist/Validations/ParentChildValidation.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/util.d.ts +5 -0
- package/dist/util.js +46 -0
- package/dist/util.js.map +1 -1
- package/package.json +7 -7
- package/src/Changes/AddAssemblyAliasesChange.ts +69 -0
- package/src/Changes/AddAssemblyAndFeaturesFromFileChange.ts +2 -1
- package/src/Changes/AddAssemblyFromFileChange.ts +1 -1
- package/src/Changes/AddFeatureChange.ts +5 -29
- package/src/Changes/AddRefSeqAliasesChange.ts +2 -4
- package/src/Changes/DeleteFeatureChange.ts +42 -36
- package/src/Changes/FeatureAttributeChange.ts +16 -7
- package/src/Changes/ImportJBrowseConfigChange.ts +33 -18
- package/src/Changes/LocationEndChange.ts +41 -50
- package/src/Changes/LocationStartChange.ts +41 -50
- package/src/Changes/MergeExonsChange.ts +201 -0
- package/src/Changes/MergeTranscriptsChange.ts +394 -0
- package/src/Changes/SplitExonChange.ts +249 -0
- package/src/Changes/UndoMergeExonsChange.ts +149 -0
- package/src/Changes/UndoMergeTranscriptsChange.ts +153 -0
- package/src/Changes/UndoSplitExonChange.ts +174 -0
- package/src/Changes/index.ts +21 -0
- package/src/Checks/CDSCheck.ts +10 -10
- package/src/Checks/TranscriptCheck.ts +139 -0
- package/src/Checks/index.ts +1 -0
- package/src/GFF3/annotationFeatureToGFF3.ts +7 -1
- package/src/GFF3/gff3ToAnnotationFeature.test.ts +1 -1
- package/src/Validations/ParentChildValidation.ts +3 -2
- package/src/util.ts +53 -0
- package/test_data/example01.json +20 -20
- package/test_data/example02.json +38 -38
- package/test_data/example04.json +57 -57
- package/test_data/gene_representations.gff3 +1054 -276
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/require-await */
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
type ChangeOptions,
|
|
5
|
+
type ClientDataStore,
|
|
6
|
+
FeatureChange,
|
|
7
|
+
type LocalGFF3DataStore,
|
|
8
|
+
type SerializedFeatureChange,
|
|
9
|
+
type ServerDataStore,
|
|
10
|
+
} from '@apollo-annotation/common'
|
|
11
|
+
import { type AnnotationFeatureSnapshot } from '@apollo-annotation/mst'
|
|
12
|
+
|
|
13
|
+
import { MergeExonsChange } from './MergeExonsChange'
|
|
14
|
+
|
|
15
|
+
interface SerializedUndoMergeExonsChangeBase extends SerializedFeatureChange {
|
|
16
|
+
typeName: 'UndoMergeExonsChange'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface UndoMergeExonsChangeDetails {
|
|
20
|
+
exonsToRestore: AnnotationFeatureSnapshot[]
|
|
21
|
+
parentFeatureId: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface SerializedUndoMergeExonsChangeSingle
|
|
25
|
+
extends SerializedUndoMergeExonsChangeBase,
|
|
26
|
+
UndoMergeExonsChangeDetails {}
|
|
27
|
+
|
|
28
|
+
interface SerializedUndoMergeExonsChangeMultiple
|
|
29
|
+
extends SerializedUndoMergeExonsChangeBase {
|
|
30
|
+
changes: UndoMergeExonsChangeDetails[]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type SerializedUndoMergeExonsChange =
|
|
34
|
+
| SerializedUndoMergeExonsChangeSingle
|
|
35
|
+
| SerializedUndoMergeExonsChangeMultiple
|
|
36
|
+
export class UndoMergeExonsChange extends FeatureChange {
|
|
37
|
+
typeName = 'UndoMergeExonsChange' as const
|
|
38
|
+
changes: UndoMergeExonsChangeDetails[]
|
|
39
|
+
|
|
40
|
+
constructor(json: SerializedUndoMergeExonsChange, options?: ChangeOptions) {
|
|
41
|
+
super(json, options)
|
|
42
|
+
this.changes = 'changes' in json ? json.changes : [json]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
toJSON(): SerializedUndoMergeExonsChange {
|
|
46
|
+
const { assembly, changedIds, changes, typeName } = this
|
|
47
|
+
if (changes.length === 1) {
|
|
48
|
+
const [{ exonsToRestore, parentFeatureId }] = changes
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
typeName,
|
|
52
|
+
changedIds,
|
|
53
|
+
assembly,
|
|
54
|
+
exonsToRestore,
|
|
55
|
+
parentFeatureId,
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return { typeName, changedIds, assembly, changes }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async executeOnServer(backend: ServerDataStore) {
|
|
62
|
+
const { featureModel, session } = backend
|
|
63
|
+
const { changes } = this
|
|
64
|
+
for (const change of changes) {
|
|
65
|
+
const { exonsToRestore, parentFeatureId } = change
|
|
66
|
+
if (exonsToRestore.length !== 2) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`Expected exactly two exons to restore. Got :${exonsToRestore.length}`,
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
const topLevelFeature = await featureModel
|
|
72
|
+
.findOne({ allIds: parentFeatureId })
|
|
73
|
+
.session(session)
|
|
74
|
+
.exec()
|
|
75
|
+
if (!topLevelFeature) {
|
|
76
|
+
throw new Error(`Could not find feature with ID "${parentFeatureId}"`)
|
|
77
|
+
}
|
|
78
|
+
const parentFeature = this.getFeatureFromId(
|
|
79
|
+
topLevelFeature,
|
|
80
|
+
parentFeatureId,
|
|
81
|
+
)
|
|
82
|
+
if (!parentFeature) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
`Could not find feature with ID "${parentFeatureId}" in feature "${topLevelFeature._id.toString()}"`,
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
if (!parentFeature.children) {
|
|
88
|
+
parentFeature.children = new Map()
|
|
89
|
+
}
|
|
90
|
+
for (const exon of exonsToRestore) {
|
|
91
|
+
this.addChild(parentFeature, exon)
|
|
92
|
+
const childIds = this.getChildFeatureIds(exon)
|
|
93
|
+
topLevelFeature.allIds.push(exon._id, ...childIds)
|
|
94
|
+
}
|
|
95
|
+
await topLevelFeature.save()
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async executeOnLocalGFF3(_backend: LocalGFF3DataStore) {
|
|
100
|
+
throw new Error('executeOnLocalGFF3 not implemented')
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async executeOnClient(dataStore: ClientDataStore) {
|
|
104
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
105
|
+
if (!dataStore) {
|
|
106
|
+
throw new Error('No data store')
|
|
107
|
+
}
|
|
108
|
+
const { changes } = this
|
|
109
|
+
for (const change of changes) {
|
|
110
|
+
const { exonsToRestore, parentFeatureId } = change
|
|
111
|
+
if (!parentFeatureId) {
|
|
112
|
+
throw new Error('Parent ID is missing')
|
|
113
|
+
}
|
|
114
|
+
const parentFeature = dataStore.getFeature(parentFeatureId)
|
|
115
|
+
if (!parentFeature) {
|
|
116
|
+
throw new Error(`Could not find parent feature "${parentFeatureId}"`)
|
|
117
|
+
}
|
|
118
|
+
// create an ID for the parent feature if it does not have one
|
|
119
|
+
if (!parentFeature.attributes.get('_id')) {
|
|
120
|
+
parentFeature.setAttribute('_id', [parentFeature._id])
|
|
121
|
+
}
|
|
122
|
+
for (const exon of exonsToRestore) {
|
|
123
|
+
parentFeature.addChild(exon)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
getInverse() {
|
|
129
|
+
const { assembly, changedIds, changes, logger } = this
|
|
130
|
+
const inverseChangedIds = [...changedIds].reverse()
|
|
131
|
+
const inverseChanges = [...changes]
|
|
132
|
+
.reverse()
|
|
133
|
+
.map((undoMergeExonsChange) => ({
|
|
134
|
+
firstExon: undoMergeExonsChange.exonsToRestore[0],
|
|
135
|
+
secondExon: undoMergeExonsChange.exonsToRestore[1],
|
|
136
|
+
parentFeatureId: undoMergeExonsChange.parentFeatureId,
|
|
137
|
+
}))
|
|
138
|
+
|
|
139
|
+
return new MergeExonsChange(
|
|
140
|
+
{
|
|
141
|
+
changedIds: inverseChangedIds,
|
|
142
|
+
typeName: 'MergeExonsChange',
|
|
143
|
+
changes: inverseChanges,
|
|
144
|
+
assembly,
|
|
145
|
+
},
|
|
146
|
+
{ logger },
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/require-await */
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
type ChangeOptions,
|
|
5
|
+
type ClientDataStore,
|
|
6
|
+
FeatureChange,
|
|
7
|
+
type LocalGFF3DataStore,
|
|
8
|
+
type SerializedFeatureChange,
|
|
9
|
+
type ServerDataStore,
|
|
10
|
+
} from '@apollo-annotation/common'
|
|
11
|
+
import { type AnnotationFeatureSnapshot } from '@apollo-annotation/mst'
|
|
12
|
+
|
|
13
|
+
import { MergeTranscriptsChange } from './MergeTranscriptsChange'
|
|
14
|
+
|
|
15
|
+
interface SerializedUndoMergeTranscriptsChangeBase
|
|
16
|
+
extends SerializedFeatureChange {
|
|
17
|
+
typeName: 'UndoMergeTranscriptsChange'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface UndoMergeTranscriptsChangeDetails {
|
|
21
|
+
transcriptsToRestore: AnnotationFeatureSnapshot[]
|
|
22
|
+
parentFeatureId: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface SerializedUndoMergeTranscriptsChangeSingle
|
|
26
|
+
extends SerializedUndoMergeTranscriptsChangeBase,
|
|
27
|
+
UndoMergeTranscriptsChangeDetails {}
|
|
28
|
+
|
|
29
|
+
interface SerializedUndoMergeTranscriptsChangeMultiple
|
|
30
|
+
extends SerializedUndoMergeTranscriptsChangeBase {
|
|
31
|
+
changes: UndoMergeTranscriptsChangeDetails[]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type SerializedUndoMergeTranscriptsChange =
|
|
35
|
+
| SerializedUndoMergeTranscriptsChangeSingle
|
|
36
|
+
| SerializedUndoMergeTranscriptsChangeMultiple
|
|
37
|
+
export class UndoMergeTranscriptsChange extends FeatureChange {
|
|
38
|
+
typeName = 'UndoMergeTranscriptsChange' as const
|
|
39
|
+
changes: UndoMergeTranscriptsChangeDetails[]
|
|
40
|
+
|
|
41
|
+
constructor(
|
|
42
|
+
json: SerializedUndoMergeTranscriptsChange,
|
|
43
|
+
options?: ChangeOptions,
|
|
44
|
+
) {
|
|
45
|
+
super(json, options)
|
|
46
|
+
this.changes = 'changes' in json ? json.changes : [json]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
toJSON(): SerializedUndoMergeTranscriptsChange {
|
|
50
|
+
const { assembly, changedIds, changes, typeName } = this
|
|
51
|
+
if (changes.length === 1) {
|
|
52
|
+
const [{ transcriptsToRestore, parentFeatureId }] = changes
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
typeName,
|
|
56
|
+
changedIds,
|
|
57
|
+
assembly,
|
|
58
|
+
transcriptsToRestore,
|
|
59
|
+
parentFeatureId,
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return { typeName, changedIds, assembly, changes }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async executeOnServer(backend: ServerDataStore) {
|
|
66
|
+
const { featureModel, session } = backend
|
|
67
|
+
const { changes } = this
|
|
68
|
+
for (const change of changes) {
|
|
69
|
+
const { transcriptsToRestore, parentFeatureId } = change
|
|
70
|
+
if (transcriptsToRestore.length !== 2) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`Expected exactly two transcripts to restore. Got :${transcriptsToRestore.length}`,
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
const topLevelFeature = await featureModel
|
|
76
|
+
.findOne({ allIds: parentFeatureId })
|
|
77
|
+
.session(session)
|
|
78
|
+
.exec()
|
|
79
|
+
if (!topLevelFeature) {
|
|
80
|
+
throw new Error(`Could not find feature with ID "${parentFeatureId}"`)
|
|
81
|
+
}
|
|
82
|
+
const parentFeature = this.getFeatureFromId(
|
|
83
|
+
topLevelFeature,
|
|
84
|
+
parentFeatureId,
|
|
85
|
+
)
|
|
86
|
+
if (!parentFeature) {
|
|
87
|
+
throw new Error(
|
|
88
|
+
`Could not find feature with ID "${parentFeatureId}" in feature "${topLevelFeature._id.toString()}"`,
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
if (!parentFeature.children) {
|
|
92
|
+
parentFeature.children = new Map()
|
|
93
|
+
}
|
|
94
|
+
for (const transcript of transcriptsToRestore) {
|
|
95
|
+
this.addChild(parentFeature, transcript)
|
|
96
|
+
const childIds = this.getChildFeatureIds(transcript)
|
|
97
|
+
topLevelFeature.allIds.push(transcript._id, ...childIds)
|
|
98
|
+
}
|
|
99
|
+
await topLevelFeature.save()
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async executeOnLocalGFF3(_backend: LocalGFF3DataStore) {
|
|
104
|
+
throw new Error('executeOnLocalGFF3 not implemented')
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async executeOnClient(dataStore: ClientDataStore) {
|
|
108
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
109
|
+
if (!dataStore) {
|
|
110
|
+
throw new Error('No data store')
|
|
111
|
+
}
|
|
112
|
+
const { changes } = this
|
|
113
|
+
for (const change of changes) {
|
|
114
|
+
const { transcriptsToRestore, parentFeatureId } = change
|
|
115
|
+
if (!parentFeatureId) {
|
|
116
|
+
throw new Error('Parent ID is missing')
|
|
117
|
+
}
|
|
118
|
+
const parentFeature = dataStore.getFeature(parentFeatureId)
|
|
119
|
+
if (!parentFeature) {
|
|
120
|
+
throw new Error(`Could not find parent feature "${parentFeatureId}"`)
|
|
121
|
+
}
|
|
122
|
+
// create an ID for the parent feature if it does not have one
|
|
123
|
+
if (!parentFeature.attributes.get('_id')) {
|
|
124
|
+
parentFeature.setAttribute('_id', [parentFeature._id])
|
|
125
|
+
}
|
|
126
|
+
for (const transcript of transcriptsToRestore) {
|
|
127
|
+
parentFeature.addChild(transcript)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
getInverse() {
|
|
133
|
+
const { assembly, changedIds, changes, logger } = this
|
|
134
|
+
const inverseChangedIds = [...changedIds].reverse()
|
|
135
|
+
const inverseChanges = [...changes]
|
|
136
|
+
.reverse()
|
|
137
|
+
.map((undoMergeTranscriptsChange) => ({
|
|
138
|
+
firstTranscript: undoMergeTranscriptsChange.transcriptsToRestore[0],
|
|
139
|
+
secondTranscript: undoMergeTranscriptsChange.transcriptsToRestore[1],
|
|
140
|
+
parentFeatureId: undoMergeTranscriptsChange.parentFeatureId,
|
|
141
|
+
}))
|
|
142
|
+
|
|
143
|
+
return new MergeTranscriptsChange(
|
|
144
|
+
{
|
|
145
|
+
changedIds: inverseChangedIds,
|
|
146
|
+
typeName: 'MergeTranscriptsChange',
|
|
147
|
+
changes: inverseChanges,
|
|
148
|
+
assembly,
|
|
149
|
+
},
|
|
150
|
+
{ logger },
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/require-await */
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
type ChangeOptions,
|
|
5
|
+
type ClientDataStore,
|
|
6
|
+
FeatureChange,
|
|
7
|
+
type LocalGFF3DataStore,
|
|
8
|
+
type SerializedFeatureChange,
|
|
9
|
+
type ServerDataStore,
|
|
10
|
+
} from '@apollo-annotation/common'
|
|
11
|
+
import { type AnnotationFeatureSnapshot } from '@apollo-annotation/mst'
|
|
12
|
+
|
|
13
|
+
import { findAndDeleteChildFeature } from './DeleteFeatureChange'
|
|
14
|
+
import { SplitExonChange } from './SplitExonChange'
|
|
15
|
+
|
|
16
|
+
interface SerializedUndoSplitExonChangeBase extends SerializedFeatureChange {
|
|
17
|
+
typeName: 'UndoSplitExonChange'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface UndoSplitExonChangeDetails {
|
|
21
|
+
exonToRestore: AnnotationFeatureSnapshot
|
|
22
|
+
parentFeatureId: string
|
|
23
|
+
idsToDelete: string[]
|
|
24
|
+
upstreamCut: number
|
|
25
|
+
downstreamCut: number
|
|
26
|
+
leftExonId: string
|
|
27
|
+
rightExonId: string
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface SerializedUndoSplitExonChangeSingle
|
|
31
|
+
extends SerializedUndoSplitExonChangeBase,
|
|
32
|
+
UndoSplitExonChangeDetails {}
|
|
33
|
+
|
|
34
|
+
interface SerializedUndoSplitExonChangeMultiple
|
|
35
|
+
extends SerializedUndoSplitExonChangeBase {
|
|
36
|
+
changes: UndoSplitExonChangeDetails[]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type SerializedUndoSplitExonChange =
|
|
40
|
+
| SerializedUndoSplitExonChangeSingle
|
|
41
|
+
| SerializedUndoSplitExonChangeMultiple
|
|
42
|
+
export class UndoSplitExonChange extends FeatureChange {
|
|
43
|
+
typeName = 'UndoSplitExonChange' as const
|
|
44
|
+
changes: UndoSplitExonChangeDetails[]
|
|
45
|
+
|
|
46
|
+
constructor(json: SerializedUndoSplitExonChange, options?: ChangeOptions) {
|
|
47
|
+
super(json, options)
|
|
48
|
+
this.changes = 'changes' in json ? json.changes : [json]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
toJSON(): SerializedUndoSplitExonChange {
|
|
52
|
+
const { assembly, changedIds, changes, typeName } = this
|
|
53
|
+
if (changes.length === 1) {
|
|
54
|
+
const [
|
|
55
|
+
{
|
|
56
|
+
exonToRestore,
|
|
57
|
+
parentFeatureId,
|
|
58
|
+
idsToDelete,
|
|
59
|
+
upstreamCut,
|
|
60
|
+
downstreamCut,
|
|
61
|
+
leftExonId,
|
|
62
|
+
rightExonId,
|
|
63
|
+
},
|
|
64
|
+
] = changes
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
typeName,
|
|
68
|
+
changedIds,
|
|
69
|
+
assembly,
|
|
70
|
+
exonToRestore,
|
|
71
|
+
parentFeatureId,
|
|
72
|
+
idsToDelete,
|
|
73
|
+
upstreamCut,
|
|
74
|
+
downstreamCut,
|
|
75
|
+
leftExonId,
|
|
76
|
+
rightExonId,
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return { typeName, changedIds, assembly, changes }
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async executeOnServer(backend: ServerDataStore) {
|
|
83
|
+
const { featureModel, session } = backend
|
|
84
|
+
const { changes } = this
|
|
85
|
+
for (const change of changes) {
|
|
86
|
+
const { exonToRestore, parentFeatureId, idsToDelete } = change
|
|
87
|
+
const topLevelFeature = await featureModel
|
|
88
|
+
.findOne({ allIds: parentFeatureId })
|
|
89
|
+
.session(session)
|
|
90
|
+
.exec()
|
|
91
|
+
if (!topLevelFeature) {
|
|
92
|
+
throw new Error(`Could not find feature with ID "${parentFeatureId}"`)
|
|
93
|
+
}
|
|
94
|
+
const parentFeature = this.getFeatureFromId(
|
|
95
|
+
topLevelFeature,
|
|
96
|
+
parentFeatureId,
|
|
97
|
+
)
|
|
98
|
+
if (!parentFeature) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
`Could not find feature with ID "${parentFeatureId}" in feature "${topLevelFeature._id.toString()}"`,
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
if (!parentFeature.children) {
|
|
104
|
+
parentFeature.children = new Map()
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
this.addChild(parentFeature, exonToRestore)
|
|
108
|
+
const childIds = this.getChildFeatureIds(exonToRestore)
|
|
109
|
+
topLevelFeature.allIds.push(exonToRestore._id, ...childIds)
|
|
110
|
+
topLevelFeature.allIds = topLevelFeature.allIds.filter(
|
|
111
|
+
(id) => !idsToDelete.includes(id),
|
|
112
|
+
)
|
|
113
|
+
idsToDelete.map((id) =>
|
|
114
|
+
findAndDeleteChildFeature(topLevelFeature, id, this),
|
|
115
|
+
)
|
|
116
|
+
await topLevelFeature.save()
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async executeOnLocalGFF3(_backend: LocalGFF3DataStore) {
|
|
121
|
+
throw new Error('executeOnLocalGFF3 not implemented')
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async executeOnClient(dataStore: ClientDataStore) {
|
|
125
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
126
|
+
if (!dataStore) {
|
|
127
|
+
throw new Error('No data store')
|
|
128
|
+
}
|
|
129
|
+
const { changes } = this
|
|
130
|
+
for (const change of changes) {
|
|
131
|
+
const { exonToRestore, parentFeatureId, idsToDelete } = change
|
|
132
|
+
if (!parentFeatureId) {
|
|
133
|
+
throw new Error('Parent ID is missing')
|
|
134
|
+
}
|
|
135
|
+
const parentFeature = dataStore.getFeature(parentFeatureId)
|
|
136
|
+
if (!parentFeature) {
|
|
137
|
+
throw new Error(`Could not find parent feature "${parentFeatureId}"`)
|
|
138
|
+
}
|
|
139
|
+
// create an ID for the parent feature if it does not have one
|
|
140
|
+
if (!parentFeature.attributes.get('_id')) {
|
|
141
|
+
parentFeature.setAttribute('_id', [parentFeature._id])
|
|
142
|
+
}
|
|
143
|
+
parentFeature.addChild(exonToRestore)
|
|
144
|
+
idsToDelete.map((id) => {
|
|
145
|
+
parentFeature.deleteChild(id)
|
|
146
|
+
})
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
getInverse() {
|
|
151
|
+
const { assembly, changedIds, changes, logger } = this
|
|
152
|
+
const inverseChangedIds = [...changedIds].reverse()
|
|
153
|
+
const inverseChanges = [...changes]
|
|
154
|
+
.reverse()
|
|
155
|
+
.map((undoSplitExonChange) => ({
|
|
156
|
+
parentFeatureId: undoSplitExonChange.parentFeatureId,
|
|
157
|
+
exonToBeSplit: undoSplitExonChange.exonToRestore,
|
|
158
|
+
upstreamCut: undoSplitExonChange.upstreamCut,
|
|
159
|
+
downstreamCut: undoSplitExonChange.downstreamCut,
|
|
160
|
+
leftExonId: undoSplitExonChange.leftExonId,
|
|
161
|
+
rightExonId: undoSplitExonChange.rightExonId,
|
|
162
|
+
}))
|
|
163
|
+
|
|
164
|
+
return new SplitExonChange(
|
|
165
|
+
{
|
|
166
|
+
changedIds: inverseChangedIds,
|
|
167
|
+
typeName: 'SplitExonChange',
|
|
168
|
+
changes: inverseChanges,
|
|
169
|
+
assembly,
|
|
170
|
+
},
|
|
171
|
+
{ logger },
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
}
|
package/src/Changes/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AddAssemblyAliasesChange } from './AddAssemblyAliasesChange'
|
|
1
2
|
import { AddAssemblyAndFeaturesFromFileChange } from './AddAssemblyAndFeaturesFromFileChange'
|
|
2
3
|
import { AddAssemblyFromExternalChange } from './AddAssemblyFromExternalChange'
|
|
3
4
|
import { AddAssemblyFromFileChange } from './AddAssemblyFromFileChange'
|
|
@@ -11,8 +12,14 @@ import { FeatureAttributeChange } from './FeatureAttributeChange'
|
|
|
11
12
|
import { ImportJBrowseConfigChange } from './ImportJBrowseConfigChange'
|
|
12
13
|
import { LocationEndChange } from './LocationEndChange'
|
|
13
14
|
import { LocationStartChange } from './LocationStartChange'
|
|
15
|
+
import { MergeExonsChange } from './MergeExonsChange'
|
|
16
|
+
import { MergeTranscriptsChange } from './MergeTranscriptsChange'
|
|
17
|
+
import { SplitExonChange } from './SplitExonChange'
|
|
14
18
|
import { StrandChange } from './StrandChange'
|
|
15
19
|
import { TypeChange } from './TypeChange'
|
|
20
|
+
import { UndoMergeExonsChange } from './UndoMergeExonsChange'
|
|
21
|
+
import { UndoMergeTranscriptsChange } from './UndoMergeTranscriptsChange'
|
|
22
|
+
import { UndoSplitExonChange } from './UndoSplitExonChange'
|
|
16
23
|
import { UserChange } from './UserChange'
|
|
17
24
|
|
|
18
25
|
export const changes = {
|
|
@@ -28,10 +35,17 @@ export const changes = {
|
|
|
28
35
|
ImportJBrowseConfigChange,
|
|
29
36
|
LocationEndChange,
|
|
30
37
|
LocationStartChange,
|
|
38
|
+
MergeExonsChange,
|
|
39
|
+
SplitExonChange,
|
|
40
|
+
MergeTranscriptsChange,
|
|
41
|
+
UndoMergeExonsChange,
|
|
42
|
+
UndoSplitExonChange,
|
|
43
|
+
UndoMergeTranscriptsChange,
|
|
31
44
|
StrandChange,
|
|
32
45
|
TypeChange,
|
|
33
46
|
UserChange,
|
|
34
47
|
AddRefSeqAliasesChange,
|
|
48
|
+
AddAssemblyAliasesChange,
|
|
35
49
|
}
|
|
36
50
|
|
|
37
51
|
export * from './AddAssemblyAndFeaturesFromFileChange'
|
|
@@ -46,7 +60,14 @@ export * from './FeatureAttributeChange'
|
|
|
46
60
|
export * from './ImportJBrowseConfigChange'
|
|
47
61
|
export * from './LocationEndChange'
|
|
48
62
|
export * from './LocationStartChange'
|
|
63
|
+
export * from './MergeExonsChange'
|
|
64
|
+
export * from './SplitExonChange'
|
|
65
|
+
export * from './MergeTranscriptsChange'
|
|
66
|
+
export * from './UndoMergeExonsChange'
|
|
67
|
+
export * from './UndoSplitExonChange'
|
|
68
|
+
export * from './UndoMergeTranscriptsChange'
|
|
49
69
|
export * from './StrandChange'
|
|
50
70
|
export * from './TypeChange'
|
|
51
71
|
export * from './UserChange'
|
|
52
72
|
export * from './AddRefSeqAliasesChange'
|
|
73
|
+
export * from './AddAssemblyAliasesChange'
|
package/src/Checks/CDSCheck.ts
CHANGED
|
@@ -22,7 +22,6 @@ enum CAUSES {
|
|
|
22
22
|
'InternalStopCodon',
|
|
23
23
|
'MissingStartCodon',
|
|
24
24
|
'MissingStopCodon',
|
|
25
|
-
'MultipleOfThree',
|
|
26
25
|
}
|
|
27
26
|
|
|
28
27
|
const iupacComplements: Record<string, string | undefined> = {
|
|
@@ -156,6 +155,10 @@ async function checkMRNA(
|
|
|
156
155
|
for (const cdsLocation of cdsLocations) {
|
|
157
156
|
const sequence = await getCDSSequence(cdsLocation, strand, getSequence)
|
|
158
157
|
const codons = splitSequenceInCodons(sequence)
|
|
158
|
+
const cdsEnd =
|
|
159
|
+
strand === -1
|
|
160
|
+
? cdsLocation.at(0)?.min ?? min
|
|
161
|
+
: cdsLocation.at(-1)?.max ?? max
|
|
159
162
|
if (sequence.length % 3 === 0) {
|
|
160
163
|
const start_codon = codons.at(0)
|
|
161
164
|
if (start_codon && !(start_codon.toUpperCase() in START_CODONS)) {
|
|
@@ -175,12 +178,9 @@ async function checkMRNA(
|
|
|
175
178
|
message: `Unexpected start codon in feature "${_id}": ${start_codon}`,
|
|
176
179
|
})
|
|
177
180
|
}
|
|
181
|
+
|
|
178
182
|
const lastCodon = codons.at(-1) // Last codon is supposed to be a stop
|
|
179
183
|
if (lastCodon && !(lastCodon.toUpperCase() in STOP_CODONS)) {
|
|
180
|
-
const cdsEnd =
|
|
181
|
-
strand === -1
|
|
182
|
-
? cdsLocation.at(0)?.min ?? min
|
|
183
|
-
: cdsLocation.at(-1)?.max ?? max
|
|
184
184
|
checkResults.push({
|
|
185
185
|
_id: new ObjectID().toHexString(),
|
|
186
186
|
name: CHECK_NAME,
|
|
@@ -196,12 +196,12 @@ async function checkMRNA(
|
|
|
196
196
|
checkResults.push({
|
|
197
197
|
_id: new ObjectID().toHexString(),
|
|
198
198
|
name: CHECK_NAME,
|
|
199
|
-
cause: CAUSES[CAUSES.
|
|
199
|
+
cause: CAUSES[CAUSES.MissingStopCodon],
|
|
200
200
|
ids,
|
|
201
201
|
refSeq: refSeq.toString(),
|
|
202
|
-
start:
|
|
203
|
-
end:
|
|
204
|
-
message: `The coding sequence for feature "${_id}" is not a multiple of three`,
|
|
202
|
+
start: cdsEnd,
|
|
203
|
+
end: cdsEnd,
|
|
204
|
+
message: `Missing stop codon: The coding sequence for feature "${_id}" is not a multiple of three`,
|
|
205
205
|
})
|
|
206
206
|
}
|
|
207
207
|
for (const [idx, codon] of codons.entries()) {
|
|
@@ -285,7 +285,7 @@ export class CDSCheck extends Check {
|
|
|
285
285
|
name = CHECK_NAME
|
|
286
286
|
causes = getCauses()
|
|
287
287
|
version = 1
|
|
288
|
-
|
|
288
|
+
isDefault = true
|
|
289
289
|
|
|
290
290
|
async checkFeature(
|
|
291
291
|
feature: AnnotationFeatureSnapshot,
|