@datagrok/helm 1.0.0 → 1.0.3
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/.eslintignore +2 -0
- package/.eslintrc.json +51 -0
- package/files/{samples → tests}/test-set-1.csv +0 -0
- package/files/{samples → tests}/test.csv +5 -5
- package/jest.config.js +34 -0
- package/package.json +27 -6
- package/src/__jest__/remote.test.ts +68 -0
- package/src/__jest__/test-node.ts +95 -0
- package/src/constants.ts +31 -0
- package/src/package-test.ts +3 -3
- package/src/package.ts +146 -75
- package/src/tests/helm-tests.ts +27 -24
- package/src/utils.ts +35 -0
- package/test-Helm-34f75e5127b8-f7696845.html +251 -0
- package/webpack.config.js +10 -1
package/.eslintignore
ADDED
package/.eslintrc.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"env": {
|
|
3
|
+
"browser": true,
|
|
4
|
+
"es2021": true
|
|
5
|
+
},
|
|
6
|
+
"extends": [
|
|
7
|
+
"google"
|
|
8
|
+
],
|
|
9
|
+
"parser": "@typescript-eslint/parser",
|
|
10
|
+
"parserOptions": {
|
|
11
|
+
"ecmaVersion": 12,
|
|
12
|
+
"sourceType": "module"
|
|
13
|
+
},
|
|
14
|
+
"plugins": [
|
|
15
|
+
"@typescript-eslint"
|
|
16
|
+
],
|
|
17
|
+
"rules": {
|
|
18
|
+
"indent": [
|
|
19
|
+
"error",
|
|
20
|
+
2
|
|
21
|
+
],
|
|
22
|
+
"max-len": [
|
|
23
|
+
"error",
|
|
24
|
+
120
|
|
25
|
+
],
|
|
26
|
+
"no-unused-vars": "warn",
|
|
27
|
+
"require-jsdoc": "off",
|
|
28
|
+
"spaced-comment": "off",
|
|
29
|
+
"linebreak-style": "off",
|
|
30
|
+
"curly": [
|
|
31
|
+
"error",
|
|
32
|
+
"multi-or-nest",
|
|
33
|
+
"consistent"
|
|
34
|
+
],
|
|
35
|
+
"brace-style": [
|
|
36
|
+
"error",
|
|
37
|
+
"1tbs",
|
|
38
|
+
{
|
|
39
|
+
"allowSingleLine": true
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"block-spacing": [2, "always"],
|
|
43
|
+
"comma-dangle": ["error", {
|
|
44
|
+
"arrays": "only-multiline",
|
|
45
|
+
"functions": "never",
|
|
46
|
+
"objects": "only-multiline",
|
|
47
|
+
"imports": "only-multiline"
|
|
48
|
+
}],
|
|
49
|
+
"guard-for-in": "off"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
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,13 +2,16 @@
|
|
|
2
2
|
"name": "@datagrok/helm",
|
|
3
3
|
"beta": false,
|
|
4
4
|
"friendlyName": "Helm",
|
|
5
|
-
"version": "1.0.
|
|
5
|
+
"version": "1.0.3",
|
|
6
6
|
"description": "",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"datagrok-api": "^1.4.12",
|
|
9
9
|
"cash-dom": "latest",
|
|
10
10
|
"dayjs": "latest",
|
|
11
|
-
"@datagrok-libraries/utils": "latest
|
|
11
|
+
"@datagrok-libraries/utils": "latest",
|
|
12
|
+
"@datagrok-libraries/bio": "^2.8.3",
|
|
13
|
+
"ts-loader": "^9.2.5",
|
|
14
|
+
"typescript": "^4.4.2"
|
|
12
15
|
},
|
|
13
16
|
"sources": [
|
|
14
17
|
"css/helm.css",
|
|
@@ -18,21 +21,39 @@
|
|
|
18
21
|
"helm/JSDraw/Pistoia.HELM-uncompressed.js"
|
|
19
22
|
],
|
|
20
23
|
"devDependencies": {
|
|
24
|
+
"@typescript-eslint/eslint-plugin": "latest",
|
|
25
|
+
"@typescript-eslint/parser": "latest",
|
|
26
|
+
"eslint": "latest",
|
|
27
|
+
"eslint-config-google": "latest",
|
|
28
|
+
"ts-loader": "latest",
|
|
29
|
+
"typescript": "latest",
|
|
21
30
|
"webpack": "latest",
|
|
22
31
|
"webpack-cli": "latest",
|
|
23
|
-
"
|
|
24
|
-
"
|
|
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"
|
|
25
39
|
},
|
|
26
40
|
"scripts": {
|
|
27
|
-
"link-all": "npm link datagrok-api @datagrok-libraries/utils",
|
|
41
|
+
"link-all": "npm link datagrok-api @datagrok-libraries/utils @datagrok-libraries/bio",
|
|
28
42
|
"debug-helm": "webpack && grok publish ",
|
|
29
43
|
"release-helm": "webpack && grok publish --release",
|
|
30
44
|
"build-helm": "webpack",
|
|
31
45
|
"build": "webpack",
|
|
46
|
+
"debug-local": "grok publish local",
|
|
47
|
+
"release-local": "grok publish local --release",
|
|
32
48
|
"debug-helm-dev": "grok publish dev --rebuild",
|
|
33
49
|
"release-helm-dev": "grok publish dev --rebuild --release",
|
|
34
50
|
"debug-helm-public": "grok publish public --rebuild",
|
|
35
|
-
"release-helm-public": "grok publish public --rebuild --release"
|
|
51
|
+
"release-helm-public": "grok publish public --rebuild --release",
|
|
52
|
+
"lint": "eslint \"./src/**/*.ts\"",
|
|
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"
|
|
36
57
|
},
|
|
37
58
|
"canEdit": [
|
|
38
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 }
|
package/src/constants.ts
ADDED
|
@@ -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-test.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import * as DG from
|
|
2
|
-
import * as grok from
|
|
1
|
+
import * as DG from 'datagrok-api/dg';
|
|
2
|
+
import * as grok from 'datagrok-api/grok';
|
|
3
3
|
import {runTests, tests} from '@datagrok-libraries/utils/src/test';
|
|
4
|
-
import './tests/helm-tests.ts'
|
|
4
|
+
import './tests/helm-tests.ts';
|
|
5
5
|
|
|
6
6
|
export const _package = new DG.Package();
|
|
7
7
|
export {tests};
|
package/src/package.ts
CHANGED
|
@@ -2,17 +2,27 @@
|
|
|
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 {lru} from '../../Bio/src/utils/cell-renderer';
|
|
6
|
+
import {NotationConverter, NOTATION} from '@datagrok-libraries/bio/src/utils/notation-converter';
|
|
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';
|
|
10
|
+
//import {ConverterFunc, DfReaderFunc} from '../../Bio/src/tests/types';
|
|
5
11
|
|
|
6
12
|
export const _package = new DG.Package();
|
|
7
13
|
|
|
8
|
-
const lru = new DG.LruCache<any, any>();
|
|
14
|
+
const lru = new DG.LruCache<any, any>();
|
|
15
|
+
const STORAGE_NAME = 'Libraries';
|
|
16
|
+
let i = 0;
|
|
17
|
+
const LIB_PATH = 'libraries/';
|
|
18
|
+
|
|
9
19
|
|
|
10
20
|
//tags: init
|
|
11
21
|
export async function initChem(): Promise<void> {
|
|
12
22
|
// apparently HELMWebEditor requires dojo to be initialized first
|
|
13
23
|
return new Promise((resolve, reject) => {
|
|
14
24
|
// @ts-ignore
|
|
15
|
-
dojo.ready(function
|
|
25
|
+
dojo.ready(function() { resolve(null); });
|
|
16
26
|
});
|
|
17
27
|
}
|
|
18
28
|
|
|
@@ -22,78 +32,120 @@ export async function initChem(): Promise<void> {
|
|
|
22
32
|
export function editMoleculeCell(cell: DG.GridCell): void {
|
|
23
33
|
let view = ui.div();
|
|
24
34
|
org.helm.webeditor.MolViewer.molscale = 0.8;
|
|
25
|
-
let app = new scil.helm.App(view, {
|
|
35
|
+
let app = new scil.helm.App(view, {
|
|
36
|
+
showabout: false,
|
|
37
|
+
mexfontsize: '90%',
|
|
38
|
+
mexrnapinontab: true,
|
|
39
|
+
topmargin: 20,
|
|
40
|
+
mexmonomerstab: true,
|
|
41
|
+
sequenceviewonly: false,
|
|
42
|
+
mexfavoritefirst: true,
|
|
43
|
+
mexfilter: true
|
|
44
|
+
});
|
|
26
45
|
var sizes = app.calculateSizes();
|
|
27
46
|
app.canvas.resize(sizes.rightwidth, sizes.topheight - 210);
|
|
28
|
-
var s = {
|
|
47
|
+
var s = {width: sizes.rightwidth + 'px', height: sizes.bottomheight + 'px'};
|
|
29
48
|
//@ts-ignore
|
|
30
49
|
scil.apply(app.sequence.style, s);
|
|
31
50
|
//@ts-ignore
|
|
32
51
|
scil.apply(app.notation.style, s);
|
|
33
|
-
s = {
|
|
52
|
+
s = {width: sizes.rightwidth + 'px', height: (sizes.bottomheight + app.toolbarheight) + 'px'};
|
|
34
53
|
//@ts-ignore
|
|
35
54
|
scil.apply(app.properties.parent.style, s);
|
|
36
55
|
app.structureview.resize(sizes.rightwidth, sizes.bottomheight + app.toolbarheight);
|
|
37
56
|
app.mex.resize(sizes.topheight - 80);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
57
|
+
if (cell.gridColumn.column.tags[DG.TAGS.UNITS] === 'HELM') {
|
|
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});
|
|
80
|
+
}
|
|
47
81
|
}
|
|
48
82
|
|
|
49
83
|
//name: Details
|
|
50
84
|
//tags: panel, widgets
|
|
51
85
|
//input: string helmString {semType: Macromolecule}
|
|
52
86
|
//output: widget result
|
|
53
|
-
export function detailsPanel(helmString: string){
|
|
87
|
+
export function detailsPanel(helmString: string) {
|
|
54
88
|
//return new DG.Widget(ui.divText(lru.get(helmString)));
|
|
55
|
-
|
|
89
|
+
const result = lru.get(helmString).split(',');
|
|
56
90
|
return new DG.Widget(
|
|
57
91
|
ui.tableFromMap({
|
|
58
92
|
'formula': result[0].replace(/<sub>/g, '').replace(/<\/sub>/g, ''),
|
|
59
93
|
'molecular weight': result[1],
|
|
60
94
|
'extinction coefficient': result[2],
|
|
61
95
|
'molfile': result[3],
|
|
62
|
-
|
|
96
|
+
'fasta': ui.wait(async () => ui.divText(await helmToFasta(helmString))),
|
|
63
97
|
'rna analogue sequence': ui.wait(async () => ui.divText(await helmToRNA(helmString))),
|
|
64
98
|
'smiles': ui.wait(async () => ui.divText(await helmToSmiles(helmString))),
|
|
65
|
-
'peptide analogue sequence': ui.wait(async () => ui.divText(await helmToPeptide(helmString)))
|
|
99
|
+
//'peptide analogue sequence': ui.wait(async () => ui.divText(await helmToPeptide(helmString))),
|
|
66
100
|
})
|
|
67
|
-
)
|
|
101
|
+
);
|
|
68
102
|
}
|
|
69
103
|
|
|
70
104
|
|
|
71
|
-
async function loadDialog
|
|
105
|
+
async function loadDialog() {
|
|
72
106
|
//@ts-ignore
|
|
73
|
-
let res = await grok.dapi.files.list('System:AppData/Helm', false, '');
|
|
107
|
+
let res = await grok.dapi.files.list('System:AppData/Helm/libraries', false, '');
|
|
74
108
|
//@ts-ignore
|
|
75
109
|
res = res.map((e) => e.path);
|
|
76
110
|
//@ts-ignore
|
|
77
111
|
let FilesList = await ui.choiceInput('Monomer Libraries', ' ', res);
|
|
112
|
+
let grid = grok.shell.tv.grid;
|
|
78
113
|
ui.dialog('Load library from file')
|
|
79
|
-
|
|
80
|
-
|
|
114
|
+
.add(FilesList)
|
|
115
|
+
.onOK(async () => {
|
|
116
|
+
await monomerManager(FilesList.value);
|
|
117
|
+
grok.dapi.userDataStorage.postValue(STORAGE_NAME, i.toString(), FilesList.value, true);
|
|
118
|
+
i += 1;
|
|
119
|
+
grid.invalidate();
|
|
120
|
+
}).show();
|
|
81
121
|
};
|
|
82
122
|
|
|
83
|
-
//name:
|
|
123
|
+
//name: Manage Libraries
|
|
84
124
|
//tags: panel, widgets
|
|
85
|
-
//input:
|
|
125
|
+
//input: column helmColumn {semType: Macromolecule}
|
|
86
126
|
//output: widget result
|
|
87
|
-
export function libraryPanel(
|
|
127
|
+
export async function libraryPanel(helmColumn: DG.Column) {
|
|
88
128
|
//@ts-ignore
|
|
89
129
|
let loadButton = ui.button('Load Library');
|
|
90
130
|
loadButton.addEventListener('click', loadDialog);
|
|
91
|
-
|
|
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
|
+
);
|
|
92
144
|
}
|
|
93
145
|
|
|
94
146
|
async function accessServer(url: string, key: string) {
|
|
95
147
|
const params: RequestInit = {
|
|
96
|
-
method: 'GET',
|
|
148
|
+
method: 'GET',
|
|
97
149
|
headers: {
|
|
98
150
|
'Accept': 'application/json',
|
|
99
151
|
}
|
|
@@ -108,7 +160,7 @@ async function accessServer(url: string, key: string) {
|
|
|
108
160
|
//input: string helmString {semType: Macromolecule}
|
|
109
161
|
//output: string res
|
|
110
162
|
export async function helmToFasta(helmString: string) {
|
|
111
|
-
const url = `http://localhost:8081/WebService/service/Fasta/Produce/${helmString}
|
|
163
|
+
const url = `http://localhost:8081/WebService/service/Fasta/Produce/${helmString}`;
|
|
112
164
|
return await accessServer(url, 'FastaFile');
|
|
113
165
|
}
|
|
114
166
|
|
|
@@ -117,7 +169,7 @@ export async function helmToFasta(helmString: string) {
|
|
|
117
169
|
//input: string helmString {semType: Macromolecule}
|
|
118
170
|
//output: string res
|
|
119
171
|
export async function helmToRNA(helmString: string) {
|
|
120
|
-
const url = `http://localhost:8081/WebService/service/Fasta/Convert/RNA/${helmString}
|
|
172
|
+
const url = `http://localhost:8081/WebService/service/Fasta/Convert/RNA/${helmString}`;
|
|
121
173
|
return await accessServer(url, 'Sequence');
|
|
122
174
|
}
|
|
123
175
|
|
|
@@ -127,7 +179,7 @@ export async function helmToRNA(helmString: string) {
|
|
|
127
179
|
//input: string helmString {semType: Macromolecule}
|
|
128
180
|
//output: string res
|
|
129
181
|
export async function helmToPeptide(helmString: string) {
|
|
130
|
-
const url = `http://localhost:8081/WebService/service/Fasta/Convert/PEPTIDE/${helmString}
|
|
182
|
+
const url = `http://localhost:8081/WebService/service/Fasta/Convert/PEPTIDE/${helmString}`;
|
|
131
183
|
return await accessServer(url, 'Sequence');
|
|
132
184
|
}
|
|
133
185
|
|
|
@@ -136,24 +188,23 @@ export async function helmToPeptide(helmString: string) {
|
|
|
136
188
|
//input: string helmString {semType: Macromolecule}
|
|
137
189
|
//output: string smiles {semType: Molecule}
|
|
138
190
|
export async function helmToSmiles(helmString: string) {
|
|
139
|
-
const url = `http://localhost:8081/WebService/service/SMILES/${helmString}
|
|
191
|
+
const url = `http://localhost:8081/WebService/service/SMILES/${helmString}`;
|
|
140
192
|
return await accessServer(url, 'SMILES');
|
|
141
193
|
}
|
|
142
194
|
|
|
143
195
|
function getRS(smiles: string) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
for (
|
|
149
|
-
if (
|
|
150
|
-
if (/\d/.test(
|
|
151
|
-
digit =
|
|
152
|
-
|
|
153
|
-
for (
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
196
|
+
const newS = smiles.match(/(?<=\[)[^\][]*(?=])/gm);
|
|
197
|
+
const res = {};
|
|
198
|
+
let el = '';
|
|
199
|
+
let digit;
|
|
200
|
+
for (let i = 0; i < newS.length; i++) {
|
|
201
|
+
if (newS[i] != null) {
|
|
202
|
+
if (/\d/.test(newS[i])) {
|
|
203
|
+
digit = newS[i][newS[i].length - 1];
|
|
204
|
+
newS[i] = newS[i].replace(/[0-9]/g, '');
|
|
205
|
+
for (let j = 0; j < newS[i].length; j++) {
|
|
206
|
+
if (newS[i][j] != ':')
|
|
207
|
+
el += newS[i][j];
|
|
157
208
|
}
|
|
158
209
|
res['R' + digit] = el;
|
|
159
210
|
el = '';
|
|
@@ -164,22 +215,36 @@ function getRS(smiles: string) {
|
|
|
164
215
|
}
|
|
165
216
|
|
|
166
217
|
async function monomerManager(value: string) {
|
|
167
|
-
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
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);
|
|
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());
|
|
180
245
|
}
|
|
181
246
|
org.helm.webeditor.Monomers.addOneMonomer(m);
|
|
182
|
-
}
|
|
247
|
+
});
|
|
183
248
|
}
|
|
184
249
|
|
|
185
250
|
//name: helmColumnToSmiles
|
|
@@ -193,36 +258,42 @@ export function helmColumnToSmiles(helmColumn: DG.Column) {
|
|
|
193
258
|
export async function findMonomers(helmString: string) {
|
|
194
259
|
const types = Object.keys(org.helm.webeditor.monomerTypeList());
|
|
195
260
|
const monomers = [];
|
|
196
|
-
const
|
|
197
|
-
for (
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
261
|
+
const monomerNames = [];
|
|
262
|
+
for (let i = 0; i < types.length; i++) {
|
|
263
|
+
// Synonym to overcome eslint error
|
|
264
|
+
const GetMonomerSet = scil.helm.Monomers.getMonomerSet;
|
|
265
|
+
monomers.push(new GetMonomerSet(types[i]));
|
|
266
|
+
Object.keys(monomers[i]).forEach((k) => {
|
|
267
|
+
monomerNames.push(monomers[i][k].id);
|
|
201
268
|
});
|
|
202
269
|
}
|
|
203
|
-
const
|
|
204
|
-
return new Set(
|
|
270
|
+
const splitString = WebLogo.splitterAsHelm(helmString);
|
|
271
|
+
return new Set(splitString.filter((val) => !monomerNames.includes(val)));
|
|
205
272
|
}
|
|
206
273
|
|
|
207
274
|
class HelmCellRenderer extends DG.GridCellRenderer {
|
|
208
|
-
|
|
209
275
|
get name() { return 'macromolecule'; }
|
|
276
|
+
|
|
210
277
|
get cellType() { return 'macromolecule'; }
|
|
278
|
+
|
|
211
279
|
get defaultWidth(): number | null { return 400; }
|
|
280
|
+
|
|
212
281
|
get defaultHeight(): number | null { return 100; }
|
|
213
282
|
|
|
214
|
-
render(g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number,
|
|
215
|
-
|
|
283
|
+
render(g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number,
|
|
284
|
+
gridCell: DG.GridCell, cellStyle: DG.GridCellStyle
|
|
285
|
+
) {
|
|
286
|
+
const host = ui.div([], {style: {width: `${w}px`, height: `${h}px`}});
|
|
216
287
|
host.setAttribute('dataformat', 'helm');
|
|
217
288
|
host.setAttribute('data', gridCell.cell.value);
|
|
218
289
|
|
|
219
290
|
gridCell.element = host;
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
291
|
+
const canvas = new JSDraw2.Editor(host, {width: w, height: h, skin: 'w8', viewonly: true});
|
|
292
|
+
const formula = canvas.getFormula(true);
|
|
293
|
+
const molWeight = Math.round(canvas.getMolWeight() * 100) / 100;
|
|
294
|
+
const coef = Math.round(canvas.getExtinctionCoefficient(true) * 100) / 100;
|
|
295
|
+
const molfile = canvas.getMolfile();
|
|
296
|
+
const result = formula + ', ' + molWeight + ', ' + coef + ', ' + molfile;
|
|
226
297
|
lru.set(gridCell.cell.value, result);
|
|
227
298
|
}
|
|
228
299
|
}
|
package/src/tests/helm-tests.ts
CHANGED
|
@@ -1,43 +1,46 @@
|
|
|
1
1
|
import {before, category, expect, test} from '@datagrok-libraries/utils/src/test';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import {helmToFasta, helmToPeptide, helmToRNA} from '../package';
|
|
3
|
+
import {_package} from '../package-test';
|
|
4
4
|
import * as DG from 'datagrok-api/dg';
|
|
5
5
|
import * as grok from 'datagrok-api/grok';
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
category('Helm', () => {
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
});
|
|
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
|
+
// });
|
|
27
30
|
|
|
28
31
|
test('detectMacromolecule', async () => {
|
|
29
|
-
const file = await _package.files.readAsText('test.csv')
|
|
32
|
+
const file = await _package.files.readAsText('tests/test.csv');
|
|
30
33
|
const df = DG.DataFrame.fromCsv(file);
|
|
31
|
-
|
|
34
|
+
const col = df.columns.byName('HELM string');
|
|
32
35
|
await grok.data.detectSemanticTypes(df);
|
|
33
36
|
expect(col.semType, DG.SEMTYPE.MACROMOLECULE);
|
|
34
37
|
});
|
|
35
38
|
|
|
36
39
|
test('detectHelm', async () => {
|
|
37
|
-
const file = await _package.files.readAsText('test.csv')
|
|
40
|
+
const file = await _package.files.readAsText('tests/test.csv');
|
|
38
41
|
const df = DG.DataFrame.fromCsv(file);
|
|
39
|
-
|
|
42
|
+
const col = df.columns.byName('HELM string');
|
|
40
43
|
await grok.data.detectSemanticTypes(df);
|
|
41
|
-
expect(col.tags[DG.TAGS.UNITS],
|
|
44
|
+
expect(col.tags[DG.TAGS.UNITS], 'HELM');
|
|
42
45
|
});
|
|
43
46
|
});
|
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 f7696845.</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 f7696845.</h1></header><div id="metadata-container"><div id="timestamp">Started: 2022-07-15 13:16:11</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">12.196s</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.124s</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 (<anonymous>)
|
|
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.<anonymous> (/home/runner/work/public/public/packages/Helm/src/__jest__/test-node.ts:61:11)
|
|
239
|
+
at Generator.next (<anonymous>)
|
|
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 (<anonymous>)
|
|
243
|
+
at /home/runner/work/public/public/packages/Helm/src/__jest__/remote.test.ts:34:71
|
|
244
|
+
at new Promise (<anonymous>)
|
|
245
|
+
at Object.<anonymous>.__awaiter (/home/runner/work/public/public/packages/Helm/src/__jest__/remote.test.ts:30:12)
|
|
246
|
+
at Object.<anonymous> (/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 (<anonymous>)</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 (<anonymous>)
|
|
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>
|
package/webpack.config.js
CHANGED
|
@@ -16,7 +16,16 @@ module.exports = {
|
|
|
16
16
|
},
|
|
17
17
|
module: {
|
|
18
18
|
rules: [
|
|
19
|
-
{
|
|
19
|
+
{
|
|
20
|
+
test: /\.ts(x?)$/,
|
|
21
|
+
use: 'ts-loader',
|
|
22
|
+
exclude: /node_modules/,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
test: /\.css$/,
|
|
26
|
+
use: ['style-loader', 'css-loader'],
|
|
27
|
+
exclude: /node_modules/,
|
|
28
|
+
},
|
|
20
29
|
],
|
|
21
30
|
},
|
|
22
31
|
devtool: 'inline-source-map',
|