@datagrok/sequence-translator 1.0.3 → 1.0.4

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.3",
4
+ "version": "1.0.4",
5
5
  "description": "SequenceTranslator is a [package](https://datagrok.ai/help/develop/develop#packages) for the [Datagrok](https://datagrok.ai) platform, used to translate [oligonucleotide](https://en.wikipedia.org/wiki/Oligonucleotide) sequences between [different representations](https://github.com/datagrok-ai/public/tree/master/packages/SequenceTranslator#sequence-representations).",
6
6
  "repository": {
7
7
  "type": "git",
@@ -21,21 +21,21 @@
21
21
  },
22
22
  "scripts": {
23
23
  "link-api": "npm link datagrok-api",
24
- "debug-sequencetranslator": "grok publish --rebuild",
25
- "release-sequencetranslator": "grok publish --rebuild --release",
24
+ "debug-sequencetranslator": "grok publish",
25
+ "release-sequencetranslator": "grok publish localhost --release",
26
26
  "build-sequencetranslator": "webpack",
27
27
  "build": "webpack",
28
- "debug-sequencetranslator-public": "grok publish public --rebuild",
29
- "release-sequencetranslator-public": "grok publish public --rebuild --release",
30
- "debug-sequencetranslator-local": "grok publish local --rebuild",
31
- "release-sequencetranslator-local": "grok publish local --rebuild --release",
28
+ "debug-sequencetranslator-public": "grok publish public",
29
+ "release-sequencetranslator-public": "grok publish public --release",
30
+ "debug-sequencetranslator-local": "grok publish local",
31
+ "release-sequencetranslator-local": "grok publish local --release",
32
32
  "test": "set HOST=dev && jest",
33
33
  "test-dev": "set HOST=dev && jest",
34
34
  "test-local": "set HOST=localhost && jest"
35
35
  },
36
36
  "sources": [
37
37
  "css/style.css",
38
- "common/openchemlib-full.js"
38
+ "vendors/openchemlib-full.js"
39
39
  ],
