@datagrok/sequence-translator 1.2.7 → 1.3.0
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 +5 -5
- package/CHANGELOG.md +14 -0
- package/dist/package-test.js +2 -1
- package/dist/package-test.js.LICENSE.txt +8 -0
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +2 -1
- package/dist/package.js.LICENSE.txt +8 -0
- package/dist/package.js.map +1 -1
- package/files/pattern-app-data.json +80 -0
- package/package.json +22 -14
- package/src/{model → apps/common/model}/const.ts +1 -1
- package/src/{model/data-loading-utils → apps/common/model/data-loader}/const.ts +7 -2
- package/src/apps/common/model/data-loader/json-loader.ts +48 -0
- package/src/{model/data-loading-utils → apps/common/model/data-loader}/types.ts +13 -6
- package/src/{model → apps/common/model}/monomer-lib/lib-wrapper.ts +9 -12
- package/src/apps/common/model/oligo-toolkit-package.ts +30 -0
- package/src/{model → apps/common/model}/parsing-validation/format-detector.ts +5 -5
- package/src/{model → apps/common/model}/parsing-validation/format-handler.ts +18 -19
- package/src/{model → apps/common/model}/parsing-validation/sequence-validator.ts +1 -1
- package/src/apps/common/view/app-ui-base.ts +28 -0
- package/src/apps/common/view/combined-app-ui.ts +66 -0
- package/src/{view/utils → apps/common/view/components}/colored-input/colored-text-input.ts +1 -1
- package/src/{view/utils → apps/common/view/components}/draw-molecule.ts +1 -1
- package/src/{view/utils → apps/common/view/components}/molecule-img.ts +3 -3
- package/src/{view/const/ui.ts → apps/common/view/const.ts} +4 -4
- package/src/apps/common/view/isolated-app-ui.ts +43 -0
- package/src/{view/monomer-lib-viewer/viewer.ts → apps/common/view/monomer-lib-viewer.ts} +2 -2
- package/src/apps/common/view/utils.ts +29 -0
- package/src/apps/pattern/model/const.ts +121 -0
- package/src/apps/pattern/model/data-manager.ts +297 -0
- package/src/apps/pattern/model/event-bus.ts +487 -0
- package/src/apps/pattern/model/router.ts +46 -0
- package/src/apps/pattern/model/subscription-manager.ts +21 -0
- package/src/apps/pattern/model/translator.ts +94 -0
- package/src/apps/pattern/model/types.ts +52 -0
- package/src/apps/pattern/model/utils.ts +110 -0
- package/src/apps/pattern/view/components/bulk-convert/column-input.ts +79 -0
- package/src/apps/pattern/view/components/bulk-convert/table-controls.ts +38 -0
- package/src/apps/pattern/view/components/bulk-convert/table-input.ts +95 -0
- package/src/apps/pattern/view/components/edit-block-controls.ts +196 -0
- package/src/apps/pattern/view/components/left-section.ts +44 -0
- package/src/apps/pattern/view/components/load-block-controls.ts +200 -0
- package/src/apps/pattern/view/components/numeric-label-visibility-controls.ts +69 -0
- package/src/apps/pattern/view/components/right-section.ts +148 -0
- package/src/apps/pattern/view/components/strand-editor/dialog.ts +79 -0
- package/src/apps/pattern/view/components/strand-editor/header-controls.ts +105 -0
- package/src/apps/pattern/view/components/strand-editor/strand-controls.ts +159 -0
- package/src/apps/pattern/view/components/terminal-modification-editor.ts +127 -0
- package/src/apps/pattern/view/components/translation-examples-block.ts +139 -0
- package/src/{view/style/pattern-app.css → apps/pattern/view/style.css} +4 -0
- package/src/apps/pattern/view/svg-utils/const.ts +77 -0
- package/src/apps/pattern/view/svg-utils/legend-block.ts +92 -0
- package/src/apps/pattern/view/svg-utils/strands-block.ts +335 -0
- package/src/apps/pattern/view/svg-utils/svg-block-base.ts +37 -0
- package/src/apps/pattern/view/svg-utils/svg-display-manager.ts +44 -0
- package/src/apps/pattern/view/svg-utils/svg-element-factory.ts +94 -0
- package/src/apps/pattern/view/svg-utils/svg-renderer.ts +51 -0
- package/src/apps/pattern/view/svg-utils/text-dimensions-calculator.ts +29 -0
- package/src/apps/pattern/view/svg-utils/title-block.ts +53 -0
- package/src/apps/pattern/view/svg-utils/utils.ts +37 -0
- package/src/apps/pattern/view/types.ts +14 -0
- package/src/apps/pattern/view/ui.ts +61 -0
- package/src/{model/structure-app → apps/structure/model}/mol-transformations.ts +3 -3
- package/src/{model/structure-app → apps/structure/model}/monomer-code-parser.ts +9 -10
- package/src/{model/structure-app → apps/structure/model}/oligo-structure.ts +4 -4
- package/src/{model/structure-app → apps/structure/model}/sequence-to-molfile.ts +2 -2
- package/src/{view/apps/oligo-structure.ts → apps/structure/view/ui.ts} +31 -17
- package/src/{model/translator-app → apps/translator/model}/conversion-utils.ts +25 -7
- package/src/{model/translator-app → apps/translator/model}/format-converter.ts +7 -12
- package/src/{view/const/oligo-translator.ts → apps/translator/view/const.ts} +1 -1
- package/src/{view/apps/oligo-translator.ts → apps/translator/view/ui.ts} +88 -42
- package/src/demo/demo-st-ui.ts +12 -32
- package/src/package.ts +91 -55
- package/src/plugins/mermade.ts +9 -9
- package/src/polytool/const.ts +28 -0
- package/src/polytool/csv-to-json-monomer-lib-converter.ts +40 -0
- package/src/polytool/cyclized.ts +56 -0
- package/src/polytool/monomer-lib-handler.ts +115 -0
- package/src/polytool/pt-conversion.ts +307 -0
- package/src/polytool/pt-dialog.ts +115 -0
- package/src/polytool/pt-enumeration.ts +127 -0
- package/src/polytool/pt-rules.ts +73 -0
- package/src/polytool/utils.ts +27 -0
- package/src/tests/const.ts +5 -5
- package/src/tests/formats-support.ts +6 -6
- package/src/tests/formats-to-helm.ts +5 -5
- package/src/tests/helm-to-nucleotides.ts +5 -10
- package/tsconfig.json +3 -9
- package/webpack.config.js +3 -0
- package/files/axolabs-style.json +0 -97
- package/src/model/data-loading-utils/json-loader.ts +0 -38
- package/src/model/pattern-app/const.ts +0 -33
- package/src/model/pattern-app/draw-svg.ts +0 -193
- package/src/model/pattern-app/helpers.ts +0 -96
- package/src/model/pattern-app/oligo-pattern.ts +0 -111
- package/src/view/app-ui.ts +0 -193
- package/src/view/apps/oligo-pattern.ts +0 -759
- /package/src/{model → apps/common/model}/helpers.ts +0 -0
- /package/src/{model → apps/common/model}/monomer-lib/const.ts +0 -0
- /package/src/{view/utils → apps/common/view/components}/app-info-dialog.ts +0 -0
- /package/src/{view/utils → apps/common/view/components}/colored-input/input-painters.ts +0 -0
- /package/src/{view/style/colored-text-input.css → apps/common/view/components/colored-input/style.css} +0 -0
- /package/src/{view/utils → apps/common/view/components}/router.ts +0 -0
- /package/src/{model/structure-app → apps/structure/model}/const.ts +0 -0
- /package/src/{view/style/structure-app.css → apps/structure/view/style.css} +0 -0
- /package/src/{model/translator-app → apps/translator/model}/const.ts +0 -0
- /package/src/{view/style/translator-app.css → apps/translator/view/style.css} +0 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Axolabs": {
|
|
3
|
+
"RNA": {
|
|
4
|
+
"color": "rgb(255,230,153)",
|
|
5
|
+
"substitution": "$1"
|
|
6
|
+
},
|
|
7
|
+
"DNA": {
|
|
8
|
+
"color": "rgb(66, 120, 245)",
|
|
9
|
+
"substitution": "d$1"
|
|
10
|
+
},
|
|
11
|
+
"2'-Fluoro": {
|
|
12
|
+
"color": "rgb(95, 212, 245)",
|
|
13
|
+
"substitution": "$1f"
|
|
14
|
+
},
|
|
15
|
+
"2'-O-Methyl": {
|
|
16
|
+
"color": "rgb(150, 95, 245)",
|
|
17
|
+
"substitution": "$1f"
|
|
18
|
+
},
|
|
19
|
+
"2'-O-MOE": {
|
|
20
|
+
"color": "rgb(129, 199, 130)",
|
|
21
|
+
"substitution": "$1m"
|
|
22
|
+
},
|
|
23
|
+
"GNA": {
|
|
24
|
+
"color": "rgb(199, 169, 129)",
|
|
25
|
+
"substitution": "(GNA-$1)"
|
|
26
|
+
},
|
|
27
|
+
"LNA": {
|
|
28
|
+
"color": "rgb(250, 185, 182)",
|
|
29
|
+
"substitution": "$1b"
|
|
30
|
+
},
|
|
31
|
+
"UNA": {
|
|
32
|
+
"color": "rgb(237, 104, 184)",
|
|
33
|
+
"substitution": "$1o"
|
|
34
|
+
},
|
|
35
|
+
"A": {
|
|
36
|
+
"color": "rgb(255,230,153)",
|
|
37
|
+
"substitution": "A"
|
|
38
|
+
},
|
|
39
|
+
"C": {
|
|
40
|
+
"color": "rgb(255,230,153)",
|
|
41
|
+
"substitution": "C"
|
|
42
|
+
},
|
|
43
|
+
"G": {
|
|
44
|
+
"color": "rgb(255,230,153)",
|
|
45
|
+
"substitution": "G"
|
|
46
|
+
},
|
|
47
|
+
"U": {
|
|
48
|
+
"color": "rgb(255,230,153)",
|
|
49
|
+
"substitution": "U"
|
|
50
|
+
},
|
|
51
|
+
"X-New": {
|
|
52
|
+
"color": "rgb(196, 91, 252)",
|
|
53
|
+
"substitution": "X"
|
|
54
|
+
},
|
|
55
|
+
"Y-New": {
|
|
56
|
+
"color": "rgb(150, 177, 255)",
|
|
57
|
+
"substitution": "Y"
|
|
58
|
+
},
|
|
59
|
+
"Z-New": {
|
|
60
|
+
"color": "rgb(11, 222, 71)",
|
|
61
|
+
"substitution": "Z"
|
|
62
|
+
},
|
|
63
|
+
"invAb": {
|
|
64
|
+
"color": "rgb(243, 153, 247)",
|
|
65
|
+
"substitution": "(invAb)"
|
|
66
|
+
},
|
|
67
|
+
"5'-vinylps": {
|
|
68
|
+
"color": "rgb(99, 3, 40)",
|
|
69
|
+
"substitution": "(vinu)"
|
|
70
|
+
},
|
|
71
|
+
"invAb(o)": {
|
|
72
|
+
"color": "rgb(240, 224, 108)",
|
|
73
|
+
"substitution": "(invAb)"
|
|
74
|
+
},
|
|
75
|
+
"2'-OMe-U(o)": {
|
|
76
|
+
"color": "rgb(190, 237, 123)",
|
|
77
|
+
"substitution": "mU"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrok/sequence-translator",
|
|
3
3
|
"friendlyName": "Sequence Translator",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.3.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Alexey Choposky",
|
|
7
7
|
"email": "achopovsky@datagrok.ai"
|
|
@@ -13,39 +13,46 @@
|
|
|
13
13
|
"directory": "packages/SequenceTranslator"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@datagrok-libraries/bio": "^5.
|
|
17
|
-
"@datagrok-libraries/chem-meta": "^1.
|
|
18
|
-
"@datagrok-libraries/tutorials": "^1.3.
|
|
19
|
-
"@datagrok-libraries/utils": "^1.
|
|
16
|
+
"@datagrok-libraries/bio": "^5.41.9",
|
|
17
|
+
"@datagrok-libraries/chem-meta": "^1.2.3",
|
|
18
|
+
"@datagrok-libraries/tutorials": "^1.3.12",
|
|
19
|
+
"@datagrok-libraries/utils": "^4.1.45",
|
|
20
20
|
"@types/react": "^18.0.15",
|
|
21
21
|
"cash-dom": "^8.1.0",
|
|
22
|
-
"datagrok-api": "^1.
|
|
22
|
+
"datagrok-api": "^1.18.6",
|
|
23
|
+
"lodash": "^4.17.21",
|
|
24
|
+
"object-hash": "^3.0.0",
|
|
23
25
|
"openchemlib": "6.0.1",
|
|
24
26
|
"save-svg-as-png": "^1.4.17",
|
|
25
27
|
"ts-loader": "^9.3.1",
|
|
26
|
-
"typescript": "^4.
|
|
28
|
+
"typescript": "^5.4.2",
|
|
29
|
+
"typeahead-standalone": "4.14.1"
|
|
27
30
|
},
|
|
28
31
|
"devDependencies": {
|
|
29
|
-
"@datagrok/bio": "^2.
|
|
30
|
-
"@datagrok/chem": "1.
|
|
32
|
+
"@datagrok/bio": "^2.12.0",
|
|
33
|
+
"@datagrok/chem": "1.9.0",
|
|
31
34
|
"@types/jquery": "^3.5.14",
|
|
32
35
|
"@types/js-yaml": "^4.0.5",
|
|
36
|
+
"@types/lodash": "^4.14.202",
|
|
33
37
|
"@types/node-fetch": "^2.6.2",
|
|
38
|
+
"@types/object-hash": "^3.0.6",
|
|
34
39
|
"@types/react": "^18.0.15",
|
|
35
|
-
"@typescript-eslint/eslint-plugin": "
|
|
36
|
-
"@typescript-eslint/parser": "
|
|
40
|
+
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
|
41
|
+
"@typescript-eslint/parser": "^7.2.0",
|
|
37
42
|
"css-loader": "^6.7.3",
|
|
38
|
-
"eslint": "^
|
|
43
|
+
"eslint": "^8.57.0",
|
|
39
44
|
"eslint-config-google": "latest",
|
|
40
45
|
"style-loader": "^3.3.1",
|
|
41
46
|
"ts-loader": "^9.3.1",
|
|
42
47
|
"typescript": "^4.7.4",
|
|
48
|
+
"typescript-eslint": "^7.2.0",
|
|
43
49
|
"webpack": "^5.75.0",
|
|
44
50
|
"webpack-cli": "latest"
|
|
45
51
|
},
|
|
46
52
|
"scripts": {
|
|
47
53
|
"link-api": "npm link datagrok-api",
|
|
48
|
-
"link-
|
|
54
|
+
"link-bio": "npm link @datagrok-libraries/bio",
|
|
55
|
+
"link-all": "npm link @datagrok-libraries/chem-meta datagrok-api @datagrok-libraries/utils @datagrok-libraries/bio @datagrok-libraries/tutorials",
|
|
49
56
|
"debug-sequencetranslator": "grok publish",
|
|
50
57
|
"release-sequencetranslator": "grok publish localhost --release",
|
|
51
58
|
"build-sequencetranslator": "webpack",
|
|
@@ -58,7 +65,8 @@
|
|
|
58
65
|
"lint-fix": "eslint \"./src/**/*.ts\" --fix",
|
|
59
66
|
"test": "grok test",
|
|
60
67
|
"test-dev": "grok test --host dev",
|
|
61
|
-
"test-local": "grok test --host localhost"
|
|
68
|
+
"test-local": "grok test --host localhost",
|
|
69
|
+
"build-all": "npm --prefix ./../../libraries/chem-meta run build && npm --prefix ./../../js-api run build && npm --prefix ./../../libraries/utils run build && npm --prefix ./../../libraries/bio run build && npm --prefix ./../../libraries/tutorials run build && npm run build"
|
|
62
70
|
},
|
|
63
71
|
"canEdit": [
|
|
64
72
|
"Developers"
|
|
@@ -3,7 +3,7 @@ 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
|
-
export const NUCLEOTIDES = ['A', 'G', 'C', 'U'
|
|
6
|
+
export const NUCLEOTIDES = ['A', 'G', 'C', 'U'];
|
|
7
7
|
|
|
8
8
|
export const TECHNOLOGIES = {
|
|
9
9
|
DNA: 'DNA',
|
|
@@ -2,7 +2,12 @@ export const LIB_PATH = 'System:AppData/SequenceTranslator';
|
|
|
2
2
|
export const DEFAULT_LIB_FILENAME = 'monomer-lib.json';
|
|
3
3
|
|
|
4
4
|
export const APP_PATH = 'System:AppData/SequenceTranslator';
|
|
5
|
-
export const
|
|
5
|
+
export const PATTERN_APP_DATA_FILENAME = 'pattern-app-data.json';
|
|
6
6
|
export const CODES_TO_HELM_DICT_FILENAME = 'formats-to-helm.json';
|
|
7
7
|
export const CODES_TO_SYMBOLS_FILENAME = 'codes-to-symbols.json';
|
|
8
|
-
export const
|
|
8
|
+
export const MONOMERS_WITH_PHOSPHATE_FILENAME = 'linkers.json';
|
|
9
|
+
|
|
10
|
+
export const enum MODIFICATION_DATA_FIELDS {
|
|
11
|
+
COLOR = 'color',
|
|
12
|
+
SUBSTITUTION = 'substitution',
|
|
13
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/* Do not change these import lines to match external modules in webpack configuration */
|
|
2
|
+
import * as DG from 'datagrok-api/dg';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
APP_PATH, PATTERN_APP_DATA_FILENAME, CODES_TO_HELM_DICT_FILENAME,
|
|
6
|
+
CODES_TO_SYMBOLS_FILENAME, MONOMERS_WITH_PHOSPHATE_FILENAME
|
|
7
|
+
} from './const';
|
|
8
|
+
import {PatternAppData, CodeToSymbol, FormatToHELMDict} from './types';
|
|
9
|
+
|
|
10
|
+
const fileSource = new DG.FileSource(APP_PATH);
|
|
11
|
+
|
|
12
|
+
export let PATTERN_APP_DATA: PatternAppData;
|
|
13
|
+
export let CODES_TO_HELM_DICT: FormatToHELMDict;
|
|
14
|
+
export let CODES_TO_SYMBOLS_DICT: CodeToSymbol;
|
|
15
|
+
export let MONOMERS_WITH_PHOSPHATE: {[key: string]: string[]};
|
|
16
|
+
|
|
17
|
+
export async function loadJsonData(): Promise<void> {
|
|
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
|
+
];
|
|
24
|
+
|
|
25
|
+
[
|
|
26
|
+
PATTERN_APP_DATA,
|
|
27
|
+
CODES_TO_HELM_DICT,
|
|
28
|
+
CODES_TO_SYMBOLS_DICT,
|
|
29
|
+
MONOMERS_WITH_PHOSPHATE
|
|
30
|
+
] = await Promise.all(
|
|
31
|
+
jsonFileNames.map((fileName) => loadAndParseJson(fileName))
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function loadAndParseJson(filePath: string): Promise<any> {
|
|
36
|
+
try {
|
|
37
|
+
const content = await fileSource.readAsText(filePath);
|
|
38
|
+
return JSON.parse(content);
|
|
39
|
+
} catch (err) {
|
|
40
|
+
console.error(`Error loading json from ${filePath}:`, err);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
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
|
+
}
|
|
@@ -1,15 +1,22 @@
|
|
|
1
|
+
import {MODIFICATION_DATA_FIELDS as F} from './const';
|
|
2
|
+
|
|
1
3
|
type KeyToValue = {[key: string]: string};
|
|
2
4
|
|
|
3
5
|
export type Edges = {
|
|
4
6
|
[key: string]: KeyToValue
|
|
5
7
|
}
|
|
6
8
|
|
|
7
|
-
export type
|
|
8
|
-
[
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
export type ModificationData = {
|
|
10
|
+
[F.COLOR]: string,
|
|
11
|
+
[F.SUBSTITUTION]: string,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type ModificationEntry = {
|
|
15
|
+
[modification: string]: ModificationData
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type PatternAppData = {
|
|
19
|
+
[format: string]: ModificationEntry
|
|
13
20
|
};
|
|
14
21
|
|
|
15
22
|
export type CodesInfo = {
|
|
@@ -1,16 +1,13 @@
|
|
|
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';
|
|
4
1
|
import * as DG from 'datagrok-api/dg';
|
|
5
2
|
|
|
6
|
-
import {_package} from '
|
|
3
|
+
import {_package} from '../../../../package';
|
|
7
4
|
import {DEFAULT_FORMATS} from '../const';
|
|
8
5
|
|
|
9
6
|
import {IMonomerLib, Monomer} from '@datagrok-libraries/bio/src/types';
|
|
7
|
+
import {HELM_REQUIRED_FIELD as REQ, HELM_OPTIONAL_FIELDS as OPT} from '@datagrok-libraries/bio/src/utils/const';
|
|
10
8
|
|
|
11
|
-
import {HELM_REQUIRED_FIELDS as REQ, HELM_OPTIONAL_FIELDS as OPT} from '@datagrok-libraries/bio/src/utils/const';
|
|
12
9
|
import {META_FIELDS as MET} from './const';
|
|
13
|
-
import {
|
|
10
|
+
import {CODES_TO_SYMBOLS_DICT} from '../data-loader/json-loader';
|
|
14
11
|
|
|
15
12
|
export class MonomerLibWrapper {
|
|
16
13
|
private constructor() {
|
|
@@ -34,10 +31,10 @@ export class MonomerLibWrapper {
|
|
|
34
31
|
formats.forEach((format) => {
|
|
35
32
|
if (format === DEFAULT_FORMATS.HELM)
|
|
36
33
|
return;
|
|
37
|
-
const map =
|
|
34
|
+
const map = CODES_TO_SYMBOLS_DICT[format];
|
|
38
35
|
const codes = Object.keys(map).filter((code) => map[code] === sourceObj.symbol);
|
|
39
36
|
formattedObject[format] = codes.join(', ');
|
|
40
|
-
})
|
|
37
|
+
});
|
|
41
38
|
|
|
42
39
|
return formattedObject;
|
|
43
40
|
}
|
|
@@ -88,15 +85,15 @@ export class MonomerLibWrapper {
|
|
|
88
85
|
}
|
|
89
86
|
|
|
90
87
|
getCodeToSymbolMap(format: string): Map<string, string> {
|
|
91
|
-
return new Map<string, string>(Object.entries(
|
|
88
|
+
return new Map<string, string>(Object.entries(CODES_TO_SYMBOLS_DICT[format]));
|
|
92
89
|
}
|
|
93
90
|
|
|
94
91
|
getCodesByFormat(format: string): string[] {
|
|
95
|
-
return Object.keys(
|
|
92
|
+
return Object.keys(CODES_TO_SYMBOLS_DICT[format]);
|
|
96
93
|
}
|
|
97
94
|
|
|
98
95
|
getAllFormats(): string[] {
|
|
99
|
-
return Object.keys(
|
|
96
|
+
return Object.keys(CODES_TO_SYMBOLS_DICT);
|
|
100
97
|
}
|
|
101
98
|
|
|
102
99
|
getTableForViewer(): DG.DataFrame {
|
|
@@ -107,7 +104,7 @@ export class MonomerLibWrapper {
|
|
|
107
104
|
|
|
108
105
|
getCodesToWeightsMap(): Map<string, number> {
|
|
109
106
|
const codesToWeightsMap = new Map<string, number>();
|
|
110
|
-
Object.entries(
|
|
107
|
+
Object.entries(CODES_TO_SYMBOLS_DICT).forEach(([_, dict]) => {
|
|
111
108
|
Object.entries(dict).forEach(([code, monomerSymbol]) => {
|
|
112
109
|
const monomer = this.getMonomer(monomerSymbol);
|
|
113
110
|
const weight = monomer[OPT.META]?.[MET.MOLWEIGHT];
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as DG from 'datagrok-api/dg';
|
|
2
|
+
|
|
3
|
+
import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
4
|
+
import {IMonomerLib} from '@datagrok-libraries/bio/src/types';
|
|
5
|
+
|
|
6
|
+
import {APP_NAME} from '../view/const';
|
|
7
|
+
import {DEFAULT_LIB_FILENAME, LIB_PATH} from './data-loader/const';
|
|
8
|
+
import {tryCatch} from './helpers';
|
|
9
|
+
|
|
10
|
+
export class OligoToolkitPackage extends DG.Package {
|
|
11
|
+
private _monomerLib?: IMonomerLib;
|
|
12
|
+
|
|
13
|
+
get monomerLib(): IMonomerLib {
|
|
14
|
+
if (!this._monomerLib)
|
|
15
|
+
throw new Error('Monomer lib not loaded');
|
|
16
|
+
return this._monomerLib!;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async initMonomerLib(): Promise<void> {
|
|
20
|
+
if (this._monomerLib !== undefined)
|
|
21
|
+
return;
|
|
22
|
+
|
|
23
|
+
const pi: DG.TaskBarProgressIndicator = DG.TaskBarProgressIndicator.create(
|
|
24
|
+
`Initializing ${APP_NAME.COMBINED} monomer library ...`);
|
|
25
|
+
await tryCatch(async () => {
|
|
26
|
+
const libHelper: IMonomerLibHelper = await getMonomerLibHelper();
|
|
27
|
+
this._monomerLib = await libHelper.readLibrary(LIB_PATH, DEFAULT_LIB_FILENAME);
|
|
28
|
+
}, () => pi.close());
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -6,13 +6,13 @@ 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
|
-
import {
|
|
9
|
+
import {CODES_TO_HELM_DICT} from '../data-loader/json-loader';
|
|
10
10
|
import {SequenceValidator} from './sequence-validator';
|
|
11
11
|
|
|
12
12
|
export class FormatDetector {
|
|
13
|
-
constructor
|
|
13
|
+
constructor(private sequence: string) {
|
|
14
14
|
this.libWrapper = MonomerLibWrapper.getInstance();
|
|
15
|
-
this.formats = Object.keys(
|
|
15
|
+
this.formats = Object.keys(CODES_TO_HELM_DICT);
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
private libWrapper: MonomerLibWrapper;
|
|
@@ -39,9 +39,9 @@ export class FormatDetector {
|
|
|
39
39
|
// todo: rename
|
|
40
40
|
private getListOfPossibleSynthesizersByFirstMatchedCode(): string[] {
|
|
41
41
|
const sequence = this.sequence;
|
|
42
|
-
|
|
42
|
+
const synthesizers: string[] = [];
|
|
43
43
|
for (const format of this.formats) {
|
|
44
|
-
|
|
44
|
+
const codes = sortByReverseLength(this.libWrapper.getCodesByFormat(format));
|
|
45
45
|
let start = 0;
|
|
46
46
|
for (let i = 0; i < sequence.length; i++) {
|
|
47
47
|
if (sequence[i] === ')' && i !== sequence.length - 1) {
|
|
@@ -3,10 +3,10 @@ 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 {
|
|
7
|
-
import {CodesInfo} from '../data-
|
|
6
|
+
import {CODES_TO_HELM_DICT} from '../data-loader/json-loader';
|
|
7
|
+
import {CodesInfo} from '../data-loader/types';
|
|
8
8
|
import {DEFAULT_FORMATS} from '../const';
|
|
9
|
-
import {GROUP_TYPE, PHOSPHATE_SYMBOL} from '
|
|
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
|
|
|
@@ -34,7 +34,7 @@ export class FormatHandler {
|
|
|
34
34
|
getHelmToFormatDict(format: string): {[key: string]: string} {
|
|
35
35
|
this.validateFormat(format);
|
|
36
36
|
|
|
37
|
-
const codesInfoObject =
|
|
37
|
+
const codesInfoObject = CODES_TO_HELM_DICT[format] as CodesInfo;
|
|
38
38
|
const dict = getHelmToCodeDict(codesInfoObject);
|
|
39
39
|
return dict;
|
|
40
40
|
}
|
|
@@ -42,7 +42,7 @@ export class FormatHandler {
|
|
|
42
42
|
getFormatToHelmDict(format: string): {[key: string]: string} {
|
|
43
43
|
this.validateFormat(format);
|
|
44
44
|
|
|
45
|
-
const codesInfoObject =
|
|
45
|
+
const codesInfoObject = CODES_TO_HELM_DICT[format] as CodesInfo;
|
|
46
46
|
const dict = Object.assign({}, ...Object.values(codesInfoObject)) as {[code: string]: string};
|
|
47
47
|
return dict;
|
|
48
48
|
}
|
|
@@ -75,7 +75,7 @@ export class FormatHandler {
|
|
|
75
75
|
getPhosphateHelmCodesRegExp(format: string): RegExp {
|
|
76
76
|
this.validateFormat(format);
|
|
77
77
|
|
|
78
|
-
const codesInfoObject =
|
|
78
|
+
const codesInfoObject = CODES_TO_HELM_DICT[format] as CodesInfo;
|
|
79
79
|
const phosphateHELMCodes = Array.from(
|
|
80
80
|
new Set(Object.values(codesInfoObject[GROUP_TYPE.LINKAGE]))
|
|
81
81
|
).sort(inverseLengthComparator);
|
|
@@ -89,7 +89,7 @@ export class FormatHandler {
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
private getFormats(): string[] {
|
|
92
|
-
return Object.keys(
|
|
92
|
+
return Object.keys(CODES_TO_HELM_DICT);
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
private validateFormat(format: string) {
|
|
@@ -106,7 +106,7 @@ export class FormatHandler {
|
|
|
106
106
|
const formatCodes = Object.keys(dict).sort(inverseLengthComparator);
|
|
107
107
|
return formatCodes;
|
|
108
108
|
}
|
|
109
|
-
|
|
109
|
+
|
|
110
110
|
private getNonHelmFormatRegExp(format: string): RegExp {
|
|
111
111
|
const formatCodes = this.getCodesByFormat(format);
|
|
112
112
|
const formatRegExp = new RegExp(getRegExpPattern(formatCodes) + '|\\([^()]*\\)|.', 'g'); // the added group before '|.' is to avoid mismatch inside parenths
|
|
@@ -116,14 +116,14 @@ export class FormatHandler {
|
|
|
116
116
|
|
|
117
117
|
export function getRegExpPattern(arr: string[]): string {
|
|
118
118
|
const negativeLookBehind = '(?<!\\([^()]*)'; // not '(' followed by non-parenths
|
|
119
|
-
const negativeLookAhead = '(?![^()]*\\))';
|
|
119
|
+
const negativeLookAhead = '(?![^()]*\\))'; // not ')' preceded by non-parenths
|
|
120
120
|
const escaped = arr.map((key) => key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
|
|
121
121
|
.map((key) => {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const result =
|
|
122
|
+
if (!key.includes('(') && !key.includes(')'))
|
|
123
|
+
return `${negativeLookBehind}${key}${negativeLookAhead}`;
|
|
124
|
+
return key;
|
|
125
|
+
});
|
|
126
|
+
const result = escaped.join('|');
|
|
127
127
|
return result;
|
|
128
128
|
}
|
|
129
129
|
|
|
@@ -132,16 +132,15 @@ function getHelmToCodeDict(infoObj: CodesInfo) {
|
|
|
132
132
|
Object.values(infoObj).forEach((obj: {[code: string]: string}) => {
|
|
133
133
|
Object.entries(obj).forEach(([code, helm]) => {
|
|
134
134
|
const key = helm.replace(/\)p/g, ')').replace(/\]p/g, ']');
|
|
135
|
-
if (result[key] === undefined)
|
|
135
|
+
if (result[key] === undefined)
|
|
136
136
|
result[key] = [code];
|
|
137
|
-
|
|
137
|
+
else
|
|
138
138
|
(result[key] as string[]).push(code);
|
|
139
|
-
|
|
140
|
-
})
|
|
139
|
+
});
|
|
141
140
|
});
|
|
142
141
|
Object.entries(result).forEach(([key, value]) => {
|
|
143
142
|
const sorted = (value as string[]).sort(inverseLengthComparator);
|
|
144
143
|
result[key] = sorted[0] as string;
|
|
145
|
-
})
|
|
144
|
+
});
|
|
146
145
|
return result as {[key: string]: string};
|
|
147
146
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/* Do not change these import lines to match external modules in webpack configuration */
|
|
2
|
+
import * as DG from 'datagrok-api/dg';
|
|
3
|
+
import * as grok from 'datagrok-api/grok';
|
|
4
|
+
import * as ui from 'datagrok-api/ui';
|
|
5
|
+
|
|
6
|
+
export abstract class AppUIBase {
|
|
7
|
+
constructor(protected appName: string, protected parentAppName?: string) { }
|
|
8
|
+
protected abstract constructView(): Promise<DG.ViewBase>;
|
|
9
|
+
|
|
10
|
+
async getAppView(): Promise<DG.ViewBase> {
|
|
11
|
+
const progressIndicator: DG.TaskBarProgressIndicator =
|
|
12
|
+
DG.TaskBarProgressIndicator.create(`Loading ${this.appName}...`);
|
|
13
|
+
|
|
14
|
+
const currentView = grok.shell.v?.root;
|
|
15
|
+
if (currentView)
|
|
16
|
+
ui.setUpdateIndicator(currentView, true);
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const view = await this.constructView();
|
|
20
|
+
return view;
|
|
21
|
+
} finally {
|
|
22
|
+
progressIndicator.close();
|
|
23
|
+
if (currentView)
|
|
24
|
+
ui.setUpdateIndicator(currentView, false);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/* Do not change these import lines to match external modules in webpack configuration */
|
|
2
|
+
import * as DG from 'datagrok-api/dg';
|
|
3
|
+
import * as grok from 'datagrok-api/grok';
|
|
4
|
+
|
|
5
|
+
import {_package} from '../../../package';
|
|
6
|
+
import {OligoPatternUI} from '../../pattern/view/ui';
|
|
7
|
+
import {OligoStructureUI} from '../../structure/view/ui';
|
|
8
|
+
import {OligoTranslatorUI} from '../../translator/view/ui';
|
|
9
|
+
import {AppUIBase} from './app-ui-base';
|
|
10
|
+
import {IsolatedAppUIBase} from './isolated-app-ui';
|
|
11
|
+
import {APP_NAME, TAB_NAME} from './const';
|
|
12
|
+
|
|
13
|
+
type ViewFactories = {[name: string]: () => DG.View};
|
|
14
|
+
|
|
15
|
+
export class CombinedAppUI extends AppUIBase {
|
|
16
|
+
constructor(externalViewFactories: ViewFactories) {
|
|
17
|
+
super(APP_NAME.COMBINED);
|
|
18
|
+
this.externalViewFactories = externalViewFactories;
|
|
19
|
+
const factories = this.getViewFactories();
|
|
20
|
+
this.multiView = new DG.MultiView({viewFactories: factories});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
private multiView: DG.MultiView;
|
|
24
|
+
private externalViewFactories?: ViewFactories;
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
private getViewFactories(): ViewFactories {
|
|
28
|
+
function viewFactory(UiConstructor: new (view: DG.View) => IsolatedAppUIBase): () => DG.View {
|
|
29
|
+
const view = DG.View.create();
|
|
30
|
+
const translateUI = new UiConstructor(view);
|
|
31
|
+
translateUI.initView().catch(
|
|
32
|
+
(e) => console.error(`Failed to initialize ${UiConstructor.name}: ${e}`)
|
|
33
|
+
);
|
|
34
|
+
return () => translateUI.getView();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let result: {[key: string]: () => DG.View } = {
|
|
38
|
+
[TAB_NAME.TRANSLATOR]: viewFactory(OligoTranslatorUI),
|
|
39
|
+
[TAB_NAME.PATTERN]: viewFactory(OligoPatternUI),
|
|
40
|
+
[TAB_NAME.STRUCTURE]: viewFactory(OligoStructureUI),
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
if (this.externalViewFactories)
|
|
44
|
+
result = Object.assign({}, result, this.externalViewFactories);
|
|
45
|
+
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private getCurrentPanePath(): string {
|
|
50
|
+
let name = this.multiView.tabs.currentPane.name;
|
|
51
|
+
name = name.charAt(0).toUpperCase() + name.substring(1).toLowerCase();
|
|
52
|
+
const path = `/apps/${_package.name}/OligoToolkit/${name}`;
|
|
53
|
+
return path;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private setUrl(): void {
|
|
57
|
+
this.multiView.path = this.getCurrentPanePath();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
protected async constructView(): Promise<DG.ViewBase> {
|
|
61
|
+
this.multiView.tabs.onTabChanged.subscribe(() => this.setUrl());
|
|
62
|
+
this.setUrl();
|
|
63
|
+
return this.multiView;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
@@ -6,7 +6,7 @@ import {errorToConsole} from '@datagrok-libraries/utils/src/to-console';
|
|
|
6
6
|
|
|
7
7
|
import $ from 'cash-dom';
|
|
8
8
|
|
|
9
|
-
import {extractAtomDataV3000} from '
|
|
9
|
+
import {extractAtomDataV3000} from '../../../structure/model/mol-transformations';
|
|
10
10
|
|
|
11
11
|
/** Draw molecule on the canvas and append it to the specified div, with the
|
|
12
12
|
* option of zoom-in */
|
|
@@ -64,7 +64,7 @@ export class MoleculeImage {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
private async zoomIn(): Promise<void> {
|
|
67
|
-
const dialog = ui.dialog({title: 'Molecule', showFooter:false});
|
|
67
|
+
const dialog = ui.dialog({title: 'Molecule', showFooter: false});
|
|
68
68
|
const dialogDivStyle = {
|
|
69
69
|
overflowX: 'scroll',
|
|
70
70
|
};
|
|
@@ -79,7 +79,7 @@ export class MoleculeImage {
|
|
|
79
79
|
|
|
80
80
|
const dialogCanvas = ui.canvas(dialogCanvasWidth, dialogCanvasHeight);
|
|
81
81
|
await this.drawMolBlockOnCanvas(dialogCanvas);
|
|
82
|
-
|
|
82
|
+
|
|
83
83
|
const dialogDiv = ui.block([dialogCanvas], {style: dialogDivStyle});
|
|
84
84
|
dialog.add(dialogDiv).showModal(true);
|
|
85
85
|
|
|
@@ -117,6 +117,6 @@ export class MoleculeImage {
|
|
|
117
117
|
//$(canvas).on('mouseover', () => $(canvas).css('cursor', 'grab')); // for some reason 'zoom-in' value wouldn't work
|
|
118
118
|
//$(canvas).on('mouseout', () => $(canvas).css('cursor', 'default'));
|
|
119
119
|
|
|
120
|
-
moleculeImgDiv.append(ui.tooltip.bind(canvas,'Click to zoom'));
|
|
120
|
+
moleculeImgDiv.append(ui.tooltip.bind(canvas, 'Click to zoom'));
|
|
121
121
|
}
|
|
122
122
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
export const enum
|
|
1
|
+
export const enum TAB_NAME {
|
|
2
2
|
TRANSLATOR = 'TRANSLATOR',
|
|
3
3
|
PATTERN = 'PATTERN',
|
|
4
|
-
|
|
4
|
+
STRUCTURE = 'STRUCTURE'
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
export const enum
|
|
7
|
+
export const enum APP_NAME {
|
|
8
8
|
COMBINED = 'Oligo Toolkit',
|
|
9
9
|
TRANSLATOR = 'Oligo Translator',
|
|
10
10
|
PATTERN = 'Oligo Pattern',
|
|
11
|
-
|
|
11
|
+
STRUCTURE = 'Oligo Structure',
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export const DEFAULT_AXOLABS_INPUT = 'Afcgacsu';
|