@datagrok/sequence-translator 0.0.9 → 0.0.12

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/package.json CHANGED
@@ -1,12 +1,17 @@
1
1
  {
2
2
  "name": "@datagrok/sequence-translator",
3
3
  "friendlyName": "Sequence Translator",
4
- "version": "0.0.9",
4
+ "version": "0.0.12",
5
5
  "description": "",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/datagrok-ai/public.git",
9
+ "directory": "packages/SequenceTranslator"
10
+ },
6
11
  "dependencies": {
7
12
  "@datagrok-libraries/utils": "^0.1.0",
8
13
  "@types/react": "latest",
9
- "datagrok-api": ">0.94.10",
14
+ "datagrok-api": "^0.151.0",
10
15
  "datagrok-tools": "^4.1.2",
11
16
  "npm": "^7.11.2",
12
17
  "save-svg-as-png": "^1.4.17",
@@ -28,6 +33,9 @@
28
33
  "test-dev": "set HOST=dev && jest",
29
34
  "test-local": "set HOST=localhost && jest"
30
35
  },
36
+ "sources": [
37
+ "css/style.css"
38
+ ],
31
39
  "devDependencies": {
32
40
  "@typescript-eslint/eslint-plugin": "^4.29.1",
33
41
  "@typescript-eslint/parser": "^4.29.1",
@@ -36,10 +44,10 @@
36
44
  "eslint-config-google": "^0.14.0",
37
45
  "webpack": "^5.31.0",
38
46
  "webpack-cli": "^4.6.0",
39
- "@types/jest": "latest",
40
- "jest": "latest",
41
- "jest-html-reporter": "latest",
42
- "puppeteer": "^13.1.2",
43
- "ts-jest": "^27.1.2"
47
+ "jest-html-reporter": "^3.5.0",
48
+ "jest": "^27.0.0",
49
+ "@types/jest": "^27.0.0",
50
+ "ts-jest": "^27.0.0",
51
+ "puppeteer": "latest"
44
52
  }
45
53
  }
package/src/package.ts CHANGED
@@ -7,7 +7,7 @@ import $ from 'cash-dom';
7
7
  import {defineAxolabsPattern} from './defineAxolabsPattern';
8
8
  import {saveSenseAntiSense} from './structures-works/save-sense-antisense';
9
9
  import {sequenceToSmiles, sequenceToMolV3000} from './structures-works/from-monomers';
10
- import {convertSequence, undefinedInputSequence} from './structures-works/sequence-codes-tools';
10
+ import {convertSequence, undefinedInputSequence, isValidSequence} from './structures-works/sequence-codes-tools';
11
11
  import {map, COL_NAMES, MODIFICATIONS} from './structures-works/map';
12
12
  import {SALTS_CSV} from './salts';
13
13
  import {USERS_CSV} from './users';
@@ -17,7 +17,7 @@ import {IDPS} from './IDPs';
17
17
 
18
18
  export const _package = new DG.Package();
19
19
 
20
- const defaultInput = 'AGGTCCTCTTGACTTAGGCC';
20
+ const defaultInput = 'fAmCmGmAmCpsmU';
21
21
  const sequenceWasCopied = 'Copied';
22
22
  const tooltipSequence = 'Copy sequence';
23
23
 
