@datagrok/sequence-translator 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/package.ts CHANGED
@@ -5,216 +5,17 @@ import * as DG from 'datagrok-api/dg';
5
5
  import * as OCL from 'openchemlib/full.js';
6
6
  import $ from 'cash-dom';
7
7
  import {defineAxolabsPattern} from './defineAxolabsPattern';
8
- import {saveSenseAntiSense} from './save-sense-antisense';
9
- import {map, stadardPhosphateLinkSmiles, SYNTHESIZERS, TECHNOLOGIES, MODIFICATIONS} from './map';
8
+ import {saveSenseAntiSense} from './structures-works/save-sense-antisense';
9
+ import {sequenceToSmiles} from './structures-works/from-monomers';
10
+ import {convertSequence, undefinedInputSequence} from './structures-works/sequence-codes-tools';
11
+ import {SALTS_CSV} from './salts';
10
12
 
11
13
  export const _package = new DG.Package();
12
14
 
13
15
  const defaultInput = 'AGGTCCTCTTGACTTAGGCC';
14
- const undefinedInputSequence = 'Type of input sequence is undefined';
15
- const noTranslationTableAvailable = 'No translation table available';
16
16
  const sequenceWasCopied = 'Copied';
17
17
  const tooltipSequence = 'Copy sequence';
18
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
- }
25
-
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]))
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;
166
- }
167
-
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
19
  //name: Sequence Translator
219
20
  //tags: app
220
21
  export function sequenceTranslator(): void {
@@ -233,11 +34,11 @@ export function sequenceTranslator(): void {
233
34
  const tableRows = [];
234
35
 
235
36
  for (const key of Object.keys(outputSequenceObj).slice(1)) {
236
- let indexOfFirstNotValidCharacter = ('indexOfFirstNotValidCharacter' in outputSequenceObj) ?
37
+ const indexOfFirstNotValidCharacter = ('indexOfFirstNotValidCharacter' in outputSequenceObj) ?
237
38
  JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!).indexOfFirstNotValidCharacter :
238
39
  -1;
239
40
  if ('indexOfFirstNotValidCharacter' in outputSequenceObj) {
240
- let indexOfFirstNotValidCharacter = ('indexOfFirstNotValidCharacter' in outputSequenceObj) ?
41
+ const indexOfFirstNotValidCharacter = ('indexOfFirstNotValidCharacter' in outputSequenceObj) ?
241
42
  JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!).indexOfFirstNotValidCharacter :
242
43
  -1;
243
44
  if (indexOfFirstNotValidCharacter != -1)
@@ -251,46 +52,50 @@ export function sequenceTranslator(): void {
251
52
  ui.divText(sequence.slice(0, indexOfFirstNotValidCharacter), {style: {color: 'grey'}}),
252
53
  ui.tooltip.bind(
253
54
  ui.divText(sequence.slice(indexOfFirstNotValidCharacter), {style: {color: 'red'}}),
254
- 'Expected format: ' + JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!).expectedSynthesizer + '. See tables with valid codes on the right'
55
+ 'Expected format: ' + JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!).expectedSynthesizer +
56
+ '. See tables with valid codes on the right',
255
57
  ),
256
58
  ]) : //@ts-ignore
257
- ui.link(outputSequenceObj[key], () => navigator.clipboard.writeText(outputSequenceObj[key]).then(() => grok.shell.info(sequenceWasCopied)), tooltipSequence, '')
59
+ ui.link(outputSequenceObj[key], () => navigator.clipboard.writeText(outputSequenceObj[key])
60
+ .then(() => grok.shell.info(sequenceWasCopied)), tooltipSequence, ''),
258
61
  });
259
62
  }
260
63
 