40
40
  "devDependencies": {
41
41
  "@typescript-eslint/eslint-plugin": "^4.29.1",
@@ -16,34 +16,53 @@ beforeAll(async () => {
16
16
  }, P_START_TIMEOUT);
17
17
 
18
18
  afterAll(async () => {
19
- await browser.close();
19
+ await browser?.close();
20
+ });
21
+
22
+ expect.extend({
23
+ checkOutput(received, expected, context) {
24
+ if (received === expected) {
25
+ return {
26
+ message: () => context,
27
+ pass: true
28
+ };
29
+ } else {
30
+ return {
31
+ message: () => context,
32
+ pass: false
33
+ };
34
+ }
35
+ }
20
36
  });
21
37
 
22
38
  it('TEST', async () => {
23
- const target_package:string = process.env.TARGET_PACKAGE ?? 'SequenceTranslator';
24
- console.log(`Testing ${target_package} package`);
39
+ const targetPackage:string = process.env.TARGET_PACKAGE ?? 'SequenceTranslator';
40
+ console.log(`Testing ${targetPackage} package`);
25
41
 
26
- //console.log(require('root-require')('package.json').version);
27
- let r = await page.evaluate((target_package):Promise<object> => {
42
+ let r = await page.evaluate((targetPackage):Promise<object> => {
28
43
  return new Promise<object>((resolve, reject) => {
29
- (<any>window).grok.functions.eval(target_package + ':test()').then((df: any) => {
44
+ (<any>window).grok.functions.eval(targetPackage + ':test()').then((df: any) => {
30
45
  let cStatus = df.columns.byName('success');
31
46
  let cMessage = df.columns.byName('result');
32
47
  let cCat = df.columns.byName('category');
33
48
  let cName = df.columns.byName('name');
34
49
  let failed = false;
35
- let report = '';
36
- for (let i = 0; i < df.rowCount; i++)
37
- if (!cStatus.get(i)) {
38
- report += `${cCat.get(i)}.${cName.get(i)}: ${cMessage.get(i)}\n`;
50
+ let passReport = '';
51
+ let failReport = '';
52
+ for (let i = 0; i < df.rowCount; i++) {
53
+ if (cStatus.get(i)) {
54
+ passReport += `Test result : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
55
+ } else {
39
56
  failed = true;
57
+ failReport += `Test result : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
40
58
  }
41
- resolve({report, failed});
59
+ }
60
+ resolve({failReport, passReport, failed});
42
61
  }).catch((e: any) => reject(e));
43
62
  });
44
- }, target_package);
63
+ }, targetPackage);
45
64
  // @ts-ignore
46
- console.log(r.report);
65
+ console.log(r.passReport);
47
66
  // @ts-ignore
48
- expect(r.failed).toBe(false);
67
+ expect(r.failed).checkOutput(false, r.failReport);
49
68
  }, 100000);
@@ -82,7 +82,9 @@ function addColumnWithIds(tableName: string, columnName: string, patternName: st
82
82
  if (columns.contains(nameOfNewColumn))
83
83
  columns.remove(nameOfNewColumn);
84
84
  const columnWithIds = columns.byName(columnName);
85
- return columns.addNewString(nameOfNewColumn).init((i: number) => columnWithIds.get(i) + '_' + patternName);
85
+ return columns.addNewString(nameOfNewColumn).init((i: number) => {
86
+ return (columnWithIds.getString(i) == '') ? '' : columnWithIds.get(i) + '_' + patternName;
87
+ });
86
88
  }
87
89
 
88
90
  function addColumnWithTranslatedSequences(
@@ -99,8 +101,10 @@ function addColumnWithTranslatedSequences(
99
101
  columns.remove(nameOfNewColumn);
100
102
  const columnWithInputSequences = columns.byName(columnName);
101
103
  return columns.addNewString(nameOfNewColumn).init((i: number) => {
102
- return translateSequence(columnWithInputSequences.getString(i),
103
- bases, ptoLinkages, startModification, endModification, firstPtoExist);
104
+ return columnWithInputSequences.getString(i) == '' ?
105
+ '' :
106
+ translateSequence(columnWithInputSequences.getString(i), bases, ptoLinkages, startModification, endModification,
107
+ firstPtoExist);
104
108
  });
105
109
  }
106
110
 
@@ -332,7 +336,7 @@ export function defineAxolabsPattern() {
332
336
  const col = tables.value!.columns.byName(colName);
333
337
  let allLengthsAreTheSame = true;
334
338
  for (let i = 1; i < col.length; i++) {
335
- if (col.get(i - 1).length != col.get(i).length) {
339
+ if (col.get(i - 1).length != col.get(i).length && col.get(i).length != 0) {
336
340
  allLengthsAreTheSame = false;
337
341
  break;
338
342
  }
@@ -361,12 +365,13 @@ export function defineAxolabsPattern() {
361
365
  }
362
366
 
363
367
  async function postPatternToUserStorage() {
364
- const author = await getCurrentUserName();
365
- if (!saveAs.stringValue.includes('(created by '))
366
- saveAs.value = saveAs.stringValue + author;
368
+ const currUserName = await getCurrentUserName();
369
+ saveAs.value = (saveAs.stringValue.includes('(created by ')) ?
370
+ getShortName(saveAs.value) + currUserName :
371
+ saveAs.stringValue + currUserName;
367
372
  return grok.dapi.userDataStorage.postValue(
368
373
  userStorageKey,
369
- saveAs.stringValue,
374
+ saveAs.value,
370
375
  JSON.stringify({
371
376
  'ssBases': ssBases.slice(0, ssLength.value!).map((e) => e.value),
372
377
  'asBases': asBases.slice(0, asLength.value!).map((e) => e.value),
@@ -387,11 +392,12 @@ export function defineAxolabsPattern() {
387
392
  const lstMy: string[] = [];
388
393
  const lstOthers: string[] = [];
389
394
 
395
+ // TODO: display short name, but use long for querying userdataStorage
390
396
  for (const ent of Object.keys(entities)) {
391
397
  if (await isCurrentUserCreatedThisPattern(ent))
392
398
  lstOthers.push(ent);
393
399
  else
394
- lstMy.push(getShortName(ent));
400
+ lstMy.push(ent);//getShortName(ent));
395
401
  }
396
402
 
397
403
  let loadPattern = ui.choiceInput('Load Pattern', '', lstMy, (v: string) => parsePatternAndUpdateUi(v));
@@ -526,7 +532,7 @@ export function defineAxolabsPattern() {
526
532
  const col = tables.value!.columns.byName(colName);
527
533
  if (col.type != DG.TYPE.INT)
528
534
  grok.shell.error('Column should contain integers only');
529
- else if (col.categories.length < col.length) {
535
+ else if (col.categories.filter((e) => e != '').length < col.toList().filter((e) => e != '').length) {
530
536
  const duplicates = findDuplicates(col.getRawData());
531
537
  ui.dialog('Non-unique IDs')
532
538
  .add(ui.divText('Press \'OK\' to select rows with non-unique values'))
@@ -541,25 +547,43 @@ export function defineAxolabsPattern() {
541
547
  }
542
548
 
543
549
  const tables = ui.tableInput('Tables', grok.shell.tables[0], grok.shell.tables, (t: DG.DataFrame) => {
544
- const inputSsColumn =
545
- ui.choiceInput('SS Column', '', t.columns.names(), (colName: string) => validateSsColumn(colName));
550
+ const inputSsColumn = ui.choiceInput('SS Column', '', t.columns.names(), (colName: string) => {
551
+ validateSsColumn(colName);
552
+ ssVar = colName;
553
+ });
546
554
  inputSsColumnDiv.innerHTML = '';
547
555
  inputSsColumnDiv.append(inputSsColumn.root);
548
- const inputAsColumn =
549
- ui.choiceInput('AS Column', '', t.columns.names(), (colName: string) => validateAsColumn(colName));
556
+ const inputAsColumn = ui.choiceInput('AS Column', '', t.columns.names(), (colName: string) => {
557
+ validateAsColumn(colName);
558
+ asVar = colName;
559
+ });
550
560
  inputAsColumnDiv.innerHTML = '';
551
561
  inputAsColumnDiv.append(inputAsColumn.root);
552
- const inputIdColumn =
553
- ui.choiceInput('ID Column', '', t.columns.names(), (colName: string) => validateIdsColumn(colName));
562
+ const inputIdColumn = ui.choiceInput('ID Column', '', t.columns.names(), (colName: string) => {
563
+ validateIdsColumn(colName);
564
+ idVar = colName;
565
+ });
554
566
  inputIdColumnDiv.innerHTML = '';
555
567
  inputIdColumnDiv.append(inputIdColumn.root);
556
568
  });
557
569
 
558
- const inputSsColumn = ui.choiceInput('SS Column', '', []);
570
+ let ssVar = '';
571
+ const inputSsColumn = ui.choiceInput('SS Column', '', [], (colName: string) => {
572
+ validateSsColumn(colName);
573
+ ssVar = colName;
574
+ });
559
575
  inputSsColumnDiv.append(inputSsColumn.root);
560
- const inputAsColumn = ui.choiceInput('AS Column', '', []);
576
+ let asVar = '';
577
+ const inputAsColumn = ui.choiceInput('AS Column', '', [], (colName: string) => {
578
+ validateAsColumn(colName);
579
+ asVar = colName;
580
+ });
561
581
  inputAsColumnDiv.append(inputAsColumn.root);
562
- const inputIdColumn = ui.choiceInput('ID Column', '', []);
582
+ let idVar = '';
583
+ const inputIdColumn = ui.choiceInput('ID Column', '', [], (colName: string) => {
584
+ validateIdsColumn(colName);
585
+ idVar = colName;
586
+ });
563
587
  inputIdColumnDiv.append(inputIdColumn.root);
564
588
 
565
589
  updatePatternsList();
@@ -638,7 +662,7 @@ export function defineAxolabsPattern() {
638
662
  });
639
663
 
640
664
  const convertSequenceButton = ui.button('Convert Sequences', () => {
641
- if (inputSsColumn.value == null || (createAsStrand.value && inputAsColumn.value == null))
665
+ if (ssVar == '' || (createAsStrand.value && asVar == ''))
642
666
  grok.shell.info('Please select table and columns on which to apply pattern');
643
667
  else if (ssLength.value != ssInputExample.value.length || asLength.value != asInputExample.value.length) {
644
668
  const dialog = ui.dialog('Length Mismatch');
@@ -652,14 +676,14 @@ export function defineAxolabsPattern() {
652
676
  })
653
677
  .show();
654
678
  } else {
655
- if (inputIdColumn.value != null)
656
- addColumnWithIds(tables.value!.name, inputIdColumn.value, getShortName(saveAs.value));
679
+ if (idVar != '')
680
+ addColumnWithIds(tables.value!.name, idVar, getShortName(saveAs.value));
657
681
  addColumnWithTranslatedSequences(
658
- tables.value!.name, inputSsColumn.value, ssBases, ssPtoLinkages,
682
+ tables.value!.name, ssVar, ssBases, ssPtoLinkages,
659
683
  ssFiveModification, ssThreeModification, firstSsPto.value!);
660
684
  if (createAsStrand.value) {
661
685
  addColumnWithTranslatedSequences(
662
- tables.value!.name, inputAsColumn.value!, asBases, asPtoLinkages,
686
+ tables.value!.name, asVar, asBases, asPtoLinkages,
663
687
  asFiveModification, asThreeModification, firstAsPto.value!);
664
688
  }
665
689
  grok.shell.v = grok.shell.getTableView(tables.value!.name);
package/src/package.ts CHANGED
@@ -2,7 +2,6 @@
2
2
  import * as grok from 'datagrok-api/grok';
3
3
  import * as ui from 'datagrok-api/ui';
4
4
  import * as DG from 'datagrok-api/dg';
5
- import * as OCL from 'openchemlib/full.js';
6
5
  import $ from 'cash-dom';
7
6
  import {defineAxolabsPattern} from './defineAxolabsPattern';
8
7
  import {saveSenseAntiSense} from './structures-works/save-sense-antisense';
@@ -10,7 +9,8 @@ import {sequenceToSmiles, sequenceToMolV3000} from './structures-works/from-mono
10
9
  import {convertSequence, undefinedInputSequence, isValidSequence, getFormat} from
11
10
  './structures-works/sequence-codes-tools';
12
11
  import {map, COL_NAMES, MODIFICATIONS} from './structures-works/map';
13
- import {siRnaAxolabsToGcrs} from './structures-works/converters';
12
+ import {siRnaAxolabsToGcrs, gcrsToNucleotides, asoGapmersBioSpringToGcrs, gcrsToMermade12,
13
+ } from './structures-works/converters';
14
14
  import {SALTS_CSV} from './salts';
15
15
  import {USERS_CSV} from './users';
16
16
  import {ICDS} from './ICDs';
@@ -309,23 +309,43 @@ function molecularWeight(sequence: string, weightsObj: {[index: string]: number}
309
309
 
310
310
  //tags: autostart
311
311
  export function autostartOligoSdFileSubscription() {
312
- let alreadyAdded = false;
313
312
  grok.events.onViewAdded.subscribe((v: any) => {
314
313
  if (v.type == 'TableView') {
315
314
  if (v.dataFrame.columns.contains(COL_NAMES.TYPE))
316
315
  oligoSdFile(v.dataFrame);
317
316
  grok.events.onContextMenu.subscribe((args) => {
318
- for (const col of v.dataFrame.columns) {
319
- if (!alreadyAdded && DG.Detector.sampleCategories(col, (s) => /^[fsACGUacgu]{6,}$/.test(s))) {
320
- alreadyAdded = true;
321
- args.args.menu.item('Convert to GCRS', () => {
322
- const seqCol = args.args.context.table.currentCol;
323
- args.args.context.table.columns.addNewString(seqCol.name + ' to GCRS').init((i: number) => {
324
- return siRnaAxolabsToGcrs(seqCol.get(i));
325
- });
317
+ const seqCol = args.args.context.table.currentCol;
318
+ if (DG.Detector.sampleCategories(seqCol, (s) => /^[fsACGUacgu]{6,}$/.test(s))) {
319
+ args.args.menu.item('Convert Axolabs to GCRS', () => {
320
+ args.args.context.table.columns.addNewString(seqCol.name + ' to GCRS').init((i: number) => {
321
+ return siRnaAxolabsToGcrs(seqCol.get(i));
326
322
  });
327
- break;
328
- };
323
+ });
324
+ } else if (DG.Detector.sampleCategories(seqCol, (s) => /^[fmpsACGU]{6,}$/.test(s)) ||
325
+ DG.Detector.sampleCategories(seqCol, (s) => /^(?=.*moe)(?=.*5mC)(?=.*ps){6,}/.test(s))) {
326
+ args.args.menu.item('Convert GCRS to raw', () => {
327
+ args.args.context.table.columns.addNewString(seqCol.name + ' to raw').init((i: number) => {
328
+ return gcrsToNucleotides(seqCol.get(i));
329
+ });
330
+ });
331
+ args.args.menu.item('Convert GCRS to MM12', () => {
332
+ args.args.context.table.columns.addNewString(seqCol.name + ' to MM12').init((i: number) => {
333
+ return gcrsToMermade12(seqCol.get(i));
334
+ });
335
+ });
336
+ } else if (DG.Detector.sampleCategories(seqCol, (s) => /^[*56789ATGC]{6,}$/.test(s))) {
337
+ args.args.menu.item('Convert Biospring to GCRS', () => {
338
+ const seqCol = args.args.context.table.currentCol;
339
+ args.args.context.table.columns.addNewString(seqCol.name + ' to GCRS').init((i: number) => {
340
+ return asoGapmersBioSpringToGcrs(seqCol.get(i));
341
+ });
342
+ });
343
+ } else if (DG.Detector.sampleCategories(seqCol, (s) => /^[*1-8]{6,}$/.test(s))) {
344
+ args.args.menu.item('Convert Biospring to GCRS', () => {
345
+ args.args.context.table.columns.addNewString(seqCol.name + ' to GCRS').init((i: number) => {
346
+ return siRnaAxolabsToGcrs(seqCol.get(i));
347
+ });
348
+ });
329
349
  }
330
350
  });
331
351
  }
@@ -1,5 +1,3 @@
1
- import * as OCL from 'openchemlib/full.js';
2
-
3
1
  const PHOSHATE = `
4
2
  Datagrok monomer library Nucleotides
5
3
 
@@ -254,6 +252,7 @@ export function linkV3000(molBlocks: string[], twoChains: boolean = false, oclRe
254
252
  }
255
253
 
256
254
  function rotateNucleotidesV3000(molecule: string) {
255
+ // @ts-ignore
257
256
  let molBlock = molecule.includes('M END') ? molecule : OCL.Molecule.fromSmiles(molecule).toMolfileV3();
258
257
  const coordinates = extractAtomDataV3000(molBlock);
259
258
  const natom = coordinates.atomIndex.length;
@@ -320,6 +319,7 @@ function rotateNucleotidesV3000(molecule: string) {
320
319
  }
321
320
 
322
321
  function invertNucleotidesV3000(molecule: string) {
322
+ // @ts-ignore
323
323
  let molBlock = molecule.includes('M END') ? molecule : OCL.Molecule.fromSmiles(molecule).toMolfileV3();
324
324
  const coordinates = extractAtomDataV3000(molBlock);
325
325
  const natom = coordinates.atomIndex.length;