@@ -35,29 +35,31 @@ export function sequenceTranslator(): void {
35
35
  const pi = DG.TaskBarProgressIndicator.create('Rendering table and molecule...');
36
36
  let errorsExist = false;
37
37
  try {
38
- const outputSequenceObj = convertSequence(sequence);
38
+ sequence = sequence.replace(/\s/g, '');
39
+ const output = isValidSequence(sequence);
40
+ const outputSequenceObj = convertSequence(sequence, output);
39
41
  const tableRows = [];
40
42
 
41
43
  for (const key of Object.keys(outputSequenceObj).slice(1)) {
42
- const indexOfFirstNotValidCharacter = ('indexOfFirstNotValidCharacter' in outputSequenceObj) ?
43
- JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!).indexOfFirstNotValidCharacter :
44
+ const indexOfFirstNotValidChar = ('indexOfFirstNotValidChar' in outputSequenceObj) ?
45
+ JSON.parse(outputSequenceObj.indexOfFirstNotValidChar!).indexOfFirstNotValidChar :
44
46
  -1;
45
- if ('indexOfFirstNotValidCharacter' in outputSequenceObj) {
46
- const indexOfFirstNotValidCharacter = ('indexOfFirstNotValidCharacter' in outputSequenceObj) ?
47
- JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!).indexOfFirstNotValidCharacter :
47
+ if ('indexOfFirstNotValidChar' in outputSequenceObj) {
48
+ const indexOfFirstNotValidChar = ('indexOfFirstNotValidChar' in outputSequenceObj) ?
49
+ JSON.parse(outputSequenceObj.indexOfFirstNotValidChar!).indexOfFirstNotValidChar :
48
50
  -1;
49
- if (indexOfFirstNotValidCharacter != -1)
51
+ if (indexOfFirstNotValidChar != -1)
50
52
  errorsExist = true;
51
53
  }
52
54
 
53
55
  tableRows.push({
54
56
  'key': key,
55
- 'value': ('indexOfFirstNotValidCharacter' in outputSequenceObj) ?
57
+ 'value': ('indexOfFirstNotValidChar' in outputSequenceObj) ?
56
58
  ui.divH([
57
- ui.divText(sequence.slice(0, indexOfFirstNotValidCharacter), {style: {color: 'grey'}}),
59
+ ui.divText(sequence.slice(0, indexOfFirstNotValidChar), {style: {color: 'grey'}}),
58
60
  ui.tooltip.bind(
59
- ui.divText(sequence.slice(indexOfFirstNotValidCharacter), {style: {color: 'red'}}),
60
- 'Expected format: ' + JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!).expectedSynthesizer +
61
+ ui.divText(sequence.slice(indexOfFirstNotValidChar), {style: {color: 'red'}}),
62
+ 'Expected format: ' + JSON.parse(outputSequenceObj.indexOfFirstNotValidChar!).synthesizer +
61
63
  '. See tables with valid codes on the right',
62
64
  ),
63
65
  ]) : //@ts-ignore
@@ -67,13 +69,12 @@ export function sequenceTranslator(): void {
67
69
  }
68
70
 
69
71
  if (errorsExist) {
70
- const expectedSynthesizer = JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!)
71
- .expectedSynthesizer.slice(0, -6);
72
+ const synthesizer = JSON.parse(outputSequenceObj.indexOfFirstNotValidChar!).synthesizer.slice(0, -6);
72
73
  asoGapmersGrid.onCellPrepare(function(gc) {
73
- gc.style.backColor = (gc.gridColumn.name == expectedSynthesizer) ? 0xFFF00000 : 0xFFFFFFFF;
74
+ gc.style.backColor = (gc.gridColumn.name == synthesizer) ? 0xFFF00000 : 0xFFFFFFFF;
74
75
  });
75
76
  omeAndFluoroGrid.onCellPrepare(function(gc) {
76
- gc.style.backColor = (gc.gridColumn.name == expectedSynthesizer) ? 0xFFF00000 : 0xFFFFFFFF;
77
+ gc.style.backColor = (gc.gridColumn.name == synthesizer) ? 0xFFF00000 : 0xFFFFFFFF;
77
78
  });
78
79
  switchInput.enabled = true;
79
80
  } else {
@@ -85,7 +86,7 @@ export function sequenceTranslator(): void {
85
86
  ui.div([
86
87
  DG.HtmlTable.create(tableRows, (item: { key: string; value: string; }) =>
87
88
  [item.key, item.value], ['Code', 'Sequence']).root,
88
- ], 'table'),
89
+ ]),
89
90
  );
90
91
  semTypeOfInputSequence.textContent = 'Detected input type: ' + outputSequenceObj.type;
91
92
 
@@ -115,7 +116,7 @@ export function sequenceTranslator(): void {
115
116
 
116
117
  const semTypeOfInputSequence = ui.divText('');
117
118
  const moleculeSvgDiv = ui.block([]);
118
- const outputTableDiv = ui.div([], 'table');
119
+ const outputTableDiv = ui.div([]);
119
120
  const inputSequenceField = ui.textInput('', defaultInput, (sequence: string) => updateTableAndMolecule(sequence));
120
121
 
121
122
  const asoDf = DG.DataFrame.fromObjects([
@@ -191,7 +192,7 @@ export function sequenceTranslator(): void {
191
192
  ui.div([
192
193
  inputSequenceField.root,
193
194
  ], 'input-base'),
194
- ], 'sequenceInput'),
195
+ ], 'inputSequence'),
195
196
  semTypeOfInputSequence,
196
197
  ui.block([
197
198
  ui.h1('Output'),
@@ -233,18 +234,6 @@ export function sequenceTranslator(): void {
233
234
  tabControl.onTabChanged.subscribe((_) =>
234
235
  v.setRibbonPanels([(tabControl.currentPane.name == 'MAIN') ? topPanel : []]));
235
236
  v.setRibbonPanels([topPanel]);
236
-
237
- $('.sequence')
238
- .children().css('padding', '5px 0');
239
- $('.sequenceInput .input-base')
240
- .css('margin', '0');
241
- $('.sequenceInput textarea')
242
- .css('resize', 'none')
243
- .css('min-height', '50px')
244
- .css('width', '100%')
245
- .attr('spellcheck', 'false');
246
- $('.sequenceInput select')
247
- .css('width', '100%');
248
237
  }
249
238
 
250
239
  async function saveTableAsSdFile(table: DG.DataFrame) {
@@ -324,6 +313,7 @@ export function oligoSdFile(table: DG.DataFrame) {
324
313
  return grok.shell.error('Columns already exist!');
325
314
 
326
315
  const sequence = t.col(COL_NAMES.SEQUENCE)!;
316
+ const salt = t.col(COL_NAMES.SALT)!;
327
317
  const equivalents = t.col(COL_NAMES.EQUIVALENTS)!;
328
318
 
329
319
  t.columns.addNewString(COL_NAMES.COMPOUND_NAME).init((i: number) => sequence.get(i));
@@ -331,11 +321,13 @@ export function oligoSdFile(table: DG.DataFrame) {
331
321
  sequence.getString(i) + '; duplex of SS: ' + sequence.getString(i - 2) + ' and AS: ' + sequence.getString(i - 1) :
332
322
  sequence.getString(i),
333
323
  );
324
+ const molWeightCol = saltsDf.col('MOLWEIGHT')!;
325
+ const saltNamesList = saltsDf.col('DISPLAY')!.toList();
334
326
  t.columns.addNewFloat(COL_NAMES.CPD_MW)
335
327
  .init((i: number) => molecularWeight(sequence.get(i), weightsObj));
336
- const mwCol = t.col(COL_NAMES.CPD_MW)!;
337
328
  t.columns.addNewFloat(COL_NAMES.SALT_MASS).init((i: number) => {
338
- const mw = mwCol.get(i);
329
+ const saltRowIndex = saltNamesList.indexOf(salt.get(i));
330
+ const mw = molWeightCol.get(saltRowIndex);
339
331
  return mw * equivalents.get(i);
340
332
  });
341
333
  t.columns.addNewCalculated(COL_NAMES.BATCH_MW,
@@ -367,7 +359,7 @@ export function oligoSdFile(table: DG.DataFrame) {
367
359
 
368
360
  view.table!.col(COL_NAMES.TYPE)!.setTag(DG.TAGS.CHOICES, '["AS", "SS", "Duplex"]');
369
361
  view.table!.col(COL_NAMES.OWNER)!.setTag(DG.TAGS.CHOICES, stringifyItems(usersDf.columns.byIndex(0).toList()));
370
- view.table!.col(COL_NAMES.SALT)!.setTag(DG.TAGS.CHOICES, stringifyItems(saltsDf.columns.byIndex(1).toList()));
362
+ view.table!.col(COL_NAMES.SALT)!.setTag(DG.TAGS.CHOICES, stringifyItems(saltsDf.columns.byIndex(0).toList()));
371
363
  view.table!.col(COL_NAMES.SOURCE)!.setTag(DG.TAGS.CHOICES, stringifyItems(sourcesDf.columns.byIndex(0).toList()));
372
364
  view.table!.col(COL_NAMES.ICD)!.setTag(DG.TAGS.CHOICES, stringifyItems(icdsDf.columns.byIndex(0).toList()));
373
365
  view.table!.col(COL_NAMES.IDP)!.setTag(DG.TAGS.CHOICES, stringifyItems(idpsDf.columns.byIndex(0).toList()));
package/src/salts.ts CHANGED
@@ -1,2 +1,2 @@
1
- export const SALTS_CSV = `CHARGE,DISPLAY,MOLWEIGHT
2
- ,no Data Added,100`;
1
+ export const SALTS_CSV = `DISPLAY,MOLWEIGHT
2
+ no Data Added,100`;
@@ -92,9 +92,9 @@ function getObjectWithCodesAndSmiles(sequence: string) {
92
92
  }
93
93
  // TODO: create object based from synthesizer type to avoid key(codes) duplicates
94
94
  const output = isValidSequence(sequence);
95
- if (output.expectedSynthesizer == SYNTHESIZERS.MERMADE_12)
95
+ if (output.synthesizer == SYNTHESIZERS.MERMADE_12)
96
96
  obj['g'] = map[SYNTHESIZERS.MERMADE_12][TECHNOLOGIES.SI_RNA]['g'].SMILES;
97
- else if (output.expectedSynthesizer == SYNTHESIZERS.AXOLABS)
97
+ else if (output.synthesizer == SYNTHESIZERS.AXOLABS)
98
98
  obj['g'] = map[SYNTHESIZERS.AXOLABS][TECHNOLOGIES.SI_RNA]['g'].SMILES;
99
99
  return obj;
100
100
  }
@@ -95,7 +95,7 @@ export function getNucleotidesMol(smilesCodes: string[], oclRender: boolean = fa
95
95
 
96
96
  export function linkV3000(molBlocks: string[], twoMolecules: boolean = false, oclRender: boolean = false) {
97
97
  let macroMolBlock = '\nDatagrok macromolecule handler\n\n';
98
- macroMolBlock += ' 0 0 0 0 0 0 0 V3000\n';
98
+ macroMolBlock += ' 0 0 0 0 0 0 999 V3000\n';
99
99
  macroMolBlock += 'M V30 BEGIN CTAB\n';
100
100
  let atomBlock = '';
101
101
  let bondBlock = '';
@@ -110,6 +110,8 @@ export function linkV3000(molBlocks: string[], twoMolecules: boolean = false, oc
110
110
  molBlocks[1] = invertNucleotidesV3000(molBlocks[1]);
111
111
 
112
112
  for (let i = 0; i < molBlocks.length; i++) {
113
+ molBlocks[i] = molBlocks[i].replaceAll('(-\nM V30 ', '(')
114
+ .replaceAll('-\nM V30 ', '').replaceAll(' )', ')');
113
115
  const numbers = extractAtomsBondsNumbersV3000(molBlocks[i]);
114
116
  const coordinates = extractAtomDataV3000(molBlocks[i]);
115
117
  let indexAtoms = molBlocks[i].indexOf('M V30 BEGIN ATOM'); // V3000 index for atoms coordinates
@@ -184,7 +186,7 @@ export function linkV3000(molBlocks: string[], twoMolecules: boolean = false, oc
184
186
  while (indexCollection != -1) {
185
187
  indexCollection += 28;
186
188
  const collectionEnd = molBlocks[i].indexOf(')', indexCollection);
187
- const collectionEntries = molBlocks[i].substring(indexCollection, collectionEnd).split(' ');
189
+ const collectionEntries = molBlocks[i].substring(indexCollection, collectionEnd).split(' ').slice(1);
188
190
  collectionEntries.forEach((e) => {
189
191
  collection.push(parseInt(e) + natom);
190
192
  });
@@ -209,13 +211,15 @@ export function linkV3000(molBlocks: string[], twoMolecules: boolean = false, oc
209
211
 
210
212
  collectionBlock += ')\n';
211
213
  } else {
214
+ collectionBlock += 'M V30 MDLV30/STEABS ATOMS=(' + collection.length + ' -\n';
212
215
  for (let i = 0; i < collNumber; i++) {
213
- collectionBlock += 'M V30 MDLV30/STEABS ATOMS=(';
216
+ collectionBlock += 'M V30 ';
214
217
  const entriesCurrent = i + 1 == collNumber ? collection.length - (collNumber - 1)*entries : entries;
215
- for (let j = 0; j < entriesCurrent; j++)
216
- collectionBlock += (j + 1 == entriesCurrent) ? collection[entries*i + j] : collection[entries*i + j] + ' ';
217
-
218
- collectionBlock += ')\n';
218
+ for (let j = 0; j < entriesCurrent; j++) {
219
+ collectionBlock += (j + 1 == entriesCurrent) ?
220
+ (i == collNumber - 1 ? collection[entries*i + j] + ')\n' : collection[entries*i + j] + ' -\n') :
221
+ collection[entries*i + j] + ' ';
222
+ }
219
223
  }
220
224
  }
221
225
 
@@ -1,3 +1,6 @@
1
+ import * as grok from 'datagrok-api/grok';
2
+ import * as ui from 'datagrok-api/ui';
3
+ // import * as DG from 'datagrok-api/dg';
1
4
  import {map, SYNTHESIZERS, TECHNOLOGIES, MODIFICATIONS} from './map';
2
5
  import {asoGapmersNucleotidesToBioSpring, asoGapmersNucleotidesToGcrs,
3
6
  asoGapmersBioSpringToNucleotides, asoGapmersBioSpringToGcrs, asoGapmersGcrsToNucleotides,
@@ -11,97 +14,112 @@ const noTranslationTableAvailable = 'No translation table available';
11
14
  export const undefinedInputSequence = 'Type of input sequence is undefined';
12
15
 
13
16
  export function isValidSequence(sequence: string): {
14
- indexOfFirstNotValidCharacter: number,
15
- expectedSynthesizer: string | null,
16
- expectedTechnology: string | null
17
+ indexOfFirstNotValidChar: number,
18
+ synthesizer: string | null,
19
+ technology: string | null
17
20
  } {
18
- const possibleSynthesizers = getListOfPossibleSynthesizersByFirstMatchedCode(sequence);
19
- if (possibleSynthesizers.length == 0)
20
- return {indexOfFirstNotValidCharacter: 0, expectedSynthesizer: null, expectedTechnology: null};
21
-
22
- let outputIndices = Array(possibleSynthesizers.length).fill(0);
21
+ let possibleSynthesizers = getListOfPossibleSynthesizersByFirstMatchedCode(sequence);
22
+
23
+ if (possibleSynthesizers.length > 1) {
24
+ const synthesizer = ui.choiceInput('Choose synthesizer from list: ', possibleSynthesizers[0], possibleSynthesizers);
25
+ ui.dialog('Choose Synthesizer')
26
+ .add(ui.panel([synthesizer.root], {style: {fontWeight: 'bold'}}))
27
+ .onOK(() => possibleSynthesizers = [synthesizer.value])
28
+ .onCancel(() => {
29
+ possibleSynthesizers = [possibleSynthesizers[0]];
30
+ grok.shell.warning('Input sequence is expected to be in format ' + possibleSynthesizers[0]);
31
+ })
32
+ .show();
33
+ } else if (possibleSynthesizers.length == 0)
34
+ return {indexOfFirstNotValidChar: 0, synthesizer: null, technology: null};
35
+
36
+ let outputIndex = 0;
23
37
 
24
38
  const firstUniqueCharacters = ['r', 'd'];
25
39
  const nucleotides = ['A', 'U', 'T', 'C', 'G'];
26
40
 
27
- possibleSynthesizers.forEach((synthesizer, synthesizerIndex) => {
41
+ possibleSynthesizers.forEach((synthesizer) => {
28
42
  const codes = getAllCodesOfSynthesizer(synthesizer);
29
- while (outputIndices[synthesizerIndex] < sequence.length) {
30
- const matchedCode = codes
31
- .find((c) => c == sequence.slice(outputIndices[synthesizerIndex], outputIndices[synthesizerIndex] + c.length));
43
+ while (outputIndex < sequence.length) {
44
+ const matchedCode = codes.find((c) => c == sequence.slice(outputIndex, outputIndex + c.length));
32
45
 
33
46
  if (matchedCode == null)
34
47
  break;
35
48
 
36
49
  if ( // for mistake pattern 'rAA'
37
- outputIndices[synthesizerIndex] > 1 &&
38
- nucleotides.includes(sequence[outputIndices[synthesizerIndex]]) &&
39
- firstUniqueCharacters.includes(sequence[outputIndices[synthesizerIndex] - 2])
50
+ outputIndex > 1 &&
51
+ nucleotides.includes(sequence[outputIndex]) &&
52
+ firstUniqueCharacters.includes(sequence[outputIndex - 2])
40
53
  ) break;
41
54
 
42
55
  if ( // for mistake pattern 'ArA'
43
- firstUniqueCharacters.includes(sequence[outputIndices[synthesizerIndex] + 1]) &&
44
- nucleotides.includes(sequence[outputIndices[synthesizerIndex]])
56
+ firstUniqueCharacters.includes(sequence[outputIndex + 1]) &&
57
+ nucleotides.includes(sequence[outputIndex])
45
58
  ) {
46
- outputIndices[synthesizerIndex]++;
59
+ outputIndex++;
47
60
  break;
48
61
  }
49
62
 
50
- outputIndices[synthesizerIndex] += matchedCode.length;
63
+ outputIndex += matchedCode.length;
51
64
  }
52
65
  });
53
66
 
54
- const indexOfExpectedSythesizer = Math.max(...outputIndices);
55
- const indexOfFirstNotValidCharacter = (indexOfExpectedSythesizer == sequence.length) ? -1 : indexOfExpectedSythesizer;
56
- const expectedSynthesizer = possibleSynthesizers[outputIndices.indexOf(indexOfExpectedSythesizer)];
57
- if (indexOfFirstNotValidCharacter != -1) {
67
+ const indexOfFirstNotValidChar = (outputIndex == sequence.length) ? -1 : outputIndex;
68
+ if (indexOfFirstNotValidChar != -1) {
58
69
  return {
59
- indexOfFirstNotValidCharacter: indexOfFirstNotValidCharacter,
60
- expectedSynthesizer: expectedSynthesizer,
61
- expectedTechnology: null,
70
+ indexOfFirstNotValidChar: indexOfFirstNotValidChar,
71
+ synthesizer: possibleSynthesizers[0],
72
+ technology: null,
62
73
  };
63
74
  }
64
75
 
65
- const possibleTechnologies = getListOfPossibleTechnologiesByFirstMatchedCode(sequence, expectedSynthesizer);
66
- if (possibleTechnologies.length == 0)
67
- return {indexOfFirstNotValidCharacter: 0, expectedSynthesizer: null, expectedTechnology: null};
76
+ let possibleTechnologies = getListOfPossibleTechnologiesByFirstMatchedCode(sequence, possibleSynthesizers[0]);
77
+
78
+ if (possibleTechnologies.length > 1) {
79
+ const technology = ui.choiceInput('Choose technology from list: ', possibleTechnologies[0], possibleTechnologies);
80
+ ui.dialog('Choose Technology')
81
+ .add(ui.panel([technology.root], {style: {fontWeight: 'bold'}}))
82
+ .onOK(() => possibleTechnologies = [technology.value])
83
+ .onCancel(() => {
84
+ possibleTechnologies = [possibleTechnologies[0]];
85
+ grok.shell.warning('Input sequence is expected to be in format ' + possibleTechnologies[0]);
86
+ })
87
+ .show();
88
+ } else if (possibleTechnologies.length == 0)
89
+ return {indexOfFirstNotValidChar: 0, synthesizer: null, technology: null};
68
90
 
69
- outputIndices = Array(possibleTechnologies.length).fill(0);
91
+ outputIndex = 0;
70
92
 
71
- possibleTechnologies.forEach((technology: string, technologyIndex: number) => {
72
- const codes = Object.keys(map[expectedSynthesizer][technology]);
73
- while (outputIndices[technologyIndex] < sequence.length) {
74
- const matchedCode = codes
75
- .find((c) => c == sequence.slice(outputIndices[technologyIndex], outputIndices[technologyIndex] + c.length));
93
+ possibleTechnologies.forEach((technology: string) => {
94
+ const codes = Object.keys(map[possibleSynthesizers[0]][technology]);
95
+ while (outputIndex < sequence.length) {
96
+ const matchedCode = codes.find((c) => c == sequence.slice(outputIndex, outputIndex + c.length));
76
97
 
77
98
  if (matchedCode == null)
78
99
  break;
79
100
 
80
101
  if ( // for mistake pattern 'rAA'
81
- outputIndices[technologyIndex] > 1 &&
82
- nucleotides.includes(sequence[outputIndices[technologyIndex]]) &&
83
- firstUniqueCharacters.includes(sequence[outputIndices[technologyIndex] - 2])
102
+ outputIndex > 1 &&
103
+ nucleotides.includes(sequence[outputIndex]) &&
104
+ firstUniqueCharacters.includes(sequence[outputIndex - 2])
84
105
  ) break;
85
106
 
86
107
  if ( // for mistake pattern 'ArA'
87
- firstUniqueCharacters.includes(sequence[outputIndices[technologyIndex] + 1]) &&
88
- nucleotides.includes(sequence[outputIndices[technologyIndex]])
108
+ firstUniqueCharacters.includes(sequence[outputIndex + 1]) &&
109
+ nucleotides.includes(sequence[outputIndex])
89
110
  ) {
90
- outputIndices[technologyIndex]++;
111
+ outputIndex++;
91
112
  break;
92
113
  }
93
114
 
94
- outputIndices[technologyIndex] += matchedCode.length;
115
+ outputIndex += matchedCode.length;
95
116
  }
96
117
  });
97
118
 
98
- const indexOfExpectedTechnology = Math.max(...outputIndices);
99
- const expectedTechnology = possibleTechnologies[outputIndices.indexOf(indexOfExpectedTechnology)];
100
-
101
119
  return {
102
- indexOfFirstNotValidCharacter: indexOfFirstNotValidCharacter,
103
- expectedSynthesizer: expectedSynthesizer,
104
- expectedTechnology: expectedTechnology,
120
+ indexOfFirstNotValidChar: indexOfFirstNotValidChar,
121
+ synthesizer: possibleSynthesizers[0],
122
+ technology: possibleTechnologies[outputIndex],
105
123
  };
106
124
  }
107
125
 
@@ -140,93 +158,91 @@ function getListOfPossibleTechnologiesByFirstMatchedCode(sequence: string, synth
140
158
  return technologies;
141
159
  }
142
160
 
143
- export function convertSequence(text: string) {
144
- text = text.replace(/\s/g, '');
145
- const seq = text;
146
- const output = isValidSequence(seq);
147
- if (output.indexOfFirstNotValidCharacter != -1) {
161
+ export function convertSequence(sequence: string, output: {
162
+ indexOfFirstNotValidChar: number, synthesizer: string | null, technology: string | null}) {
163
+ if (output.indexOfFirstNotValidChar != -1) {
148
164
  return {
149
165
  // type: '',
150
- indexOfFirstNotValidCharacter: JSON.stringify(output),
166
+ indexOfFirstNotValidChar: JSON.stringify(output),
151
167
  Error: undefinedInputSequence,
152
168
  };
153
169
  }
154
- if (output.expectedSynthesizer == SYNTHESIZERS.RAW_NUCLEOTIDES && output.expectedTechnology == TECHNOLOGIES.DNA) {
170
+ if (output.synthesizer == SYNTHESIZERS.RAW_NUCLEOTIDES && output.technology == TECHNOLOGIES.DNA) {
155
171
  return {
156
172
  type: SYNTHESIZERS.RAW_NUCLEOTIDES + ' ' + TECHNOLOGIES.DNA,
157
- Nucleotides: seq,
158
- BioSpring: asoGapmersNucleotidesToBioSpring(seq),
159
- GCRS: asoGapmersNucleotidesToGcrs(seq),
173
+ Nucleotides: sequence,
174
+ BioSpring: asoGapmersNucleotidesToBioSpring(sequence),
175
+ GCRS: asoGapmersNucleotidesToGcrs(sequence),
160
176
  };
161
177
  }
162
- if (output.expectedSynthesizer == SYNTHESIZERS.BIOSPRING && output.expectedTechnology == TECHNOLOGIES.ASO_GAPMERS) {
178
+ if (output.synthesizer == SYNTHESIZERS.BIOSPRING && output.technology == TECHNOLOGIES.ASO_GAPMERS) {
163
179
  return {
164
180
  type: SYNTHESIZERS.BIOSPRING + ' ' + TECHNOLOGIES.ASO_GAPMERS,
165
- Nucleotides: asoGapmersBioSpringToNucleotides(seq),
166
- BioSpring: seq,
167
- GCRS: asoGapmersBioSpringToGcrs(seq),
181
+ Nucleotides: asoGapmersBioSpringToNucleotides(sequence),
182
+ BioSpring: sequence,
183
+ GCRS: asoGapmersBioSpringToGcrs(sequence),
168
184
  };
169
185
  }
170
- if (output.expectedSynthesizer == SYNTHESIZERS.GCRS && output.expectedTechnology == TECHNOLOGIES.ASO_GAPMERS) {
186
+ if (output.synthesizer == SYNTHESIZERS.GCRS && output.technology == TECHNOLOGIES.ASO_GAPMERS) {
171
187
  return {
172
188
  type: SYNTHESIZERS.GCRS + ' ' + TECHNOLOGIES.ASO_GAPMERS,
173
- Nucleotides: asoGapmersGcrsToNucleotides(seq),
174
- BioSpring: asoGapmersGcrsToBioSpring(seq),
175
- Mermade12: gcrsToMermade12(seq),
176
- GCRS: seq,
189
+ Nucleotides: asoGapmersGcrsToNucleotides(sequence),
190
+ BioSpring: asoGapmersGcrsToBioSpring(sequence),
191
+ Mermade12: gcrsToMermade12(sequence),
192
+ GCRS: sequence,
177
193
  };
178
194
  }
179
- if (output.expectedSynthesizer == SYNTHESIZERS.RAW_NUCLEOTIDES && output.expectedTechnology == TECHNOLOGIES.RNA) {
195
+ if (output.synthesizer == SYNTHESIZERS.RAW_NUCLEOTIDES && output.technology == TECHNOLOGIES.RNA) {
180
196
  return {
181
197
  type: SYNTHESIZERS.RAW_NUCLEOTIDES + ' ' + TECHNOLOGIES.RNA,
182
- Nucleotides: seq,
183
- BioSpring: siRnaNucleotideToBioSpringSenseStrand(seq),
184
- Axolabs: siRnaNucleotideToAxolabsSenseStrand(seq),
185
- GCRS: siRnaNucleotidesToGcrs(seq),
198
+ Nucleotides: sequence,
199
+ BioSpring: siRnaNucleotideToBioSpringSenseStrand(sequence),
200
+ Axolabs: siRnaNucleotideToAxolabsSenseStrand(sequence),
201
+ GCRS: siRnaNucleotidesToGcrs(sequence),
186
202
  };
187
203
  }
188
- if (output.expectedSynthesizer == SYNTHESIZERS.BIOSPRING && output.expectedTechnology == TECHNOLOGIES.SI_RNA) {
204
+ if (output.synthesizer == SYNTHESIZERS.BIOSPRING && output.technology == TECHNOLOGIES.SI_RNA) {
189
205
  return {
190
206
  type: SYNTHESIZERS.BIOSPRING + ' ' + TECHNOLOGIES.SI_RNA,
191
- Nucleotides: siRnaBioSpringToNucleotides(seq),
192
- BioSpring: seq,
193
- Axolabs: siRnaBioSpringToAxolabs(seq),
194
- GCRS: siRnaBioSpringToGcrs(seq),
207
+ Nucleotides: siRnaBioSpringToNucleotides(sequence),
208
+ BioSpring: sequence,
209
+ Axolabs: siRnaBioSpringToAxolabs(sequence),
210
+ GCRS: siRnaBioSpringToGcrs(sequence),
195
211
  };
196
212
  }
197
- if (output.expectedSynthesizer == SYNTHESIZERS.AXOLABS && output.expectedTechnology == TECHNOLOGIES.SI_RNA) {
213
+ if (output.synthesizer == SYNTHESIZERS.AXOLABS && output.technology == TECHNOLOGIES.SI_RNA) {
198
214
  return {
199
215
  type: SYNTHESIZERS.AXOLABS + ' ' + TECHNOLOGIES.SI_RNA,
200
- Nucleotides: siRnaAxolabsToNucleotides(seq),
201
- BioSpring: siRnaAxolabsToBioSpring(seq),
202
- Axolabs: seq,
203
- GCRS: siRnaAxolabsToGcrs(seq),
216
+ Nucleotides: siRnaAxolabsToNucleotides(sequence),
217
+ BioSpring: siRnaAxolabsToBioSpring(sequence),
218
+ Axolabs: sequence,
219
+ GCRS: siRnaAxolabsToGcrs(sequence),
204
220
  };
205
221
  }
206
- if (output.expectedSynthesizer == SYNTHESIZERS.GCRS && output.expectedTechnology == TECHNOLOGIES.SI_RNA) {
222
+ if (output.synthesizer == SYNTHESIZERS.GCRS && output.technology == TECHNOLOGIES.SI_RNA) {
207
223
  return {
208
224
  type: SYNTHESIZERS.GCRS + ' ' + TECHNOLOGIES.SI_RNA,
209
- Nucleotides: siRnaGcrsToNucleotides(seq),
210
- BioSpring: siRnaGcrsToBioSpring(seq),
211
- Axolabs: siRnaGcrsToAxolabs(seq),
212
- MM12: gcrsToMermade12(seq),
213
- GCRS: seq,
225
+ Nucleotides: siRnaGcrsToNucleotides(sequence),
226
+ BioSpring: siRnaGcrsToBioSpring(sequence),
227
+ Axolabs: siRnaGcrsToAxolabs(sequence),
228
+ MM12: gcrsToMermade12(sequence),
229
+ GCRS: sequence,
214
230
  };
215
231
  }
216
- if (output.expectedSynthesizer == SYNTHESIZERS.GCRS) {
232
+ if (output.synthesizer == SYNTHESIZERS.GCRS) {
217
233
  return {
218
234
  type: SYNTHESIZERS.GCRS,
219
- Nucleotides: gcrsToNucleotides(seq),
220
- GCRS: seq,
221
- Mermade12: gcrsToMermade12(seq),
235
+ Nucleotides: gcrsToNucleotides(sequence),
236
+ GCRS: sequence,
237
+ Mermade12: gcrsToMermade12(sequence),
222
238
  };
223
239
  }
224
- if (output.expectedSynthesizer == SYNTHESIZERS.MERMADE_12) {
240
+ if (output.synthesizer == SYNTHESIZERS.MERMADE_12) {
225
241
  return {
226
242
  type: SYNTHESIZERS.MERMADE_12,
227
243
  Nucleotides: noTranslationTableAvailable,
228
244
  GCRS: noTranslationTableAvailable,
229
- Mermade12: seq,
245
+ Mermade12: sequence,
230
246
  };
231
247
  }
232
248
  return {
@@ -1,4 +1,4 @@
1
- <html><head><meta charset="utf-8"/><title>SequenceTranslator Test Report. Datagrok version datagrok/datagrok:latest SHA=2e08c8e54bde. Commit 1367d435.</title><style type="text/css">html,
1
+ <html><head><meta charset="utf-8"/><title>SequenceTranslator Test Report. Datagrok version datagrok/datagrok:latest SHA=c2bbc2b235db. Commit afc0e1c5.</title><style type="text/css">html,
2
2
  body {
3
3
  font-family: Arial, Helvetica, sans-serif;
4
4
  font-size: 1rem;
@@ -229,7 +229,7 @@ header {
229
229
  font-size: 1rem;
230
230
  padding: 0 0.5rem;
231
231
  }
232
- </style></head><body><div id="jesthtml-content"><header><h1 id="title">SequenceTranslator Test Report. Datagrok version datagrok/datagrok:latest SHA=2e08c8e54bde. Commit 1367d435.</h1></header><div id="metadata-container"><div id="timestamp">Started: 2022-04-20 13:02:23</div><div id="summary"><div id="suite-summary"><div class="summary-total">Suites (1)</div><div class="summary-passed summary-empty">0 passed</div><div class="summary-failed">1 failed</div><div class="summary-pending summary-empty">0 pending</div></div><div id="test-summary"><div class="summary-total">Tests (1)</div><div class="summary-passed summary-empty">0 passed</div><div class="summary-failed">1 failed</div><div class="summary-pending summary-empty">0 pending</div></div></div></div><div id="suite-1" class="suite-container"><div class="suite-info"><div class="suite-path">/home/runner/work/public/public/packages/SequenceTranslator/src/__jest__/remote.test.ts</div><div class="suite-time warn">18.061s</div></div><div class="suite-tests"><div class="test-result failed"><div class="test-info"><div class="test-suitename"> </div><div class="test-title">TEST</div><div class="test-status">failed</div><div class="test-duration">0.524s</div></div><div class="failureMessages"> <pre class="failureMsg">Error: Evaluation failed: Unable to find JS function "test"
232
+ </style></head><body><div id="jesthtml-content"><header><h1 id="title">SequenceTranslator Test Report. Datagrok version datagrok/datagrok:latest SHA=c2bbc2b235db. Commit afc0e1c5.</h1></header><div id="metadata-container"><div id="timestamp">Started: 2022-05-13 15:45:08</div><div id="summary"><div id="suite-summary"><div class="summary-total">Suites (1)</div><div class="summary-passed summary-empty">0 passed</div><div class="summary-failed">1 failed</div><div class="summary-pending summary-empty">0 pending</div></div><div id="test-summary"><div class="summary-total">Tests (1)</div><div class="summary-passed summary-empty">0 passed</div><div class="summary-failed">1 failed</div><div class="summary-pending summary-empty">0 pending</div></div></div></div><div id="suite-1" class="suite-container"><div class="suite-info"><div class="suite-path">/home/runner/work/public/public/packages/SequenceTranslator/src/__jest__/remote.test.ts</div><div class="suite-time warn">26.07s</div></div><div class="suite-tests"><div class="test-result failed"><div class="test-info"><div class="test-suitename"> </div><div class="test-title">TEST</div><div class="test-status">failed</div><div class="test-duration">2.12s</div></div><div class="failureMessages"> <pre class="failureMsg">Error: Evaluation failed: Unable to find JS function "test"
233
233
  at ExecutionContext._evaluateInternal (/home/runner/work/public/public/packages/SequenceTranslator/node_modules/puppeteer/src/common/ExecutionContext.ts:273:13)
234
234
  at processTicksAndRejections (internal/process/task_queues.js:97:5)
235
235
  at ExecutionContext.evaluate (/home/runner/work/public/public/packages/SequenceTranslator/node_modules/puppeteer/src/common/ExecutionContext.ts:140:12)</pre></div></div></div><div class="suite-consolelog"><div class="suite-consolelog-header">Console Log</div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at Object.&lt;anonymous&gt; (/home/runner/work/public/public/packages/SequenceTranslator/src/__jest__/test-node.ts:62:11)