261
64
  if (errorsExist) {
262
- const expectedSynthesizer = JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!).expectedSynthesizer.slice(0, -6);
263
- asoGapmersGrid.onCellPrepare(function (gc) {
65
+ const expectedSynthesizer = JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!)
66
+ .expectedSynthesizer.slice(0, -6);
67
+ asoGapmersGrid.onCellPrepare(function(gc) {
264
68
  gc.style.backColor = (gc.gridColumn.name == expectedSynthesizer) ? 0xFFF00000 : 0xFFFFFFFF;
265
69
  });
266
- omeAndFluoroGrid.onCellPrepare(function (gc) {
70
+ omeAndFluoroGrid.onCellPrepare(function(gc) {
267
71
  gc.style.backColor = (gc.gridColumn.name == expectedSynthesizer) ? 0xFFF00000 : 0xFFFFFFFF;
268
72
  });
269
73
  switchInput.enabled = true;
270
74
  } else {
271
- asoGapmersGrid.onCellPrepare(function (gc) {
75
+ asoGapmersGrid.onCellPrepare(function(gc) {
272
76
  gc.style.backColor = 0xFFFFFFFF;
273
77
  });
274
- omeAndFluoroGrid.onCellPrepare(function (gc) {
78
+ omeAndFluoroGrid.onCellPrepare(function(gc) {
275
79
  gc.style.backColor = 0xFFFFFFFF;
276
80
  });
277
81
  }
278
82
 
279
83
  outputTableDiv.append(
280
84
  ui.div([
281
- DG.HtmlTable.create(tableRows, (item: { key: string; value: string; }) => [item.key, item.value], ['Code', 'Sequence']).root
282
- ], 'table')
85
+ DG.HtmlTable.create(tableRows, (item: { key: string; value: string; }) =>
86
+ [item.key, item.value], ['Code', 'Sequence']).root,
87
+ ], 'table'),
283
88
  );
284
89
  semTypeOfInputSequence.textContent = 'Detected input type: ' + outputSequenceObj.type;
285
90
 
286
91
  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());
92
+ const canvas = ui.canvas(300, 170);
93
+ canvas.addEventListener('click', () => {
94
+ const canv = ui.canvas($(window).width(), $(window).height());
290
95
  const smiles = sequenceToSmiles(inputSequenceField.value.replace(/\s/g, ''));
291
96
  // @ts-ignore
292
- OCL.StructureView.drawMolecule(canv, OCL.Molecule.fromSmiles(smiles), { suppressChiralText: true });
293
- ui.dialog('Molecule')
97
+ OCL.StructureView.drawMolecule(canv, OCL.Molecule.fromSmiles(smiles), {suppressChiralText: true});
98
+ ui.dialog('Molecule: ' + inputSequenceField.value)
294
99
  .add(canv)
295
100
  .showModal(true);
296
101
  });
@@ -298,7 +103,7 @@ export function sequenceTranslator(): void {
298
103
  $(canvas).on('mouseout', () => $(canvas).css('cursor', 'default'));
299
104
  const smiles = sequenceToSmiles(inputSequenceField.value.replace(/\s/g, ''));
300
105
  // @ts-ignore
301
- OCL.StructureView.drawMolecule(canvas, OCL.Molecule.fromSmiles(smiles), { suppressChiralText: true });
106
+ OCL.StructureView.drawMolecule(canvas, OCL.Molecule.fromSmiles(smiles), {suppressChiralText: true});
302
107
  moleculeSvgDiv.append(canvas);
303
108
  } else
304
109
  moleculeSvgDiv.innerHTML = '';
@@ -313,69 +118,66 @@ export function sequenceTranslator(): void {
313
118
  const inputSequenceField = ui.textInput('', defaultInput, (sequence: string) => updateTableAndMolecule(sequence));
314
119
 
315
120
  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" }
121
+ {'Name': '2\'MOE-5Me-rU', 'BioSpring': '5', 'Janssen GCRS': 'moeT'},
122
+ {'Name': '2\'MOE-rA', 'BioSpring': '6', 'Janssen GCRS': 'moeA'},
123
+ {'Name': '2\'MOE-5Me-rC', 'BioSpring': '7', 'Janssen GCRS': 'moe5mC'},
124
+ {'Name': '2\'MOE-rG', 'BioSpring': '8', 'Janssen GCRS': 'moeG'},
125
+ {'Name': '5-Methyl-dC', 'BioSpring': '9', 'Janssen GCRS': '5mC'},
126
+ {'Name': 'ps linkage', 'BioSpring': '*', 'Janssen GCRS': 'ps'},
127
+ {'Name': 'dA', 'BioSpring': 'A', 'Janssen GCRS': 'A, dA'},
128
+ {'Name': 'dC', 'BioSpring': 'C', 'Janssen GCRS': 'C, dC'},
129
+ {'Name': 'dG', 'BioSpring': 'G', 'Janssen GCRS': 'G, dG'},
130
+ {'Name': 'dT', 'BioSpring': 'T', 'Janssen GCRS': 'T, dT'},
131
+ {'Name': 'rA', 'BioSpring': '', 'Janssen GCRS': 'rA'},
132
+ {'Name': 'rC', 'BioSpring': '', 'Janssen GCRS': 'rC'},
133
+ {'Name': 'rG', 'BioSpring': '', 'Janssen GCRS': 'rG'},
134
+ {'Name': 'rU', 'BioSpring': '', 'Janssen GCRS': 'rU'},
330
135
  ])!;
331
- const asoGapmersGrid = DG.Viewer.grid(
332
- asoDf, { showRowHeader: false, showCellTooltip: false }
333
- );
136
+ const asoGapmersGrid = DG.Viewer.grid(asoDf, {showRowHeader: false, showCellTooltip: false});
334
137
 
335
138
  asoDf.onCurrentCellChanged.subscribe((_) => {
336
- navigator.clipboard.writeText(asoDf.currentCell.value).then(() => grok.shell.info('Copied'))
139
+ navigator.clipboard.writeText(asoDf.currentCell.value).then(() => grok.shell.info('Copied'));
337
140
  });
338
141
 
339
- let omeAndFluoroGrid = DG.Viewer.grid(
142
+ const omeAndFluoroGrid = DG.Viewer.grid(
340
143
  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 }
144
+ {'Name': '2\'-fluoro-U', 'BioSpring': '1', 'Axolabs': 'Uf', 'Janssen GCRS': 'fU'},
145
+ {'Name': '2\'-fluoro-A', 'BioSpring': '2', 'Axolabs': 'Af', 'Janssen GCRS': 'fA'},
146
+ {'Name': '2\'-fluoro-C', 'BioSpring': '3', 'Axolabs': 'Cf', 'Janssen GCRS': 'fC'},
147
+ {'Name': '2\'-fluoro-G', 'BioSpring': '4', 'Axolabs': 'Gf', 'Janssen GCRS': 'fG'},
148
+ {'Name': '2\'OMe-rU', 'BioSpring': '5', 'Axolabs': 'u', 'Janssen GCRS': 'mU'},
149
+ {'Name': '2\'OMe-rA', 'BioSpring': '6', 'Axolabs': 'a', 'Janssen GCRS': 'mA'},
150
+ {'Name': '2\'OMe-rC', 'BioSpring': '7', 'Axolabs': 'c', 'Janssen GCRS': 'mC'},
151
+ {'Name': '2\'OMe-rG', 'BioSpring': '8', 'Axolabs': 'g', 'Janssen GCRS': 'mG'},
152
+ {'Name': 'ps linkage', 'BioSpring': '*', 'Axolabs': 's', 'Janssen GCRS': 'ps'},
153
+ ])!, {showRowHeader: false, showCellTooltip: false},
351
154
  );
