@datagrok/helm 1.0.2 → 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.
File without changes
@@ -1,6 +1,6 @@
1
- ID,Test type,HELM string,Valid?,Mol Weight,Mol Formula,SMILES
2
- RNA,Simple RNA ,RNA1{R(U)P.R(T)P.R(G)P.R(C)P.R(A)}$$$$,yes,1543.98,C48H61N17O34P4,[H]OCC1OC(N2C=CC(=O)NC2=O)C(O)C1OP(=O)(O)OCC3OC(N4C=C(C(=O)NC4=O)C)C(O)C3OP(=O)(O)OCC5OC(N6C=NC=7C(=O)NC(=NC76)N)C(O)C5OP(=O)(O)OCC8OC(N9C=CC(=NC9=O)N)C(O)C8OP(=O)(O)OCC%10OC(N%11C=NC=%12C(=NC=NC%12%11)N)C(O)C%10O[H]
3
- Different arrangements of dots,Only dots beween the backbone monomers,RNA1{P.R(U)P.R(T)}$$$$,yes,644.37,C19H26N4O17P2,OP(O)(OC[C@H]1O[C@@H](N(C2=O)C=CC(N2)=O)[C@H](O)[C@@H]1OP(O)(OC[C@H]3O[C@@H](N(C4=O)C=C(C)C(N4)=O)[C@H](O)[C@@H]3O[H])=O)=O
4
- Different arrangements of dots,Dot after the branch,RNA1{P.R(U).P.R(T)}$$$$,yes,644.37,C19H26N4O17P2,OP(O)(OC[C@H]1O[C@@H](N(C2=O)C=CC(N2)=O)[C@H](O)[C@@H]1OP(O)(OC[C@H]3O[C@@H](N(C4=O)C=C(C)C(N4)=O)[C@H](O)[C@@H]3O[H])=O)=O
5
- Hydrogen bonding,RNA with hydrogen bonding,"RNA1{R(A)P.R(C)P.R(G)P}|RNA2{P.R(C)P.R(G)P.R(T)}$RNA1,RNA2,2:pair-9:pair|RNA1,RNA2,5:pair-6:pair|RNA1,RNA2,8:pair-3:pair$$$",yes,1986.2,C58H77N23O44P6,NA
1
+ ID,Test type,HELM string,Valid?,Mol Weight,Mol Formula,SMILES
2
+ RNA,Simple RNA ,RNA1{R(U)P.R(T)P.R(G)P.R(C)P.R(A)}$$$$,yes,1543.98,C48H61N17O34P4,[H]OCC1OC(N2C=CC(=O)NC2=O)C(O)C1OP(=O)(O)OCC3OC(N4C=C(C(=O)NC4=O)C)C(O)C3OP(=O)(O)OCC5OC(N6C=NC=7C(=O)NC(=NC76)N)C(O)C5OP(=O)(O)OCC8OC(N9C=CC(=NC9=O)N)C(O)C8OP(=O)(O)OCC%10OC(N%11C=NC=%12C(=NC=NC%12%11)N)C(O)C%10O[H]
3
+ Different arrangements of dots,Only dots beween the backbone monomers,RNA1{P.R(U)P.R(T)}$$$$,yes,644.37,C19H26N4O17P2,OP(O)(OC[C@H]1O[C@@H](N(C2=O)C=CC(N2)=O)[C@H](O)[C@@H]1OP(O)(OC[C@H]3O[C@@H](N(C4=O)C=C(C)C(N4)=O)[C@H](O)[C@@H]3O[H])=O)=O
4
+ Different arrangements of dots,Dot after the branch,RNA1{P.R(U).P.R(T)}$$$$,yes,644.37,C19H26N4O17P2,OP(O)(OC[C@H]1O[C@@H](N(C2=O)C=CC(N2)=O)[C@H](O)[C@@H]1OP(O)(OC[C@H]3O[C@@H](N(C4=O)C=C(C)C(N4)=O)[C@H](O)[C@@H]3O[H])=O)=O
5
+ Hydrogen bonding,RNA with hydrogen bonding,"RNA1{R(A)P.R(C)P.R(G)P}|RNA2{P.R(C)P.R(G)P.R(T)}$RNA1,RNA2,2:pair-9:pair|RNA1,RNA2,5:pair-6:pair|RNA1,RNA2,8:pair-3:pair$$$",yes,1986.2,C58H77N23O44P6,NA
6
6
  Hydrogen bonding,Shorter RNA with H bonding,"RNA1{R(U)P.R(T)P}|RNA2{P.R(A)P.R(A)}$RNA1,RNA2,2:pair-6:pair|RNA1,RNA2,5:pair-3:pair$$$",yes,1320.8,C39H52N14O30P4,NA
package/jest.config.js ADDED
@@ -0,0 +1,34 @@
1
+ module.exports = {
2
+ "roots": [
3
+ "<rootDir>/src"
4
+ ],
5
+ "testMatch": [
6
+ "**/__jest__/**/*.test.+(ts|tsx)"
7
+ ],
8
+ moduleFileExtensions: [
9
+ 'ts',
10
+ 'js',
11
+ ],
12
+ "transform": {
13
+ "^.+\\.(ts|tsx)$": "ts-jest"
14
+ },
15
+ transformIgnorePatterns: ['^.+\\.js$'],
16
+ globals: {
17
+ 'ts-jest': {
18
+ 'tsconfig': {
19
+ "target": "es6",
20
+ "module": "es2020",
21
+ }
22
+ }
23
+ },
24
+ reporters: [
25
+ "default",
26
+ [
27
+ "./node_modules/jest-html-reporter",
28
+ {
29
+ "includeConsoleLog": true,
30
+ "includeFailureMsg": true
31
+ }
32
+ ]
33
+ ]
34
+ }
package/package.json CHANGED
@@ -2,14 +2,14 @@
2
2
  "name": "@datagrok/helm",
