@datagrok/sequence-translator 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@datagrok/sequence-translator",
3
3
  "friendlyName": "Sequence Translator",
4
- "version": "1.0.5",
4
+ "version": "1.0.6",
5
5
  "author": {
6
6
  "name": "Vadym Kovadlo",
7
7
  "email": "vkovadlo@datagrok.ai"
@@ -15,7 +15,7 @@
15
15
  "dependencies": {
16
16
  "@datagrok-libraries/utils": "^0.1.0",
17
17
  "@types/react": "^18.0.15",
18
- "datagrok-api": "^1.1.7",
18
+ "datagrok-api": "^1.6.0",
19
19
  "datagrok-tools": "^4.1.2",
20
20
  "npm": "^8.11.0",
21
21
  "openchemlib": "6.0.1",
@@ -33,7 +33,7 @@
33
33
  "release-sequencetranslator-public": "grok publish public --release",
34
34
  "debug-sequencetranslator-local": "grok publish local",
35
35
  "release-sequencetranslator-local": "grok publish local --release",
36
- "test": "set HOST=dev && jest",
36
+ "test": "jest",
37
37
  "test-dev": "set HOST=dev && jest",
38
38
  "test-local": "set HOST=localhost && jest"
39
39
  },
@@ -54,7 +54,11 @@
54
54
  "puppeteer": "^13.7.0",
55
55
  "ts-jest": "^27.0.0",
56
56
  "webpack": "^5.31.0",
57
- "webpack-cli": "^4.6.0"
57
+ "webpack-cli": "^4.6.0",
58
+ "@types/js-yaml": "^4.0.5",
59
+ "js-yaml": "^4.1.0",
60
+ "@types/node-fetch": "^2.6.2",
61
+ "node-fetch": "^2.6.7"
58
62
  },
59
63
  "category": "Bioinformatics"
60
64
  }
@@ -5,7 +5,7 @@
5
5
  import * as utils from './test-node';
6
6
  import puppeteer from 'puppeteer';
7
7
 
8
- const P_START_TIMEOUT: number = 100000;
8
+ const P_START_TIMEOUT: number = 3600000;
9
9
  let browser: puppeteer.Browser;
10
10
  let page: puppeteer.Page;
11
11
 
@@ -51,10 +51,10 @@ it('TEST', async () => {
51
51
  let failReport = '';
52
52
  for (let i = 0; i < df.rowCount; i++) {
53
53
  if (cStatus.get(i)) {
54
- passReport += `Test result : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
54
+ passReport += `Test result : Success : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
55
55
  } else {
56
56
  failed = true;
57
- failReport += `Test result : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
57
+ failReport += `Test result : Failed : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
58
58
  }
59
59
  }
60
60
  resolve({failReport, passReport, failed});
@@ -65,4 +65,4 @@ it('TEST', async () => {
65
65
  console.log(r.passReport);
66
66
  // @ts-ignore
67
67
  expect(r.failed).checkOutput(false, r.failReport);
68
- }, 100000);
68
+ }, 3600000);
@@ -67,6 +67,7 @@ export async function getBrowserPage(puppeteer: any): Promise<{browser: any, pag
67
67
  });
68
68
 
69
69
  let page = await browser.newPage();
70
+ await page.setDefaultNavigationTimeout(0);
70
71
  await page.goto(`${url}/oauth/`);
71
72
  await page.setCookie({name: 'auth', value: token});