352
155
 
353
156
  const overhangModificationsGrid = DG.Viewer.grid(
354
157
  DG.DataFrame.fromObjects([
355
- { Name: "(invabasic)" },
356
- { Name: "(GalNAc-2-JNJ)" }
357
- ])!, { showRowHeader: false, showCellTooltip: false }
158
+ {'Name': '(invabasic)'},
159
+ {'Name': '(GalNAc-2-JNJ)'},
160
+ ])!, {showRowHeader: false, showCellTooltip: false},
358
161
  );
359
162
  updateTableAndMolecule(defaultInput);
360
163
 
361
164
  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
- );
165
+ ui.divText('How to convert one sequence:', {style: {'font-weight': 'bolder'}}),
166
+ ui.divText('Paste sequence into the text field below'),
167
+ ui.divText('\n How to convert many sequences:', {style: {'font-weight': 'bolder'}}),
168
+ ui.divText('1. Drag & drop an Excel or CSV file with sequences into Datagrok'),
169
+ ui.divText('2. Right-click on the column header, then see the \'Convert\' menu'),
170
+ ui.divText('This will add the result column to the right of the table'),
171
+ ], 'Convert oligonucleotide sequences between Nucleotides, BioSpring, Axolabs, Mermade 12 and GCRS representations.');
370
172
 
371
173
  const codesTablesDiv = ui.splitV([
372
- ui.box(ui.h2('ASO Gapmers'), { style: {maxHeight: '40px'} }),
174
+ ui.box(ui.h2('ASO Gapmers'), {style: {maxHeight: '40px'}}),
373
175
  asoGapmersGrid.root,
374
- ui.box(ui.h2("2'-OMe and 2'-F siRNA"), { style: {maxHeight: '40px'} }),
176
+ ui.box(ui.h2('2\'-OMe and 2\'-F siRNA'), {style: {maxHeight: '40px'}}),
375
177
  omeAndFluoroGrid.root,
376
- ui.box(ui.h2('Overhang modifications'), { style: {maxHeight: '40px'} }),
377
- overhangModificationsGrid.root
378
- ], { style: { maxWidth: '350px' } });
178
+ ui.box(ui.h2('Overhang modifications'), {style: {maxHeight: '40px'}}),
179
+ overhangModificationsGrid.root,
180
+ ], {style: {maxWidth: '350px'}});
379
181
 
