@datagrok/sequence-translator 0.0.1 → 0.0.5
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 +11 -15
- package/package.json +10 -3
- 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 +540 -0
- package/src/package-test.ts +12 -0
- package/src/package.ts +635 -357
- package/src/save-sense-antisense.ts +36 -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
|
@@ -2,321 +2,527 @@
|
|
|
2
2
|
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
|
-
import
|
|
5
|
+
import * as OCL from 'openchemlib/full.js';
|
|
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';
|
|
10
|
+
|
|
11
|
+
export const _package = new DG.Package();
|
|
12
|
+
|
|
13
|
+
const defaultInput = 'AGGTCCTCTTGACTTAGGCC';
|
|
14
|
+
const undefinedInputSequence = 'Type of input sequence is undefined';
|
|
15
|
+
const noTranslationTableAvailable = 'No translation table available';
|
|
16
|
+
const sequenceWasCopied = 'Copied';
|
|
17
|
+
const tooltipSequence = 'Copy sequence';
|
|
18
|
+
|
|
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));
|
|
24
|
+
}
|
|
6
25
|
|
|
7
|
-
|
|
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
|
+
}
|
|
8
43
|
|
|
9
|
-
|
|
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
|
+
}
|
|
10
53
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
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
|
+
}
|
|
17
90
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
91
|
+
outputIndices[synthesizerIndex] += matchedCode.length;
|
|
92
|
+
}
|
|
93
|
+
});
|
|
21
94
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
+
};
|
|
26
104
|
|
|
27
|
-
let
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
ui.divText("Paste sequence into the text field below"),
|
|
31
|
-
ui.divText('\n How to convert many sequences:',{style:{'font-weight':'bolder'}}),
|
|
32
|
-
ui.divText("1. Drag & drop an Excel or CSV file with sequences into Datagrok. The platform will automatically detect columns with sequences"),
|
|
33
|
-
ui.divText('2. Right-click on the column header, then see the \'Convert\' menu'),
|
|
34
|
-
ui.divText("This will add the result column to the right of the table"),
|
|
35
|
-
], 'Convert oligonucleotide sequences between Nucleotides, BioSpring, Axolabs, and GCRS representations.'
|
|
36
|
-
);
|
|
105
|
+
let possibleTechnologies = getListOfPossibleTechnologiesByFirstMatchedCode(sequence, expectedSynthesizer);
|
|
106
|
+
if (possibleTechnologies.length == 0)
|
|
107
|
+
return { indexOfFirstNotValidCharacter: 0, expectedSynthesizer: null, expectedTechnology: null };
|
|
37
108
|
|
|
38
|
-
|
|
39
|
-
moleculeSvg.innerHTML = "";
|
|
40
|
-
let outputSequencesObj = convertSequence(seq);
|
|
109
|
+
outputIndices = Array(possibleTechnologies.length).fill(0);
|
|
41
110
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
tableRows.push({'key': key, 'value': ui.link(outputSequencesObj[key], () => navigator.clipboard.writeText(outputSequencesObj[key]).then(() => grok.shell.info(sequenceWasCopied)), tooltipSequence, '')})
|
|
46
|
-
}
|
|
111
|
+
possibleTechnologies.forEach((technology: string, technologyIndex: number) => {
|
|
112
|
+
let codes = Object.keys(map[expectedSynthesizer][technology]);
|
|
113
|
+
while (outputIndices[technologyIndex] < sequence.length) {
|
|
47
114
|
|
|
48
|
-
|
|
115
|
+
let matchedCode = codes
|
|
116
|
+
.find((c) => c == sequence.slice(outputIndices[technologyIndex], outputIndices[technologyIndex] + c.length));
|
|
49
117
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
let flavor: string = (outputSequencesObj.Nucleotides.includes('U')) ? "RNA_both_caps" : "DNA_both_caps";
|
|
66
|
-
let mol = grok.chem.svgMol(<string> await nucleotidesToSmiles(outputSequencesObj.Nucleotides, flavor), 900, 300);
|
|
67
|
-
moleculeSvg.append(mol);
|
|
68
|
-
} finally {
|
|
69
|
-
pi.close();
|
|
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;
|
|
70
133
|
}
|
|
134
|
+
|
|
135
|
+
outputIndices[technologyIndex] += matchedCode.length;
|
|
71
136
|
}
|
|
72
137
|
});
|
|
73
|
-
let semTypeOfInputSequence = ui.divText('Detected input type: DNA Nucleotides Code');
|
|
74
|
-
|
|
75
|
-
let outputTableDiv = ui.div([
|
|
76
|
-
DG.HtmlTable.create([
|
|
77
|
-
{key: 'Nucleotides', value: ui.link(defaultNucleotidesInput, () => navigator.clipboard.writeText(defaultNucleotidesInput).then(() => grok.shell.info(sequenceWasCopied)), tooltipSequence, '')},
|
|
78
|
-
{key: 'BioSpring', value: ui.link(asoGapmersNucleotidesToBioSpring(defaultNucleotidesInput), () => navigator.clipboard.writeText(asoGapmersNucleotidesToBioSpring(defaultNucleotidesInput)).then(() => grok.shell.info(sequenceWasCopied)), tooltipSequence, '')},
|
|
79
|
-
{key: 'Axolabs', value: ui.link(noTranslationTableAvailable, () => navigator.clipboard.writeText(defaultNucleotidesInput).then(() => grok.shell.info(sequenceWasCopied)), tooltipSequence, '')},
|
|
80
|
-
{key: 'GCRS', value: ui.link(asoGapmersNucleotidesToGcrs(defaultNucleotidesInput), () => navigator.clipboard.writeText(asoGapmersNucleotidesToGcrs(defaultNucleotidesInput)).then(() => grok.shell.info(sequenceWasCopied)), tooltipSequence, '')}
|
|
81
|
-
], (item: {key: string; value: string;}) => [item.key, item.value], ['Code', 'Sequence']).root
|
|
82
|
-
], 'table');
|
|
83
|
-
|
|
84
|
-
let accordionWithCmoCodes = ui.accordion();
|
|
85
|
-
accordionWithCmoCodes.addPane('CMO Codes', () =>
|
|
86
|
-
ui.divH([
|
|
87
|
-
DG.HtmlTable.create(
|
|
88
|
-
[
|
|
89
|
-
{name: "2'MOE-5Me-rU", bioSpring: '5', gcrs: 'moeT'},
|
|
90
|
-
{name: "2'MOE-rA", bioSpring: '6', gcrs: 'moeA'},
|
|
91
|
-
{name: "2'MOE-5Me-rC", bioSpring: '7', gcrs: 'moe5mC'},
|
|
92
|
-
{name: "2'MOE-rG", bioSpring: '8', gcrs: 'moeG'},
|
|
93
|
-
{name: "5-Methyl-dC", bioSpring: '9', gcrs: '5mC'},
|
|
94
|
-
{name: "ps linkage", bioSpring: '*', gcrs: 'ps'},
|
|
95
|
-
{name: "dA", bioSpring: 'A', gcrs: 'A'},
|
|
96
|
-
{name: "dC", bioSpring: 'C', gcrs: 'C'},
|
|
97
|
-
{name: "dT", bioSpring: 'T', gcrs: 'T'},
|
|
98
|
-
{name: "dG", bioSpring: 'G', gcrs: 'G'}
|
|
99
|
-
],
|
|
100
|
-
(item: {name: string; bioSpring: string; gcrs: string}) => [item.name, item.bioSpring, item.gcrs],
|
|
101
|
-
['For ASO Gapmers', 'BioSpring', 'GCRS']
|
|
102
|
-
).root,
|
|
103
|
-
ui.div([], {style: {width: '50px'}}),
|
|
104
|
-
DG.HtmlTable.create(
|
|
105
|
-
[
|
|
106
|
-
{name: "2'-fluoro-U", axolabs: '1', bioSpring: 'Uf', gcrs: 'fU'},
|
|
107
|
-
{name: "2'-fluoro-A", axolabs: '2', bioSpring: 'Af', gcrs: 'fA'},
|
|
108
|
-
{name: "2'-fluoro-C", axolabs: '3', bioSpring: 'Cf', gcrs: 'fC'},
|
|
109
|
-
{name: "2'-fluoro-G", axolabs: '4', bioSpring: 'Gf', gcrs: 'fG'},
|
|
110
|
-
{name: "OMe-rU", axolabs: '5', bioSpring: 'u', gcrs: 'mU'},
|
|
111
|
-
{name: "OMe-rA", axolabs: '6', bioSpring: 'a', gcrs: 'mA'},
|
|
112
|
-
{name: "OMe-rC", axolabs: '7', bioSpring: 'c', gcrs: 'mC'},
|
|
113
|
-
{name: "OMe-rG", axolabs: '8', bioSpring: 'g', gcrs: 'mG'},
|
|
114
|
-
{name: "ps linkage", axolabs: '*', bioSpring: 's', gcrs: 'ps'}
|
|
115
|
-
],
|
|
116
|
-
(item: {name: string; axolabs: string, bioSpring: string; gcrs: string}) => [item.name, item.bioSpring, item.axolabs, item.gcrs],
|
|
117
|
-
["For 2\'-OMe and 2\'-F modified siRNA", 'BioSpring', 'Axolabs', 'GCRS']
|
|
118
|
-
).root
|
|
119
|
-
]), false
|
|
120
|
-
);
|
|
121
138
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
'4cc(C)c(=O)[nH]c4=O)C[C@@H]3OP(=O)(O)OC[C@H]3O[C@@H](n4cc(C)c(=O)[nH]c4=O)C[C@@H]3OP(=O)(O)OC[C@H]3O[C@@H](n4cnc5' +
|
|
125
|
-
'c(=O)[nH]c(N)nc54)C[C@@H]3OP(=O)(O)OC[C@H]3O[C@@H](n4cnc5c(N)ncnc54)C[C@@H]3OP(=O)(O)OC[C@H]3O[C@@H](n4ccc(N)nc4=O)' +
|
|
126
|
-
'C[C@@H]3OP(=O)(O)OC[C@H]3O[C@@H](n4cc(C)c(=O)[nH]c4=O)C[C@@H]3OP(=O)(O)OC[C@H]3O[C@@H](n4cc(C)c(=O)[nH]c4=O)C[C@@H]3OP(=O)(O)' +
|
|
127
|
-
'OC[C@H]3O[C@@H](n4cnc5c(N)ncnc54)C[C@@H]3OP(=O)(O)OC[C@H]3O[C@@H](n4cnc5c(=O)[nH]c(N)nc54)C[C@@H]3OP(=O)(O)OC[C@H]' +
|
|
128
|
-
'3O[C@@H](n4cnc5c(=O)[nH]c(N)nc54)C[C@@H]3OP(=O)(O)OC[C@H]3O[C@@H](n4ccc(N)nc4=O)C[C@@H]3OP(=O)(O)OC[C@H]3O[C@@H]' +
|
|
129
|
-
'(n4ccc(N)nc4=O)C[C@@H]3OP(=O)(O)O)[C@@H](COP(=O)(O)O[C@H]3C[C@H](n4ccc(N)nc4=O)O[C@@H]3COP(=O)(O)O[C@H]3C[C@H]' +
|
|
130
|
-
'(n4ccc(N)nc4=O)O[C@@H]3COP(=O)(O)O[C@H]3C[C@H](n4cc(C)c(=O)[nH]c4=O)O[C@@H]3COP(=O)(O)O[C@H]3C[C@H](n4cnc5c(=O)' +
|
|
131
|
-
'[nH]c(N)nc54)O[C@@H]3COP(=O)(O)O[C@H]3C[C@H](n4cnc5c(=O)[nH]c(N)nc54)O[C@@H]3COP(=O)(O)O[C@H]3C[C@H](n4cnc5c(N)' +
|
|
132
|
-
'ncnc54)O[C@@H]3COP(=O)(O)O)O2)c(=O)[nH]c1=O', 900, 300
|
|
133
|
-
)
|
|
134
|
-
]);
|
|
139
|
+
const indexOfExpectedTechnology = Math.max.apply(Math, outputIndices);
|
|
140
|
+
const expectedTechnology = possibleTechnologies[outputIndices.indexOf(indexOfExpectedTechnology)];
|
|
135
141
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
ui.div([
|
|
143
|
-
inputSequenceField.root
|
|
144
|
-
],'input-base')
|
|
145
|
-
], 'sequenceInput'),
|
|
146
|
-
semTypeOfInputSequence,
|
|
147
|
-
ui.block([
|
|
148
|
-
ui.h1('Output'),
|
|
149
|
-
ui.h1('Output'),
|
|
150
|
-
outputTableDiv
|
|
151
|
-
]),
|
|
152
|
-
accordionWithCmoCodes.root,
|
|
153
|
-
moleculeSvg,
|
|
154
|
-
ui.button('SAVE SD FILE', async() => {
|
|
155
|
-
let outputSequenceObj = convertSequence(inputSequenceField.value);
|
|
156
|
-
let flavor: string = outputSequenceObj.Nucleotides.includes('U') ? "RNA_both_caps" : "DNA_both_caps";
|
|
157
|
-
let smiles = await nucleotidesToSmiles(outputSequenceObj.Nucleotides, flavor);
|
|
158
|
-
smiles = smiles.replace(/@/g, ''); // Remove StereoChemistry on the Nucleic acid chain and remove the Chiral label
|
|
159
|
-
//@ts-ignore
|
|
160
|
-
let mol = new OCL.Molecule.fromSmiles(smiles);
|
|
161
|
-
let result = `${mol.toMolfile()}\n` + '$$$$';
|
|
162
|
-
var element = document.createElement('a');
|
|
163
|
-
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(result));
|
|
164
|
-
element.setAttribute('download', outputSequenceObj.Nucleotides + '.sdf');
|
|
165
|
-
element.click();
|
|
166
|
-
})
|
|
167
|
-
], 'sequence')!
|
|
168
|
-
]),
|
|
169
|
-
'AXOLABS': _defineAxolabsPattern()
|
|
170
|
-
}).root;
|
|
171
|
-
tab.style.height = '100%';
|
|
172
|
-
tab.style.width = '100%';
|
|
173
|
-
|
|
174
|
-
let v = grok.shell.newView('Sequence Translator', [
|
|
175
|
-
tab
|
|
176
|
-
]);
|
|
177
|
-
v.box = true;
|
|
142
|
+
return {
|
|
143
|
+
indexOfFirstNotValidCharacter: indexOfFirstNotValidCharacter,
|
|
144
|
+
expectedSynthesizer: expectedSynthesizer,
|
|
145
|
+
expectedTechnology: expectedTechnology
|
|
146
|
+
};
|
|
147
|
+
}
|
|
178
148
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
$('.sequenceInput .input-base').css('margin','0');
|
|
182
|
-
$('.sequenceInput textarea')
|
|
183
|
-
.css('resize','none')
|
|
184
|
-
.css('min-height','50px')
|
|
185
|
-
.css('width','100%');
|
|
186
|
-
$('.sequenceInput select')
|
|
187
|
-
.css('width','100%');
|
|
149
|
+
function sortByStringLengthInDescendingOrder(array: string[]): string[] {
|
|
150
|
+
return array.sort(function(a: string, b: string) { return b.length - a.length; });
|
|
188
151
|
}
|
|
189
152
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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]))
|
|
157
|
+
for (let code of Object.keys(map[synthesizer][technology]))
|
|
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;
|
|
165
|
+
return obj;
|
|
195
166
|
}
|
|
196
167
|
|
|
197
|
-
export function
|
|
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 = [];
|
|
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);
|
|
178
|
+
while (i < sequence.length) {
|
|
179
|
+
const code = codes.find((s: string) => s == sequence.slice(i, i + s.length))!;
|
|
180
|
+
i += code.length;
|
|
181
|
+
inverted ? codesList.unshift(code) : codesList.push(code);
|
|
182
|
+
}
|
|
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);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
//name: Sequence Translator
|
|
219
|
+
//tags: app
|
|
220
|
+
export function sequenceTranslator(): void {
|
|
221
|
+
const windows = grok.shell.windows;
|
|
222
|
+
windows.showProperties = false;
|
|
223
|
+
windows.showToolbox = false;
|
|
224
|
+
windows.showHelp = false;
|
|
225
|
+
|
|
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
|
+
});
|
|
277
|
+
}
|
|
198
278
|
|
|
199
|
-
|
|
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();
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
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 }
|
|
333
|
+
);
|
|
200
334
|
|
|
201
|
-
|
|
335
|
+
asoDf.onCurrentCellChanged.subscribe((_) => {
|
|
336
|
+
navigator.clipboard.writeText(asoDf.currentCell.value).then(() => grok.shell.info('Copied'))
|
|
337
|
+
});
|
|
202
338
|
|
|
203
|
-
|
|
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 }
|
|
351
|
+
);
|
|
204
352
|
|
|
205
|
-
|
|
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);
|
|
206
360
|
|
|
207
|
-
|
|
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
|
+
);
|
|
208
370
|
|
|
209
|
-
|
|
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,
|
|
386
|
+
ui.div([
|
|
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
|
+
});
|
|
210
406
|
|
|
211
|
-
|
|
407
|
+
let v = grok.shell.newView('Sequence Translator', [tabControl]);
|
|
408
|
+
v.box = true;
|
|
212
409
|
|
|
213
|
-
|
|
410
|
+
const switchInput = ui.switchInput('Codes', true, (v: boolean) => (v) ?
|
|
411
|
+
$(codesTablesDiv).show() :
|
|
412
|
+
$(codesTablesDiv).hide()
|
|
413
|
+
);
|
|
214
414
|
|
|
215
|
-
|
|
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]);
|
|
216
434
|
|
|
217
|
-
|
|
435
|
+
$('.sequence')
|
|
436
|
+
.children().css('padding','5px 0');
|
|
437
|
+
$('.sequenceInput .input-base')
|
|
438
|
+
.css('margin','0');
|
|
439
|
+
$('.sequenceInput textarea')
|
|
440
|
+
.css('resize','none')
|
|
441
|
+
.css('min-height','50px')
|
|
442
|
+
.css('width','100%')
|
|
443
|
+
.attr('spellcheck', 'false');
|
|
444
|
+
$('.sequenceInput select')
|
|
445
|
+
.css('width','100%');
|
|
446
|
+
}
|
|
218
447
|
|
|
219
|
-
function convertSequence(
|
|
220
|
-
|
|
221
|
-
|
|
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)
|
|
222
453
|
return {
|
|
223
|
-
type:
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
Axolabs: smallNumberOfCharacters,
|
|
227
|
-
GCRS: smallNumberOfCharacters
|
|
454
|
+
// type: '',
|
|
455
|
+
indexOfFirstNotValidCharacter: JSON.stringify(output),
|
|
456
|
+
Error: undefinedInputSequence
|
|
228
457
|
};
|
|
229
|
-
if (
|
|
458
|
+
if (output.expectedSynthesizer == SYNTHESIZERS.RAW_NUCLEOTIDES && output.expectedTechnology == TECHNOLOGIES.DNA)
|
|
230
459
|
return {
|
|
231
|
-
type:
|
|
460
|
+
type: SYNTHESIZERS.RAW_NUCLEOTIDES + ' ' + TECHNOLOGIES.DNA,
|
|
232
461
|
Nucleotides: seq,
|
|
233
462
|
BioSpring: asoGapmersNucleotidesToBioSpring(seq),
|
|
234
|
-
Axolabs: noTranslationTableAvailable,
|
|
235
463
|
GCRS: asoGapmersNucleotidesToGcrs(seq)
|
|
236
464
|
};
|
|
237
|
-
if (
|
|
465
|
+
if (output.expectedSynthesizer == SYNTHESIZERS.BIOSPRING && output.expectedTechnology == TECHNOLOGIES.ASO_GAPMERS)
|
|
238
466
|
return {
|
|
239
|
-
type:
|
|
240
|
-
Nucleotides: noTranslationTableAvailable,
|
|
241
|
-
GCRS: noTranslationTableAvailable,
|
|
242
|
-
MM12: noTranslationTableAvailable,
|
|
243
|
-
OP100: noTranslationTableAvailable,
|
|
244
|
-
ABI: seq
|
|
245
|
-
};
|
|
246
|
-
if (isAsoGapmerBioSpringCode(seq))
|
|
247
|
-
return {
|
|
248
|
-
type: "ASO Gapmers / BioSpring Code",
|
|
467
|
+
type: SYNTHESIZERS.BIOSPRING + ' ' + TECHNOLOGIES.ASO_GAPMERS,
|
|
249
468
|
Nucleotides: asoGapmersBioSpringToNucleotides(seq),
|
|
250
469
|
BioSpring: seq,
|
|
251
|
-
Axolabs: noTranslationTableAvailable,
|
|
252
470
|
GCRS: asoGapmersBioSpringToGcrs(seq)
|
|
253
471
|
};
|
|
254
|
-
if (
|
|
472
|
+
if (output.expectedSynthesizer == SYNTHESIZERS.GCRS && output.expectedTechnology == TECHNOLOGIES.ASO_GAPMERS)
|
|
255
473
|
return {
|
|
256
|
-
type:
|
|
474
|
+
type: SYNTHESIZERS.GCRS + ' ' + TECHNOLOGIES.ASO_GAPMERS,
|
|
257
475
|
Nucleotides: asoGapmersGcrsToNucleotides(seq),
|
|
258
476
|
BioSpring: asoGapmersGcrsToBioSpring(seq),
|
|
259
|
-
|
|
477
|
+
Mermade12: gcrsToMermade12(seq),
|
|
260
478
|
GCRS: seq
|
|
261
479
|
};
|
|
262
|
-
if (
|
|
480
|
+
if (output.expectedSynthesizer == SYNTHESIZERS.RAW_NUCLEOTIDES && output.expectedTechnology == TECHNOLOGIES.RNA)
|
|
263
481
|
return {
|
|
264
|
-
type:
|
|
482
|
+
type: SYNTHESIZERS.RAW_NUCLEOTIDES + ' ' + TECHNOLOGIES.RNA,
|
|
265
483
|
Nucleotides: seq,
|
|
266
484
|
BioSpring: siRnaNucleotideToBioSpringSenseStrand(seq),
|
|
267
485
|
Axolabs: siRnaNucleotideToAxolabsSenseStrand(seq),
|
|
268
486
|
GCRS: siRnaNucleotidesToGcrs(seq)
|
|
269
487
|
};
|
|
270
|
-
if (
|
|
488
|
+
if (output.expectedSynthesizer == SYNTHESIZERS.BIOSPRING && output.expectedTechnology == TECHNOLOGIES.SI_RNA)
|
|
271
489
|
return {
|
|
272
|
-
type:
|
|
490
|
+
type: SYNTHESIZERS.BIOSPRING + ' ' + TECHNOLOGIES.SI_RNA,
|
|
273
491
|
Nucleotides: siRnaBioSpringToNucleotides(seq),
|
|
274
492
|
BioSpring: seq,
|
|
275
493
|
Axolabs: siRnaBioSpringToAxolabs(seq),
|
|
276
494
|
GCRS: siRnaBioSpringToGcrs(seq)
|
|
277
495
|
};
|
|
278
|
-
if (
|
|
496
|
+
if (output.expectedSynthesizer == SYNTHESIZERS.AXOLABS && output.expectedTechnology == TECHNOLOGIES.SI_RNA)
|
|
279
497
|
return {
|
|
280
|
-
type:
|
|
498
|
+
type: SYNTHESIZERS.AXOLABS + ' ' + TECHNOLOGIES.SI_RNA,
|
|
281
499
|
Nucleotides: siRnaAxolabsToNucleotides(seq),
|
|
282
500
|
BioSpring: siRnaAxolabsToBioSpring(seq),
|
|
283
501
|
Axolabs: seq,
|
|
284
502
|
GCRS: siRnaAxolabsToGcrs(seq)
|
|
285
503
|
};
|
|
286
|
-
if (
|
|
504
|
+
if (output.expectedSynthesizer == SYNTHESIZERS.GCRS && output.expectedTechnology == TECHNOLOGIES.SI_RNA)
|
|
287
505
|
return {
|
|
288
|
-
type:
|
|
506
|
+
type: SYNTHESIZERS.GCRS + ' ' + TECHNOLOGIES.SI_RNA,
|
|
289
507
|
Nucleotides: siRnaGcrsToNucleotides(seq),
|
|
290
508
|
BioSpring: siRnaGcrsToBioSpring(seq),
|
|
291
509
|
Axolabs: siRnaGcrsToAxolabs(seq),
|
|
510
|
+
MM12: gcrsToMermade12(seq),
|
|
292
511
|
GCRS: seq
|
|
293
512
|
};
|
|
294
|
-
if (
|
|
513
|
+
if (output.expectedSynthesizer == SYNTHESIZERS.GCRS)
|
|
295
514
|
return {
|
|
296
|
-
type:
|
|
515
|
+
type: SYNTHESIZERS.GCRS,
|
|
297
516
|
Nucleotides: gcrsToNucleotides(seq),
|
|
298
517
|
GCRS: seq,
|
|
299
|
-
|
|
300
|
-
OP100: gcrsToOP100(seq),
|
|
301
|
-
ABI: gcrsToABI(seq)
|
|
518
|
+
Mermade12: gcrsToMermade12(seq)
|
|
302
519
|
}
|
|
303
|
-
if (
|
|
304
|
-
return {
|
|
305
|
-
type: "MM12 Code",
|
|
306
|
-
Nucleotides: noTranslationTableAvailable,
|
|
307
|
-
GCRS: noTranslationTableAvailable,
|
|
308
|
-
MM12: seq,
|
|
309
|
-
OP100: noTranslationTableAvailable,
|
|
310
|
-
ABI: noTranslationTableAvailable
|
|
311
|
-
};
|
|
312
|
-
if (isOP100Code(seq))
|
|
520
|
+
if (output.expectedSynthesizer == SYNTHESIZERS.MERMADE_12)
|
|
313
521
|
return {
|
|
314
|
-
type:
|
|
522
|
+
type: SYNTHESIZERS.MERMADE_12,
|
|
315
523
|
Nucleotides: noTranslationTableAvailable,
|
|
316
524
|
GCRS: noTranslationTableAvailable,
|
|
317
|
-
|
|
318
|
-
OP100: seq,
|
|
319
|
-
ABI: noTranslationTableAvailable
|
|
525
|
+
Mermade12: seq
|
|
320
526
|
};
|
|
321
527
|
return {
|
|
322
528
|
type: undefinedInputSequence,
|
|
@@ -327,49 +533,49 @@ function convertSequence(seq: string) {
|
|
|
327
533
|
//name: asoGapmersNucleotidesToBioSpring
|
|
328
534
|
//input: string nucleotides {semType: DNA nucleotides}
|
|
329
535
|
//output: string result {semType: BioSpring / Gapmers}
|
|
330
|
-
export function asoGapmersNucleotidesToBioSpring(nucleotides: string) {
|
|
536
|
+
export function asoGapmersNucleotidesToBioSpring(nucleotides: string): string {
|
|
331
537
|
let count: number = -1;
|
|
332
|
-
const objForEdges: {[index: string]: string} = {
|
|
333
|
-
const objForCenter: {[index: string]: string} = {
|
|
334
|
-
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) {
|
|
335
541
|
count++;
|
|
336
542
|
return (count > 4 && count < 15) ? objForCenter[x] : objForEdges[x];
|
|
337
|
-
}).slice(0, 2 * count + 1);
|
|
543
|
+
}).slice(0, (nucleotides.endsWith('(invabasic)') || nucleotides.endsWith('(GalNAc-2-JNJ)')) ? nucleotides.length : 2 * count + 1);
|
|
338
544
|
}
|
|
339
545
|
|
|
340
546
|
//name: asoGapmersNucleotidesToGcrs
|
|
341
547
|
//input: string nucleotides {semType: DNA nucleotides}
|
|
342
548
|
//output: string result {semType: GCRS / Gapmers}
|
|
343
|
-
export function asoGapmersNucleotidesToGcrs(nucleotides: string) {
|
|
549
|
+
export function asoGapmersNucleotidesToGcrs(nucleotides: string): string {
|
|
344
550
|
let count: number = -1;
|
|
345
|
-
const objForEdges: {[index: string]: string} = {
|
|
346
|
-
const objForCenter: {[index: string]: string} = {
|
|
347
|
-
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) {
|
|
348
554
|
count++;
|
|
349
555
|
if (count < 5) return (count == 4) ? objForEdges[x].slice(0, -3) + 'ps' : objForEdges[x];
|
|
350
556
|
if (count < 15) return (count == 14) ? objForCenter[x].slice(0, -2) + 'nps' : objForCenter[x];
|
|
351
557
|
return objForEdges[x];
|
|
352
|
-
}).slice(0, -3);
|
|
558
|
+
}).slice(0, (nucleotides.endsWith('(invabasic)') || nucleotides.endsWith('(GalNAc-2-JNJ)')) ? nucleotides.length : -3);
|
|
353
559
|
}
|
|
354
560
|
|
|
355
561
|
//name: asoGapmersBioSpringToNucleotides
|
|
356
562
|
//input: string nucleotides {semType: BioSpring / Gapmers}
|
|
357
563
|
//output: string result {semType: DNA nucleotides}
|
|
358
|
-
export function asoGapmersBioSpringToNucleotides(nucleotides: string) {
|
|
359
|
-
const obj: {[index: string]: string} = {
|
|
360
|
-
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];});
|
|
361
567
|
}
|
|
362
568
|
|
|
363
569
|
//name: asoGapmersBioSpringToGcrs
|
|
364
570
|
//input: string nucleotides {semType: BioSpring / Gapmers}
|
|
365
571
|
//output: string result {semType: GCRS / Gapmers}
|
|
366
|
-
export function asoGapmersBioSpringToGcrs(nucleotides: string) {
|
|
572
|
+
export function asoGapmersBioSpringToGcrs(nucleotides: string): string {
|
|
367
573
|
let count: number = -1;
|
|
368
|
-
const obj: {[index: string]: string} = {
|
|
369
|
-
|
|
370
|
-
|
|
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'
|
|
371
577
|
};
|
|
372
|
-
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) {
|
|
373
579
|
count++;
|
|
374
580
|
return (count == 4) ? obj[x].slice(0, -3) + 'ps' : (count == 14) ? obj[x].slice(0, -2) + 'nps' : obj[x];
|
|
375
581
|
});
|
|
@@ -378,103 +584,103 @@ export function asoGapmersBioSpringToGcrs(nucleotides: string) {
|
|
|
378
584
|
//name: asoGapmersGcrsToBioSpring
|
|
379
585
|
//input: string nucleotides {semType: GCRS / Gapmers}
|
|
380
586
|
//output: string result {semType: BioSpring / Gapmers}
|
|
381
|
-
export function asoGapmersGcrsToBioSpring(nucleotides: string) {
|
|
382
|
-
const obj: {[index: string]: string} = {
|
|
383
|
-
|
|
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'
|
|
384
590
|
};
|
|
385
|
-
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];});
|
|
386
592
|
}
|
|
387
593
|
|
|
388
594
|
//name: asoGapmersGcrsToNucleotides
|
|
389
595
|
//input: string nucleotides {semType: GCRS / Gapmers}
|
|
390
596
|
//output: string result {semType: DNA nucleotides}
|
|
391
597
|
export function asoGapmersGcrsToNucleotides(nucleotides: string) {
|
|
392
|
-
const obj: {[index: string]: string} = {
|
|
393
|
-
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];});
|
|
394
600
|
}
|
|
395
601
|
|
|
396
602
|
//name: siRnaBioSpringToNucleotides
|
|
397
603
|
//input: string nucleotides {semType: BioSpring / siRNA}
|
|
398
604
|
//output: string result {semType: RNA nucleotides}
|
|
399
605
|
export function siRnaBioSpringToNucleotides(nucleotides: string) {
|
|
400
|
-
const obj: {[index: string]: string} = {
|
|
401
|
-
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];});
|
|
402
608
|
}
|
|
403
609
|
|
|
404
610
|
//name: siRnaBioSpringToAxolabs
|
|
405
611
|
//input: string nucleotides {semType: BioSpring / siRNA}
|
|
406
612
|
//output: string result {semType: Axolabs / siRNA}
|
|
407
613
|
export function siRnaBioSpringToAxolabs(nucleotides: string) {
|
|
408
|
-
const obj: {[index: string]: string} = {
|
|
409
|
-
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];});
|
|
410
616
|
}
|
|
411
617
|
|
|
412
618
|
//name: siRnaBioSpringToGcrs
|
|
413
619
|
//input: string nucleotides {semType: BioSpring / siRNA}
|
|
414
620
|
//output: string result {semType: GCRS}
|
|
415
621
|
export function siRnaBioSpringToGcrs(nucleotides: string) {
|
|
416
|
-
const obj: {[index: string]: string} = {
|
|
417
|
-
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];});
|
|
418
624
|
}
|
|
419
625
|
|
|
420
626
|
//name: siRnaAxolabsToGcrs
|
|
421
627
|
//input: string nucleotides {semType: Axolabs / siRNA}
|
|
422
628
|
//output: string result {semType: GCRS}
|
|
423
629
|
export function siRnaAxolabsToGcrs(nucleotides: string) {
|
|
424
|
-
const obj: {[index: string]: string} = {
|
|
425
|
-
|
|
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'
|
|
426
632
|
};
|
|
427
|
-
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];});
|
|
428
634
|
}
|
|
429
635
|
|
|
430
636
|
//name: siRnaAxolabsToBioSpring
|
|
431
637
|
//input: string nucleotides {semType: Axolabs / siRNA}
|
|
432
638
|
//output: string result {semType: BioSpring / siRNA}
|
|
433
639
|
export function siRnaAxolabsToBioSpring(nucleotides: string) {
|
|
434
|
-
const obj: {[index: string]: string} = {
|
|
435
|
-
|
|
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': '*'
|
|
436
642
|
};
|
|
437
|
-
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];});
|
|
438
644
|
}
|
|
439
645
|
|
|
440
646
|
//name: siRnaAxolabsToNucleotides
|
|
441
647
|
//input: string nucleotides {semType: Axolabs / siRNA}
|
|
442
648
|
//output: string result {semType: RNA nucleotides}
|
|
443
649
|
export function siRnaAxolabsToNucleotides(nucleotides: string) {
|
|
444
|
-
const obj: {[index: string]: string} = {
|
|
445
|
-
|
|
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': ''
|
|
446
652
|
};
|
|
447
|
-
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];});
|
|
448
654
|
}
|
|
449
655
|
|
|
450
656
|
//name: siRnaGcrsToNucleotides
|
|
451
657
|
//input: string nucleotides {semType: GCRS}
|
|
452
658
|
//output: string result {semType: RNA nucleotides}
|
|
453
659
|
export function siRnaGcrsToNucleotides(nucleotides: string) {
|
|
454
|
-
const obj: {[index: string]: string} = {
|
|
455
|
-
|
|
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': ''
|
|
456
662
|
};
|
|
457
|
-
return nucleotides.replace(/(fU|fA|fC|fG|mU|mA|mC|mG|ps
|
|
663
|
+
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|fU|fA|fC|fG|mU|mA|mC|mG|ps)/g, function (x: string) {return obj[x];});
|
|
458
664
|
}
|
|
459
665
|
|
|
460
666
|
//name: siRnaGcrsToBioSpring
|
|
461
667
|
//input: string nucleotides {semType: GCRS}
|
|
462
668
|
//output: string result {semType: BioSpring / siRNA}
|
|
463
669
|
export function siRnaGcrsToBioSpring(nucleotides: string) {
|
|
464
|
-
const obj: {[index: string]: string} = {
|
|
465
|
-
|
|
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': '*'
|
|
466
672
|
};
|
|
467
|
-
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];});
|
|
468
674
|
}
|
|
469
675
|
|
|
470
676
|
//name: siRnaGcrsToAxolabs
|
|
471
677
|
//input: string nucleotides {semType: GCRS}
|
|
472
678
|
//output: string result {semType: Axolabs / siRNA}
|
|
473
679
|
export function siRnaGcrsToAxolabs(nucleotides: string) {
|
|
474
|
-
const obj: {[index: string]: string} = {
|
|
475
|
-
|
|
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'
|
|
476
682
|
};
|
|
477
|
-
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];});
|
|
478
684
|
}
|
|
479
685
|
|
|
480
686
|
//name: siRnaNucleotideToBioSpringSenseStrand
|
|
@@ -482,11 +688,11 @@ export function siRnaGcrsToAxolabs(nucleotides: string) {
|
|
|
482
688
|
//output: string result {semType: BioSpring / siRNA}
|
|
483
689
|
export function siRnaNucleotideToBioSpringSenseStrand(nucleotides: string) {
|
|
484
690
|
let count: number = -1;
|
|
485
|
-
const objForLeftEdge: {[index: string]: string} = {
|
|
486
|
-
const objForRightEdge: {[index: string]: string} = {
|
|
487
|
-
const objForOddIndices: {[index: string]: string} = {
|
|
488
|
-
const objForEvenIndices: {[index: string]: string} = {
|
|
489
|
-
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) {
|
|
490
696
|
count++;
|
|
491
697
|
if (count < 2) return objForLeftEdge[x];
|
|
492
698
|
if (count > nucleotides.length - 3) return objForRightEdge[x];
|
|
@@ -499,11 +705,11 @@ export function siRnaNucleotideToBioSpringSenseStrand(nucleotides: string) {
|
|
|
499
705
|
//output: string result {semType: GCRS}
|
|
500
706
|
export function siRnaNucleotidesToGcrs(nucleotides: string) {
|
|
501
707
|
let count: number = -1;
|
|
502
|
-
const objForLeftEdge: {[index: string]: string} = {
|
|
503
|
-
const objForRightEdge: {[index: string]: string} = {
|
|
504
|
-
const objForEvenIndices: {[index: string]: string} = {
|
|
505
|
-
const objForOddIndices: {[index: string]: string} = {
|
|
506
|
-
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) {
|
|
507
713
|
count++;
|
|
508
714
|
if (count < 2) return objForLeftEdge[x];
|
|
509
715
|
if (count > nucleotides.length - 3) return objForRightEdge[x];
|
|
@@ -516,10 +722,10 @@ export function siRnaNucleotidesToGcrs(nucleotides: string) {
|
|
|
516
722
|
//output: string result {semType: Axolabs}
|
|
517
723
|
export function siRnaNucleotideToAxolabsSenseStrand(nucleotides: string) {
|
|
518
724
|
let count: number = -1;
|
|
519
|
-
const objForLeftEdge: {[index: string]: string} = {
|
|
520
|
-
const objForSomeIndices: {[index: string]: string} = {
|
|
521
|
-
const obj: {[index: string]: string} = {
|
|
522
|
-
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) {
|
|
523
729
|
count++;
|
|
524
730
|
if (count < 2) return objForLeftEdge[x];
|
|
525
731
|
if (count == 6 || (count > 7 && count < 11)) return objForSomeIndices[x]
|
|
@@ -533,11 +739,11 @@ export function siRnaNucleotideToAxolabsSenseStrand(nucleotides: string) {
|
|
|
533
739
|
//output: string result {semType: Axolabs}
|
|
534
740
|
export function siRnaNucleotideToAxolabsAntisenseStrand(nucleotides: string) {
|
|
535
741
|
let count: number = -1;
|
|
536
|
-
const objForSmallLinkages: {[index: string]: string} = {
|
|
537
|
-
const objForBigLinkages: {[index: string]: string} = {
|
|
538
|
-
const objForSomeIndices: {[index: string]: string} = {
|
|
539
|
-
const obj: {[index: string]: string} = {
|
|
540
|
-
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) {
|
|
541
747
|
count++;
|
|
542
748
|
if (count > 19 && count < 22) return objForSmallLinkages[x];
|
|
543
749
|
if (count == 0) return 'us';
|
|
@@ -550,69 +756,141 @@ export function siRnaNucleotideToAxolabsAntisenseStrand(nucleotides: string) {
|
|
|
550
756
|
//input: string nucleotides {semType: GCRS}
|
|
551
757
|
//output: string result {semType: RNA nucleotides}
|
|
552
758
|
export function gcrsToNucleotides(nucleotides: string) {
|
|
553
|
-
const obj: {[index: string]: string} = {
|
|
554
|
-
|
|
555
|
-
|
|
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'
|
|
556
762
|
};
|
|
557
|
-
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];});
|
|
558
764
|
}
|
|
559
765
|
|
|
560
|
-
//name:
|
|
766
|
+
//name: gcrsToMermade12
|
|
561
767
|
//input: string nucleotides {semType: GCRS}
|
|
562
|
-
//output: string result {semType:
|
|
563
|
-
export function
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
};
|
|
568
|
-
const objForOddIndicesAtLeftEdge: {[index: string]: string} = {
|
|
569
|
-
"mAps": "a*", "mUps": "u*", "mGps": "g*", "mCps": "c*", "fAps": "a*", "fUps": "u*", "fGps": "g*", "fCps": "c*"
|
|
570
|
-
};
|
|
571
|
-
// const objForEvenIndicesAtRightEdge: {[index: string]: string} = {
|
|
572
|
-
// "fU": "u*", "fA": "a*", "fC": "c*", "fG": "g*", "mU": "u*", "mA": "a*", "mC": "c*", "mG": "g*"
|
|
573
|
-
// };
|
|
574
|
-
const objForOddIndicesAtRightEdge: {[index: string]: string} = {
|
|
575
|
-
"mAps": "a", "mUps": "u", "mGps": "g", "mCps": "c", "fAps": "a", "fUps": "u", "fGps": "g", "fCps": "c"
|
|
576
|
-
};
|
|
577
|
-
const objForEvenIndicesAtCenter: {[index: string]: string} = {
|
|
578
|
-
"fU": "u*", "fA": "a*", "fC": "c*", "fG": "g*", "mU": "u*", "mA": "a*", "mC": "c*", "mG": "g*"
|
|
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'
|
|
579
773
|
};
|
|
580
|
-
|
|
581
|
-
"fU": "u", "fA": "a", "fC": "c", "fG": "g", "mU": "u", "mA": "a", "mC": "c", "mG": "g"
|
|
582
|
-
};
|
|
583
|
-
return nucleotides.replace(/(mAps|mUps|mGps|mCps|fAps|fUps|fGps|fCps|fU|fA|fC|fG|mU|mA|mC|mG)/g, function (x: string) {
|
|
584
|
-
count++;
|
|
585
|
-
if (count < 3) return (count % 2 == 0) ? objForEvenIndicesAtLeftEdge[x] : objForOddIndicesAtLeftEdge[x];
|
|
586
|
-
if (count == 19) return objForOddIndicesAtRightEdge[x];
|
|
587
|
-
return (count % 2 == 1) ? objForEvenIndicesAtCenter[x] : objForOddIndicesAtCenter[x];
|
|
588
|
-
});
|
|
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]});
|
|
589
775
|
}
|
|
590
776
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
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();
|
|
600
800
|
}
|
|
601
801
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
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);
|
|
612
814
|
});
|
|
613
815
|
}
|
|
614
816
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
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
|
+
}
|