@datagrok/sequence-translator 1.3.0 → 1.3.2
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/.eslintrc.json +1 -1
- package/CHANGELOG.md +18 -0
- package/dist/package-test.js +1 -2
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/files/monomers-sample/README.md +12 -0
- package/files/polytool-rules/rules_example.json +34 -0
- package/files/samples/bulk-translation-axolabs.csv +6 -0
- package/files/tests/README.md +2 -0
- package/files/tests/axolabs1.csv +2 -0
- package/package.json +23 -13
- package/src/apps/common/model/data-loader/const.ts +1 -2
- package/src/apps/common/model/data-loader/json-loader.ts +22 -31
- package/src/apps/common/model/monomer-lib/lib-wrapper.ts +13 -19
- package/src/apps/common/model/oligo-toolkit-package.ts +80 -13
- package/src/apps/common/model/parsing-validation/format-detector.ts +9 -6
- package/src/apps/common/model/parsing-validation/format-handler.ts +16 -13
- package/src/apps/common/model/parsing-validation/sequence-validator.ts +8 -3
- package/src/apps/common/view/combined-app-ui.ts +12 -10
- package/src/apps/common/view/components/colored-input/input-painters.ts +4 -3
- package/src/apps/common/view/monomer-lib-viewer.ts +2 -1
- package/src/apps/common/view/utils.ts +5 -4
- package/src/apps/pattern/model/data-manager.ts +9 -6
- package/src/apps/pattern/model/translator.ts +8 -10
- package/src/apps/pattern/model/utils.ts +0 -1
- package/src/apps/pattern/view/components/strand-editor/strand-controls.ts +0 -1
- package/src/apps/pattern/view/components/translation-examples-block.ts +2 -1
- package/src/apps/pattern/view/svg-utils/utils.ts +6 -4
- package/src/apps/pattern/view/ui.ts +4 -1
- package/src/apps/structure/model/monomer-code-parser.ts +15 -5
- package/src/apps/structure/model/oligo-structure.ts +17 -16
- package/src/apps/structure/model/sequence-to-molfile.ts +2 -1
- package/src/apps/structure/view/ui.ts +19 -11
- package/src/apps/translator/model/conversion-utils.ts +16 -11
- package/src/apps/translator/model/format-converter.ts +15 -5
- package/src/apps/translator/view/ui.ts +32 -20
- package/src/demo/demo-st-ui.ts +2 -2
- package/src/package-test.ts +9 -2
- package/src/package.ts +18 -17
- package/src/plugins/mermade.ts +11 -8
- package/src/polytool/pt-rules.ts +1 -1
- package/src/tests/const.ts +7 -5
- package/src/tests/files-tests.ts +75 -0
- package/src/tests/formats-support.ts +12 -11
- package/src/tests/formats-to-helm.ts +12 -19
- package/src/tests/helm-to-nucleotides.ts +12 -6
- package/src/tests/utils.ts +20 -0
- package/src/types.ts +18 -0
- package/dist/package-test.js.LICENSE.txt +0 -8
- /package/files/{codes-to-symbols.json → monomers-sample/codes-to-symbols.json} +0 -0
- /package/files/{formats-to-helm.json → monomers-sample/formats-to-helm.json} +0 -0
- /package/files/{linkers.json → monomers-sample/linkers.json} +0 -0
- /package/files/{monomer-lib.json → monomers-sample/monomer-lib.json} +0 -0
- /package/files/{pattern-app-data.json → monomers-sample/pattern-app-data.json} +0 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Sample files of the package SequenceTranslator with samples of
|
|
2
|
+
additional monomer libraries and dictionaries of substituting HELM substructures into sequences.
|
|
3
|
+
|
|
4
|
+
codes-to-symbols.json: monomer codes in different formats corresponding to monomer symbols in monomer-lib.json
|
|
5
|
+
|
|
6
|
+
formats-to-helm.json: monomer codes corresponding to helm substructures
|
|
7
|
+
|
|
8
|
+
linkers.json: monomers containing phospate or phosphorothioate groups
|
|
9
|
+
|
|
10
|
+
monomer-lib.json: pseudo-helm monomer library (R-groups are dummy)
|
|
11
|
+
|
|
12
|
+
pattern-app-data.json: color maps for Pattern app
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"type": "link",
|
|
4
|
+
"code": "1",
|
|
5
|
+
"monomericSubstitution": {
|
|
6
|
+
"firstMonomer": "C",
|
|
7
|
+
"secondMonomer": "C",
|
|
8
|
+
"firstLinkingGroup":"3",
|
|
9
|
+
"secondLinkingGroup":"3",
|
|
10
|
+
"firstSubstitution": "C",
|
|
11
|
+
"secondSubstitution": "C"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"type": "link",
|
|
16
|
+
"code": "2",
|
|
17
|
+
"monomericSubstitution": {
|
|
18
|
+
"firstMonomer": "NH2",
|
|
19
|
+
"secondMonomer": "L",
|
|
20
|
+
"firstLinkingGroup":"2",
|
|
21
|
+
"secondLinkingGroup":"3",
|
|
22
|
+
"firstSubstitution": "NH2",
|
|
23
|
+
"secondSubstitution": "L"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"type": "fragmentDuplication",
|
|
28
|
+
"code": "#3"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"type": "differentFragments",
|
|
32
|
+
"code": "$4"
|
|
33
|
+
}
|
|
34
|
+
]
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrok/sequence-translator",
|
|
3
3
|
"friendlyName": "Sequence Translator",
|
|
4
|
-
"version": "1.3.
|
|
4
|
+
"version": "1.3.2",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Alexey Choposky",
|
|
7
7
|
"email": "achopovsky@datagrok.ai"
|
|
@@ -12,11 +12,20 @@
|
|
|
12
12
|
"url": "https://github.com/datagrok-ai/public.git",
|
|
13
13
|
"directory": "packages/SequenceTranslator"
|
|
14
14
|
},
|
|
15
|
+
"properties": [
|
|
16
|
+
{
|
|
17
|
+
"name": "MonomersPath",
|
|
18
|
+
"description": "Path to additional monomer libraries and dictionaries of substituting HELM substructures into sequences",
|
|
19
|
+
"propertyType": "string",
|
|
20
|
+
"defaultValue": "System:AppData/SequenceTranslator/monomers",
|
|
21
|
+
"nullable": false
|
|
22
|
+
}
|
|
23
|
+
],
|
|
15
24
|
"dependencies": {
|
|
16
25
|
"@datagrok-libraries/bio": "^5.41.9",
|
|
17
|
-
"@datagrok-libraries/chem-meta": "^1.2.
|
|
26
|
+
"@datagrok-libraries/chem-meta": "^1.2.5",
|
|
18
27
|
"@datagrok-libraries/tutorials": "^1.3.12",
|
|
19
|
-
"@datagrok-libraries/utils": "^4.
|
|
28
|
+
"@datagrok-libraries/utils": "^4.2.6",
|
|
20
29
|
"@types/react": "^18.0.15",
|
|
21
30
|
"cash-dom": "^8.1.0",
|
|
22
31
|
"datagrok-api": "^1.18.6",
|
|
@@ -25,12 +34,12 @@
|
|
|
25
34
|
"openchemlib": "6.0.1",
|
|
26
35
|
"save-svg-as-png": "^1.4.17",
|
|
27
36
|
"ts-loader": "^9.3.1",
|
|
28
|
-
"
|
|
29
|
-
"
|
|
37
|
+
"typeahead-standalone": "4.14.1",
|
|
38
|
+
"typescript": "^5.4.2"
|
|
30
39
|
},
|
|
31
40
|
"devDependencies": {
|
|
32
|
-
"@datagrok/bio": "^2.12.
|
|
33
|
-
"@datagrok/chem": "1.9.
|
|
41
|
+
"@datagrok/bio": "^2.12.23",
|
|
42
|
+
"@datagrok/chem": "1.9.2",
|
|
34
43
|
"@types/jquery": "^3.5.14",
|
|
35
44
|
"@types/js-yaml": "^4.0.5",
|
|
36
45
|
"@types/lodash": "^4.14.202",
|
|
@@ -40,6 +49,7 @@
|
|
|
40
49
|
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
|
41
50
|
"@typescript-eslint/parser": "^7.2.0",
|
|
42
51
|
"css-loader": "^6.7.3",
|
|
52
|
+
"datagrok-tools": "latest",
|
|
43
53
|
"eslint": "^8.57.0",
|
|
44
54
|
"eslint-config-google": "latest",
|
|
45
55
|
"style-loader": "^3.3.1",
|
|
@@ -53,14 +63,14 @@
|
|
|
53
63
|
"link-api": "npm link datagrok-api",
|
|
54
64
|
"link-bio": "npm link @datagrok-libraries/bio",
|
|
55
65
|
"link-all": "npm link @datagrok-libraries/chem-meta datagrok-api @datagrok-libraries/utils @datagrok-libraries/bio @datagrok-libraries/tutorials",
|
|
56
|
-
"debug-sequencetranslator": "grok publish",
|
|
57
|
-
"release-sequencetranslator": "grok publish
|
|
66
|
+
"debug-sequencetranslator": "webpack && grok publish",
|
|
67
|
+
"release-sequencetranslator": "webpack && grok publish --release",
|
|
58
68
|
"build-sequencetranslator": "webpack",
|
|
59
69
|
"build": "webpack",
|
|
60
|
-
"debug-sequencetranslator-public": "grok publish public",
|
|
61
|
-
"release-sequencetranslator-public": "grok publish public --release",
|
|
62
|
-
"debug-sequencetranslator-local": "grok publish local",
|
|
63
|
-
"release-sequencetranslator-local": "grok publish local --release",
|
|
70
|
+
"debug-sequencetranslator-public": "webpack && grok publish public",
|
|
71
|
+
"release-sequencetranslator-public": "webpack && grok publish public --release",
|
|
72
|
+
"debug-sequencetranslator-local": "webpack && grok publish local",
|
|
73
|
+
"release-sequencetranslator-local": "webpack && grok publish local --release",
|
|
64
74
|
"lint": "eslint \"./src/**/*.ts\"",
|
|
65
75
|
"lint-fix": "eslint \"./src/**/*.ts\" --fix",
|
|
66
76
|
"test": "grok test",
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
export const
|
|
1
|
+
export const FALLBACK_LIB_PATH = 'System:AppData/SequenceTranslator/monomers-sample';
|
|
2
2
|
export const DEFAULT_LIB_FILENAME = 'monomer-lib.json';
|
|
3
3
|
|
|
4
|
-
export const APP_PATH = 'System:AppData/SequenceTranslator';
|
|
5
4
|
export const PATTERN_APP_DATA_FILENAME = 'pattern-app-data.json';
|
|
6
5
|
export const CODES_TO_HELM_DICT_FILENAME = 'formats-to-helm.json';
|
|
7
6
|
export const CODES_TO_SYMBOLS_FILENAME = 'codes-to-symbols.json';
|
|
@@ -1,48 +1,39 @@
|
|
|
1
1
|
/* Do not change these import lines to match external modules in webpack configuration */
|
|
2
|
+
import * as grok from 'datagrok-api/grok';
|
|
3
|
+
import * as ui from 'datagrok-api/ui';
|
|
2
4
|
import * as DG from 'datagrok-api/dg';
|
|
3
5
|
|
|
4
6
|
import {
|
|
5
|
-
|
|
7
|
+
PATTERN_APP_DATA_FILENAME, CODES_TO_HELM_DICT_FILENAME,
|
|
6
8
|
CODES_TO_SYMBOLS_FILENAME, MONOMERS_WITH_PHOSPHATE_FILENAME
|
|
7
9
|
} from './const';
|
|
8
10
|
import {PatternAppData, CodeToSymbol, FormatToHELMDict} from './types';
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (isAllJsonDataLoaded())
|
|
19
|
-
return;
|
|
20
|
-
|
|
21
|
-
const jsonFileNames = [
|
|
22
|
-
PATTERN_APP_DATA_FILENAME, CODES_TO_HELM_DICT_FILENAME, CODES_TO_SYMBOLS_FILENAME, MONOMERS_WITH_PHOSPHATE_FILENAME
|
|
23
|
-
];
|
|
12
|
+
export class JsonData {
|
|
13
|
+
constructor(
|
|
14
|
+
public readonly patternAppData: PatternAppData,
|
|
15
|
+
public readonly codesToHelmDict: FormatToHELMDict,
|
|
16
|
+
public readonly codesToSymbolsDict: CodeToSymbol,
|
|
17
|
+
public readonly monomersWithPhosphate: { [key: string]: string[] }
|
|
18
|
+
) {};
|
|
19
|
+
}
|
|
24
20
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
jsonFileNames.map((fileName) => loadAndParseJson(fileName))
|
|
21
|
+
export async function loadJsonData(monomersPath: string): Promise<JsonData> {
|
|
22
|
+
const data = await Promise.all(
|
|
23
|
+
[
|
|
24
|
+
PATTERN_APP_DATA_FILENAME, CODES_TO_HELM_DICT_FILENAME,
|
|
25
|
+
CODES_TO_SYMBOLS_FILENAME, MONOMERS_WITH_PHOSPHATE_FILENAME
|
|
26
|
+
].map((fileName) => loadAndParseJson(monomersPath, fileName))
|
|
32
27
|
);
|
|
28
|
+
return new JsonData(data[0], data[1], data[2], data[3]);
|
|
33
29
|
}
|
|
34
30
|
|
|
35
|
-
async function loadAndParseJson(
|
|
31
|
+
async function loadAndParseJson(path: string, fileName: string): Promise<any> {
|
|
32
|
+
const filePath = path.endsWith('/') ? `${path}${fileName}` : `${path}/${fileName}`;
|
|
36
33
|
try {
|
|
37
|
-
const content = await
|
|
34
|
+
const content = await grok.dapi.files.readAsText(filePath);
|
|
38
35
|
return JSON.parse(content);
|
|
39
36
|
} catch (err) {
|
|
40
|
-
console.error(`Error loading json from ${filePath}:`, err);
|
|
37
|
+
console.error(`Error loading json from '${filePath}':`, err);
|
|
41
38
|
}
|
|
42
39
|
}
|
|
43
|
-
|
|
44
|
-
function isAllJsonDataLoaded(): boolean {
|
|
45
|
-
const data = [PATTERN_APP_DATA, CODES_TO_HELM_DICT, CODES_TO_SYMBOLS_DICT, MONOMERS_WITH_PHOSPHATE];
|
|
46
|
-
|
|
47
|
-
return data.every((item) => item !== undefined);
|
|
48
|
-
}
|
|
@@ -7,23 +7,23 @@ import {IMonomerLib, Monomer} from '@datagrok-libraries/bio/src/types';
|
|
|
7
7
|
import {HELM_REQUIRED_FIELD as REQ, HELM_OPTIONAL_FIELDS as OPT} from '@datagrok-libraries/bio/src/utils/const';
|
|
8
8
|
|
|
9
9
|
import {META_FIELDS as MET} from './const';
|
|
10
|
-
import {
|
|
10
|
+
import {JsonData} from '../data-loader/json-loader';
|
|
11
11
|
|
|
12
12
|
export class MonomerLibWrapper {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
public constructor(
|
|
14
|
+
private readonly lib: IMonomerLib,
|
|
15
|
+
private readonly jsonData: JsonData
|
|
16
|
+
) {
|
|
17
|
+
if (this.lib === null)
|
|
16
18
|
throw new Error('SequenceTranslator: monomer library is null');
|
|
17
|
-
this.lib = lib!;
|
|
18
19
|
this.allMonomers = this.getAllMonomers();
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
private lib: IMonomerLib;
|
|
22
22
|
private static instance?: MonomerLibWrapper;
|
|
23
23
|
private allMonomers: Monomer[];
|
|
24
24
|
|
|
25
|
-
private formatMonomerForViewer(sourceObj: Monomer): {[key: string]: string} {
|
|
26
|
-
const formattedObject: {[key: string]: string} = {};
|
|
25
|
+
private formatMonomerForViewer(sourceObj: Monomer): { [key: string]: string } {
|
|
26
|
+
const formattedObject: { [key: string]: string } = {};
|
|
27
27
|
formattedObject[REQ.NAME] = sourceObj[REQ.SYMBOL];
|
|
28
28
|
formattedObject[REQ.SYMBOL] = sourceObj[REQ.SYMBOL];
|
|
29
29
|
formattedObject[REQ.MOLFILE] = sourceObj[REQ.MOLFILE];
|
|
@@ -31,7 +31,7 @@ export class MonomerLibWrapper {
|
|
|
31
31
|
formats.forEach((format) => {
|
|
32
32
|
if (format === DEFAULT_FORMATS.HELM)
|
|
33
33
|
return;
|
|
34
|
-
const map =
|
|
34
|
+
const map = this.jsonData.codesToSymbolsDict[format];
|
|
35
35
|
const codes = Object.keys(map).filter((code) => map[code] === sourceObj.symbol);
|
|
36
36
|
formattedObject[format] = codes.join(', ');
|
|
37
37
|
});
|
|
@@ -59,12 +59,6 @@ export class MonomerLibWrapper {
|
|
|
59
59
|
return monomer!;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
static getInstance(): MonomerLibWrapper {
|
|
63
|
-
if (MonomerLibWrapper.instance === undefined)
|
|
64
|
-
MonomerLibWrapper.instance = new MonomerLibWrapper();
|
|
65
|
-
return MonomerLibWrapper.instance!;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
62
|
getMolfileBySymbol(monomerSymbol: string): string {
|
|
69
63
|
const monomer = this.getMonomer(monomerSymbol);
|
|
70
64
|
return monomer.molfile;
|
|
@@ -85,15 +79,15 @@ export class MonomerLibWrapper {
|
|
|
85
79
|
}
|
|
86
80
|
|
|
87
81
|
getCodeToSymbolMap(format: string): Map<string, string> {
|
|
88
|
-
return new Map<string, string>(Object.entries(
|
|
82
|
+
return new Map<string, string>(Object.entries(this.jsonData.codesToSymbolsDict[format]));
|
|
89
83
|
}
|
|
90
84
|
|
|
91
85
|
getCodesByFormat(format: string): string[] {
|
|
92
|
-
return Object.keys(
|
|
86
|
+
return Object.keys(this.jsonData.codesToSymbolsDict[format]);
|
|
93
87
|
}
|
|
94
88
|
|
|
95
89
|
getAllFormats(): string[] {
|
|
96
|
-
return Object.keys(
|
|
90
|
+
return Object.keys(this.jsonData.codesToSymbolsDict);
|
|
97
91
|
}
|
|
98
92
|
|
|
99
93
|
getTableForViewer(): DG.DataFrame {
|
|
@@ -104,7 +98,7 @@ export class MonomerLibWrapper {
|
|
|
104
98
|
|
|
105
99
|
getCodesToWeightsMap(): Map<string, number> {
|
|
106
100
|
const codesToWeightsMap = new Map<string, number>();
|
|
107
|
-
Object.entries(
|
|
101
|
+
Object.entries(this.jsonData.codesToSymbolsDict).forEach(([_, dict]) => {
|
|
108
102
|
Object.entries(dict).forEach(([code, monomerSymbol]) => {
|
|
109
103
|
const monomer = this.getMonomer(monomerSymbol);
|
|
110
104
|
const weight = monomer[OPT.META]?.[MET.MOLWEIGHT];
|
|
@@ -1,30 +1,97 @@
|
|
|
1
|
+
import * as grok from 'datagrok-api/grok';
|
|
2
|
+
import * as ui from 'datagrok-api/ui';
|
|
1
3
|
import * as DG from 'datagrok-api/dg';
|
|
2
4
|
|
|
3
5
|
import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
4
|
-
import {IMonomerLib} from '@datagrok-libraries/bio/src/types';
|
|
6
|
+
import {IMonomerLib, Monomer} from '@datagrok-libraries/bio/src/types';
|
|
5
7
|
|
|
6
8
|
import {APP_NAME} from '../view/const';
|
|
7
|
-
import {DEFAULT_LIB_FILENAME,
|
|
9
|
+
import {DEFAULT_LIB_FILENAME, FALLBACK_LIB_PATH} from './data-loader/const';
|
|
8
10
|
import {tryCatch} from './helpers';
|
|
11
|
+
import {ITranslationHelper} from '../../../types';
|
|
12
|
+
import {SequenceValidator} from './parsing-validation/sequence-validator';
|
|
13
|
+
import {JsonData, loadJsonData} from './data-loader/json-loader';
|
|
14
|
+
import {MonomerLibWrapper} from './monomer-lib/lib-wrapper';
|
|
15
|
+
import {_package} from '../../../package';
|
|
16
|
+
import {FormatConverter} from '../../translator/model/format-converter';
|
|
17
|
+
import {FormatDetector} from './parsing-validation/format-detector';
|
|
18
|
+
import {highlightInvalidSubsequence} from '../view/components/colored-input/input-painters';
|
|
9
19
|
|
|
10
|
-
export class OligoToolkitPackage extends DG.Package {
|
|
20
|
+
export class OligoToolkitPackage extends DG.Package implements ITranslationHelper {
|
|
11
21
|
private _monomerLib?: IMonomerLib;
|
|
12
|
-
|
|
13
22
|
get monomerLib(): IMonomerLib {
|
|
14
23
|
if (!this._monomerLib)
|
|
15
24
|
throw new Error('Monomer lib not loaded');
|
|
16
25
|
return this._monomerLib!;
|
|
17
26
|
}
|
|
18
27
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
28
|
+
private _jsonData: JsonData;
|
|
29
|
+
get jsonData(): JsonData {
|
|
30
|
+
if (!this._jsonData)
|
|
31
|
+
throw new Error('Json data not loaded');
|
|
32
|
+
return this._jsonData;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private _monomerLibWrapper: MonomerLibWrapper;
|
|
36
|
+
get monomerLibWrapper(): MonomerLibWrapper {
|
|
37
|
+
if (!this._monomerLibWrapper)
|
|
38
|
+
throw new Error('Monomer lib wrapper not loaded');
|
|
39
|
+
return this._monomerLibWrapper;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
constructor() {
|
|
43
|
+
super();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private initPromise?: Promise<void>;
|
|
47
|
+
|
|
48
|
+
async initLibData(): Promise<void> {
|
|
49
|
+
if (!this.initPromise) {
|
|
50
|
+
this.initPromise = (async () => {
|
|
51
|
+
const packageSettings = await this.getSettings();
|
|
52
|
+
let monomersPath: string = packageSettings['MonomersPath'];
|
|
53
|
+
if (!monomersPath || !(await grok.dapi.files.exists(monomersPath))) {
|
|
54
|
+
_package.logger.warning(`Monomers path '${monomersPath}' not found. ` +
|
|
55
|
+
`Fallback to monomers sample path '${FALLBACK_LIB_PATH}'.`);
|
|
56
|
+
monomersPath = FALLBACK_LIB_PATH;
|
|
57
|
+
}
|
|
58
|
+
[this._jsonData, this._monomerLib] = await Promise.all([
|
|
59
|
+
loadJsonData(monomersPath),
|
|
60
|
+
loadMonomerLib(monomersPath)
|
|
61
|
+
]);
|
|
62
|
+
this._monomerLibWrapper = new MonomerLibWrapper(this.monomerLib, this.jsonData);
|
|
63
|
+
})();
|
|
64
|
+
}
|
|
65
|
+
return this.initPromise;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async getTranslationHelper(): Promise<ITranslationHelper> {
|
|
69
|
+
return (await grok.functions.call(`${this.name}:getTranslationHelper`)) as ITranslationHelper;
|
|
70
|
+
}
|
|
22
71
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
await tryCatch(async () => {
|
|
26
|
-
const libHelper: IMonomerLibHelper = await getMonomerLibHelper();
|
|
27
|
-
this._monomerLib = await libHelper.readLibrary(LIB_PATH, DEFAULT_LIB_FILENAME);
|
|
28
|
-
}, () => pi.close());
|
|
72
|
+
createSequenceValidator(sequence: string): SequenceValidator {
|
|
73
|
+
return new SequenceValidator(sequence, this);
|
|
29
74
|
}
|
|
75
|
+
|
|
76
|
+
createFormatConverter(sequence: string, sourceFormat: string): FormatConverter {
|
|
77
|
+
return new FormatConverter(sequence, sourceFormat, this);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
createFormatDetector(sequence: string): FormatDetector {
|
|
81
|
+
return new FormatDetector(sequence, this);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
highlightInvalidSubsequence = (input: string): HTMLSpanElement[] => {
|
|
85
|
+
return highlightInvalidSubsequence(input, this);
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function loadMonomerLib(monomersPath: string): Promise<IMonomerLib> {
|
|
90
|
+
const pi: DG.TaskBarProgressIndicator = DG.TaskBarProgressIndicator.create(
|
|
91
|
+
`Initializing ${APP_NAME.COMBINED} monomer library ...`);
|
|
92
|
+
try {
|
|
93
|
+
const libHelper = await getMonomerLibHelper();
|
|
94
|
+
const res = await libHelper.readLibrary(monomersPath, DEFAULT_LIB_FILENAME);
|
|
95
|
+
return res;
|
|
96
|
+
} finally { pi.close(); }
|
|
30
97
|
}
|
|
@@ -6,13 +6,16 @@ import * as DG from 'datagrok-api/dg';
|
|
|
6
6
|
import {sortByReverseLength} from '../helpers';
|
|
7
7
|
import {DEFAULT_FORMATS} from '../const';
|
|
8
8
|
import {MonomerLibWrapper} from '../monomer-lib/lib-wrapper';
|
|
9
|
-
|
|
10
|
-
import {
|
|
9
|
+
|
|
10
|
+
import {ITranslationHelper} from '../../../../types';
|
|
11
11
|
|
|
12
12
|
export class FormatDetector {
|
|
13
|
-
constructor(
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
constructor(
|
|
14
|
+
private sequence: string,
|
|
15
|
+
private readonly th: ITranslationHelper,
|
|
16
|
+
) {
|
|
17
|
+
this.libWrapper = this.th.monomerLibWrapper;
|
|
18
|
+
this.formats = Object.keys(this.th.jsonData.codesToHelmDict);
|
|
16
19
|
};
|
|
17
20
|
|
|
18
21
|
private libWrapper: MonomerLibWrapper;
|
|
@@ -26,7 +29,7 @@ export class FormatDetector {
|
|
|
26
29
|
if (possibleFormats.length === 0)
|
|
27
30
|
return null;
|
|
28
31
|
|
|
29
|
-
const validator =
|
|
32
|
+
const validator = this.th.createSequenceValidator(this.sequence);
|
|
30
33
|
const outputIndices = Array(possibleFormats.length).fill(0);
|
|
31
34
|
for (let i = 0; i < possibleFormats.length; ++i) {
|
|
32
35
|
const format = possibleFormats[i];
|
|
@@ -3,15 +3,17 @@ 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
5
|
|
|
6
|
-
import {CODES_TO_HELM_DICT} from '../data-loader/json-loader';
|
|
7
6
|
import {CodesInfo} from '../data-loader/types';
|
|
8
7
|
import {DEFAULT_FORMATS} from '../const';
|
|
8
|
+
import {ITranslationHelper} from '../../../../types';
|
|
9
9
|
import {GROUP_TYPE, PHOSPHATE_SYMBOL} from '../../../translator/model/const';
|
|
10
10
|
|
|
11
11
|
const inverseLengthComparator = (a: string, b: string) => b.length - a.length;
|
|
12
12
|
|
|
13
13
|
export class FormatHandler {
|
|
14
|
-
constructor(
|
|
14
|
+
constructor(
|
|
15
|
+
private readonly th: ITranslationHelper,
|
|
16
|
+
) {
|
|
15
17
|
this.formats = this.getFormats();
|
|
16
18
|
}
|
|
17
19
|
|
|
@@ -31,19 +33,19 @@ export class FormatHandler {
|
|
|
31
33
|
return this.getFormatCodes(format);
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
getHelmToFormatDict(format: string): {[key: string]: string} {
|
|
36
|
+
getHelmToFormatDict(format: string): { [key: string]: string } {
|
|
35
37
|
this.validateFormat(format);
|
|
36
38
|
|
|
37
|
-
const codesInfoObject =
|
|
39
|
+
const codesInfoObject = this.th.jsonData.codesToHelmDict[format] as CodesInfo;
|
|
38
40
|
const dict = getHelmToCodeDict(codesInfoObject);
|
|
39
41
|
return dict;
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
getFormatToHelmDict(format: string): {[key: string]: string} {
|
|
44
|
+
getFormatToHelmDict(format: string): { [key: string]: string } {
|
|
43
45
|
this.validateFormat(format);
|
|
44
46
|
|
|
45
|
-
const codesInfoObject =
|
|
46
|
-
const dict = Object.assign({}, ...Object.values(codesInfoObject)) as {[code: string]: string};
|
|
47
|
+
const codesInfoObject = this.th.jsonData.codesToHelmDict[format] as CodesInfo;
|
|
48
|
+
const dict = Object.assign({}, ...Object.values(codesInfoObject)) as { [code: string]: string };
|
|
47
49
|
return dict;
|
|
48
50
|
}
|
|
49
51
|
|
|
@@ -75,7 +77,7 @@ export class FormatHandler {
|
|
|
75
77
|
getPhosphateHelmCodesRegExp(format: string): RegExp {
|
|
76
78
|
this.validateFormat(format);
|
|
77
79
|
|
|
78
|
-
const codesInfoObject =
|
|
80
|
+
const codesInfoObject = this.th.jsonData.codesToHelmDict[format] as CodesInfo;
|
|
79
81
|
const phosphateHELMCodes = Array.from(
|
|
80
82
|
new Set(Object.values(codesInfoObject[GROUP_TYPE.LINKAGE]))
|
|
81
83
|
).sort(inverseLengthComparator);
|
|
@@ -89,7 +91,7 @@ export class FormatHandler {
|
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
private getFormats(): string[] {
|
|
92
|
-
return Object.keys(
|
|
94
|
+
return Object.keys(this.th.jsonData.codesToHelmDict);
|
|
93
95
|
}
|
|
94
96
|
|
|
95
97
|
private validateFormat(format: string) {
|
|
@@ -109,7 +111,8 @@ export class FormatHandler {
|
|
|
109
111
|
|
|
110
112
|
private getNonHelmFormatRegExp(format: string): RegExp {
|
|
111
113
|
const formatCodes = this.getCodesByFormat(format);
|
|
112
|
-
|
|
114
|
+
// the added group before '|.' is to avoid mismatch inside parenthesis
|
|
115
|
+
const formatRegExp = new RegExp(getRegExpPattern(formatCodes) + '|\\([^()]*\\)|.', 'g');
|
|
113
116
|
return formatRegExp;
|
|
114
117
|
}
|
|
115
118
|
}
|
|
@@ -128,8 +131,8 @@ export function getRegExpPattern(arr: string[]): string {
|
|
|
128
131
|
}
|
|
129
132
|
|
|
130
133
|
function getHelmToCodeDict(infoObj: CodesInfo) {
|
|
131
|
-
const result: {[key: string]: string | string[]} = {};
|
|
132
|
-
Object.values(infoObj).forEach((obj: {[code: string]: string}) => {
|
|
134
|
+
const result: { [key: string]: string | string[] } = {};
|
|
135
|
+
Object.values(infoObj).forEach((obj: { [code: string]: string }) => {
|
|
133
136
|
Object.entries(obj).forEach(([code, helm]) => {
|
|
134
137
|
const key = helm.replace(/\)p/g, ')').replace(/\]p/g, ']');
|
|
135
138
|
if (result[key] === undefined)
|
|
@@ -142,5 +145,5 @@ function getHelmToCodeDict(infoObj: CodesInfo) {
|
|
|
142
145
|
const sorted = (value as string[]).sort(inverseLengthComparator);
|
|
143
146
|
result[key] = sorted[0] as string;
|
|
144
147
|
});
|
|
145
|
-
return result as {[key: string]: string};
|
|
148
|
+
return result as { [key: string]: string };
|
|
146
149
|
}
|
|
@@ -2,13 +2,18 @@ import {NUCLEOTIDES} from '../const';
|
|
|
2
2
|
import {MonomerLibWrapper} from '../monomer-lib/lib-wrapper';
|
|
3
3
|
import {sortByReverseLength} from '../helpers';
|
|
4
4
|
import {DEFAULT_FORMATS} from '../const';
|
|
5
|
+
import {ITranslationHelper} from '../../../../types';
|
|
5
6
|
|
|
6
7
|
export class SequenceValidator {
|
|
7
|
-
constructor(private sequence: string) {
|
|
8
|
-
this.libWrapper = MonomerLibWrapper.getInstance();
|
|
9
|
-
};
|
|
10
8
|
private libWrapper: MonomerLibWrapper;
|
|
11
9
|
|
|
10
|
+
constructor(
|
|
11
|
+
private readonly sequence: string,
|
|
12
|
+
private readonly th: ITranslationHelper,
|
|
13
|
+
) {
|
|
14
|
+
this.libWrapper = this.th.monomerLibWrapper;
|
|
15
|
+
};
|
|
16
|
+
|
|
12
17
|
getInvalidCodeIndex(format: string): number {
|
|
13
18
|
if (format === DEFAULT_FORMATS.HELM)
|
|
14
19
|
return this.sequence.length;
|
|
@@ -9,32 +9,34 @@ import {OligoTranslatorUI} from '../../translator/view/ui';
|
|
|
9
9
|
import {AppUIBase} from './app-ui-base';
|
|
10
10
|
import {IsolatedAppUIBase} from './isolated-app-ui';
|
|
11
11
|
import {APP_NAME, TAB_NAME} from './const';
|
|
12
|
+
import {ITranslationHelper} from '../../../types';
|
|
12
13
|
|
|
13
|
-
type ViewFactories = {[name: string]: () => DG.View};
|
|
14
|
+
type ViewFactories = { [name: string]: () => DG.View };
|
|
14
15
|
|
|
15
16
|
export class CombinedAppUI extends AppUIBase {
|
|
16
|
-
constructor(
|
|
17
|
+
constructor(
|
|
18
|
+
private readonly externalViewFactories: ViewFactories,
|
|
19
|
+
private readonly th: ITranslationHelper
|
|
20
|
+
) {
|
|
17
21
|
super(APP_NAME.COMBINED);
|
|
18
|
-
|
|
19
|
-
const factories = this.getViewFactories();
|
|
22
|
+
|
|
23
|
+
const factories = this.getViewFactories(this.th);
|
|
20
24
|
this.multiView = new DG.MultiView({viewFactories: factories});
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
private multiView: DG.MultiView;
|
|
24
|
-
private externalViewFactories?: ViewFactories;
|
|
25
|
-
|
|
26
28
|
|
|
27
|
-
private getViewFactories(): ViewFactories {
|
|
28
|
-
function viewFactory(UiConstructor: new (
|
|
29
|
+
private getViewFactories(th: ITranslationHelper): ViewFactories {
|
|
30
|
+
function viewFactory(UiConstructor: new (th: ITranslationHelper) => IsolatedAppUIBase): () => DG.View {
|
|
29
31
|
const view = DG.View.create();
|
|
30
|
-
const translateUI = new UiConstructor(
|
|
32
|
+
const translateUI = new UiConstructor(th);
|
|
31
33
|
translateUI.initView().catch(
|
|
32
34
|
(e) => console.error(`Failed to initialize ${UiConstructor.name}: ${e}`)
|
|
33
35
|
);
|
|
34
36
|
return () => translateUI.getView();
|
|
35
37
|
}
|
|
36
38
|
|
|
37
|
-
let result: {[key: string]: () => DG.View } = {
|
|
39
|
+
let result: { [key: string]: () => DG.View } = {
|
|
38
40
|
[TAB_NAME.TRANSLATOR]: viewFactory(OligoTranslatorUI),
|
|
39
41
|
[TAB_NAME.PATTERN]: viewFactory(OligoPatternUI),
|
|
40
42
|
[TAB_NAME.STRUCTURE]: viewFactory(OligoStructureUI),
|
|
@@ -7,6 +7,7 @@ import {SequenceValidator} from '../../../model/parsing-validation/sequence-vali
|
|
|
7
7
|
import {FormatDetector} from '../../../model/parsing-validation/format-detector';
|
|
8
8
|
|
|
9
9
|
import $ from 'cash-dom';
|
|
10
|
+
import {ITranslationHelper} from '../../../../../types';
|
|
10
11
|
|
|
11
12
|
/** Set different colors for letters, can be upgraded to color various monomers */
|
|
12
13
|
export function demoPainter(input: string): HTMLSpanElement[] {
|
|
@@ -24,12 +25,12 @@ export function demoPainter(input: string): HTMLSpanElement[] {
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
// todo: port to another place
|
|
27
|
-
export function highlightInvalidSubsequence(input: string): HTMLSpanElement[] {
|
|
28
|
+
export function highlightInvalidSubsequence(input: string, th: ITranslationHelper): HTMLSpanElement[] {
|
|
28
29
|
// validate sequence
|
|
29
30
|
let cutoff = 0;
|
|
30
|
-
const format = (
|
|
31
|
+
const format = th.createFormatDetector(input).getFormat();
|
|
31
32
|
if (format !== null)
|
|
32
|
-
cutoff = (new SequenceValidator(input)).getInvalidCodeIndex(format!);
|
|
33
|
+
cutoff = (new SequenceValidator(input, th)).getInvalidCodeIndex(format!);
|
|
33
34
|
const isValid = cutoff < 0 || input === '';
|
|
34
35
|
const greyTextSpan = ui.span([]);
|
|
35
36
|
$(greyTextSpan).css('-webkit-text-fill-color', 'var(--grey-6)');
|
|
@@ -5,10 +5,11 @@ import * as DG from 'datagrok-api/dg';
|
|
|
5
5
|
|
|
6
6
|
import {drawZoomedInMolecule} from './components/draw-molecule';
|
|
7
7
|
import {MonomerLibWrapper} from '../model/monomer-lib/lib-wrapper';
|
|
8
|
+
import {_package} from '../../../package';
|
|
8
9
|
|
|
9
10
|
export class MonomerLibViewer {
|
|
10
11
|
static async view(): Promise<void> {
|
|
11
|
-
const table =
|
|
12
|
+
const table = _package.monomerLibWrapper.getTableForViewer();
|
|
12
13
|
table.name = 'Monomer Library';
|
|
13
14
|
const view = grok.shell.addTableView(table);
|
|
14
15
|
view.grid.props.allowEdit = false;
|