@datagrok/sequence-translator 0.0.3 → 0.0.6
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/.eslintrc.json +39 -0
- package/detectors.js +10 -14
- package/package.json +8 -2
- package/setup.cmd +11 -0
- package/src/axolabsMap.ts +101 -99
- package/src/defineAxolabsPattern.ts +242 -207
- package/src/drawAxolabsPattern.ts +127 -92
- package/src/map.ts +538 -353
- package/src/package-test.ts +12 -0
- package/src/package.ts +619 -293
- package/src/save-sense-antisense.ts +44 -0
- package/src/tests/smiles-tests.ts +454 -0
- package/webpack.config.js +7 -1
- package/scripts/convertFastaToSmiles +0 -24
- package/scripts/drawAxolabsPattern +0 -50
package/src/package.ts
CHANGED
|
@@ -3,182 +3,435 @@ import * as grok from 'datagrok-api/grok';
|
|
|
3
3
|
import * as ui from 'datagrok-api/ui';
|
|
4
4
|
import * as DG from 'datagrok-api/dg';
|
|
5
5
|
import * as OCL from 'openchemlib/full.js';
|
|
6
|
-
import $ from
|
|
7
|
-
import {defineAxolabsPattern} from
|
|
8
|
-
import {
|
|
6
|
+
import $ from 'cash-dom';
|
|
7
|
+
import {defineAxolabsPattern} from './defineAxolabsPattern';
|
|
8
|
+
import {saveSenseAntiSense} from './save-sense-antisense';
|
|
9
|
+
import {map, stadardPhosphateLinkSmiles, SYNTHESIZERS, TECHNOLOGIES, MODIFICATIONS} from './map';
|
|
9
10
|
|
|
10
|
-
export
|
|
11
|
+
export const _package = new DG.Package();
|
|
11
12
|
|
|
12
|
-
const defaultInput =
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const undefinedInputSequence = "Type of input sequence is undefined";
|
|
16
|
-
const noTranslationTableAvailable = "No translation table available";
|
|
13
|
+
const defaultInput = 'AGGTCCTCTTGACTTAGGCC';
|
|
14
|
+
const undefinedInputSequence = 'Type of input sequence is undefined';
|
|
15
|
+
const noTranslationTableAvailable = 'No translation table available';
|
|
17
16
|
const sequenceWasCopied = 'Copied';
|
|
18
17
|
const tooltipSequence = 'Copy sequence';
|
|
19
18
|
|
|
20
|
-
function
|
|
21
|
-
|
|
19
|
+
function getAllCodesOfSynthesizer(synthesizer: string): string[] {
|
|
20
|
+
let codes: string[] = [];
|
|
21
|
+
for (const technology of Object.keys(map[synthesizer]))
|
|
22
|
+
codes = codes.concat(Object.keys(map[synthesizer][technology]));
|
|
23
|
+
return codes.concat(Object.keys(MODIFICATIONS));
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
function
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
function getListOfPossibleSynthesizersByFirstMatchedCode(sequence: string): string[] {
|
|
27
|
+
const synthesizers: string[] = [];
|
|
28
|
+
Object.keys(map).forEach((synthesizer: string) => {
|
|
29
|
+
const codes = getAllCodesOfSynthesizer(synthesizer);
|
|
30
|
+
//TODO: get first non-dropdown code when there are two modifications
|
|
31
|
+
let start = 0;
|
|
32
|
+
for (let i = 0; i < sequence.length; i++) {
|
|
33
|
+
if (sequence[i] == ')') {
|
|
34
|
+
start = i + 1;
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (codes.some((s: string) => s == sequence.slice(start, start + s.length)))
|
|
39
|
+
synthesizers.push(synthesizer);
|
|
40
|
+
});
|
|
41
|
+
return synthesizers;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function getListOfPossibleTechnologiesByFirstMatchedCode(sequence: string, synthesizer: string): string[] {
|
|
45
|
+
const technologies: string[] = [];
|
|
46
|
+
Object.keys(map[synthesizer]).forEach((technology: string) => {
|
|
47
|
+
const codes = Object.keys(map[synthesizer][technology]).concat(Object.keys(MODIFICATIONS));
|
|
48
|
+
if (codes.some((s) => s == sequence.slice(0, s.length)))
|
|
49
|
+
technologies.push(technology);
|
|
50
|
+
});
|
|
51
|
+
return technologies;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function isValidSequence(sequence: string): {
|
|
55
|
+
indexOfFirstNotValidCharacter: number,
|
|
56
|
+
expectedSynthesizer: string | null,
|
|
57
|
+
expectedTechnology: string | null
|
|
58
|
+
} {
|
|
59
|
+
const possibleSynthesizers = getListOfPossibleSynthesizersByFirstMatchedCode(sequence);
|
|
60
|
+
if (possibleSynthesizers.length == 0)
|
|
61
|
+
return {indexOfFirstNotValidCharacter: 0, expectedSynthesizer: null, expectedTechnology: null};
|
|
62
|
+
|
|
63
|
+
let outputIndices = Array(possibleSynthesizers.length).fill(0);
|
|
64
|
+
|
|
65
|
+
const firstUniqueCharacters = ['r', 'd'];
|
|
66
|
+
const nucleotides = ['A', 'U', 'T', 'C', 'G'];
|
|
67
|
+
|
|
68
|
+
possibleSynthesizers.forEach((synthesizer, synthesizerIndex) => {
|
|
69
|
+
const codes = getAllCodesOfSynthesizer(synthesizer);
|
|
70
|
+
while (outputIndices[synthesizerIndex] < sequence.length) {
|
|
71
|
+
const matchedCode = codes
|
|
72
|
+
.find((c) => c == sequence.slice(outputIndices[synthesizerIndex], outputIndices[synthesizerIndex] + c.length));
|
|
73
|
+
|
|
74
|
+
if (matchedCode == null)
|
|
75
|
+
break;
|
|
76
|
+
|
|
77
|
+
if ( // for mistake pattern 'rAA'
|
|
78
|
+
outputIndices[synthesizerIndex] > 1 &&
|
|
79
|
+
nucleotides.includes(sequence[outputIndices[synthesizerIndex]]) &&
|
|
80
|
+
firstUniqueCharacters.includes(sequence[outputIndices[synthesizerIndex] - 2])
|
|
81
|
+
) break;
|
|
82
|
+
|
|
83
|
+
if ( // for mistake pattern 'ArA'
|
|
84
|
+
firstUniqueCharacters.includes(sequence[outputIndices[synthesizerIndex] + 1]) &&
|
|
85
|
+
nucleotides.includes(sequence[outputIndices[synthesizerIndex]])
|
|
86
|
+
) {
|
|
87
|
+
outputIndices[synthesizerIndex]++;
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
outputIndices[synthesizerIndex] += matchedCode.length;
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const indexOfExpectedSythesizer = Math.max.apply(Math, outputIndices);
|
|
96
|
+
const indexOfFirstNotValidCharacter = (indexOfExpectedSythesizer == sequence.length) ? -1 : indexOfExpectedSythesizer;
|
|
97
|
+
const expectedSynthesizer = possibleSynthesizers[outputIndices.indexOf(indexOfExpectedSythesizer)];
|
|
98
|
+
if (indexOfFirstNotValidCharacter != -1)
|
|
99
|
+
return {
|
|
100
|
+
indexOfFirstNotValidCharacter: indexOfFirstNotValidCharacter,
|
|
101
|
+
expectedSynthesizer: expectedSynthesizer,
|
|
102
|
+
expectedTechnology: null
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
let possibleTechnologies = getListOfPossibleTechnologiesByFirstMatchedCode(sequence, expectedSynthesizer);
|
|
106
|
+
if (possibleTechnologies.length == 0)
|
|
107
|
+
return { indexOfFirstNotValidCharacter: 0, expectedSynthesizer: null, expectedTechnology: null };
|
|
108
|
+
|
|
109
|
+
outputIndices = Array(possibleTechnologies.length).fill(0);
|
|
110
|
+
|
|
111
|
+
possibleTechnologies.forEach((technology: string, technologyIndex: number) => {
|
|
112
|
+
let codes = Object.keys(map[expectedSynthesizer][technology]);
|
|
113
|
+
while (outputIndices[technologyIndex] < sequence.length) {
|
|
114
|
+
|
|
115
|
+
let matchedCode = codes
|
|
116
|
+
.find((c) => c == sequence.slice(outputIndices[technologyIndex], outputIndices[technologyIndex] + c.length));
|
|
117
|
+
|
|
118
|
+
if (matchedCode == null)
|
|
119
|
+
break;
|
|
120
|
+
|
|
121
|
+
if ( // for mistake pattern 'rAA'
|
|
122
|
+
outputIndices[technologyIndex] > 1 &&
|
|
123
|
+
nucleotides.includes(sequence[outputIndices[technologyIndex]]) &&
|
|
124
|
+
firstUniqueCharacters.includes(sequence[outputIndices[technologyIndex] - 2])
|
|
125
|
+
) break;
|
|
126
|
+
|
|
127
|
+
if ( // for mistake pattern 'ArA'
|
|
128
|
+
firstUniqueCharacters.includes(sequence[outputIndices[technologyIndex] + 1]) &&
|
|
129
|
+
nucleotides.includes(sequence[outputIndices[technologyIndex]])
|
|
130
|
+
) {
|
|
131
|
+
outputIndices[technologyIndex]++;
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
outputIndices[technologyIndex] += matchedCode.length;
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const indexOfExpectedTechnology = Math.max.apply(Math, outputIndices);
|
|
140
|
+
const expectedTechnology = possibleTechnologies[outputIndices.indexOf(indexOfExpectedTechnology)];
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
indexOfFirstNotValidCharacter: indexOfFirstNotValidCharacter,
|
|
144
|
+
expectedSynthesizer: expectedSynthesizer,
|
|
145
|
+
expectedTechnology: expectedTechnology
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function sortByStringLengthInDescendingOrder(array: string[]): string[] {
|
|
150
|
+
return array.sort(function(a: string, b: string) { return b.length - a.length; });
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function getObjectWithCodesAndSmiles(sequence: string) {
|
|
154
|
+
const obj: { [code: string]: string } = {};
|
|
155
|
+
for (const synthesizer of Object.keys(map))
|
|
156
|
+
for (const technology of Object.keys(map[synthesizer]))
|
|
28
157
|
for (let code of Object.keys(map[synthesizer][technology]))
|
|
29
158
|
obj[code] = map[synthesizer][technology][code].SMILES;
|
|
159
|
+
// TODO: create object based from synthesizer type to avoid key(codes) duplicates
|
|
160
|
+
const output = isValidSequence(sequence);
|
|
161
|
+
if (output.expectedSynthesizer == SYNTHESIZERS.MERMADE_12)
|
|
162
|
+
obj['g'] = map[SYNTHESIZERS.MERMADE_12][TECHNOLOGIES.SI_RNA]['g'].SMILES;
|
|
163
|
+
else if (output.expectedSynthesizer == SYNTHESIZERS.AXOLABS)
|
|
164
|
+
obj['g'] = map[SYNTHESIZERS.AXOLABS][TECHNOLOGIES.SI_RNA]['g'].SMILES;
|
|
30
165
|
return obj;
|
|
31
166
|
}
|
|
32
167
|
|
|
33
|
-
function
|
|
34
|
-
const obj = getObjectWithCodesAndSmiles();
|
|
35
|
-
|
|
36
|
-
let i = 0
|
|
168
|
+
export function sequenceToSmiles(sequence: string, inverted: boolean = false): string {
|
|
169
|
+
const obj = getObjectWithCodesAndSmiles(sequence);
|
|
170
|
+
let codes = sortByStringLengthInDescendingOrder(Object.keys(obj));
|
|
171
|
+
let i = 0;
|
|
172
|
+
let smiles = '';
|
|
173
|
+
const codesList = [];
|
|
37
174
|
const links = ['s', 'ps', '*'];
|
|
175
|
+
const includesStandardLinkAlready = ['e', 'h', /*'g',*/ 'f', 'i', 'l', 'k', 'j'];
|
|
176
|
+
const dropdowns = Object.keys(MODIFICATIONS);
|
|
177
|
+
codes = codes.concat(dropdowns);
|
|
38
178
|
while (i < sequence.length) {
|
|
39
|
-
|
|
179
|
+
const code = codes.find((s: string) => s == sequence.slice(i, i + s.length))!;
|
|
40
180
|
i += code.length;
|
|
41
|
-
codesList.push(code);
|
|
181
|
+
inverted ? codesList.unshift(code) : codesList.push(code);
|
|
42
182
|
}
|
|
43
|
-
for (let i = 0; i < codesList.length; i++)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
183
|
+
for (let i = 0; i < codesList.length; i++) {
|
|
184
|
+
if (dropdowns.includes(codesList[i])) {
|
|
185
|
+
if (i == codesList.length -1 || (i < codesList.length - 1 && links.includes(codesList[i + 1]))) {
|
|
186
|
+
smiles += (i >= codesList.length / 2) ?
|
|
187
|
+
MODIFICATIONS[codesList[i]].right:
|
|
188
|
+
MODIFICATIONS[codesList[i]].left;
|
|
189
|
+
} else if (i < codesList.length - 1) {
|
|
190
|
+
smiles += (i >= codesList.length / 2) ?
|
|
191
|
+
MODIFICATIONS[codesList[i]].right + stadardPhosphateLinkSmiles:
|
|
192
|
+
MODIFICATIONS[codesList[i]].left + stadardPhosphateLinkSmiles;
|
|
193
|
+
}
|
|
194
|
+
} else {
|
|
195
|
+
if (links.includes(codesList[i]) ||
|
|
196
|
+
includesStandardLinkAlready.includes(codesList[i]) ||
|
|
197
|
+
(i < codesList.length - 1 && links.includes(codesList[i + 1]))
|
|
198
|
+
)
|
|
199
|
+
smiles += obj[codesList[i]];
|
|
200
|
+
else
|
|
201
|
+
smiles += obj[codesList[i]] + stadardPhosphateLinkSmiles;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
smiles = smiles.replace(/OO/g, 'O');
|
|
205
|
+
return (
|
|
206
|
+
(
|
|
207
|
+
links.includes(codesList[codesList.length - 1]) &&
|
|
208
|
+
codesList.length > 1 &&
|
|
209
|
+
!includesStandardLinkAlready.includes(codesList[codesList.length - 2])
|
|
210
|
+
) ||
|
|
211
|
+
dropdowns.includes(codesList[codesList.length - 1]) ||
|
|
212
|
+
includesStandardLinkAlready.includes(codesList[codesList.length - 1])
|
|
213
|
+
) ?
|
|
214
|
+
smiles :
|
|
215
|
+
smiles.slice(0, smiles.length - stadardPhosphateLinkSmiles.length + 1);
|
|
49
216
|
}
|
|
50
217
|
|
|
51
218
|
//name: Sequence Translator
|
|
52
219
|
//tags: app
|
|
53
|
-
export function sequenceTranslator() {
|
|
54
|
-
|
|
55
|
-
let windows = grok.shell.windows;
|
|
220
|
+
export function sequenceTranslator(): void {
|
|
221
|
+
const windows = grok.shell.windows;
|
|
56
222
|
windows.showProperties = false;
|
|
57
223
|
windows.showToolbox = false;
|
|
58
224
|
windows.showHelp = false;
|
|
59
225
|
|
|
60
|
-
function
|
|
61
|
-
moleculeSvgDiv.innerHTML =
|
|
62
|
-
outputTableDiv.innerHTML =
|
|
63
|
-
|
|
64
|
-
let
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
tableRows
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
226
|
+
function updateTableAndMolecule(sequence: string): void {
|
|
227
|
+
moleculeSvgDiv.innerHTML = '';
|
|
228
|
+
outputTableDiv.innerHTML = '';
|
|
229
|
+
const pi = DG.TaskBarProgressIndicator.create('Rendering table and molecule...');
|
|
230
|
+
let errorsExist = false;
|
|
231
|
+
try {
|
|
232
|
+
const outputSequenceObj = convertSequence(sequence);
|
|
233
|
+
const tableRows = [];
|
|
234
|
+
|
|
235
|
+
for (const key of Object.keys(outputSequenceObj).slice(1)) {
|
|
236
|
+
let indexOfFirstNotValidCharacter = ('indexOfFirstNotValidCharacter' in outputSequenceObj) ?
|
|
237
|
+
JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!).indexOfFirstNotValidCharacter :
|
|
238
|
+
-1;
|
|
239
|
+
if ('indexOfFirstNotValidCharacter' in outputSequenceObj) {
|
|
240
|
+
let indexOfFirstNotValidCharacter = ('indexOfFirstNotValidCharacter' in outputSequenceObj) ?
|
|
241
|
+
JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!).indexOfFirstNotValidCharacter :
|
|
242
|
+
-1;
|
|
243
|
+
if (indexOfFirstNotValidCharacter != -1)
|
|
244
|
+
errorsExist = true;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
tableRows.push({
|
|
248
|
+
'key': key,
|
|
249
|
+
'value': ('indexOfFirstNotValidCharacter' in outputSequenceObj) ?
|
|
250
|
+
ui.divH([
|
|
251
|
+
ui.divText(sequence.slice(0, indexOfFirstNotValidCharacter), {style: {color: 'grey'}}),
|
|
252
|
+
ui.tooltip.bind(
|
|
253
|
+
ui.divText(sequence.slice(indexOfFirstNotValidCharacter), {style: {color: 'red'}}),
|
|
254
|
+
'Expected format: ' + JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!).expectedSynthesizer + '. See tables with valid codes on the right'
|
|
255
|
+
),
|
|
256
|
+
]) : //@ts-ignore
|
|
257
|
+
ui.link(outputSequenceObj[key], () => navigator.clipboard.writeText(outputSequenceObj[key]).then(() => grok.shell.info(sequenceWasCopied)), tooltipSequence, '')
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (errorsExist) {
|
|
262
|
+
const expectedSynthesizer = JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!).expectedSynthesizer.slice(0, -6);
|
|
263
|
+
asoGapmersGrid.onCellPrepare(function (gc) {
|
|
264
|
+
gc.style.backColor = (gc.gridColumn.name == expectedSynthesizer) ? 0xFFF00000 : 0xFFFFFFFF;
|
|
265
|
+
});
|
|
266
|
+
omeAndFluoroGrid.onCellPrepare(function (gc) {
|
|
267
|
+
gc.style.backColor = (gc.gridColumn.name == expectedSynthesizer) ? 0xFFF00000 : 0xFFFFFFFF;
|
|
268
|
+
});
|
|
269
|
+
switchInput.enabled = true;
|
|
270
|
+
} else {
|
|
271
|
+
asoGapmersGrid.onCellPrepare(function (gc) {
|
|
272
|
+
gc.style.backColor = 0xFFFFFFFF;
|
|
273
|
+
});
|
|
274
|
+
omeAndFluoroGrid.onCellPrepare(function (gc) {
|
|
275
|
+
gc.style.backColor = 0xFFFFFFFF;
|
|
276
|
+
});
|
|
90
277
|
}
|
|
278
|
+
|
|
279
|
+
outputTableDiv.append(
|
|
280
|
+
ui.div([
|
|
281
|
+
DG.HtmlTable.create(tableRows, (item: { key: string; value: string; }) => [item.key, item.value], ['Code', 'Sequence']).root
|
|
282
|
+
], 'table')
|
|
283
|
+
);
|
|
284
|
+
semTypeOfInputSequence.textContent = 'Detected input type: ' + outputSequenceObj.type;
|
|
285
|
+
|
|
286
|
+
if (outputSequenceObj.type != undefinedInputSequence && outputSequenceObj.Error != undefinedInputSequence) {
|
|
287
|
+
let canvas = ui.canvas(300, 170);
|
|
288
|
+
canvas.addEventListener("click", () => {
|
|
289
|
+
let canv = ui.canvas($(window).width(), $(window).height());
|
|
290
|
+
const smiles = sequenceToSmiles(inputSequenceField.value.replace(/\s/g, ''));
|
|
291
|
+
// @ts-ignore
|
|
292
|
+
OCL.StructureView.drawMolecule(canv, OCL.Molecule.fromSmiles(smiles), { suppressChiralText: true });
|
|
293
|
+
ui.dialog('Molecule')
|
|
294
|
+
.add(canv)
|
|
295
|
+
.showModal(true);
|
|
296
|
+
});
|
|
297
|
+
$(canvas).on('mouseover', () => $(canvas).css('cursor', 'zoom-in'));
|
|
298
|
+
$(canvas).on('mouseout', () => $(canvas).css('cursor', 'default'));
|
|
299
|
+
const smiles = sequenceToSmiles(inputSequenceField.value.replace(/\s/g, ''));
|
|
300
|
+
// @ts-ignore
|
|
301
|
+
OCL.StructureView.drawMolecule(canvas, OCL.Molecule.fromSmiles(smiles), { suppressChiralText: true });
|
|
302
|
+
moleculeSvgDiv.append(canvas);
|
|
303
|
+
} else
|
|
304
|
+
moleculeSvgDiv.innerHTML = '';
|
|
305
|
+
} finally {
|
|
306
|
+
pi.close();
|
|
91
307
|
}
|
|
92
308
|
}
|
|
93
309
|
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
310
|
+
const semTypeOfInputSequence = ui.divText('');
|
|
311
|
+
const moleculeSvgDiv = ui.block([]);
|
|
312
|
+
const outputTableDiv = ui.div([], 'table');
|
|
313
|
+
const inputSequenceField = ui.textInput('', defaultInput, (sequence: string) => updateTableAndMolecule(sequence));
|
|
314
|
+
|
|
315
|
+
const asoDf = DG.DataFrame.fromObjects([
|
|
316
|
+
{ Name: "2'MOE-5Me-rU", BioSpring: "5", "Janssen GCRS": "moeT" },
|
|
317
|
+
{ Name: "2'MOE-rA", BioSpring: "6", "Janssen GCRS": "moeA" },
|
|
318
|
+
{ Name: "2'MOE-5Me-rC", BioSpring: "7", "Janssen GCRS": "moe5mC" },
|
|
319
|
+
{ Name: "2'MOE-rG", BioSpring: "8", "Janssen GCRS": "moeG" },
|
|
320
|
+
{ Name: "5-Methyl-dC", BioSpring: "9", "Janssen GCRS": "5mC" },
|
|
321
|
+
{ Name: "ps linkage", BioSpring: "*", "Janssen GCRS": "ps" },
|
|
322
|
+
{ Name: "dA", BioSpring: "A", "Janssen GCRS": "A, dA" },
|
|
323
|
+
{ Name: "dC", BioSpring: "C", "Janssen GCRS": "C, dC" },
|
|
324
|
+
{ Name: "dG", BioSpring: "G", "Janssen GCRS": "G, dG" },
|
|
325
|
+
{ Name: "dT", BioSpring: "T", "Janssen GCRS": "T, dT" },
|
|
326
|
+
{ Name: "rA", BioSpring: "", "Janssen GCRS": "rA" },
|
|
327
|
+
{ Name: "rC", BioSpring: "", "Janssen GCRS": "rC" },
|
|
328
|
+
{ Name: "rG", BioSpring: "", "Janssen GCRS": "rG" },
|
|
329
|
+
{ Name: "rU", BioSpring: "", "Janssen GCRS": "rU" }
|
|
330
|
+
])!;
|
|
331
|
+
const asoGapmersGrid = DG.Viewer.grid(
|
|
332
|
+
asoDf, { showRowHeader: false, showCellTooltip: false }
|
|
102
333
|
);
|
|
103
334
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
335
|
+
asoDf.onCurrentCellChanged.subscribe((_) => {
|
|
336
|
+
navigator.clipboard.writeText(asoDf.currentCell.value).then(() => grok.shell.info('Copied'))
|
|
337
|
+
});
|
|
107
338
|
|
|
108
|
-
let
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
339
|
+
let omeAndFluoroGrid = DG.Viewer.grid(
|
|
340
|
+
DG.DataFrame.fromObjects([
|
|
341
|
+
{ Name: "2'-fluoro-U", BioSpring: "1", Axolabs: "Uf", "Janssen GCRS": "fU" },
|
|
342
|
+
{ Name: "2'-fluoro-A", BioSpring: "2", Axolabs: "Af", "Janssen GCRS": "fA" },
|
|
343
|
+
{ Name: "2'-fluoro-C", BioSpring: "3", Axolabs: "Cf", "Janssen GCRS": "fC" },
|
|
344
|
+
{ Name: "2'-fluoro-G", BioSpring: "4", Axolabs: "Gf", "Janssen GCRS": "fG" },
|
|
345
|
+
{ Name: "2'OMe-rU", BioSpring: "5", Axolabs: "u", "Janssen GCRS": "mU" },
|
|
346
|
+
{ Name: "2'OMe-rA", BioSpring: "6", Axolabs: "a", "Janssen GCRS": "mA" },
|
|
347
|
+
{ Name: "2'OMe-rC", BioSpring: "7", Axolabs: "c", "Janssen GCRS": "mC" },
|
|
348
|
+
{ Name: "2'OMe-rG", BioSpring: "8", Axolabs: "g", "Janssen GCRS": "mG" },
|
|
349
|
+
{ Name: "ps linkage", BioSpring: "*", Axolabs: "s", "Janssen GCRS": "ps" }
|
|
350
|
+
])!, { showRowHeader: false, showCellTooltip: false }
|
|
116
351
|
);
|
|
117
352
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
DG.HtmlTable.create(
|
|
126
|
-
tableRows,
|
|
127
|
-
(item: {name: string; code: string;}) => [item['name'], item['code']],
|
|
128
|
-
[synthesizer + ' ' + technology, 'Code']
|
|
129
|
-
).root,
|
|
130
|
-
ui.div([], {style: {height: '30px'}})
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
353
|
+
const overhangModificationsGrid = DG.Viewer.grid(
|
|
354
|
+
DG.DataFrame.fromObjects([
|
|
355
|
+
{ Name: "(invabasic)" },
|
|
356
|
+
{ Name: "(GalNAc-2-JNJ)" }
|
|
357
|
+
])!, { showRowHeader: false, showCellTooltip: false }
|
|
358
|
+
);
|
|
359
|
+
updateTableAndMolecule(defaultInput);
|
|
134
360
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
flavor = outputSequenceObj.Nucleotides.includes('U') ? "RNA_both_caps" : "DNA_both_caps";
|
|
145
|
-
let smiles = (/^[ATGCU]{6,}$/.test(inputSequenceField.value.replace(/\s/g, ''))) ?
|
|
146
|
-
await nucleotidesToSmiles(outputSequenceObj.Nucleotides, flavor) :
|
|
147
|
-
modifiedToSmiles(inputSequenceField.value.replace(/\s/g, ''));
|
|
148
|
-
smiles = smiles.replace(/@/g, ''); // Remove StereoChemistry on the Nucleic acid chain and remove the Chiral label
|
|
149
|
-
let mol = OCL.Molecule.fromSmiles(smiles);
|
|
150
|
-
let result = `${mol.toMolfile()}\n`;// + '$$$$';
|
|
151
|
-
var element = document.createElement('a');
|
|
152
|
-
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(result));
|
|
153
|
-
element.setAttribute('download', inputSequenceField.value.replace(/\s/g, '') + '.mol');
|
|
154
|
-
element.click();
|
|
155
|
-
});
|
|
361
|
+
const appMainDescription = ui.info([
|
|
362
|
+
ui.divText('How to convert one sequence:',{style:{'font-weight':'bolder'}}),
|
|
363
|
+
ui.divText('Paste sequence into the text field below'),
|
|
364
|
+
ui.divText('\n How to convert many sequences:',{style:{'font-weight':'bolder'}}),
|
|
365
|
+
ui.divText('1. Drag & drop an Excel or CSV file with sequences into Datagrok. The platform will automatically detect columns with sequences'),
|
|
366
|
+
ui.divText('2. Right-click on the column header, then see the \'Convert\' menu'),
|
|
367
|
+
ui.divText('This will add the result column to the right of the table'),
|
|
368
|
+
], 'Convert oligonucleotide sequences between Nucleotides, BioSpring, Axolabs, Mermade 12 and GCRS representations.'
|
|
369
|
+
);
|
|
156
370
|
|
|
157
|
-
|
|
158
|
-
ui.
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
371
|
+
const codesTablesDiv = ui.splitV([
|
|
372
|
+
ui.box(ui.h2('ASO Gapmers'), { style: {maxHeight: '40px'} }),
|
|
373
|
+
asoGapmersGrid.root,
|
|
374
|
+
ui.box(ui.h2("2'-OMe and 2'-F siRNA"), { style: {maxHeight: '40px'} }),
|
|
375
|
+
omeAndFluoroGrid.root,
|
|
376
|
+
ui.box(ui.h2('Overhang modifications'), { style: {maxHeight: '40px'} }),
|
|
377
|
+
overhangModificationsGrid.root
|
|
378
|
+
], { style: { maxWidth: '350px' } });
|
|
379
|
+
|
|
380
|
+
const tabControl = ui.tabControl({
|
|
381
|
+
'MAIN': ui.box(
|
|
382
|
+
ui.splitH([
|
|
383
|
+
ui.splitV([
|
|
384
|
+
ui.panel([
|
|
385
|
+
appMainDescription,
|
|
164
386
|
ui.div([
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
387
|
+
ui.h1('Input sequence'),
|
|
388
|
+
ui.div([
|
|
389
|
+
inputSequenceField.root,
|
|
390
|
+
], 'input-base'),
|
|
391
|
+
], 'sequenceInput'),
|
|
392
|
+
semTypeOfInputSequence,
|
|
393
|
+
ui.block([
|
|
394
|
+
ui.h1('Output'),
|
|
395
|
+
outputTableDiv,
|
|
396
|
+
]),
|
|
397
|
+
moleculeSvgDiv,
|
|
398
|
+
], 'sequence'),
|
|
399
|
+
]),
|
|
400
|
+
codesTablesDiv,
|
|
401
|
+
], {style: {height: '100%', width: '100%'}}),
|
|
402
|
+
),
|
|
403
|
+
'AXOLABS': defineAxolabsPattern(),
|
|
404
|
+
'SDF': saveSenseAntiSense(),
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
let v = grok.shell.newView('Sequence Translator', [tabControl]);
|
|
180
408
|
v.box = true;
|
|
181
409
|
|
|
410
|
+
const switchInput = ui.switchInput('Codes', true, (v: boolean) => (v) ?
|
|
411
|
+
$(codesTablesDiv).show() :
|
|
412
|
+
$(codesTablesDiv).hide()
|
|
413
|
+
);
|
|
414
|
+
|
|
415
|
+
const topPanel = [
|
|
416
|
+
ui.iconFA('download', () => {
|
|
417
|
+
const smiles = sequenceToSmiles(inputSequenceField.value.replace(/\s/g, ''));
|
|
418
|
+
const result = `${OCL.Molecule.fromSmiles(smiles).toMolfile()}\n`;
|
|
419
|
+
const element = document.createElement('a');
|
|
420
|
+
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(result));
|
|
421
|
+
element.setAttribute('download', inputSequenceField.value.replace(/\s/g, '') + '.mol');
|
|
422
|
+
element.click();
|
|
423
|
+
}, 'Save .mol file'),
|
|
424
|
+
ui.iconFA('copy', () => {
|
|
425
|
+
navigator.clipboard.writeText(sequenceToSmiles(inputSequenceField.value.replace(/\s/g, '')))
|
|
426
|
+
.then(() => grok.shell.info(sequenceWasCopied));
|
|
427
|
+
}, 'Copy SMILES'),
|
|
428
|
+
switchInput.root,
|
|
429
|
+
];
|
|
430
|
+
|
|
431
|
+
tabControl.onTabChanged.subscribe((_) =>
|
|
432
|
+
v.setRibbonPanels([(tabControl.currentPane.name == 'MAIN') ? topPanel : []]));
|
|
433
|
+
v.setRibbonPanels([topPanel]);
|
|
434
|
+
|
|
182
435
|
$('.sequence')
|
|
183
436
|
.children().css('padding','5px 0');
|
|
184
437
|
$('.sequenceInput .input-base')
|
|
@@ -187,109 +440,89 @@ export function sequenceTranslator() {
|
|
|
187
440
|
.css('resize','none')
|
|
188
441
|
.css('min-height','50px')
|
|
189
442
|
.css('width','100%')
|
|
190
|
-
.attr(
|
|
443
|
+
.attr('spellcheck', 'false');
|
|
191
444
|
$('.sequenceInput select')
|
|
192
445
|
.css('width','100%');
|
|
193
446
|
}
|
|
194
447
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
export function isDnaNucleotidesCode(sequence: string) {return /^[ATGC]{6,}$/.test(sequence);}
|
|
203
|
-
export function isRnaNucleotidesCode(sequence: string) {return /^[AUGC]{6,}$/.test(sequence);}
|
|
204
|
-
export function isAsoGapmerBioSpringCode(sequence: string) {return /^[*56789ATGC]{6,}$/.test(sequence);}
|
|
205
|
-
export function isAsoGapmerGcrsCode(sequence: string) {return /^(?=.*moe)(?=.*5mC)(?=.*ps){6,}/.test(sequence);}
|
|
206
|
-
export function isSiRnaBioSpringCode(sequence: string) {return /^[*1-8]{6,}$/.test(sequence);}
|
|
207
|
-
export function isSiRnaAxolabsCode(sequence: string) {return /^[fsACGUacgu]{6,}$/.test(sequence);}
|
|
208
|
-
export function isSiRnaGcrsCode(sequence: string) {return /^[fmpsACGU]{6,}$/.test(sequence);}
|
|
209
|
-
export function isGcrsCode(sequence: string) {return /^[fmpsACGU]{6,}$/.test(sequence);}
|
|
210
|
-
export function isMM12Code(sequence: string) {return /^[IiJjKkLlEeFfGgHhQq]{6,}$/.test(sequence);}
|
|
211
|
-
|
|
212
|
-
function convertSequence(seq: string) {
|
|
213
|
-
seq = seq.replace(/\s/g, '');
|
|
214
|
-
if (seq.length < minimalValidNumberOfCharacters)
|
|
448
|
+
function convertSequence(text: string) {
|
|
449
|
+
text = text.replace(/\s/g, '');
|
|
450
|
+
let seq = text;
|
|
451
|
+
let output = isValidSequence(seq);
|
|
452
|
+
if (output.indexOfFirstNotValidCharacter != -1)
|
|
215
453
|
return {
|
|
216
|
-
type:
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
Axolabs: smallNumberOfCharacters,
|
|
220
|
-
GCRS: smallNumberOfCharacters
|
|
454
|
+
// type: '',
|
|
455
|
+
indexOfFirstNotValidCharacter: JSON.stringify(output),
|
|
456
|
+
Error: undefinedInputSequence
|
|
221
457
|
};
|
|
222
|
-
if (
|
|
458
|
+
if (output.expectedSynthesizer == SYNTHESIZERS.RAW_NUCLEOTIDES && output.expectedTechnology == TECHNOLOGIES.DNA)
|
|
223
459
|
return {
|
|
224
|
-
type:
|
|
460
|
+
type: SYNTHESIZERS.RAW_NUCLEOTIDES + ' ' + TECHNOLOGIES.DNA,
|
|
225
461
|
Nucleotides: seq,
|
|
226
462
|
BioSpring: asoGapmersNucleotidesToBioSpring(seq),
|
|
227
|
-
Axolabs: noTranslationTableAvailable,
|
|
228
463
|
GCRS: asoGapmersNucleotidesToGcrs(seq)
|
|
229
464
|
};
|
|
230
|
-
if (
|
|
465
|
+
if (output.expectedSynthesizer == SYNTHESIZERS.BIOSPRING && output.expectedTechnology == TECHNOLOGIES.ASO_GAPMERS)
|
|
231
466
|
return {
|
|
232
|
-
type:
|
|
467
|
+
type: SYNTHESIZERS.BIOSPRING + ' ' + TECHNOLOGIES.ASO_GAPMERS,
|
|
233
468
|
Nucleotides: asoGapmersBioSpringToNucleotides(seq),
|
|
234
469
|
BioSpring: seq,
|
|
235
|
-
Axolabs: noTranslationTableAvailable,
|
|
236
470
|
GCRS: asoGapmersBioSpringToGcrs(seq)
|
|
237
471
|
};
|
|
238
|
-
if (
|
|
472
|
+
if (output.expectedSynthesizer == SYNTHESIZERS.GCRS && output.expectedTechnology == TECHNOLOGIES.ASO_GAPMERS)
|
|
239
473
|
return {
|
|
240
|
-
type:
|
|
474
|
+
type: SYNTHESIZERS.GCRS + ' ' + TECHNOLOGIES.ASO_GAPMERS,
|
|
241
475
|
Nucleotides: asoGapmersGcrsToNucleotides(seq),
|
|
242
476
|
BioSpring: asoGapmersGcrsToBioSpring(seq),
|
|
243
|
-
|
|
244
|
-
MM12: gcrsToMM12(seq),
|
|
477
|
+
Mermade12: gcrsToMermade12(seq),
|
|
245
478
|
GCRS: seq
|
|
246
479
|
};
|
|
247
|
-
if (
|
|
480
|
+
if (output.expectedSynthesizer == SYNTHESIZERS.RAW_NUCLEOTIDES && output.expectedTechnology == TECHNOLOGIES.RNA)
|
|
248
481
|
return {
|
|
249
|
-
type:
|
|
482
|
+
type: SYNTHESIZERS.RAW_NUCLEOTIDES + ' ' + TECHNOLOGIES.RNA,
|
|
250
483
|
Nucleotides: seq,
|
|
251
484
|
BioSpring: siRnaNucleotideToBioSpringSenseStrand(seq),
|
|
252
485
|
Axolabs: siRnaNucleotideToAxolabsSenseStrand(seq),
|
|
253
486
|
GCRS: siRnaNucleotidesToGcrs(seq)
|
|
254
487
|
};
|
|
255
|
-
if (
|
|
488
|
+
if (output.expectedSynthesizer == SYNTHESIZERS.BIOSPRING && output.expectedTechnology == TECHNOLOGIES.SI_RNA)
|
|
256
489
|
return {
|
|
257
|
-
type:
|
|
490
|
+
type: SYNTHESIZERS.BIOSPRING + ' ' + TECHNOLOGIES.SI_RNA,
|
|
258
491
|
Nucleotides: siRnaBioSpringToNucleotides(seq),
|
|
259
492
|
BioSpring: seq,
|
|
260
493
|
Axolabs: siRnaBioSpringToAxolabs(seq),
|
|
261
494
|
GCRS: siRnaBioSpringToGcrs(seq)
|
|
262
495
|
};
|
|
263
|
-
if (
|
|
496
|
+
if (output.expectedSynthesizer == SYNTHESIZERS.AXOLABS && output.expectedTechnology == TECHNOLOGIES.SI_RNA)
|
|
264
497
|
return {
|
|
265
|
-
type:
|
|
498
|
+
type: SYNTHESIZERS.AXOLABS + ' ' + TECHNOLOGIES.SI_RNA,
|
|
266
499
|
Nucleotides: siRnaAxolabsToNucleotides(seq),
|
|
267
500
|
BioSpring: siRnaAxolabsToBioSpring(seq),
|
|
268
501
|
Axolabs: seq,
|
|
269
502
|
GCRS: siRnaAxolabsToGcrs(seq)
|
|
270
503
|
};
|
|
271
|
-
if (
|
|
504
|
+
if (output.expectedSynthesizer == SYNTHESIZERS.GCRS && output.expectedTechnology == TECHNOLOGIES.SI_RNA)
|
|
272
505
|
return {
|
|
273
|
-
type:
|
|
506
|
+
type: SYNTHESIZERS.GCRS + ' ' + TECHNOLOGIES.SI_RNA,
|
|
274
507
|
Nucleotides: siRnaGcrsToNucleotides(seq),
|
|
275
508
|
BioSpring: siRnaGcrsToBioSpring(seq),
|
|
276
509
|
Axolabs: siRnaGcrsToAxolabs(seq),
|
|
277
|
-
MM12:
|
|
510
|
+
MM12: gcrsToMermade12(seq),
|
|
278
511
|
GCRS: seq
|
|
279
512
|
};
|
|
280
|
-
if (
|
|
513
|
+
if (output.expectedSynthesizer == SYNTHESIZERS.GCRS)
|
|
281
514
|
return {
|
|
282
|
-
type:
|
|
515
|
+
type: SYNTHESIZERS.GCRS,
|
|
283
516
|
Nucleotides: gcrsToNucleotides(seq),
|
|
284
517
|
GCRS: seq,
|
|
285
|
-
|
|
518
|
+
Mermade12: gcrsToMermade12(seq)
|
|
286
519
|
}
|
|
287
|
-
if (
|
|
520
|
+
if (output.expectedSynthesizer == SYNTHESIZERS.MERMADE_12)
|
|
288
521
|
return {
|
|
289
|
-
type:
|
|
522
|
+
type: SYNTHESIZERS.MERMADE_12,
|
|
290
523
|
Nucleotides: noTranslationTableAvailable,
|
|
291
524
|
GCRS: noTranslationTableAvailable,
|
|
292
|
-
|
|
525
|
+
Mermade12: seq
|
|
293
526
|
};
|
|
294
527
|
return {
|
|
295
528
|
type: undefinedInputSequence,
|
|
@@ -300,49 +533,49 @@ function convertSequence(seq: string) {
|
|
|
300
533
|
//name: asoGapmersNucleotidesToBioSpring
|
|
301
534
|
//input: string nucleotides {semType: DNA nucleotides}
|
|
302
535
|
//output: string result {semType: BioSpring / Gapmers}
|
|
303
|
-
export function asoGapmersNucleotidesToBioSpring(nucleotides: string) {
|
|
536
|
+
export function asoGapmersNucleotidesToBioSpring(nucleotides: string): string {
|
|
304
537
|
let count: number = -1;
|
|
305
|
-
const objForEdges: {[index: string]: string} = {
|
|
306
|
-
const objForCenter: {[index: string]: string} = {
|
|
307
|
-
return nucleotides.replace(/
|
|
538
|
+
const objForEdges: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'T': '5*', 'A': '6*', 'C': '7*', 'G': '8*'};
|
|
539
|
+
const objForCenter: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'T': 'T*', 'A': 'A*', 'C': '9*', 'G': 'G*'};
|
|
540
|
+
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|A|T|C|G)/g, function (x: string) {
|
|
308
541
|
count++;
|
|
309
542
|
return (count > 4 && count < 15) ? objForCenter[x] : objForEdges[x];
|
|
310
|
-
}).slice(0, 2 * count + 1);
|
|
543
|
+
}).slice(0, (nucleotides.endsWith('(invabasic)') || nucleotides.endsWith('(GalNAc-2-JNJ)')) ? nucleotides.length : 2 * count + 1);
|
|
311
544
|
}
|
|
312
545
|
|
|
313
546
|
//name: asoGapmersNucleotidesToGcrs
|
|
314
547
|
//input: string nucleotides {semType: DNA nucleotides}
|
|
315
548
|
//output: string result {semType: GCRS / Gapmers}
|
|
316
|
-
export function asoGapmersNucleotidesToGcrs(nucleotides: string) {
|
|
549
|
+
export function asoGapmersNucleotidesToGcrs(nucleotides: string): string {
|
|
317
550
|
let count: number = -1;
|
|
318
|
-
const objForEdges: {[index: string]: string} = {
|
|
319
|
-
const objForCenter: {[index: string]: string} = {
|
|
320
|
-
return nucleotides.replace(/
|
|
551
|
+
const objForEdges: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'T': 'moeUnps', 'A': 'moeAnps', 'C': 'moe5mCnps', 'G': 'moeGnps'};
|
|
552
|
+
const objForCenter: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'C': '5mCps', 'A': 'Aps', 'T': 'Tps', 'G': 'Gps'};
|
|
553
|
+
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|A|T|C|G)/g, function (x: string) {
|
|
321
554
|
count++;
|
|
322
555
|
if (count < 5) return (count == 4) ? objForEdges[x].slice(0, -3) + 'ps' : objForEdges[x];
|
|
323
556
|
if (count < 15) return (count == 14) ? objForCenter[x].slice(0, -2) + 'nps' : objForCenter[x];
|
|
324
557
|
return objForEdges[x];
|
|
325
|
-
}).slice(0, -3);
|
|
558
|
+
}).slice(0, (nucleotides.endsWith('(invabasic)') || nucleotides.endsWith('(GalNAc-2-JNJ)')) ? nucleotides.length : -3);
|
|
326
559
|
}
|
|
327
560
|
|
|
328
561
|
//name: asoGapmersBioSpringToNucleotides
|
|
329
562
|
//input: string nucleotides {semType: BioSpring / Gapmers}
|
|
330
563
|
//output: string result {semType: DNA nucleotides}
|
|
331
|
-
export function asoGapmersBioSpringToNucleotides(nucleotides: string) {
|
|
332
|
-
const obj: {[index: string]: string} = {
|
|
333
|
-
return nucleotides.replace(/
|
|
564
|
+
export function asoGapmersBioSpringToNucleotides(nucleotides: string): string {
|
|
565
|
+
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', '*': '', '5': 'T', '6': 'A', '7': 'C', '8': 'G', '9': 'C'};
|
|
566
|
+
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|\*|5|6|7|8|9)/g, function (x: string) {return obj[x];});
|
|
334
567
|
}
|
|
335
568
|
|
|
336
569
|
//name: asoGapmersBioSpringToGcrs
|
|
337
570
|
//input: string nucleotides {semType: BioSpring / Gapmers}
|
|
338
571
|
//output: string result {semType: GCRS / Gapmers}
|
|
339
|
-
export function asoGapmersBioSpringToGcrs(nucleotides: string) {
|
|
572
|
+
export function asoGapmersBioSpringToGcrs(nucleotides: string): string {
|
|
340
573
|
let count: number = -1;
|
|
341
|
-
const obj: {[index: string]: string} = {
|
|
342
|
-
|
|
343
|
-
|
|
574
|
+
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)',
|
|
575
|
+
'5*': 'moeUnps', '6*': 'moeAnps', '7*': 'moe5mCnps', '8*': 'moeGnps', '9*': '5mCps', 'A*': 'Aps', 'T*': 'Tps',
|
|
576
|
+
'G*': 'Gps', 'C*': 'Cps', '5': 'moeU', '6': 'moeA', '7': 'moe5mC', '8': 'moeG'
|
|
344
577
|
};
|
|
345
|
-
return nucleotides.replace(/(5\*|6\*|7\*|8\*|9\*|A\*|T\*|G\*|C\*|5|6|7|8)/g, function (x: string) {
|
|
578
|
+
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|5\*|6\*|7\*|8\*|9\*|A\*|T\*|G\*|C\*|5|6|7|8)/g, function (x: string) {
|
|
346
579
|
count++;
|
|
347
580
|
return (count == 4) ? obj[x].slice(0, -3) + 'ps' : (count == 14) ? obj[x].slice(0, -2) + 'nps' : obj[x];
|
|
348
581
|
});
|
|
@@ -351,103 +584,103 @@ export function asoGapmersBioSpringToGcrs(nucleotides: string) {
|
|
|
351
584
|
//name: asoGapmersGcrsToBioSpring
|
|
352
585
|
//input: string nucleotides {semType: GCRS / Gapmers}
|
|
353
586
|
//output: string result {semType: BioSpring / Gapmers}
|
|
354
|
-
export function asoGapmersGcrsToBioSpring(nucleotides: string) {
|
|
355
|
-
const obj: {[index: string]: string} = {
|
|
356
|
-
|
|
587
|
+
export function asoGapmersGcrsToBioSpring(nucleotides: string): string {
|
|
588
|
+
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)',
|
|
589
|
+
'moeT': '5', 'moeA': '6', 'moe5mC': '7', 'moeG': '8', 'moeU': '5', '5mC': '9', 'nps': '*', 'ps': '*', 'U': 'T'
|
|
357
590
|
};
|
|
358
|
-
return nucleotides.replace(/(moeT|moeA|moe5mC|moeG|moeU|5mC|nps|ps|U)/g, function (x: string) {return obj[x];});
|
|
591
|
+
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|moeT|moeA|moe5mC|moeG|moeU|5mC|nps|ps|U)/g, function (x: string) {return obj[x];});
|
|
359
592
|
}
|
|
360
593
|
|
|
361
594
|
//name: asoGapmersGcrsToNucleotides
|
|
362
595
|
//input: string nucleotides {semType: GCRS / Gapmers}
|
|
363
596
|
//output: string result {semType: DNA nucleotides}
|
|
364
597
|
export function asoGapmersGcrsToNucleotides(nucleotides: string) {
|
|
365
|
-
const obj: {[index: string]: string} = {
|
|
366
|
-
return nucleotides.replace(/(moe|5m|n|ps|U)/g, function (x: string) {return obj[x];});
|
|
598
|
+
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'moe': '', '5m': '', 'n': '', 'ps': '', 'U': 'T'};
|
|
599
|
+
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|moe|5m|n|ps|U)/g, function (x: string) {return obj[x];});
|
|
367
600
|
}
|
|
368
601
|
|
|
369
602
|
//name: siRnaBioSpringToNucleotides
|
|
370
603
|
//input: string nucleotides {semType: BioSpring / siRNA}
|
|
371
604
|
//output: string result {semType: RNA nucleotides}
|
|
372
605
|
export function siRnaBioSpringToNucleotides(nucleotides: string) {
|
|
373
|
-
const obj: {[index: string]: string} = {
|
|
374
|
-
return nucleotides.replace(/
|
|
606
|
+
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', '1': 'U', '2': 'A', '3': 'C', '4': 'G', '5': 'U', '6': 'A', '7': 'C', '8': 'G', '*': ''};
|
|
607
|
+
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|1|2|3|4|5|6|7|8|\*)/g, function (x: string) {return obj[x];});
|
|
375
608
|
}
|
|
376
609
|
|
|
377
610
|
//name: siRnaBioSpringToAxolabs
|
|
378
611
|
//input: string nucleotides {semType: BioSpring / siRNA}
|
|
379
612
|
//output: string result {semType: Axolabs / siRNA}
|
|
380
613
|
export function siRnaBioSpringToAxolabs(nucleotides: string) {
|
|
381
|
-
const obj: {[index: string]: string} = {
|
|
382
|
-
return nucleotides.replace(/
|
|
614
|
+
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', '1': 'Uf', '2': 'Af', '3': 'Cf', '4': 'Gf', '5': 'u', '6': 'a', '7': 'c', '8': 'g', '*': 's'};
|
|
615
|
+
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|1|2|3|4|5|6|7|8|\*)/g, function (x: string) {return obj[x];});
|
|
383
616
|
}
|
|
384
617
|
|
|
385
618
|
//name: siRnaBioSpringToGcrs
|
|
386
619
|
//input: string nucleotides {semType: BioSpring / siRNA}
|
|
387
620
|
//output: string result {semType: GCRS}
|
|
388
621
|
export function siRnaBioSpringToGcrs(nucleotides: string) {
|
|
389
|
-
const obj: {[index: string]: string} = {
|
|
390
|
-
return nucleotides.replace(/
|
|
622
|
+
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', '1': 'fU', '2': 'fA', '3': 'fC', '4': 'fG', '5': 'mU', '6': 'mA', '7': 'mC', '8': 'mG', '*': 'ps'};
|
|
623
|
+
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|1|2|3|4|5|6|7|8|\*)/g, function (x: string) {return obj[x];});
|
|
391
624
|
}
|
|
392
625
|
|
|
393
626
|
//name: siRnaAxolabsToGcrs
|
|
394
627
|
//input: string nucleotides {semType: Axolabs / siRNA}
|
|
395
628
|
//output: string result {semType: GCRS}
|
|
396
629
|
export function siRnaAxolabsToGcrs(nucleotides: string) {
|
|
397
|
-
const obj: {[index: string]: string} = {
|
|
398
|
-
|
|
630
|
+
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)',
|
|
631
|
+
'Uf': 'fU', 'Af': 'fA', 'Cf': 'fC', 'Gf': 'fG', 'u': 'mU', 'a': 'mA', 'c': 'mC', 'g': 'mG', 's': 'ps'
|
|
399
632
|
};
|
|
400
|
-
return nucleotides.replace(/(Uf|Af|Cf|Gf|u|a|c|g|s)/g, function (x: string) {return obj[x];});
|
|
633
|
+
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|Uf|Af|Cf|Gf|u|a|c|g|s)/g, function (x: string) {return obj[x];});
|
|
401
634
|
}
|
|
402
635
|
|
|
403
636
|
//name: siRnaAxolabsToBioSpring
|
|
404
637
|
//input: string nucleotides {semType: Axolabs / siRNA}
|
|
405
638
|
//output: string result {semType: BioSpring / siRNA}
|
|
406
639
|
export function siRnaAxolabsToBioSpring(nucleotides: string) {
|
|
407
|
-
const obj: {[index: string]: string} = {
|
|
408
|
-
|
|
640
|
+
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)',
|
|
641
|
+
'Uf': '1', 'Af': '2', 'Cf': '3', 'Gf': '4', 'u': '5', 'a': '6', 'c': '7', 'g': '8', 's': '*'
|
|
409
642
|
};
|
|
410
|
-
return nucleotides.replace(/(Uf|Af|Cf|Gf|u|a|c|g|s)/g, function (x: string) {return obj[x];});
|
|
643
|
+
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|Uf|Af|Cf|Gf|u|a|c|g|s)/g, function (x: string) {return obj[x];});
|
|
411
644
|
}
|
|
412
645
|
|
|
413
646
|
//name: siRnaAxolabsToNucleotides
|
|
414
647
|
//input: string nucleotides {semType: Axolabs / siRNA}
|
|
415
648
|
//output: string result {semType: RNA nucleotides}
|
|
416
649
|
export function siRnaAxolabsToNucleotides(nucleotides: string) {
|
|
417
|
-
const obj: {[index: string]: string} = {
|
|
418
|
-
|
|
650
|
+
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)',
|
|
651
|
+
'Uf': 'U', 'Af': 'A', 'Cf': 'C', 'Gf': 'G', 'u': 'U', 'a': 'A', 'c': 'C', 'g': 'G', 's': ''
|
|
419
652
|
};
|
|
420
|
-
return nucleotides.replace(/(Uf|Af|Cf|Gf|u|a|c|g|s)/g, function (x: string) {return obj[x];});
|
|
653
|
+
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|Uf|Af|Cf|Gf|u|a|c|g|s)/g, function (x: string) {return obj[x];});
|
|
421
654
|
}
|
|
422
655
|
|
|
423
656
|
//name: siRnaGcrsToNucleotides
|
|
424
657
|
//input: string nucleotides {semType: GCRS}
|
|
425
658
|
//output: string result {semType: RNA nucleotides}
|
|
426
659
|
export function siRnaGcrsToNucleotides(nucleotides: string) {
|
|
427
|
-
const obj: {[index: string]: string} = {
|
|
428
|
-
|
|
660
|
+
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)',
|
|
661
|
+
'fU': 'U', 'fA': 'A', 'fC': 'C', 'fG': 'G', 'mU': 'U', 'mA': 'A', 'mC': 'C', 'mG': 'G', 'ps': ''
|
|
429
662
|
};
|
|
430
|
-
return nucleotides.replace(/(fU|fA|fC|fG|mU|mA|mC|mG|ps)/g, function (x: string) {return obj[x];});
|
|
663
|
+
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|fU|fA|fC|fG|mU|mA|mC|mG|ps)/g, function (x: string) {return obj[x];});
|
|
431
664
|
}
|
|
432
665
|
|
|
433
666
|
//name: siRnaGcrsToBioSpring
|
|
434
667
|
//input: string nucleotides {semType: GCRS}
|
|
435
668
|
//output: string result {semType: BioSpring / siRNA}
|
|
436
669
|
export function siRnaGcrsToBioSpring(nucleotides: string) {
|
|
437
|
-
const obj: {[index: string]: string} = {
|
|
438
|
-
|
|
670
|
+
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)',
|
|
671
|
+
'fU': '1', 'fA': '2', 'fC': '3', 'fG': '4', 'mU': '5', 'mA': '6', 'mC': '7', 'mG': '8', 'ps': '*'
|
|
439
672
|
};
|
|
440
|
-
return nucleotides.replace(/(fU|fA|fC|fG|mU|mA|mC|mG|ps)/g, function (x: string) {return obj[x];});
|
|
673
|
+
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|fU|fA|fC|fG|mU|mA|mC|mG|ps)/g, function (x: string) {return obj[x];});
|
|
441
674
|
}
|
|
442
675
|
|
|
443
676
|
//name: siRnaGcrsToAxolabs
|
|
444
677
|
//input: string nucleotides {semType: GCRS}
|
|
445
678
|
//output: string result {semType: Axolabs / siRNA}
|
|
446
679
|
export function siRnaGcrsToAxolabs(nucleotides: string) {
|
|
447
|
-
const obj: {[index: string]: string} = {
|
|
448
|
-
|
|
680
|
+
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)',
|
|
681
|
+
'fU': 'Uf', 'fA': 'Af', 'fC': 'Cf', 'fG': 'Gf', 'mU': 'u', 'mA': 'a', 'mC': 'c', 'mG': 'g', 'ps': 's'
|
|
449
682
|
};
|
|
450
|
-
return nucleotides.replace(/(fU|fA|fC|fG|mU|mA|mC|mG|ps)/g, function (x: string) {return obj[x];});
|
|
683
|
+
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|fU|fA|fC|fG|mU|mA|mC|mG|ps)/g, function (x: string) {return obj[x];});
|
|
451
684
|
}
|
|
452
685
|
|
|
453
686
|
//name: siRnaNucleotideToBioSpringSenseStrand
|
|
@@ -455,11 +688,11 @@ export function siRnaGcrsToAxolabs(nucleotides: string) {
|
|
|
455
688
|
//output: string result {semType: BioSpring / siRNA}
|
|
456
689
|
export function siRnaNucleotideToBioSpringSenseStrand(nucleotides: string) {
|
|
457
690
|
let count: number = -1;
|
|
458
|
-
const objForLeftEdge: {[index: string]: string} = {
|
|
459
|
-
const objForRightEdge: {[index: string]: string} = {
|
|
460
|
-
const objForOddIndices: {[index: string]: string} = {
|
|
461
|
-
const objForEvenIndices: {[index: string]: string} = {
|
|
462
|
-
return nucleotides.replace(/
|
|
691
|
+
const objForLeftEdge: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': '6*', 'U': '5*', 'G': '8*', 'C': '7*'};
|
|
692
|
+
const objForRightEdge: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': '*6', 'U': '*5', 'G': '*8', 'C': '*7'};
|
|
693
|
+
const objForOddIndices: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': '6', 'U': '5', 'G': '8', 'C': '7'};
|
|
694
|
+
const objForEvenIndices: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': '2', 'U': '1', 'G': '4', 'C': '3'};
|
|
695
|
+
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|A|U|G|C)/g, function (x: string) {
|
|
463
696
|
count++;
|
|
464
697
|
if (count < 2) return objForLeftEdge[x];
|
|
465
698
|
if (count > nucleotides.length - 3) return objForRightEdge[x];
|
|
@@ -472,11 +705,11 @@ export function siRnaNucleotideToBioSpringSenseStrand(nucleotides: string) {
|
|
|
472
705
|
//output: string result {semType: GCRS}
|
|
473
706
|
export function siRnaNucleotidesToGcrs(nucleotides: string) {
|
|
474
707
|
let count: number = -1;
|
|
475
|
-
const objForLeftEdge: {[index: string]: string} = {
|
|
476
|
-
const objForRightEdge: {[index: string]: string} = {
|
|
477
|
-
const objForEvenIndices: {[index: string]: string} = {
|
|
478
|
-
const objForOddIndices: {[index: string]: string} = {
|
|
479
|
-
return nucleotides.replace(/
|
|
708
|
+
const objForLeftEdge: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': 'mAps', 'U': 'mUps', 'G': 'mGps', 'C': 'mCps'};
|
|
709
|
+
const objForRightEdge: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': 'psmA', 'U': 'psmU', 'G': 'psmG', 'C': 'psmC'};
|
|
710
|
+
const objForEvenIndices: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': 'fA', 'U': 'fU', 'G': 'fG', 'C': 'fC'};
|
|
711
|
+
const objForOddIndices: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': 'mA', 'U': 'mU', 'G': 'mG', 'C': 'mC'};
|
|
712
|
+
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|A|U|G|C)/g, function (x: string) {
|
|
480
713
|
count++;
|
|
481
714
|
if (count < 2) return objForLeftEdge[x];
|
|
482
715
|
if (count > nucleotides.length - 3) return objForRightEdge[x];
|
|
@@ -489,10 +722,10 @@ export function siRnaNucleotidesToGcrs(nucleotides: string) {
|
|
|
489
722
|
//output: string result {semType: Axolabs}
|
|
490
723
|
export function siRnaNucleotideToAxolabsSenseStrand(nucleotides: string) {
|
|
491
724
|
let count: number = -1;
|
|
492
|
-
const objForLeftEdge: {[index: string]: string} = {
|
|
493
|
-
const objForSomeIndices: {[index: string]: string} = {
|
|
494
|
-
const obj: {[index: string]: string} = {
|
|
495
|
-
return nucleotides.replace(/
|
|
725
|
+
const objForLeftEdge: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': 'as', 'U': 'us', 'G': 'gs', 'C': 'cs'};
|
|
726
|
+
const objForSomeIndices: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': 'Af', 'U': 'Uf', 'G': 'Gf', 'C': 'Cf'};
|
|
727
|
+
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': 'a', 'U': 'u', 'G': 'g', 'C': 'c'};
|
|
728
|
+
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|A|U|G|C)/g, function (x: string) {
|
|
496
729
|
count++;
|
|
497
730
|
if (count < 2) return objForLeftEdge[x];
|
|
498
731
|
if (count == 6 || (count > 7 && count < 11)) return objForSomeIndices[x]
|
|
@@ -506,11 +739,11 @@ export function siRnaNucleotideToAxolabsSenseStrand(nucleotides: string) {
|
|
|
506
739
|
//output: string result {semType: Axolabs}
|
|
507
740
|
export function siRnaNucleotideToAxolabsAntisenseStrand(nucleotides: string) {
|
|
508
741
|
let count: number = -1;
|
|
509
|
-
const objForSmallLinkages: {[index: string]: string} = {
|
|
510
|
-
const objForBigLinkages: {[index: string]: string} = {
|
|
511
|
-
const objForSomeIndices: {[index: string]: string} = {
|
|
512
|
-
const obj: {[index: string]: string} = {
|
|
513
|
-
return nucleotides.replace(/
|
|
742
|
+
const objForSmallLinkages: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': 'as', 'U': 'us', 'G': 'gs', 'C': 'cs'};
|
|
743
|
+
const objForBigLinkages: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': 'Afs', 'U': 'Ufs', 'G': 'Gfs', 'C': 'Cfs'};
|
|
744
|
+
const objForSomeIndices: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': 'Af', 'U': 'Uf', 'G': 'Gf', 'C': 'Cf'};
|
|
745
|
+
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': 'a', 'U': 'u', 'G': 'g', 'C': 'c'};
|
|
746
|
+
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|A|U|G|C)/g, function (x: string) {
|
|
514
747
|
count++;
|
|
515
748
|
if (count > 19 && count < 22) return objForSmallLinkages[x];
|
|
516
749
|
if (count == 0) return 'us';
|
|
@@ -523,48 +756,141 @@ export function siRnaNucleotideToAxolabsAntisenseStrand(nucleotides: string) {
|
|
|
523
756
|
//input: string nucleotides {semType: GCRS}
|
|
524
757
|
//output: string result {semType: RNA nucleotides}
|
|
525
758
|
export function gcrsToNucleotides(nucleotides: string) {
|
|
526
|
-
const obj: {[index: string]: string} = {
|
|
527
|
-
|
|
528
|
-
|
|
759
|
+
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)',
|
|
760
|
+
'mAps': 'A', 'mUps': 'U', 'mGps': 'G', 'mCps': 'C', 'fAps': 'A', 'fUps': 'U', 'fGps': 'G', 'fCps': 'C',
|
|
761
|
+
'fU': 'U', 'fA': 'A', 'fC': 'C', 'fG': 'G', 'mU': 'U', 'mA': 'A', 'mC': 'C', 'mG': 'G'
|
|
529
762
|
};
|
|
530
|
-
return nucleotides.replace(/(mAps|mUps|mGps|mCps|fAps|fUps|fGps|fCps|fU|fA|fC|fG|mU|mA|mC|mG)/g, function (x: string) {return obj[x];});
|
|
763
|
+
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|mAps|mUps|mGps|mCps|fAps|fUps|fGps|fCps|fU|fA|fC|fG|mU|mA|mC|mG)/g, function (x: string) {return obj[x];});
|
|
531
764
|
}
|
|
532
765
|
|
|
533
|
-
//name:
|
|
766
|
+
//name: gcrsToMermade12
|
|
534
767
|
//input: string nucleotides {semType: GCRS}
|
|
535
|
-
//output: string result {semType:
|
|
536
|
-
export function
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
};
|
|
541
|
-
const objForOddIndicesAtLeftEdge: {[index: string]: string} = {
|
|
542
|
-
"mAps": "a*", "mUps": "u*", "mGps": "g*", "mCps": "c*", "fAps": "a*", "fUps": "u*", "fGps": "g*", "fCps": "c*"
|
|
543
|
-
};
|
|
544
|
-
const objForOddIndicesAtRightEdge: {[index: string]: string} = {
|
|
545
|
-
"mAps": "a", "mUps": "u", "mGps": "g", "mCps": "c", "fAps": "a", "fUps": "u", "fGps": "g", "fCps": "c"
|
|
768
|
+
//output: string result {semType: Mermade 12 / siRNA}
|
|
769
|
+
export function gcrsToMermade12(nucleotides: string) {
|
|
770
|
+
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)',
|
|
771
|
+
'mAps': 'e', 'mUps': 'h', 'mGps': 'g', 'mCps': 'f', 'fAps': 'i', 'fUps': 'l', 'fGps': 'k', 'fCps': 'j', 'fU': 'L',
|
|
772
|
+
'fA': 'I', 'fC': 'J', 'fG': 'K', 'mU': 'H', 'mA': 'E', 'mC': 'F', 'mG': 'G'
|
|
546
773
|
};
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
774
|
+
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|mAps|mUps|mGps|mCps|fAps|fUps|fGps|fCps|fU|fA|fC|fG|mU|mA|mC|mG)/g, function (x: string) {return obj[x]});
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
async function saveTableAsSdFile(table: DG.DataFrame) {
|
|
778
|
+
if (!table.columns.contains('Compound Name'))
|
|
779
|
+
grok.shell.warning("File was saved without columns 'Compound Name', 'Compound Components', 'Cpd MW', 'Salt mass', 'Batch MW'!");
|
|
780
|
+
let structureColumn = table.columns.byName('Sequence');
|
|
781
|
+
let result = '';
|
|
782
|
+
for (let i = 0; i < table.rowCount; i++) {
|
|
783
|
+
try {
|
|
784
|
+
let smiles = sequenceToSmiles(structureColumn.get(i));
|
|
785
|
+
//@ts-ignore
|
|
786
|
+
let mol = new OCL.Molecule.fromSmiles(smiles);
|
|
787
|
+
result += `\n${mol.toMolfile()}\n`;
|
|
788
|
+
for (let col of table.columns)
|
|
789
|
+
result += `> <${col.name}>\n${col.get(i)}\n\n`;
|
|
790
|
+
result += '$$$$';
|
|
791
|
+
}
|
|
792
|
+
catch (error) {
|
|
793
|
+
console.error(error);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
let element = document.createElement('a');
|
|
797
|
+
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(result));
|
|
798
|
+
element.setAttribute('download', table.name + '.sdf');
|
|
799
|
+
element.click();
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
function parseNumber(saltName: string) {
|
|
803
|
+
let i = saltName.length;
|
|
804
|
+
while (saltName.length > -1 && saltName[i] != '(')
|
|
805
|
+
i--;
|
|
806
|
+
return parseInt(saltName.slice(i + 2));
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
//tags: autostart
|
|
810
|
+
export function autostartOligoSdFileSubscription() {
|
|
811
|
+
grok.events.onViewAdded.subscribe((v: any) => {
|
|
812
|
+
if (v.type == 'TableView' && v.dataFrame.columns.contains('Type'))
|
|
813
|
+
oligoSdFile(v.dataFrame);
|
|
558
814
|
});
|
|
559
815
|
}
|
|
560
816
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
817
|
+
let weightsObj: {[code: string]: number} = {};
|
|
818
|
+
for (let synthesizer of Object.keys(map))
|
|
819
|
+
for (let technology of Object.keys(map[synthesizer]))
|
|
820
|
+
for (let code of Object.keys(map[synthesizer][technology]))
|
|
821
|
+
weightsObj[code] = map[synthesizer][technology][code].weight;
|
|
822
|
+
|
|
823
|
+
function molecularWeight(sequence: string): number {
|
|
824
|
+
const codes = sortByStringLengthInDescendingOrder(Object.keys(weightsObj));
|
|
825
|
+
let weight = 0, i = 0;
|
|
826
|
+
while (i < sequence.length) {
|
|
827
|
+
let matchedCode = codes.find((s) => s == sequence.slice(i, i + s.length))!;
|
|
828
|
+
weight += weightsObj[sequence.slice(i, i + matchedCode.length)];
|
|
829
|
+
i += matchedCode!.length;
|
|
830
|
+
}
|
|
831
|
+
return weight - 61.97;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
export function oligoSdFile(table: DG.DataFrame) {
|
|
835
|
+
|
|
836
|
+
function addColumns(t: DG.DataFrame) {
|
|
837
|
+
if (t.columns.contains('Compound Name'))
|
|
838
|
+
return grok.shell.error('Columns already exist!');
|
|
839
|
+
|
|
840
|
+
table.col('Source')?.init('Johnson and Johnson Pharma');
|
|
841
|
+
table.col('ICD')?.init('No Contract');
|
|
842
|
+
|
|
843
|
+
let sequence = t.col('Sequence')!;
|
|
844
|
+
let salt = t.col('Salt')!;
|
|
845
|
+
let equivalents = t.col('Equivalents')!;
|
|
846
|
+
|
|
847
|
+
t.columns.addNewString('Compound Name').init((i: number) => sequence.get(i));
|
|
848
|
+
t.columns.addNewString('Compound Comments').init((i: number) => (i > 0 && i % 2 == 0) ?
|
|
849
|
+
sequence.getString(i) + '; duplex of SS: ' + sequence.getString(i - 2) + ' and AS: ' + sequence.getString(i - 1) :
|
|
850
|
+
sequence.getString(i)
|
|
851
|
+
);
|
|
852
|
+
t.columns.addNewFloat('Cpd MW').init((i: number) => ((i + 1) % 3 == 0) ? DG.FLOAT_NULL : molecularWeight(sequence.get(i)));
|
|
853
|
+
t.columns.addNewFloat('Salt mass').init((i: number) => parseNumber(salt.get(i)) * equivalents.get(i));
|
|
854
|
+
t.columns.addNewCalculated('Batch MW', '${Cpd MW} + ${Salt mass}', DG.COLUMN_TYPE.FLOAT, false);
|
|
855
|
+
|
|
856
|
+
addColumnsPressed = true;
|
|
857
|
+
return newDf = t;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
const columnsOrder = ["Chemistry", "Number", "Type", "Chemistry Name", "Internal compound ID", "IDP", "Sequence", "Compound Name",
|
|
861
|
+
"Compound Comments", "Salt", "Equivalents", "Purity", "Cpd MW", "Salt mass", "Batch MW", "Source", "ICD", "Owner"];
|
|
862
|
+
let newDf: DG.DataFrame;
|
|
863
|
+
let addColumnsPressed = false;
|
|
864
|
+
|
|
865
|
+
let d = ui.div([
|
|
866
|
+
ui.icons.edit(() => {
|
|
867
|
+
d.innerHTML = '';
|
|
868
|
+
d.append(
|
|
869
|
+
ui.link('Add Columns', async () => {
|
|
870
|
+
await addColumns(table);
|
|
871
|
+
grok.shell.tableView(table.name).grid.columns.setOrder(columnsOrder);
|
|
872
|
+
}, 'Add columns: Compound Name, Compound Components, Cpd MW, Salt mass, Batch MW', ''),
|
|
873
|
+
ui.button('Save SD file', () => saveTableAsSdFile(addColumnsPressed ? newDf : table))
|
|
874
|
+
);
|
|
875
|
+
let view = grok.shell.getTableView(table.name);
|
|
876
|
+
let typeCol = view.grid.col('Type')!;
|
|
877
|
+
let saltCol = view.grid.col('Salt')!;
|
|
878
|
+
saltCol.cellType = 'html';
|
|
879
|
+
typeCol.cellType = 'html';
|
|
880
|
+
view.grid.onCellPrepare(function (gc: DG.GridCell) {
|
|
881
|
+
if (gc.isTableCell) {
|
|
882
|
+
if (gc.gridColumn.name == 'Type')
|
|
883
|
+
gc.style.element = ui.choiceInput('', gc.cell.value, ['AS', 'SS', 'Duplex']).root;
|
|
884
|
+
else if (gc.gridColumn.name == 'Salt')
|
|
885
|
+
gc.style.element = ui.choiceInput('', gc.cell.value, ['Sodium (+1)', 'Sodium (+2)']).root;
|
|
886
|
+
}
|
|
887
|
+
});
|
|
888
|
+
|
|
889
|
+
table.onDataChanged.subscribe((_) => {
|
|
890
|
+
if (table.currentCol.name == 'IDP' && typeof table.currentCell.value != 'number')
|
|
891
|
+
grok.shell.error('Value should be numeric');
|
|
892
|
+
});
|
|
893
|
+
})
|
|
894
|
+
]);
|
|
895
|
+
grok.shell.v.setRibbonPanels([[d]]);
|
|
896
|
+
}
|