380
182
  const tabControl = ui.tabControl({
381
183
  'MAIN': ui.box(
@@ -404,12 +206,12 @@ export function sequenceTranslator(): void {
404
206
  'SDF': saveSenseAntiSense(),
405
207
  });
406
208
 
407
- let v = grok.shell.newView('Sequence Translator', [tabControl]);
209
+ const v = grok.shell.newView('Sequence Translator', [tabControl]);
408
210
  v.box = true;
409
211
 
410
212
  const switchInput = ui.switchInput('Codes', true, (v: boolean) => (v) ?
411
213
  $(codesTablesDiv).show() :
412
- $(codesTablesDiv).hide()
214
+ $(codesTablesDiv).hide(),
413
215
  );
414
216
 
415
217
  const topPanel = [
@@ -433,379 +235,43 @@ export function sequenceTranslator(): void {
433
235
  v.setRibbonPanels([topPanel]);
434
236
 
435
237
  $('.sequence')
436
- .children().css('padding','5px 0');
238
+ .children().css('padding', '5px 0');
437
239
  $('.sequenceInput .input-base')
438
- .css('margin','0');
240
+ .css('margin', '0');
439
241
  $('.sequenceInput textarea')
440
- .css('resize','none')
441
- .css('min-height','50px')
442
- .css('width','100%')
242
+ .css('resize', 'none')
243
+ .css('min-height', '50px')
244
+ .css('width', '100%')
443
245
  .attr('spellcheck', 'false');
444
246
  $('.sequenceInput select')
445
- .css('width','100%');
446
- }
447
-
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)
453
- return {
454
- // type: '',
455
- indexOfFirstNotValidCharacter: JSON.stringify(output),
456
- Error: undefinedInputSequence
457
- };
458
- if (output.expectedSynthesizer == SYNTHESIZERS.RAW_NUCLEOTIDES && output.expectedTechnology == TECHNOLOGIES.DNA)
459
- return {
460
- type: SYNTHESIZERS.RAW_NUCLEOTIDES + ' ' + TECHNOLOGIES.DNA,
461
- Nucleotides: seq,
462
- BioSpring: asoGapmersNucleotidesToBioSpring(seq),
463
- GCRS: asoGapmersNucleotidesToGcrs(seq)
464
- };
465
- if (output.expectedSynthesizer == SYNTHESIZERS.BIOSPRING && output.expectedTechnology == TECHNOLOGIES.ASO_GAPMERS)
466
- return {
467
- type: SYNTHESIZERS.BIOSPRING + ' ' + TECHNOLOGIES.ASO_GAPMERS,
468
- Nucleotides: asoGapmersBioSpringToNucleotides(seq),
469
- BioSpring: seq,
470
- GCRS: asoGapmersBioSpringToGcrs(seq)
471
- };
472
- if (output.expectedSynthesizer == SYNTHESIZERS.GCRS && output.expectedTechnology == TECHNOLOGIES.ASO_GAPMERS)
473
- return {
474
- type: SYNTHESIZERS.GCRS + ' ' + TECHNOLOGIES.ASO_GAPMERS,
475
- Nucleotides: asoGapmersGcrsToNucleotides(seq),
476
- BioSpring: asoGapmersGcrsToBioSpring(seq),
477
- Mermade12: gcrsToMermade12(seq),
478
- GCRS: seq
479
- };
480
- if (output.expectedSynthesizer == SYNTHESIZERS.RAW_NUCLEOTIDES && output.expectedTechnology == TECHNOLOGIES.RNA)
481
- return {
482
- type: SYNTHESIZERS.RAW_NUCLEOTIDES + ' ' + TECHNOLOGIES.RNA,
483
- Nucleotides: seq,
484
- BioSpring: siRnaNucleotideToBioSpringSenseStrand(seq),
485
- Axolabs: siRnaNucleotideToAxolabsSenseStrand(seq),
486
- GCRS: siRnaNucleotidesToGcrs(seq)
487
- };
488
- if (output.expectedSynthesizer == SYNTHESIZERS.BIOSPRING && output.expectedTechnology == TECHNOLOGIES.SI_RNA)
489
- return {
490
- type: SYNTHESIZERS.BIOSPRING + ' ' + TECHNOLOGIES.SI_RNA,
491
- Nucleotides: siRnaBioSpringToNucleotides(seq),
492
- BioSpring: seq,
493
- Axolabs: siRnaBioSpringToAxolabs(seq),
494
- GCRS: siRnaBioSpringToGcrs(seq)
495
- };
496
- if (output.expectedSynthesizer == SYNTHESIZERS.AXOLABS && output.expectedTechnology == TECHNOLOGIES.SI_RNA)
497
- return {
498
- type: SYNTHESIZERS.AXOLABS + ' ' + TECHNOLOGIES.SI_RNA,
499
- Nucleotides: siRnaAxolabsToNucleotides(seq),
500
- BioSpring: siRnaAxolabsToBioSpring(seq),
501
- Axolabs: seq,
502
- GCRS: siRnaAxolabsToGcrs(seq)
503
- };
504
- if (output.expectedSynthesizer == SYNTHESIZERS.GCRS && output.expectedTechnology == TECHNOLOGIES.SI_RNA)
505
- return {
506
- type: SYNTHESIZERS.GCRS + ' ' + TECHNOLOGIES.SI_RNA,
507
- Nucleotides: siRnaGcrsToNucleotides(seq),
508
- BioSpring: siRnaGcrsToBioSpring(seq),
509
- Axolabs: siRnaGcrsToAxolabs(seq),
510
- MM12: gcrsToMermade12(seq),
511
- GCRS: seq
512
- };
513
- if (output.expectedSynthesizer == SYNTHESIZERS.GCRS)
514
- return {
515
- type: SYNTHESIZERS.GCRS,
516
- Nucleotides: gcrsToNucleotides(seq),
517
- GCRS: seq,
518
- Mermade12: gcrsToMermade12(seq)
519
- }
520
- if (output.expectedSynthesizer == SYNTHESIZERS.MERMADE_12)
521
- return {
522
- type: SYNTHESIZERS.MERMADE_12,
523
- Nucleotides: noTranslationTableAvailable,
524
- GCRS: noTranslationTableAvailable,
525
- Mermade12: seq
526
- };
527
- return {
528
- type: undefinedInputSequence,
529
- Nucleotides: undefinedInputSequence
530
- };
531
- }
532
-
533
- //name: asoGapmersNucleotidesToBioSpring
534
- //input: string nucleotides {semType: DNA nucleotides}
535
- //output: string result {semType: BioSpring / Gapmers}
536
- export function asoGapmersNucleotidesToBioSpring(nucleotides: string): string {
537
- let count: number = -1;
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) {
541
- count++;
542
- return (count > 4 && count < 15) ? objForCenter[x] : objForEdges[x];
543
- }).slice(0, (nucleotides.endsWith('(invabasic)') || nucleotides.endsWith('(GalNAc-2-JNJ)')) ? nucleotides.length : 2 * count + 1);
544
- }
545
-
546
- //name: asoGapmersNucleotidesToGcrs
547
- //input: string nucleotides {semType: DNA nucleotides}
548
- //output: string result {semType: GCRS / Gapmers}
549
- export function asoGapmersNucleotidesToGcrs(nucleotides: string): string {
550
- let count: number = -1;
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) {
554
- count++;
555
- if (count < 5) return (count == 4) ? objForEdges[x].slice(0, -3) + 'ps' : objForEdges[x];
556
- if (count < 15) return (count == 14) ? objForCenter[x].slice(0, -2) + 'nps' : objForCenter[x];
557
- return objForEdges[x];
558
- }).slice(0, (nucleotides.endsWith('(invabasic)') || nucleotides.endsWith('(GalNAc-2-JNJ)')) ? nucleotides.length : -3);
559
- }
560
-
561
- //name: asoGapmersBioSpringToNucleotides
562
- //input: string nucleotides {semType: BioSpring / Gapmers}
563
- //output: string result {semType: DNA nucleotides}
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];});
567
- }
568
-
569
- //name: asoGapmersBioSpringToGcrs
570
- //input: string nucleotides {semType: BioSpring / Gapmers}
571
- //output: string result {semType: GCRS / Gapmers}
572
- export function asoGapmersBioSpringToGcrs(nucleotides: string): string {
573
- let count: number = -1;
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'
577
- };
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) {
579
- count++;
580
- return (count == 4) ? obj[x].slice(0, -3) + 'ps' : (count == 14) ? obj[x].slice(0, -2) + 'nps' : obj[x];
581
- });
582
- }
583
-
584
- //name: asoGapmersGcrsToBioSpring
585
- //input: string nucleotides {semType: GCRS / Gapmers}
586
- //output: string result {semType: BioSpring / Gapmers}
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'
590
- };
591
- return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|moeT|moeA|moe5mC|moeG|moeU|5mC|nps|ps|U)/g, function (x: string) {return obj[x];});
592
- }
593
-
594
- //name: asoGapmersGcrsToNucleotides
595
- //input: string nucleotides {semType: GCRS / Gapmers}
596
- //output: string result {semType: DNA nucleotides}
597
- export function asoGapmersGcrsToNucleotides(nucleotides: string) {
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];});
600
- }
601
-
602
- //name: siRnaBioSpringToNucleotides
603
- //input: string nucleotides {semType: BioSpring / siRNA}
604
- //output: string result {semType: RNA nucleotides}
605
- export function siRnaBioSpringToNucleotides(nucleotides: string) {
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];});
608
- }
609
-
610
- //name: siRnaBioSpringToAxolabs
611
- //input: string nucleotides {semType: BioSpring / siRNA}
612
- //output: string result {semType: Axolabs / siRNA}
613
- export function siRnaBioSpringToAxolabs(nucleotides: string) {
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];});
616
- }
617
-
618
- //name: siRnaBioSpringToGcrs
619
- //input: string nucleotides {semType: BioSpring / siRNA}
620
- //output: string result {semType: GCRS}
621
- export function siRnaBioSpringToGcrs(nucleotides: string) {
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];});
624
- }
625
-
626
- //name: siRnaAxolabsToGcrs
627
- //input: string nucleotides {semType: Axolabs / siRNA}
628
- //output: string result {semType: GCRS}
629
- export function siRnaAxolabsToGcrs(nucleotides: string) {
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'
632
- };
633
- return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|Uf|Af|Cf|Gf|u|a|c|g|s)/g, function (x: string) {return obj[x];});
634
- }
635
-
636
- //name: siRnaAxolabsToBioSpring
637
- //input: string nucleotides {semType: Axolabs / siRNA}
638
- //output: string result {semType: BioSpring / siRNA}
639
- export function siRnaAxolabsToBioSpring(nucleotides: string) {
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': '*'
642
- };
643
- return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|Uf|Af|Cf|Gf|u|a|c|g|s)/g, function (x: string) {return obj[x];});
644
- }
645
-
646
- //name: siRnaAxolabsToNucleotides
647
- //input: string nucleotides {semType: Axolabs / siRNA}
648
- //output: string result {semType: RNA nucleotides}
649
- export function siRnaAxolabsToNucleotides(nucleotides: string) {
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': ''
652
- };
653
- return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|Uf|Af|Cf|Gf|u|a|c|g|s)/g, function (x: string) {return obj[x];});
654
- }
655
-
656
- //name: siRnaGcrsToNucleotides
657
- //input: string nucleotides {semType: GCRS}
658
- //output: string result {semType: RNA nucleotides}
659
- export function siRnaGcrsToNucleotides(nucleotides: string) {
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': ''
662
- };
663
- return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|fU|fA|fC|fG|mU|mA|mC|mG|ps)/g, function (x: string) {return obj[x];});
664
- }
665
-
666
- //name: siRnaGcrsToBioSpring
667
- //input: string nucleotides {semType: GCRS}
668
- //output: string result {semType: BioSpring / siRNA}
669
- export function siRnaGcrsToBioSpring(nucleotides: string) {
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': '*'
672
- };
673
- return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|fU|fA|fC|fG|mU|mA|mC|mG|ps)/g, function (x: string) {return obj[x];});
674
- }
675
-
676
- //name: siRnaGcrsToAxolabs
677
- //input: string nucleotides {semType: GCRS}
678
- //output: string result {semType: Axolabs / siRNA}
679
- export function siRnaGcrsToAxolabs(nucleotides: string) {
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'
682
- };
683
- return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|fU|fA|fC|fG|mU|mA|mC|mG|ps)/g, function (x: string) {return obj[x];});
684
- }
685
-
686
- //name: siRnaNucleotideToBioSpringSenseStrand
687
- //input: string nucleotides {semType: RNA nucleotides}
688
- //output: string result {semType: BioSpring / siRNA}
689
- export function siRnaNucleotideToBioSpringSenseStrand(nucleotides: string) {
690
- let count: number = -1;
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) {
696
- count++;
697
- if (count < 2) return objForLeftEdge[x];
698
- if (count > nucleotides.length - 3) return objForRightEdge[x];
699
- return (count % 2 == 0) ? objForEvenIndices[x] : objForOddIndices[x];
700
- });
701
- }
702
-
703
- //name: siRnaNucleotidesToGcrs
704
- //input: string nucleotides {semType: RNA nucleotides}
705
- //output: string result {semType: GCRS}
706
- export function siRnaNucleotidesToGcrs(nucleotides: string) {
707
- let count: number = -1;
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) {
713
- count++;
714
- if (count < 2) return objForLeftEdge[x];
715
- if (count > nucleotides.length - 3) return objForRightEdge[x];
716
- return (count % 2 == 0) ? objForEvenIndices[x] : objForOddIndices[x];
717
- });
718
- }
719
-
720
- //name: siRnaNucleotideToAxolabsSenseStrand
721
- //input: string nucleotides {semType: RNA nucleotides}
722
- //output: string result {semType: Axolabs}
723
- export function siRnaNucleotideToAxolabsSenseStrand(nucleotides: string) {
724
- let count: number = -1;
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) {
729
- count++;
730
- if (count < 2) return objForLeftEdge[x];
731
- if (count == 6 || (count > 7 && count < 11)) return objForSomeIndices[x]
732
- if (count == nucleotides.length - 1) return 'a';
733
- return obj[x];
734
- });
735
- }
736
-
737
- //name: siRnaNucleotideToAxolabsAntisenseStrand
738
- //input: string nucleotides {semType: RNA nucleotides}
739
- //output: string result {semType: Axolabs}
740
- export function siRnaNucleotideToAxolabsAntisenseStrand(nucleotides: string) {
741
- let count: number = -1;
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) {
747
- count++;
748
- if (count > 19 && count < 22) return objForSmallLinkages[x];
749
- if (count == 0) return 'us';
750
- if (count == 1) return objForBigLinkages[x];
751
- return (count == 5 || count == 7 || count == 8 || count == 13 || count == 15) ? objForSomeIndices[x] : obj[x];
752
- });
753
- }
754
-
755
- //name: gcrsToNucleotides
756
- //input: string nucleotides {semType: GCRS}
757
- //output: string result {semType: RNA nucleotides}
758
- export function gcrsToNucleotides(nucleotides: string) {
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'
762
- };
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];});
764
- }
765
-
766
- //name: gcrsToMermade12
767
- //input: string nucleotides {semType: GCRS}
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'
773
- };
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]});
247
+ .css('width', '100%');
775
248
  }