3
3
  "beta": false,
4
4
  "friendlyName": "Helm",
5
- "version": "1.0.2",
5
+ "version": "1.0.6",
6
6
  "description": "",
7
7
  "dependencies": {
8
8
  "datagrok-api": "^1.4.12",
9
9
  "cash-dom": "latest",
10
10
  "dayjs": "latest",
11
11
  "@datagrok-libraries/utils": "latest",
12
- "@datagrok-libraries/bio": "^2.8.3",
12
+ "@datagrok-libraries/bio": "^2.8.4",
13
13
  "ts-loader": "^9.2.5",
14
14
  "typescript": "^4.4.2"
15
15
  },
@@ -28,7 +28,14 @@
28
28
  "ts-loader": "latest",
29
29
  "typescript": "latest",
30
30
  "webpack": "latest",
31
- "webpack-cli": "latest"
31
+ "webpack-cli": "latest",
32
+ "@types/jest": "^27.0.0",
33
+ "jest": "^27.0.0",
34
+ "jest-html-reporter": "^3.5.0",
35
+ "puppeteer": "^13.7.0",
36
+ "ts-jest": "^27.0.0",
37
+ "@types/js-yaml": "^4.0.5",
38
+ "@types/node-fetch": "^2.6.1"
32
39
  },
33
40
  "scripts": {
34
41
  "link-all": "npm link datagrok-api @datagrok-libraries/utils @datagrok-libraries/bio",
@@ -43,7 +50,10 @@
43
50
  "debug-helm-public": "grok publish public --rebuild",
44
51
  "release-helm-public": "grok publish public --rebuild --release",
45
52
  "lint": "eslint \"./src/**/*.ts\"",
46
- "lint-fix": "eslint \"./src/**/*.ts\" --fix"
53
+ "lint-fix": "eslint \"./src/**/*.ts\" --fix",
54
+ "test": "set HOST=dev && jest",
55
+ "test-dev": "set HOST=dev && jest",
56
+ "test-local": "set HOST=localhost && jest"
47
57
  },