72
73
  await page.evaluate((token: any) => {
@@ -74,8 +75,8 @@ export async function getBrowserPage(puppeteer: any): Promise<{browser: any, pag
74
75
  }, token);
75
76
  await page.goto(url);
76
77
  try {
77
- await page.waitForSelector('.grok-preloader');
78
- await page.waitForFunction(() => document.querySelector('.grok-preloader') == null, {timeout: 100000});
78
+ await page.waitForSelector('.grok-preloader', { timeout: 1800000 });
79
+ await page.waitForFunction(() => document.querySelector('.grok-preloader') == null, {timeout: 3600000});
79
80
  } catch (error) {
80
81
  throw error;
81
82
  }
@@ -4,7 +4,7 @@ import * as DG from 'datagrok-api/dg';
4
4
  import {siRnaAxolabsToGcrs, gcrsToNucleotides, asoGapmersBioSpringToGcrs, gcrsToMermade12,
5
5
  } from '../structures-works/converters';
6
6
  import {map, COL_NAMES, MODIFICATIONS} from '../structures-works/map';
7
- import {getFormat} from '../structures-works/sequence-codes-tools';
7
+ import {getFormat, isValidSequence} from '../structures-works/sequence-codes-tools';
8
8
  import {sequenceToMolV3000} from '../structures-works/from-monomers';
9
9
 
10
10
  import {SALTS_CSV} from '../salts';
@@ -13,16 +13,6 @@ import {ICDS} from '../ICDs';
13
13
  import {SOURCES} from '../sources';
14
14
  import {IDPS} from '../IDPs';
15
15
 
16
- const weightsObj: {[code: string]: number} = {};
17
- for (const synthesizer of Object.keys(map)) {
18
- for (const technology of Object.keys(map[synthesizer])) {
19
- for (const code of Object.keys(map[synthesizer][technology]))
20
- weightsObj[code] ?? map[synthesizer][technology][code].weight;
21
- }
22
- }
23
- for (const [key, value] of Object.entries(MODIFICATIONS))
24
- weightsObj[key] = value.molecularWeight;
25
-
26
16
 
27
17
  function sortByStringLengthInDescendingOrder(array: string[]): string[] {
28
18
  return array.sort(function(a, b) {return b.length - a.length;});
@@ -56,7 +46,7 @@ async function saveTableAsSdFile(table: DG.DataFrame) {
56
46
  const typeColumn = table.getCol(COL_NAMES.TYPE);
57
47
  let result = '';
58
48
  for (let i = 0; i < table.rowCount; i++) {
59
- const format = getFormat(structureColumn.get(i))!;
49
+ const format = 'Janssen GCRS Codes'; //getFormat(structureColumn.get(i))!;
60
50
  result += (typeColumn.get(i) == 'SS') ?
61
51
  sequenceToMolV3000(structureColumn.get(i), false, true, format) + '\n' + `> <Sequence>\nSense Strand\n\n` :
62
52
  sequenceToMolV3000(structureColumn.get(i), true, true, format) + '\n' + `> <Sequence>\nAnti Sense\n\n`;
@@ -78,14 +68,16 @@ export function autostartOligoSdFileSubscription() {
78
68
  if (v.dataFrame.columns.contains(COL_NAMES.TYPE))
79
69
  oligoSdFile(v.dataFrame);
80
70
  grok.events.onContextMenu.subscribe((args) => {
81
- const seqCol = args.args.context.table.currentCol;
82
- if (DG.Detector.sampleCategories(seqCol, (s) => /^[fsACGUacgu]{6,}$/.test(s))) {
71
+ const seqCol = args.args.context.table.currentCol; // /^[fsACGUacgu]{6,}$/
72
+ if (DG.Detector.sampleCategories(seqCol,
73
+ (s) => /(\(invabasic\)|\(GalNAc-2-JNJ\)|f|s|A|C|G|U|a|c|g|u){6,}$/.test(s))) {
83
74
  args.args.menu.item('Convert Axolabs to GCRS', () => {
84
75
  args.args.context.table.columns.addNewString(seqCol.name + ' to GCRS').init((i: number) => {
85
76
  return siRnaAxolabsToGcrs(seqCol.get(i));
86
77
  });
87
- });
88
- } else if (DG.Detector.sampleCategories(seqCol, (s) => /^[fmpsACGU]{6,}$/.test(s)) ||
78
+ }); // /^[fmpsACGU]{6,}$/
79
+ } else if (DG.Detector.sampleCategories(seqCol,
80
+ (s) => /(\(invabasic\)|\(GalNAc-2-JNJ\)|f|m|ps|A|C|G|U){6,}$/.test(s)) ||
89
81
  DG.Detector.sampleCategories(seqCol, (s) => /^(?=.*moe)(?=.*5mC)(?=.*ps){6,}/.test(s))) {
90
82
  args.args.menu.item('Convert GCRS to raw', () => {
91
83
  args.args.context.table.columns.addNewString(seqCol.name + ' to raw').init((i: number) => {
@@ -96,15 +88,17 @@ export function autostartOligoSdFileSubscription() {
96
88
  args.args.context.table.columns.addNewString(seqCol.name + ' to MM12').init((i: number) => {
97
89
  return gcrsToMermade12(seqCol.get(i));
98
90
  });
99
- });
100
- } else if (DG.Detector.sampleCategories(seqCol, (s) => /^[*56789ATGC]{6,}$/.test(s))) {
91
+ }); // /^[*56789ATGC]{6,}$/
92
+ } else if (DG.Detector.sampleCategories(seqCol,
93
+ (s) => /(\(invabasic\)|\(GalNAc-2-JNJ\)|\*|5|6|7|8|9|A|T|G|C){6,}$/.test(s))) {
101
94
  args.args.menu.item('Convert Biospring to GCRS', () => {
102
95
  const seqCol = args.args.context.table.currentCol;
103
96
  args.args.context.table.columns.addNewString(seqCol.name + ' to GCRS').init((i: number) => {
104
97
  return asoGapmersBioSpringToGcrs(seqCol.get(i));
105
98
  });
106
- });
107
- } else if (DG.Detector.sampleCategories(seqCol, (s) => /^[*1-8]{6,}$/.test(s))) {
99
+ }); // /^[*1-8]{6,}$/
100
+ } else if (DG.Detector.sampleCategories(seqCol,
101
+ (s) => /(\(invabasic\)|\(GalNAc-2-JNJ\)|\*|1|2|3|4|5|6|7|8){6,}$/.test(s))) {
108
102
  args.args.menu.item('Convert Biospring to GCRS', () => {
109
103
  args.args.context.table.columns.addNewString(seqCol.name + ' to GCRS').init((i: number) => {
110
104
  return siRnaAxolabsToGcrs(seqCol.get(i));
@@ -123,29 +117,46 @@ export function oligoSdFile(table: DG.DataFrame) {
123
117
  const icdsDf = DG.DataFrame.fromCsv(ICDS);
124
118
  const idpsDf = DG.DataFrame.fromCsv(IDPS);
125
119
 
126
- function addColumns(t: DG.DataFrame, saltsDf: DG.DataFrame) {
120
+ async function addColumns(t: DG.DataFrame, saltsDf: DG.DataFrame) {
127
121
  if (t.columns.contains(COL_NAMES.COMPOUND_NAME))
128
122
  return grok.shell.error('Columns already exist');
129
123
 
130
- const sequence = t.getCol(COL_NAMES.SEQUENCE);
131
- const salt = t.getCol(COL_NAMES.SALT);
132
- const equivalents = t.getCol(COL_NAMES.EQUIVALENTS);
124
+ const sequenceCol = t.getCol(COL_NAMES.SEQUENCE);
125
+ const saltCol = t.getCol(COL_NAMES.SALT);
126
+ const equivalentsCol = t.getCol(COL_NAMES.EQUIVALENTS);
127
+
128
+ t.columns.addNewString(COL_NAMES.COMPOUND_NAME).init((i: number) => sequenceCol.get(i));
133
129
 
134
- t.columns.addNewString(COL_NAMES.COMPOUND_NAME).init((i: number) => sequence.get(i));
135
130
  t.columns.addNewString(COL_NAMES.COMPOUND_COMMENTS).init((i: number) => (i > 0 && i % 2 == 0) ?
136
- sequence.getString(i) + '; duplex of SS: ' + sequence.getString(i - 2) + ' and AS: ' + sequence.getString(i - 1) :
137
- sequence.getString(i),
131
+ sequenceCol.get(i) + '; duplex of SS: ' + sequenceCol.get(i - 2) + ' and AS: ' + sequenceCol.get(i - 1) :
132
+ sequenceCol.get(i),
138
133
  );
139
134
  const molWeightCol = saltsDf.getCol('MOLWEIGHT');
140
135
  const saltNamesList = saltsDf.getCol('DISPLAY').toList();
141
- t.columns.addNewFloat(COL_NAMES.CPD_MW)
142
- .init((i: number) => molecularWeight(sequence.get(i), weightsObj));
136
+ const weightsObj: {[code: string]: number} = {};
137
+ for (const synthesizer of Object.keys(map)) {
138
+ for (const technology of Object.keys(map[synthesizer])) {
139
+ for (const code of Object.keys(map[synthesizer][technology]))
140
+ weightsObj[code] = map[synthesizer][technology][code].weight!;
141
+ }
142
+ }
143
+ for (const [key, value] of Object.entries(MODIFICATIONS))
144
+ weightsObj[key] = value.molecularWeight;
145
+
146
+ t.columns.addNewFloat(COL_NAMES.CPD_MW).init((i: number) => {
147
+ return (isValidSequence(sequenceCol.get(i), null).indexOfFirstNotValidChar == -1) ?
148
+ molecularWeight(sequenceCol.get(i), weightsObj) :
149
+ DG.FLOAT_NULL;
150
+ });
151
+
143
152
  t.columns.addNewFloat(COL_NAMES.SALT_MASS).init((i: number) => {
144
- const saltRowIndex = saltNamesList.indexOf(salt.get(i));
145
- const mw = molWeightCol.get(saltRowIndex);
146
- return mw * equivalents.get(i);
153
+ const saltRowIndex = saltNamesList.indexOf(saltCol.get(i));
154
+ return (saltRowIndex == -1) ?
155
+ DG.FLOAT_NULL :
156
+ molWeightCol.get(saltRowIndex) * equivalentsCol.get(i);
147
157
  });
148
- t.columns.addNewCalculated(COL_NAMES.BATCH_MW,
158
+
159
+ await t.columns.addNewCalculated(COL_NAMES.BATCH_MW,
149
160
  '${' + COL_NAMES.CPD_MW + '} + ${' + COL_NAMES.SALT_MASS + '}', DG.COLUMN_TYPE.FLOAT, false,
150
161
  );
151
162
 
@@ -162,11 +173,12 @@ export function oligoSdFile(table: DG.DataFrame) {
162
173
  if (table.getCol(COL_NAMES.IDP).type != DG.COLUMN_TYPE.STRING)
163
174
  table.changeColumnType(COL_NAMES.IDP, DG.COLUMN_TYPE.STRING);
164
175
  d.append(
165
- ui.link('Add Columns', () => {
166
- addColumns(table, saltsDf);
167
- grok.shell.tableView(table.name).grid.columns.setOrder(Object.values(COL_NAMES));
176
+ ui.link('Add Columns', async () => {
177
+ await addColumns(table, saltsDf);
178
+ view.grid.columns.setOrder(Object.values(COL_NAMES));
168
179
  }, 'Add columns: \'' + [COL_NAMES.COMPOUND_NAME, COL_NAMES.COMPOUND_COMMENTS, COL_NAMES.CPD_MW,
169
- COL_NAMES.SALT_MASS, COL_NAMES.BATCH_MW].join('\', \''), ''),
180
+ COL_NAMES.SALT_MASS, COL_NAMES.BATCH_MW].join('\', \''), '',
181
+ ),
170
182
  ui.button('Save SD file', () => saveTableAsSdFile(addColumnsPressed ? newDf : table)),
171
183
  );
172
184
 
@@ -16,9 +16,9 @@ export function gcrsToLcms(sequence: string): string {
16
16
  }
17
17
  const regExp = new RegExp('(' + arr1.join('|') + ')', 'g');
18
18
  let r1 = sequence.replace(regExp, function(code) {return obj[code];});
19
- r1 = r1.replace('//', '/');
20
- r1 = r1.replace('//', '/');
21
- return r1.replace('//', '/');
19
+ while (r1.indexOf('//') != -1)
20
+ r1 = r1.replace('//', '/');
21
+ return r1;
22
22
  }
23
23
 
24
24
  //name: asoGapmersNucleotidesToBioSpring
@@ -36,7 +36,7 @@ export function sequenceToMolV3000(sequence: string, inverted: boolean = false,
36
36
  }
37
37
  }
38
38
 
39
- return getNucleotidesMol(smilesCodes, oclRender);
39
+ return getNucleotidesMol(smilesCodes);
40
40
  }
41
41
 
42
42
  export function sequenceToSmiles(sequence: string, inverted: boolean = false, format: string): string {
@@ -340,6 +340,12 @@ export const map: {[synthesizer: string]:
340
340
  'normalized': '',
341
341
  'SMILES': 'OP(=O)(S)O',
342
342
  },
343
+ 's': {
344
+ 'name': 'ps linkage',
345
+ 'weight': 16.07,
346
+ 'normalized': '',
347
+ 'SMILES': 'OP(=O)(S)O',
348
+ },
343
349
  'A': {
344
350
  'name': 'Adenine',
345
351
  'weight': 313.21,
@@ -78,7 +78,7 @@ M V30 END COLLECTION
78
78
  M V30 END CTAB
79
79
  M END`;
80
80
 
81
- export function getNucleotidesMol(smilesCodes: string[], oclRender: boolean = false) {
81
+ export function getNucleotidesMol(smilesCodes: string[]) {
82
82
  const molBlocks: string[] = [];
83
83
 
84
84
  for (let i = 0; i < smilesCodes.length - 1; i++) {
@@ -88,10 +88,10 @@ export function getNucleotidesMol(smilesCodes: string[], oclRender: boolean = fa
88
88
  molBlocks.push(rotateNucleotidesV3000(smilesCodes[i]));
89
89
  }
90
90
 
91
- return linkV3000(molBlocks, false, oclRender);
91
+ return linkV3000(molBlocks, false);
92
92
  }
93
93
 
94
- export function linkV3000(molBlocks: string[], twoChains: boolean = false, oclRender: boolean = false) {
94
+ export function linkV3000(molBlocks: string[], twoChains: boolean = false, useChirality: boolean = true) {
95
95
  let macroMolBlock = '\nDatagrok macromolecule handler\n\n';
96
96
  macroMolBlock += ' 0 0 0 0 0 0 999 V3000\n';
97
97
  macroMolBlock += 'M V30 BEGIN CTAB\n';
@@ -213,14 +213,14 @@ export function linkV3000(molBlocks: string[], twoChains: boolean = false, oclRe
213
213
  const entries = 4;
214
214
  const collNumber = Math.ceil(collection.length / entries);
215
215
 
216
- if (oclRender) {
217
- collectionBlock += 'M V30 MDLV30/STEABS ATOMS=(' + collection.length;
216
+ //if (oclRender) {
217
+ // collectionBlock += 'M V30 MDLV30/STEABS ATOMS=(' + collection.length;
218
218
 
219
- for (let j = 0; j < collection.length; j++)
220
- collectionBlock += ' ' + collection[j];
219
+ // for (let j = 0; j < collection.length; j++)
220
+ // collectionBlock += ' ' + collection[j];
221
221
 
222
- collectionBlock += ')\n';
223
- } else {
222
+ // collectionBlock += ')\n';
223
+ //} else {
224
224
  collectionBlock += 'M V30 MDLV30/STEABS ATOMS=(' + collection.length + ' -\n';
225
225
  for (let i = 0; i < collNumber; i++) {
226
226
  collectionBlock += 'M V30 ';
@@ -231,7 +231,7 @@ export function linkV3000(molBlocks: string[], twoChains: boolean = false, oclRe
231
231
  collection[entries*i + j] + ' ';
232
232
  }
233
233
  }
234
- }
234
+ //}
235
235
 
236
236
  //generate file
237
237
  twoChains? natom : natom++;
@@ -242,14 +242,16 @@ export function linkV3000(molBlocks: string[], twoChains: boolean = false, oclRe
242
242
  macroMolBlock += 'M V30 BEGIN BOND\n';
243
243
  macroMolBlock += bondBlock;
244
244
  macroMolBlock += 'M V30 END BOND\n';
245
- //macroMolBlock += 'M V30 BEGIN COLLECTION\n';
246
- //macroMolBlock += collectionBlock;
247
- //macroMolBlock += 'M V30 END COLLECTION\n';
245
+ if(useChirality){
246
+ macroMolBlock += 'M V30 BEGIN COLLECTION\n';
247
+ macroMolBlock += collectionBlock;
248
+ macroMolBlock += 'M V30 END COLLECTION\n';
249
+ } else
250
+ macroMolBlock = macroMolBlock.replace(/ CFG=\d/g, ' ');
251
+
248
252
  macroMolBlock += 'M V30 END CTAB\n';
249
253
  macroMolBlock += 'M END\n';
250
254
 
251
- macroMolBlock = macroMolBlock.replaceAll('CFG=1', '').replaceAll('CFG=2', '').replaceAll('CFG=3', '').replaceAll('CFG=4', '');
252
-
253
255
  return macroMolBlock;
254
256
  }
255
257
 
@@ -3,14 +3,14 @@ import {sequenceToMolV3000} from '../structures-works/from-monomers';
3
3
  import {linkV3000} from '../structures-works/mol-transformations';
4
4
  import {getFormat} from '../structures-works/sequence-codes-tools';
5
5
 
6
- export function saveSdf(as: string, ss: string, oneEntity: boolean, fit3dx: boolean) {
6
+ export function saveSdf(as: string, ss: string, oneEntity: boolean, useChirality: boolean, invertSS: boolean, invertAS: boolean) {
7
7
  const formatAs = getFormat(as);
8
8
  const formatSs = getFormat(ss);
9
- const molSS = sequenceToMolV3000(ss, false, false, formatSs!);
10
- const molAS = sequenceToMolV3000(as, true, false, formatAs!);
9
+ const molSS = sequenceToMolV3000(ss, invertSS, false, formatSs!);
10
+ const molAS = sequenceToMolV3000(as, invertAS, false, formatAs!);
11
11
  let result: string;
12
12
  if (oneEntity)
13
- result = linkV3000([molSS, molAS], true, !fit3dx) + '\n\n$$$$\n';
13
+ result = linkV3000([molSS, molAS], true, useChirality) + '\n\n$$$$\n';
14
14
  else {
15
15
  result =
16
16
  molSS + '\n' +
@@ -27,22 +27,35 @@ export function saveSdf(as: string, ss: string, oneEntity: boolean, fit3dx: bool
27
27
 
28
28
  export function saveSenseAntiSense() {
29
29
  const moleculeSvgDiv = ui.block([]);
30
- const ssInput = ui.textInput('Sense Strand 5\' ->3\'', '');
31
- const asInput = ui.textInput('Anti Sense 3\' ->5\'', '');
30
+ const ssInput = ui.textInput('Sense Strand', '');
31
+ const asInput = ui.textInput('Anti Sense', '');
32
+ const straight = '5\' ->3\'';
33
+ const inverse = '3\' ->5\'';
34
+ let ssInverse = false;
35
+ let asInverse = false;
36
+
37
+ const changeSense = ui.choiceInput('SS direction', straight, [straight, inverse]);
38
+ changeSense.onChanged(() => {ssInverse = changeSense.value == inverse;});
39
+ const changeAntiSense = ui.choiceInput('AS direction', straight, [straight, inverse]);
40
+ changeAntiSense.onChanged(() => {asInverse = changeAntiSense.value == inverse;});
41
+
32
42
  const saveOption = ui.switchInput('Save as one entity', true);
33
- const save3dx = ui.switchInput('Save 3dx', true);
43
+ const chirality = ui.switchInput('Use chiral', true);
34
44
  const saveBtn = ui.button('Save SDF', () =>
35
- saveSdf(asInput.value, ssInput.value, saveOption.value, save3dx.value));
45
+ saveSdf(asInput.value, ssInput.value, saveOption.value, chirality.value, ssInverse, asInverse));
36
46
 
37
47
  const saveSection = ui.panel([
38
48
  ui.div([
39
49
  ui.div([
40
50
  ui.divH([ui.h1('Inputs')]),
41
51
  ui.divV([
42
- ui.div([ssInput.root]),
43
- ui.div([asInput.root]),
52
+ ssInput,
53
+ asInput,
54
+ ui.div([changeSense], {style: {width: '40'}}),
55
+ changeSense,
56
+ changeAntiSense,
44
57
  saveOption,
45
- save3dx,
58
+ chirality,
46
59
  ui.buttonsInput([saveBtn]),
47
60
  ], 'ui-form'),
48
61
  ], 'ui-form'),
@@ -1,5 +1,5 @@
1
1
 
2
- import {map, SYNTHESIZERS, TECHNOLOGIES, MODIFICATIONS, delimiter} from './map';
2
+ import {map, SYNTHESIZERS, TECHNOLOGIES, MODIFICATIONS, delimiter, gcrsCodesWithoutSmiles} from './map';
3
3
  import {asoGapmersNucleotidesToBioSpring, asoGapmersNucleotidesToGcrs,
4
4
  asoGapmersBioSpringToNucleotides, asoGapmersBioSpringToGcrs, asoGapmersGcrsToNucleotides,
5
5
  asoGapmersGcrsToBioSpring, gcrsToMermade12, siRnaNucleotideToBioSpringSenseStrand,
@@ -88,6 +88,10 @@ export function getFormat(sequence: string): string | null {
88
88
  return possibleSynthesizers[0];
89
89
  }
90
90
 
91
+ function sortByStringLengthInDescendingOrder(array: string[]): string[] {
92
+ return array.sort(function(a: string, b: string) {return b.length - a.length;});
93
+ }
94
+
91
95
  export function isValidSequence(sequence: string, format: string | null): {
92
96
  indexOfFirstNotValidChar: number,
93
97
  synthesizer: string[] | null,
@@ -118,7 +122,7 @@ export function isValidSequence(sequence: string, format: string | null): {
118
122
  const nucleotides = ['A', 'U', 'T', 'C', 'G'];
119
123
 
120
124
  possibleSynthesizers.forEach((synthesizer) => {
121
- const codes = getAllCodesOfSynthesizer(synthesizer);
125
+ const codes = sortByStringLengthInDescendingOrder(getAllCodesOfSynthesizer(synthesizer));
122
126
  while (outputIndex < sequence.length) {
123
127
  const matchedCode = codes.find((c) => c == sequence.slice(outputIndex, outputIndex + c.length));
124
128
 
@@ -212,9 +216,11 @@ export function getAllCodesOfSynthesizer(synthesizer: string): string[] {
212
216
  }
213
217
 
214
218
  function getListOfPossibleSynthesizersByFirstMatchedCode(sequence: string): string[] {
215
- const synthesizers: string[] = [];
219
+ let synthesizers: string[] = [];
216
220
  Object.keys(map).forEach((synthesizer: string) => {
217
- const codes = getAllCodesOfSynthesizer(synthesizer);
221
+ let codes = sortByStringLengthInDescendingOrder(getAllCodesOfSynthesizer(synthesizer));
222
+ if (synthesizer == 'Janssen GCRS Codes')
223
+ codes = codes.concat(gcrsCodesWithoutSmiles);
218
224
  //TODO: get first non-dropdown code when there are two modifications
219
225
  let start = 0;
220
226
  for (let i = 0; i < sequence.length; i++) {
@@ -223,6 +229,8 @@ function getListOfPossibleSynthesizersByFirstMatchedCode(sequence: string): stri
223
229
  break;
224
230
  }
225
231
  }
232
+ if (gcrsCodesWithoutSmiles.some((s: string) => s == sequence.slice(start, start + s.length)))
233
+ synthesizers = ['Janssen GCRS Codes'];
226
234
  if (codes.some((s: string) => s == sequence.slice(start, start + s.length)))
227
235
  synthesizers.push(synthesizer);
228
236
  });