776
249
 
777
250
  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');
251
+ if (!table.columns.contains('Compound Name')) {
252
+ grok.shell.warning(
253
+ 'File saved without columns \'Compound Name\', \'Compound Components\', \'Cpd MW\', \'Salt mass\', \'Batch MW\'');
254
+ }
255
+ const structureColumn = table.columns.byName('Sequence');
781
256
  let result = '';
782
257
  for (let i = 0; i < table.rowCount; i++) {
783
258
  try {
784
- let smiles = sequenceToSmiles(structureColumn.get(i));
785
- //@ts-ignore
786
- let mol = new OCL.Molecule.fromSmiles(smiles);
259
+ const smiles = sequenceToSmiles(structureColumn.get(i));
260
+ const mol = OCL.Molecule.fromSmiles(smiles);
787
261
  result += `\n${mol.toMolfile()}\n`;
788
- for (let col of table.columns)
262
+ for (const col of table.columns)
789
263
  result += `> <${col.name}>\n${col.get(i)}\n\n`;
790
264
  result += '$$$$';
791
- }
792
- catch (error) {
265
+ } catch (error) {
793
266
  console.error(error);
794
267
  }
795
268
  }
796
- let element = document.createElement('a');
269
+ const element = document.createElement('a');
797
270
  element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(result));