48
58
  "canEdit": [
49
59
  "Developers"
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @jest-environment jsdom
3
+ */
4
+
5
+ import * as utils from './test-node';
6
+ import puppeteer from 'puppeteer';
7
+
8
+ const P_START_TIMEOUT: number = 100000;
9
+ let browser: puppeteer.Browser;
10
+ let page: puppeteer.Page;
11
+
12
+ beforeAll(async () => {
13
+ let out = await utils.getBrowserPage(puppeteer);
14
+ browser = out.browser;
15
+ page = out.page;
16
+ }, P_START_TIMEOUT);
17
+
18
+ afterAll(async () => {
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
+ }
36
+ });
37
+
38
+ it('TEST', async () => {
39
+ const targetPackage:string = process.env.TARGET_PACKAGE ?? 'Helm';
40
+ console.log(`Testing ${targetPackage} package`);
41
+
42
+ let r = await page.evaluate((targetPackage):Promise<object> => {
43
+ return new Promise<object>((resolve, reject) => {
44
+ (<any>window).grok.functions.eval(targetPackage + ':test()').then((df: any) => {
45
+ let cStatus = df.columns.byName('success');
46
+ let cMessage = df.columns.byName('result');
47
+ let cCat = df.columns.byName('category');
48
+ let cName = df.columns.byName('name');
49
+ let failed = false;
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 {
56
+ failed = true;
57
+ failReport += `Test result : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
58
+ }
59
+ }
60
+ resolve({failReport, passReport, failed});
61
+ }).catch((e: any) => reject(e));
62
+ });
63
+ }, targetPackage);
64
+ // @ts-ignore
65
+ console.log(r.passReport);
66
+ // @ts-ignore
67
+ expect(r.failed).checkOutput(false, r.failReport);
68
+ }, 100000);
@@ -0,0 +1,95 @@
1
+ import * as path from "path";
2
+ import * as os from "os";
3
+ import * as fs from "fs";
4
+ import * as yaml from 'js-yaml';
5
+ import fetch from 'node-fetch';
6
+
7
+ export async function getToken(url: string, key: string) {
8
+ let response = await fetch(`${url}/users/login/dev/${key}`, {method: 'POST'});
9
+ let json = await response.json() as Record<string, any>;
10
+ if (json.isSuccess == true)
11
+ return json.token;
12
+ else
13
+ throw 'Unable to login to server. Check your dev key';
14
+ }
15
+
16
+ export async function getWebUrl(url: string, token: string) {
17
+ let response = await fetch(`${url}/admin/plugins/admin/settings`, {headers: {Authorization: token}});
18
+ let json = await response.json() as Record<string, any>;
19
+ return json.settings.webRoot;
20
+ }
21
+
22
+ const grokDir = path.join(os.homedir(), '.grok');
23
+ const confPath = path.join(grokDir, 'config.yaml');
24
+
25
+ function mapURL(conf: Config): Indexable {
26
+ let urls: Indexable = {};
27
+ for (let server in conf.servers) {
28
+ urls[conf['servers'][server]['url']] = conf['servers'][server];
29
+ }
30
+ return urls;
31
+ }
32
+
33
+ export function getDevKey(hostKey: string): {url: string, key: string} {
34
+ let config = yaml.load(fs.readFileSync(confPath, 'utf8')) as any;
35
+ let host = hostKey == '' ? config.default : hostKey;
36
+ host = host.trim();
37
+ let urls = mapURL(config);
38
+ let key = '';
39
+ let url = '';
40
+ try {
41
+ let url = new URL(host).href;
42
+ if (url.endsWith('/')) url = url.slice(0, -1);
43
+ if (url in urls) key = config['servers'][urls[url]]['key'];
44
+ } catch (error) {
45
+ if (config['servers'][host] == null)
46
+ throw `Unknown server alias. Please add it to ${confPath}`;
47
+ url = config['servers'][host]['url'];
48
+ key = config['servers'][host]['key'];
49
+ }
50
+ return {url, key};
51
+ }
52
+
53
+ export async function getBrowserPage(puppeteer: any): Promise<{browser: any, page: any}> {
54
+ let url:string = process.env.HOST ?? '';
55
+ let cfg = getDevKey(url);
56
+ url = cfg.url;
57
+
58
+ let key = cfg.key;
59
+ let token = await getToken(url, key);
60
+ url = await getWebUrl(url, token);
61
+ console.log(`Using web root: ${url}`);
62
+
63
+ let browser = await puppeteer.launch({
64
+ args: ['--disable-dev-shm-usage', '--disable-features=site-per-process'],
65
+ ignoreHTTPSErrors: true,
66
+ });
67
+
68
+ let page = await browser.newPage();
69
+ await page.goto(`${url}/oauth/`);
70
+ await page.setCookie({name: 'auth', value: token});
71
+ await page.evaluate((token: any) => {
72
+ window.localStorage.setItem('auth', token);
73
+ }, token);
74
+ await page.goto(url);
75
+ try {
76
+ await page.waitForSelector('.grok-preloader');
77
+ await page.waitForFunction(() => document.querySelector('.grok-preloader') == null, {timeout: 100000});
78
+ } catch (error) {
79
+ throw error;
80
+ }
81
+ return {browser, page};
82
+ }
83
+
84
+
85
+ interface Config {
86
+ servers: {
87
+ [alias: string]: {
88
+ url: string,
89
+ key: string
90
+ }
91
+ },
92
+ default: string,
93
+ }
94
+
95
+ interface Indexable { [key: string]: any }
@@ -0,0 +1,31 @@
1
+ export const jsonSdfMonomerLibDict = {
2
+ "monomerType": null,
3
+ "smiles": null,
4
+ "name": "MonomerName",
5
+ "author": null,
6
+ "molfile": "molecule",
7
+ "naturalAnalog": "MonomerNaturalAnalogCode",
8
+ "rgroups": "MonomerCaps",
9
+ "createDate": null,
10
+ "id": null,
11
+ "polymerType": "MonomerType",
12
+ "symbol": "MonomerCode"
13
+ }
14
+
15
+ export const MONOMER_MANAGER_MAP = {
16
+ 'id': 'symbol',
17
+ 'n': 'name',
18
+ 'na': 'naturalAnalog',
19
+ 'type': 'polymerType',
20
+ 'mt': 'monomerType',
21
+ 'm': 'molfile',
22
+ }
23
+
24
+ export const SMILES = 'smiles';
25
+ export const RGROUPS = "rgroups";
26
+ export const MONOMER_SYMBOL = "symbol";
27
+ export const RGROUP_CAP_GROUP_SMILES = "capGroupSmiles";
28
+ export const RGROUP_ALTER_ID = "alternateId";
29
+ export const RGROUP_CAP_GROUP_NAME = "capGroupName";
30
+ export const RGROUP_LABEL = "label";
31
+ export const SDF_MONOMER_NAME = "MonomerName";
package/src/package.ts CHANGED
@@ -5,29 +5,34 @@ import * as DG from 'datagrok-api/dg';
5
5
  //import {lru} from '../../Bio/src/utils/cell-renderer';
6
6
  import {NotationConverter, NOTATION} from '@datagrok-libraries/bio/src/utils/notation-converter';
7
7
  import {WebLogo} from '@datagrok-libraries/bio/src/viewers/web-logo';
8
+ import {createJsonMonomerLibFromSdf} from './utils';
9
+ import {MONOMER_MANAGER_MAP, RGROUPS, RGROUP_CAP_GROUP_NAME, RGROUP_LABEL, SMILES} from './constants';
8
10
  //import {ConverterFunc, DfReaderFunc} from '../../Bio/src/tests/types';
9
11
 
10
12
  export const _package = new DG.Package();
11
13
 
12
14
  const lru = new DG.LruCache<any, any>();
15
+ const STORAGE_NAME = 'Libraries';
16
+ let i = 0;
17
+ const LIB_PATH = 'libraries/';
13
18
 
14
19
 
15
20
  //tags: init
16
- export async function initChem(): Promise<void> {
17
- // apparently HELMWebEditor requires dojo to be initialized first
18
- return new Promise((resolve, reject) => {
19
- // @ts-ignore
20
- dojo.ready(function() { resolve(null); });
21
- });
21
+ export async function initHelm(): Promise<void> {
22
+ let grid = grok.shell.tv.grid;
23
+ for (let j = 0; j <= i; j++) {
24
+ await monomerManager(await grok.dapi.userDataStorage.getValue(STORAGE_NAME, j.toString(), true));
25
+ }
26
+ grid.invalidate();
22
27
  }
23
28
 
24
29
  //tags: cellEditor
25
30
  //description: Macromolecule
26
31
  //input: grid_cell cell
27
32
  export function editMoleculeCell(cell: DG.GridCell): void {
28
- const view = ui.div();
33
+ let view = ui.div();
29
34
  org.helm.webeditor.MolViewer.molscale = 0.8;
30
- const app = new scil.helm.App(view, {
35
+ let app = new scil.helm.App(view, {
31
36
  showabout: false,
32
37
  mexfontsize: '90%',
33
38
  mexrnapinontab: true,
@@ -37,9 +42,9 @@ export function editMoleculeCell(cell: DG.GridCell): void {
37
42
  mexfavoritefirst: true,
38
43
  mexfilter: true
39
44
  });
40
- const sizes = app.calculateSizes();
45
+ var sizes = app.calculateSizes();
41
46
  app.canvas.resize(sizes.rightwidth, sizes.topheight - 210);
42
- let s = {width: sizes.rightwidth + 'px', height: sizes.bottomheight + 'px'};
47
+ var s = {width: sizes.rightwidth + 'px', height: sizes.bottomheight + 'px'};
43
48
  //@ts-ignore
44
49
  scil.apply(app.sequence.style, s);
45
50
  //@ts-ignore
@@ -49,24 +54,30 @@ export function editMoleculeCell(cell: DG.GridCell): void {
49
54
  scil.apply(app.properties.parent.style, s);
50
55
  app.structureview.resize(sizes.rightwidth, sizes.bottomheight + app.toolbarheight);
51
56
  app.mex.resize(sizes.topheight - 80);
52
-
53
- let dialogValue: string;
54
57
  if (cell.gridColumn.column.tags[DG.TAGS.UNITS] === 'HELM') {
55
- dialogValue = cell.cell.value;
56
- } else {
57
- const converter: NotationConverter = new NotationConverter(cell.cell.column);
58
- dialogValue = converter.convertStringToHelm(cell.cell.value);
58
+ setTimeout(function() {
59
+ app.canvas.helm.setSequence(cell.cell.value, 'HELM');
60
+ }, 200);
61
+ //@ts-ignore
62
+ ui.dialog({showHeader: false, showFooter: true})
63
+ .add(view)
64
+ .onOK(() => {
65
+ const val = app.canvas.getHelm(true).replace(/<\/span>/g, '').replace(/<span style='background:#bbf;'>/g, '');
66
+ cell.cell.value = val;
67
+ }).show({modal: true, fullScreen: true});
68
+ } else if (cell.gridColumn.column.tags[DG.TAGS.UNITS] === 'fasta:SEQ:PT') {
69
+ const converter = new NotationConverter(cell.gridColumn.column);
70
+ const resStr = converter.convertStringToHelm(cell.cell.value, '-');
71
+ setTimeout(function() {
72
+ app.canvas.helm.setSequence(resStr, 'HELM');
73
+ }, 200);
74
+ //@ts-ignore
75
+ ui.dialog({showHeader: false, showFooter: true})
76
+ .add(view)
77
+ .onOK(() => {
78
+ cell.cell.value;
79
+ }).show({modal: true, fullScreen: true});
59
80
  }
60
-
61
- setTimeout(function() {
62
- app.canvas.helm.setSequence(dialogValue, 'HELM');
63
- }, 200);
64
- //@ts-ignore
65
- ui.dialog({showHeader: false, showFooter: true})
66
- .add(view)
67
- .onOK(() => {
68
- cell.cell.value;
69
- }).show({modal: true, fullScreen: true});
70
81
  }
71
82
 
72
83
  //name: Details
@@ -93,29 +104,43 @@ export function detailsPanel(helmString: string) {
93
104
 
94
105
  async function loadDialog() {
95
106
  //@ts-ignore
96
- let res = await grok.dapi.files.list('System:AppData/Helm', false, '');
107
+ let res = await grok.dapi.files.list('System:AppData/Helm/libraries', false, '');
97
108
  //@ts-ignore
98
109
  res = res.map((e) => e.path);
99
110
  //@ts-ignore
100
- const FilesList = await ui.choiceInput('Monomer Libraries', ' ', res);
101
- const grid = grok.shell.tv.grid;
111
+ let FilesList = await ui.choiceInput('Monomer Libraries', ' ', res);
112
+ let grid = grok.shell.tv.grid;
102
113
  ui.dialog('Load library from file')
103
114
  .add(FilesList)
104
115
  .onOK(async () => {
105
116
  await monomerManager(FilesList.value);
117
+ grok.dapi.userDataStorage.postValue(STORAGE_NAME, i.toString(), FilesList.value, true);
118
+ i += 1;
106
119
  grid.invalidate();
107
120
  }).show();
108
121
  };
109
122
 
110
- //name: Library
123
+ //name: Manage Libraries
111
124
  //tags: panel, widgets
112
- //input: string helmString {semType: Macromolecule}
125
+ //input: column helmColumn {semType: Macromolecule}
113
126
  //output: widget result
114
- export function libraryPanel(helmString: string) {
127
+ export async function libraryPanel(helmColumn: DG.Column) {
115
128
  //@ts-ignore
116
- const loadButton = ui.button('Load Library');
129
+ let loadButton = ui.button('Load Library');
117
130
  loadButton.addEventListener('click', loadDialog);
118
- return new DG.Widget(ui.divH([loadButton]));
131
+ let list = (await grok.dapi.files.list('System:AppData/Helm/libraries', false, '')).toString().split(',');
132
+ let usedLibraries = [];
133
+ for (let j = 0; j <= i; j++) {
134
+ usedLibraries.push(await grok.dapi.userDataStorage.getValue(STORAGE_NAME, j.toString(), true));
135
+ }
136
+ let unusedLibraries = list.filter(x => !usedLibraries.includes(x));
137
+ return new DG.Widget(
138
+ ui.tableFromMap({
139
+ 'Uploaded libraries': ui.divText(usedLibraries.toString()),
140
+ 'Not used libraries': ui.divText(unusedLibraries.toString()),
141
+ 'Upload new library': ui.divH([loadButton]),
142
+ })
143
+ );
119
144
  }
120
145
 
121
146
  async function accessServer(url: string, key: string) {
@@ -190,22 +215,36 @@ function getRS(smiles: string) {
190
215
  }
191
216
 
192
217
  async function monomerManager(value: string) {
193
- const file = await _package.files.readAsText(value.split('/')[1]);
194
- const df = DG.DataFrame.fromJson(file);
195
- let m;
196
- for (let i = 0; i < df.rowCount; i++) {
197
- m = {
198
- 'id': df.get('symbol', i).toString(),
199
- 'n': df.get('name', i).toString(),
200
- 'na': df.get('naturalAnalog', i).toString(),
201
- 'type': df.get('polymerType', i).toString(),
202
- 'mt': df.get('monomerType', i).toString(),
203
- 'm': df.get('molfile', i).toString(),
204
- 'rs': Object.keys(getRS(df.get('smiles', i).toString())).length,
205
- 'at': getRS(df.get('smiles', i).toString()),
206
- };
207
- org.helm.webeditor.Monomers.addOneMonomer(m);
218
+ let df: any[];
219
+ const libName = value.substring(value.lastIndexOf('/') + 1);
220
+ if (value.endsWith('.sdf')) {
221
+ const file = await _package.files.readAsBytes(`${LIB_PATH}${libName}`);
222
+ const dfSdf = await grok.functions.call('Chem:importSdf', {bytes: file});
223
+ df = createJsonMonomerLibFromSdf(dfSdf[0]);
224
+
225
+ } else {
226
+ const file = await _package.files.readAsText(`${LIB_PATH}${libName}`);
227
+ df = JSON.parse(file);
208
228
  }
229
+
230
+ df.forEach(monomer => {
231
+ const m = {};
232
+ Object.keys(MONOMER_MANAGER_MAP).forEach(field => {
233
+ m[field] = monomer[MONOMER_MANAGER_MAP[field]] ?? '';
234
+ });
235
+ if (monomer[RGROUPS]) {
236
+ m['rs'] = monomer[RGROUPS].length;
237
+ const at = {};
238
+ monomer[RGROUPS].forEach(it => {
239
+ at[it[RGROUP_LABEL]] = it[RGROUP_CAP_GROUP_NAME];
240
+ });
241
+ m['at'] = at;
242
+ } else {
243
+ m['rs'] = Object.keys(getRS(df[SMILES].toString())).length;
244
+ m['at'] = getRS(df[SMILES].toString());
245
+ }
246
+ org.helm.webeditor.Monomers.addOneMonomer(m);
247
+ });
209
248
  }
210
249
 
211
250
  //name: helmColumnToSmiles
@@ -214,9 +253,6 @@ export function helmColumnToSmiles(helmColumn: DG.Column) {
214
253
  //todo: add column with smiles to col.dataFrame.
215
254
  }
216
255
 
217
- // Synonym to overcome eslint error
218
- const GetMonomerSet = scil.helm.Monomers.getMonomerSet;
219
-
220
256
  //name: findMonomers
221
257
  //input: string helmString { semType: Macromolecule }
222
258
  export async function findMonomers(helmString: string) {
@@ -224,6 +260,8 @@ export async function findMonomers(helmString: string) {
224
260
  const monomers = [];
225
261
  const monomerNames = [];
226
262
  for (let i = 0; i < types.length; i++) {
263
+ // Synonym to overcome eslint error
264
+ const GetMonomerSet = scil.helm.Monomers.getMonomerSet;
227
265
  monomers.push(new GetMonomerSet(types[i]));
228
266
  Object.keys(monomers[i]).forEach((k) => {
229
267
  monomerNames.push(monomers[i][k].id);
@@ -6,28 +6,30 @@ import * as grok from 'datagrok-api/grok';
6
6
 
7
7
 
8
8
  category('Helm', () => {
9
- test('helmToFasta', async () => {
10
- expect(await helmToFasta('RNA1{R(U)P.R(T)P.R(G)P.R(C)P.R(A)}$$$$'), '>RNA1UTGCA');
11
- expect(await helmToFasta('RNA1{P.R(U).P.R(T)}$$$$'), '>RNA1UT');
12
- expect(await helmToFasta('PEPTIDE1{A.G}$$$$V2.0'), '>PEPTIDE1AG');
13
- });
14
-
15
- test('helmToRNA', async () => {
16
- expect(await helmToRNA('RNA1{R(U)P.R(T)P.R(G)P.R(C)P.R(A)}$$$$'), 'UTGCA');
17
- expect(await helmToRNA('RNA1{P.R(U).P.R(T)}$$$$'), 'UT');
18
- // eslint-disable-next-line max-len
19
- expect(await helmToRNA('RNA1{R(U)P.R(T)P}|RNA2{P.R(A)P.R(A)}$RNA1,RNA2,2:pair-6:pair|RNA1,RNA2,5:pair-3:pair$$$'), 'UT AA');
20
- });
21
9
 
22
- test('helmToPeptide', async () => {
23
- expect(await helmToPeptide('PEPTIDE1{A.G}$$$$V2.0'), 'AG');
24
- expect(await helmToPeptide('PEPTIDE1{L.V.A}|PEPTIDE2{L.V.A}$$$$'), 'LVA LVA');
25
- // eslint-disable-next-line max-len
26
- expect(await helmToPeptide('PEPTIDE1{A.R.C.A.A.K.T.C.D.A}$PEPTIDE1,PEPTIDE1,8:R3-3:R3$$$'), 'ARCAAKTCDA');
27
- });
10
+ // These tests require webservice that is not present on test stand
11
+ // test('helmToFasta', async () => {
12
+ // expect(await helmToFasta('RNA1{R(U)P.R(T)P.R(G)P.R(C)P.R(A)}$$$$'), '>RNA1UTGCA');
13
+ // expect(await helmToFasta('RNA1{P.R(U).P.R(T)}$$$$'), '>RNA1UT');
14
+ // expect(await helmToFasta('PEPTIDE1{A.G}$$$$V2.0'), '>PEPTIDE1AG');
15
+ // });
16
+ //
17
+ // test('helmToRNA', async () => {
18
+ // expect(await helmToRNA('RNA1{R(U)P.R(T)P.R(G)P.R(C)P.R(A)}$$$$'), 'UTGCA');
19
+ // expect(await helmToRNA('RNA1{P.R(U).P.R(T)}$$$$'), 'UT');
20
+ // // eslint-disable-next-line max-len
21
+ // expect(await helmToRNA('RNA1{R(U)P.R(T)P}|RNA2{P.R(A)P.R(A)}$RNA1,RNA2,2:pair-6:pair|RNA1,RNA2,5:pair-3:pair$$$'), 'UT AA');
22
+ // });
23
+ //
24
+ // test('helmToPeptide', async () => {
25
+ // expect(await helmToPeptide('PEPTIDE1{A.G}$$$$V2.0'), 'AG');
26
+ // expect(await helmToPeptide('PEPTIDE1{L.V.A}|PEPTIDE2{L.V.A}$$$$'), 'LVA LVA');
27
+ // // eslint-disable-next-line max-len
28
+ // expect(await helmToPeptide('PEPTIDE1{A.R.C.A.A.K.T.C.D.A}$PEPTIDE1,PEPTIDE1,8:R3-3:R3$$$'), 'ARCAAKTCDA');
29
+ // });
28
30
 
29
31
  test('detectMacromolecule', async () => {
30
- const file = await _package.files.readAsText('test.csv');
32
+ const file = await _package.files.readAsText('tests/test.csv');
31
33
  const df = DG.DataFrame.fromCsv(file);
32
34
  const col = df.columns.byName('HELM string');
33
35
  await grok.data.detectSemanticTypes(df);
@@ -35,7 +37,7 @@ category('Helm', () => {
35
37
  });
36
38
 
37
39
  test('detectHelm', async () => {
38
- const file = await _package.files.readAsText('test.csv');
40
+ const file = await _package.files.readAsText('tests/test.csv');
39
41
  const df = DG.DataFrame.fromCsv(file);
40
42
  const col = df.columns.byName('HELM string');
41
43
  await grok.data.detectSemanticTypes(df);
package/src/utils.ts ADDED
@@ -0,0 +1,35 @@
1
+ import * as DG from 'datagrok-api/dg';
2
+ import { RGROUP_CAP_GROUP_NAME, RGROUP_CAP_GROUP_SMILES, jsonSdfMonomerLibDict, MONOMER_SYMBOL, RGROUP_ALTER_ID, RGROUPS, RGROUP_LABEL, SDF_MONOMER_NAME } from "./constants";
3
+
4
+ export function createJsonMonomerLibFromSdf(table: DG.DataFrame): any {
5
+ const resultLib = [];
6
+ for (let i = 0; i < table.rowCount; i++) {
7
+ const monomer: { [key: string]: string | any } = {};
8
+ Object.keys(jsonSdfMonomerLibDict).forEach(key => {
9
+ if (key === MONOMER_SYMBOL) {
10
+ const monomerSymbol = table.get(jsonSdfMonomerLibDict[key], i);
11
+ monomer[key] = monomerSymbol === '.' ? table.get(SDF_MONOMER_NAME, i) : monomerSymbol;
12
+ } else if (key === RGROUPS) {
13
+ const rgroups = table.get(jsonSdfMonomerLibDict[key], i).split('\n');
14
+ const jsonRgroups: any[] = [];
15
+ rgroups.forEach((g: string) => {
16
+ const rgroup: { [key: string]: string | any } = {};
17
+ const altAtom = g.substring(g.lastIndexOf("]") + 1);
18
+ let radicalNum = g.match(/\[R(\d+)\]/)![1];
19
+ rgroup[RGROUP_CAP_GROUP_SMILES] = altAtom === 'H' ? `[*:${radicalNum}][H]` : `O[*:${radicalNum}]`;
20
+ rgroup[RGROUP_ALTER_ID] = altAtom === 'H' ? `R${radicalNum}-H` : `R${radicalNum}-OH`;
21
+ rgroup[RGROUP_CAP_GROUP_NAME] = altAtom === 'H' ? `H` : `OH`;
22
+ rgroup[RGROUP_LABEL] = `R${radicalNum}`;
23
+ jsonRgroups.push(rgroup);
24
+ })
25
+ monomer[key] = jsonRgroups;
26
+ } else {
27
+ if((jsonSdfMonomerLibDict as { [key: string]: string | any })[key]) {
28
+ monomer[key] = table.get((jsonSdfMonomerLibDict as { [key: string]: string | any })[key], i);
29
+ }
30
+ }
31
+ })
32
+ resultLib.push(monomer);
33
+ }
34
+ return resultLib;
35
+ }
@@ -0,0 +1,251 @@
1
+ <html><head><meta charset="utf-8"/><title>Helm Test Report. Datagrok version datagrok/datagrok:latest SHA=34f75e5127b8. Commit 7d82c3f3.</title><style type="text/css">html,
2
+ body {
3
+ font-family: Arial, Helvetica, sans-serif;
4
+ font-size: 1rem;
5
+ margin: 0;
6
+ padding: 0;
7
+ color: #333;
8
+ }
9
+ body {
10
+ padding: 2rem 1rem;
11
+ font-size: 0.85rem;
12
+ }
13
+ #jesthtml-content {
14
+ margin: 0 auto;
15
+ max-width: 70rem;
16
+ }
17
+ header {
18
+ display: flex;
19
+ align-items: center;
20
+ }
21
+ #title {
22
+ margin: 0;
23
+ flex-grow: 1;
24
+ }
25
+ #logo {
26
+ height: 4rem;
27
+ }
28
+ #timestamp {
29
+ color: #777;
30
+ margin-top: 0.5rem;
31
+ }
32
+
33
+ /** SUMMARY */
34
+ #summary {
35
+ color: #333;
36
+ margin: 2rem 0;
37
+ display: flex;
38
+ font-family: monospace;
39
+ font-size: 1rem;
40
+ }
41
+ #summary > div {
42
+ margin-right: 2rem;
43
+ background: #eee;
44
+ padding: 1rem;
45
+ min-width: 15rem;
46
+ }
47
+ #summary > div:last-child {
48
+ margin-right: 0;
49
+ }
50
+ @media only screen and (max-width: 720px) {
51
+ #summary {
52
+ flex-direction: column;
53
+ }
54
+ #summary > div {
55
+ margin-right: 0;
56
+ margin-top: 2rem;
57
+ }
58
+ #summary > div:first-child {
59
+ margin-top: 0;
60
+ }
61
+ }
62
+
63
+ .summary-total {
64
+ font-weight: bold;
65
+ margin-bottom: 0.5rem;
66
+ }
67
+ .summary-passed {
68
+ color: #4f8a10;
69
+ border-left: 0.4rem solid #4f8a10;
70
+ padding-left: 0.5rem;
71
+ }
72
+ .summary-failed,
73
+ .summary-obsolete-snapshots {
74
+ color: #d8000c;
75
+ border-left: 0.4rem solid #d8000c;
76
+ padding-left: 0.5rem;
77
+ }
78
+ .summary-pending {
79
+ color: #9f6000;
80
+ border-left: 0.4rem solid #9f6000;
81
+ padding-left: 0.5rem;
82
+ }
83
+ .summary-empty {
84
+ color: #999;
85
+ border-left: 0.4rem solid #999;
86
+ }
87
+
88
+ .test-result {
89
+ padding: 1rem;
90
+ margin-bottom: 0.25rem;
91
+ }
92
+ .test-result:last-child {
93
+ border: 0;
94
+ }
95
+ .test-result.passed {
96
+ background-color: #dff2bf;
97
+ color: #4f8a10;
98
+ }
99
+ .test-result.failed {
100
+ background-color: #ffbaba;
101
+ color: #d8000c;
102
+ }
103
+ .test-result.pending {
104
+ background-color: #ffdf61;
105
+ color: #9f6000;
106
+ }
107
+
108
+ .test-info {
109
+ display: flex;
110
+ justify-content: space-between;
111
+ }
112
+ .test-suitename {
113
+ width: 20%;
114
+ text-align: left;
115
+ font-weight: bold;
116
+ word-break: break-word;
117
+ }
118
+ .test-title {
119
+ width: 40%;
120
+ text-align: left;
121
+ font-style: italic;
122
+ }
123
+ .test-status {
124
+ width: 20%;
125
+ text-align: right;
126
+ }
127
+ .test-duration {
128
+ width: 10%;
129
+ text-align: right;
130
+ font-size: 0.75rem;
131
+ }
132
+
133
+ .failureMessages {
134
+ padding: 0 1rem;
135
+ margin-top: 1rem;
136
+ border-top: 1px dashed #d8000c;
137
+ }
138
+ .failureMessages.suiteFailure {
139
+ border-top: none;
140
+ }
141
+ .failureMsg {
142
+ white-space: pre-wrap;
143
+ white-space: -moz-pre-wrap;
144
+ white-space: -pre-wrap;
145
+ white-space: -o-pre-wrap;
146
+ word-wrap: break-word;
147
+ }
148
+
149
+ .suite-container {
150
+ margin-bottom: 2rem;
151
+ }
152
+ .suite-info {
153
+ padding: 1rem;
154
+ background-color: #eee;
155
+ color: #777;
156
+ display: flex;
157
+ align-items: center;
158
+ margin-bottom: 0.25rem;
159
+ }
160
+ .suite-info .suite-path {
161
+ word-break: break-all;
162
+ flex-grow: 1;
163
+ font-family: monospace;
164
+ font-size: 1rem;
165
+ }
166
+ .suite-info .suite-time {
167
+ margin-left: 0.5rem;
168
+ padding: 0.2rem 0.3rem;
169
+ font-size: 0.75rem;
170
+ }
171
+ .suite-info .suite-time.warn {
172
+ background-color: #d8000c;
173
+ color: #fff;
174
+ }
175
+
176
+ /* CONSOLE LOGS */
177
+ .suite-consolelog {
178
+ margin-bottom: 0.25rem;
179
+ padding: 1rem;
180
+ background-color: #efefef;
181
+ }
182
+ .suite-consolelog-header {
183
+ font-weight: bold;
184
+ }
185
+ .suite-consolelog-item {
186
+ padding: 0.5rem;
187
+ }
188
+ .suite-consolelog-item pre {
189
+ margin: 0.5rem 0;
190
+ white-space: pre-wrap;
191
+ white-space: -moz-pre-wrap;
192
+ white-space: -pre-wrap;
193
+ white-space: -o-pre-wrap;
194
+ word-wrap: break-word;
195
+ }
196
+ .suite-consolelog-item-origin {
197
+ color: #777;
198
+ font-weight: bold;
199
+ }
200
+ .suite-consolelog-item-message {
201
+ color: #000;
202
+ font-size: 1rem;
203
+ padding: 0 0.5rem;
204
+ }
205
+
206
+ /* OBSOLETE SNAPSHOTS */
207
+ .suite-obsolete-snapshots {
208
+ margin-bottom: 0.25rem;
209
+ padding: 1rem;
210
+ background-color: #ffbaba;
211
+ color: #d8000c;
212
+ }
213
+ .suite-obsolete-snapshots-header {
214
+ font-weight: bold;
215
+ }
216
+ .suite-obsolete-snapshots-item {
217
+ padding: 0.5rem;
218
+ }
219
+ .suite-obsolete-snapshots-item pre {
220
+ margin: 0.5rem 0;
221
+ white-space: pre-wrap;
222
+ white-space: -moz-pre-wrap;
223
+ white-space: -pre-wrap;
224
+ white-space: -o-pre-wrap;
225
+ word-wrap: break-word;
226
+ }
227
+ .suite-obsolete-snapshots-item-message {
228
+ color: #000;
229
+ font-size: 1rem;
230
+ padding: 0 0.5rem;
231
+ }
232
+ </style></head><body><div id="jesthtml-content"><header><h1 id="title">Helm Test Report. Datagrok version datagrok/datagrok:latest SHA=34f75e5127b8. Commit 7d82c3f3.</h1></header><div id="metadata-container"><div id="timestamp">Started: 2022-07-15 17:15:38</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/Helm/src/__jest__/remote.test.ts</div><div class="suite-time warn">14.146s</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">1.721s</div></div><div class="failureMessages"> <pre class="failureMsg">Error: Test result : Helm.Helm.detectMacromolecule : Error: Expected "Macromolecule", got "null"
233
+ Test result : Helm.Helm.detectHelm : Error: Expected "HELM", got "null"
234
+
235
+ at /home/runner/work/public/public/packages/Helm/src/__jest__/remote.test.ts:67:20
236
+ at Generator.next (&lt;anonymous&gt;)
237
+ at fulfilled (/home/runner/work/public/public/packages/Helm/src/__jest__/remote.test.ts:31:58)
238
+ at processTicksAndRejections (internal/process/task_queues.js:97:5)</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/Helm/src/__jest__/test-node.ts:61:11)
239
+ at Generator.next (&lt;anonymous&gt;)
240
+ at fulfilled (/home/runner/work/public/public/packages/Helm/src/__jest__/test-node.ts:28:58)
241
+ at processTicksAndRejections (internal/process/task_queues.js:97:5)</pre><pre class="suite-consolelog-item-message">Using web root: http://localhost:8080</pre></div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at /home/runner/work/public/public/packages/Helm/src/__jest__/remote.test.ts:40:11
242
+ at Generator.next (&lt;anonymous&gt;)
243
+ at /home/runner/work/public/public/packages/Helm/src/__jest__/remote.test.ts:34:71
244
+ at new Promise (&lt;anonymous&gt;)
245
+ at Object.&lt;anonymous&gt;.__awaiter (/home/runner/work/public/public/packages/Helm/src/__jest__/remote.test.ts:30:12)
246
+ at Object.&lt;anonymous&gt; (/home/runner/work/public/public/packages/Helm/src/__jest__/remote.test.ts:38:23)
247
+ at Promise.then.completed (/home/runner/work/public/public/packages/Helm/node_modules/jest-circus/build/utils.js:391:28)
248
+ at new Promise (&lt;anonymous&gt;)</pre><pre class="suite-consolelog-item-message">Testing Helm package</pre></div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at /home/runner/work/public/public/packages/Helm/src/__jest__/remote.test.ts:65:11
249
+ at Generator.next (&lt;anonymous&gt;)
250
+ at fulfilled (/home/runner/work/public/public/packages/Helm/src/__jest__/remote.test.ts:31:58)
251
+ at processTicksAndRejections (internal/process/task_queues.js:97:5)</pre><pre class="suite-consolelog-item-message"/></div></div></div></div></body></html>