798
271
  element.setAttribute('download', table.name + '.sdf');
799
272
  element.click();
800
273
  }
801
274
 
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
275
  //tags: autostart
810
276
  export function autostartOligoSdFileSubscription() {
811
277
  grok.events.onViewAdded.subscribe((v: any) => {
@@ -814,75 +280,69 @@ export function autostartOligoSdFileSubscription() {
814
280
  });
815
281
  }
816
282
 
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
283
  export function oligoSdFile(table: DG.DataFrame) {
835
-
836
- function addColumns(t: DG.DataFrame) {
284
+ const saltsDf = DG.DataFrame.fromCsv(SALTS_CSV);
285
+ function addColumns(t: DG.DataFrame, saltsDf: DG.DataFrame) {
837
286
  if (t.columns.contains('Compound Name'))
838
287
  return grok.shell.error('Columns already exist!');
839
288
 
840
289
  table.col('Source')?.init('Johnson and Johnson Pharma');
841
290
  table.col('ICD')?.init('No Contract');
842
291
 
843
- let sequence = t.col('Sequence')!;
844
- let salt = t.col('Salt')!;
845
- let equivalents = t.col('Equivalents')!;
292
+ const sequence = t.col('Sequence')!;
293
+ const salt = t.col('Salt')!;
294
+ const equivalents = t.col('Equivalents')!;
846
295
 
847
296
  t.columns.addNewString('Compound Name').init((i: number) => sequence.get(i));
848
297
  t.columns.addNewString('Compound Comments').init((i: number) => (i > 0 && i % 2 == 0) ?
849
298
  sequence.getString(i) + '; duplex of SS: ' + sequence.getString(i - 2) + ' and AS: ' + sequence.getString(i - 1) :
850
- sequence.getString(i)
299
+ sequence.getString(i),
851
300
  );
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));
301
+ const chargeCol = saltsDf.col('CHARGE')!.toList();
302
+ const saltNames = saltsDf.col('DISPLAY')!.toList();
303
+ const molWeight = saltsDf.col('MOLWEIGHT')!.toList();
304
+ t.columns.addNewFloat('Cpd MW').init((i: number) => ((i + 1) % 3 == 0) ? DG.FLOAT_NULL : molWeight[i]);
305
+ t.columns.addNewFloat('Salt mass').init((i: number) => {
306
+ const v = chargeCol[saltNames.indexOf(salt.get(i))];
307
+ const n = (v == null) ? 0 : chargeCol[saltNames.indexOf(salt.get(i))];
308
+ return n * equivalents.get(i);
309
+ });
854
310
  t.columns.addNewCalculated('Batch MW', '${Cpd MW} + ${Salt mass}', DG.COLUMN_TYPE.FLOAT, false);
855
311
 
856
312
  addColumnsPressed = true;
857
313
  return newDf = t;
858
314
  }
859
315
 
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"];
316
+ const columnsOrder = ['Chemistry', 'Number', 'Type', 'Chemistry Name', 'Internal compound ID',
317
+ 'IDP', 'Sequence', 'Compound Name', 'Compound Comments', 'Salt', 'Equivalents', 'Purity', 'Cpd MW', 'Salt mass',
318
+ 'Batch MW', 'Source', 'ICD', 'Owner'];
862
319
  let newDf: DG.DataFrame;
863
320
  let addColumnsPressed = false;
864
321
 
865
- let d = ui.div([
322
+ const d = ui.div([
866
323
  ui.icons.edit(() => {
867
324
  d.innerHTML = '';
868
325
  d.append(
869
326
  ui.link('Add Columns', async () => {
870
- await addColumns(table);
327
+ await addColumns(table, saltsDf);
871
328
  grok.shell.tableView(table.name).grid.columns.setOrder(columnsOrder);
872
329
  }, 'Add columns: Compound Name, Compound Components, Cpd MW, Salt mass, Batch MW', ''),
873
- ui.button('Save SD file', () => saveTableAsSdFile(addColumnsPressed ? newDf : table))
330
+ ui.button('Save SD file', () => saveTableAsSdFile(addColumnsPressed ? newDf : table)),
874
331
  );
875
- let view = grok.shell.getTableView(table.name);
876
- let typeCol = view.grid.col('Type')!;
877
- let saltCol = view.grid.col('Salt')!;
332
+ const view = grok.shell.getTableView(table.name);
333
+ const typeCol = view.grid.col('Type')!;
334
+ const saltCol = view.grid.col('Salt')!;
878
335
  saltCol.cellType = 'html';
879
336
  typeCol.cellType = 'html';
880
- view.grid.onCellPrepare(function (gc: DG.GridCell) {
337
+ view.grid.onCellPrepare(function(gc: DG.GridCell) {
881
338
  if (gc.isTableCell) {
882
339
  if (gc.gridColumn.name == 'Type')
883
340
  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;
341
+ else if (gc.gridColumn.name == 'Salt') {
342
+ gc.style.element = ui.choiceInput('', gc.cell.value, saltsDf.columns.byIndex(1).toList(), () => {
343
+ view.dataFrame.col('Salt')!.set(gc.gridRow, '');
344
+ }).root;
345
+ }
886
346
  }
887
347
  });
888
348
 
@@ -890,7 +350,7 @@ export function oligoSdFile(table: DG.DataFrame) {
890
350
  if (table.currentCol.name == 'IDP' && typeof table.currentCell.value != 'number')
891
351
  grok.shell.error('Value should be numeric');
892
352
  });
893
- })
353
+ }),
894
354
  ]);
895
355
  grok.shell.v.setRibbonPanels([[d]]);
896
356
  }