@datagrok/helm 2.1.29 → 2.1.31
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 +2 -2
- package/CHANGELOG.md +14 -1
- package/dist/package-test.js +1 -1
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/files/tests/sample_HELM-missedInLib.csv +1 -1
- package/package.json +6 -5
- package/src/cell-renderer.ts +64 -69
- package/src/helm-monomer-placer.ts +1 -0
- package/src/package.ts +17 -15
- package/src/tests/findMonomers-tests.ts +3 -2
- package/src/tests/get-molfiles.ts +3 -2
- package/src/tests/properties-widget-tests.ts +2 -2
- package/src/utils/index.ts +18 -8
- package/src/widgets/properties-widget.ts +8 -7
|
@@ -2,7 +2,7 @@ HELM,Activity
|
|
|
2
2
|
PEPTIDE1{meI.missed2.Aca.N.T.dE.Thr_PO3H2.Aca.D-Tyr_Et.Tyr_ab-dehydroMe.dV.E.N.D-Orn.D-aThr.Phe_4Me}$$$$,5.307510973968128
|
|
3
3
|
PEPTIDE1{meI.hHis.Aca.Cys_SEt.T.dK.Thr_PO3H2.Aca.Tyr_PO3H2.D-Chg.dV.Phe_ab-dehydro.N.D-Orn.D-aThr.Phe_4Me}$$$$,5.723876853431544
|
|
4
4
|
PEPTIDE1{missed1.hHis.Aca.Cys_SEt.T.dK.Thr_PO3H2.Aca.Tyr_PO3H2.D-Chg.dV.Thr_PO3H2.N.D-Orn.D-aThr.Phe_4Me}$$$$,5.185811246022437
|
|
5
|
-
PEPTIDE1{meI.
|
|
5
|
+
PEPTIDE1{meI.m0.Aca.m1.T.m2.m3.Aca.Tyr_PO3H2.D-Chg.dV.Thr_PO3H2.N.D-Orn.D-aThr.Phe_4Me}$$$$,6.223502390804369
|
|
6
6
|
,3.8459123763832412
|
|
7
7
|
PEPTIDE1{meI.hHis.Aca.N.T.dK.Thr_PO3H2.Aca.D-Tyr_Et.Tyr_Bn.dV.E.N.dV.Phe_4Me}$$$$,3.27920438824657
|
|
8
8
|
PEPTIDE1{meI.hHis.Aca.N.T.dK.Thr_PO3H2.Aca.D-Tyr_Et.Aze.dV.E.N.dV.Phe_4Me}$$$$,2.105852152992568
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrok/helm",
|
|
3
3
|
"friendlyName": "Helm",
|
|
4
|
-
"version": "2.1.
|
|
4
|
+
"version": "2.1.31",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Oleksandra Serhiienko",
|
|
7
7
|
"email": "oserhiienko@datagrok.ai"
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
"helm/JSDraw/Pistoia.HELM-uncompressed.js"
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@datagrok-libraries/bio": "^5.
|
|
19
|
-
"@datagrok-libraries/chem-meta": "^1.2.
|
|
20
|
-
"@datagrok-libraries/utils": "^4.1.
|
|
18
|
+
"@datagrok-libraries/bio": "^5.40.0",
|
|
19
|
+
"@datagrok-libraries/chem-meta": "^1.2.3",
|
|
20
|
+
"@datagrok-libraries/utils": "^4.1.45",
|
|
21
21
|
"cash-dom": "^8.1.1",
|
|
22
22
|
"datagrok-api": "^1.17.0",
|
|
23
23
|
"dayjs": "^1.10.6",
|
|
@@ -37,7 +37,8 @@
|
|
|
37
37
|
"@typescript-eslint/parser": "^5.11.0",
|
|
38
38
|
"eslint": "^8.18.0",
|
|
39
39
|
"eslint-config-google": "^0.14.0",
|
|
40
|
-
"@datagrok/bio": "^2.
|
|
40
|
+
"@datagrok/bio": "^2.12.0",
|
|
41
|
+
"@datagrok/chem": "^1.9.0"
|
|
41
42
|
},
|
|
42
43
|
"scripts": {
|
|
43
44
|
"link-all": "npm link @datagrok-libraries/chem-meta datagrok-api @datagrok-libraries/utils @datagrok-libraries/bio",
|
package/src/cell-renderer.ts
CHANGED
|
@@ -7,7 +7,7 @@ import wu from 'wu';
|
|
|
7
7
|
import {printLeftOrCentered} from '@datagrok-libraries/bio/src/utils/cell-renderer';
|
|
8
8
|
import {errorToConsole} from '@datagrok-libraries/utils/src/to-console';
|
|
9
9
|
|
|
10
|
-
import {findMonomers, parseHelm} from './utils';
|
|
10
|
+
import {findMonomers, parseHelm, removeGapsFromHelm} from './utils';
|
|
11
11
|
import {IEditor, HelmMonomerPlacer, IEditorMolAtom, ISeqMonomer} from './helm-monomer-placer';
|
|
12
12
|
import {IMonomerLib} from '@datagrok-libraries/bio/src/types/index';
|
|
13
13
|
|
|
@@ -20,11 +20,6 @@ const enum tempTAGS {
|
|
|
20
20
|
helmPlacer = 'bio-helmPlacer',
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
// Global flag is for replaceAll
|
|
24
|
-
const helmGapStartRe = /\{(\*\.)+/g;
|
|
25
|
-
const helmGapIntRe = /\.(\*\.)+/g;
|
|
26
|
-
const helmGapEndRe = /(\.\*)+\}/g;
|
|
27
|
-
|
|
28
23
|
function getSeqMonomerFromHelm(
|
|
29
24
|
helmPrefix: string, symbol: string, monomerLib: IMonomerLib
|
|
30
25
|
): ISeqMonomer {
|
|
@@ -42,16 +37,16 @@ function getSeqMonomerFromHelmAtom(atom: IEditorMolAtom): ISeqMonomer {
|
|
|
42
37
|
let polymerType: string | undefined = undefined;
|
|
43
38
|
// @ts-ignore
|
|
44
39
|
switch (atom.bio.type) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
40
|
+
case 'HELM_BASE':
|
|
41
|
+
case 'HELM_SUGAR': // r - ribose, d - deoxyribose
|
|
42
|
+
case 'HELM_LINKER': // p - phosphate
|
|
43
|
+
polymerType = 'RNA';
|
|
44
|
+
break;
|
|
45
|
+
case 'HELM_AA':
|
|
46
|
+
polymerType = 'PEPTIDE';
|
|
47
|
+
break;
|
|
48
|
+
default:
|
|
49
|
+
polymerType = 'PEPTIDE';
|
|
55
50
|
}
|
|
56
51
|
return {symbol: atom.elem, polymerType: polymerType};
|
|
57
52
|
}
|
|
@@ -163,63 +158,63 @@ export class HelmCellRenderer extends DG.GridCellRenderer {
|
|
|
163
158
|
try { tableCol = gridCell.tableColumn; } catch { }
|
|
164
159
|
if (!tableCol) return;
|
|
165
160
|
|
|
166
|
-
const
|
|
167
|
-
const
|
|
161
|
+
/** {@link gridCell}.bounds */ const gcb = gridCell.bounds;
|
|
162
|
+
const argsX = e.offsetX - gcb.x;
|
|
163
|
+
const argsY = e.offsetY - gcb.y;
|
|
168
164
|
|
|
169
165
|
const helmPlacer = HelmMonomerPlacer.getOrCreate(tableCol);
|
|
170
166
|
const editor: IEditor | null = helmPlacer.getEditor(gridCell.tableRowIndex!);
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
if (
|
|
174
|
-
|
|
175
|
-
|
|
167
|
+
let seqMonomer: ISeqMonomer | null;
|
|
168
|
+
let missedMonomers: Set<string> = new Set<string>(); // of .size = 0
|
|
169
|
+
if (editor)
|
|
170
|
+
seqMonomer = getHoveredMonomerFromEditor(argsX, argsY, gridCell, editor);
|
|
171
|
+
else {
|
|
172
|
+
const seq: string = !gridCell.cell.value ? '' : removeGapsFromHelm(gridCell.cell.value as string);
|
|
173
|
+
const monomerList = parseHelm(seq);
|
|
174
|
+
missedMonomers = findMonomers(monomerList);
|
|
175
|
+
const parsedMonomers = new Set<string>(monomerList);
|
|
176
|
+
seqMonomer = getHoveredMonomerFallback(argsX, argsY, gridCell, helmPlacer);
|
|
177
|
+
if (seqMonomer && !parsedMonomers.has(seqMonomer.symbol)) seqMonomer = null;
|
|
178
|
+
if (seqMonomer) {
|
|
179
|
+
const textSize = helmPlacer.monomerTextSizeMap[seqMonomer.symbol];
|
|
180
|
+
if (textSize) {
|
|
181
|
+
const textBaseLine = gcb.height / 2 -
|
|
182
|
+
(textSize.fontBoundingBoxAscent + textSize.fontBoundingBoxDescent) / 2 + 1;
|
|
183
|
+
const textTop = textBaseLine - textSize.fontBoundingBoxAscent;
|
|
184
|
+
const textBottom = textBaseLine + textSize.fontBoundingBoxDescent;
|
|
185
|
+
if (argsY < textTop || textBottom < argsY) seqMonomer = null;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
176
188
|
}
|
|
177
189
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const monomer = helmPlacer.getMonomer(seqMonomer);
|
|
191
|
-
if (monomer) {
|
|
192
|
-
const options = {autoCrop: true, autoCropMargin: 0, suppressChiralText: true};
|
|
193
|
-
const monomerSvg = grok.chem.svgMol(monomer.smiles, undefined, undefined, options);
|
|
190
|
+
if (seqMonomer) {
|
|
191
|
+
if (!missedMonomers.has(seqMonomer.symbol)) {
|
|
192
|
+
const monomer = helmPlacer.getMonomer(seqMonomer);
|
|
193
|
+
if (monomer) {
|
|
194
|
+
const options = {autoCrop: true, autoCropMargin: 0, suppressChiralText: true};
|
|
195
|
+
const monomerSvg = grok.chem.svgMol(monomer.smiles, undefined, undefined, options);
|
|
196
|
+
ui.tooltip.show(ui.divV([
|
|
197
|
+
ui.divText(seqMonomer.symbol),
|
|
198
|
+
monomerSvg,
|
|
199
|
+
]), e.x + 16, e.y + 16);
|
|
200
|
+
}
|
|
201
|
+
} else {
|
|
194
202
|
ui.tooltip.show(ui.divV([
|
|
195
|
-
ui.divText(seqMonomer.symbol),
|
|
196
|
-
|
|
203
|
+
ui.divText(`Monomer '${seqMonomer.symbol}' not found.`),
|
|
204
|
+
ui.divText('Open the Context Panel, then expand Manage Libraries'),
|
|
197
205
|
]), e.x + 16, e.y + 16);
|
|
198
206
|
}
|
|
207
|
+
} else if (missedMonomers.size == 0) {
|
|
208
|
+
ui.tooltip.hide();
|
|
209
|
+
return;
|
|
210
|
+
} else { // seqMonomer == null && missedMonomers.size > 0
|
|
211
|
+
const mmStrList = wu(missedMonomers.keys()).toArray().sort()
|
|
212
|
+
.filter((_, i) => i < 3);
|
|
213
|
+
const missedMonomersStr = mmStrList.join(', ') + (missedMonomers.size > 3 ? ', ...' : '');
|
|
214
|
+
ui.tooltip.show(ui.divV([ui.divText('Monomers missed in monomer libraries:'),
|
|
215
|
+
ui.divText(missedMonomersStr)
|
|
216
|
+
]), e.x + 16, e.y + 16);
|
|
199
217
|
}
|
|
200
|
-
|
|
201
|
-
// const tooltipMessage: HTMLElement[] = [];
|
|
202
|
-
// for (const [part, partI] of wu.enumerate(allParts)) {
|
|
203
|
-
// if (missedMonomers.has(part)) {
|
|
204
|
-
// tooltipMessage[partI] = ui.divV([
|
|
205
|
-
// ui.divText(`Monomer ${allParts[partI]} not found.`),
|
|
206
|
-
// ui.divText('Open the Context Panel, then expand Manage Libraries')
|
|
207
|
-
// ]);
|
|
208
|
-
// } else if (monomers.has(part)) {
|
|
209
|
-
// const elList = [ui.div(part)];
|
|
210
|
-
// const monomer = helmPlacer.getMonomer(part);
|
|
211
|
-
// if (monomer) {
|
|
212
|
-
// const options = {autoCrop: true, autoCropMargin: 0, suppressChiralText: true};
|
|
213
|
-
// const monomerSvg = grok.chem.svgMol(monomer.smiles, undefined, undefined, options);
|
|
214
|
-
// elList.push(monomerSvg);
|
|
215
|
-
// }
|
|
216
|
-
// tooltipMessage[partI] = ui.divV(elList);
|
|
217
|
-
// }
|
|
218
|
-
// }
|
|
219
|
-
//
|
|
220
|
-
// (((tooltipMessage[left]?.childNodes.length ?? 0) > 0)) ?
|
|
221
|
-
// ui.tooltip.show(tooltipMessage[left], e.x + 16, e.y + 16) :
|
|
222
|
-
// ui.tooltip.hide();
|
|
223
218
|
} catch (err: any) {
|
|
224
219
|
const errMsg: string = errorToConsole(err);
|
|
225
220
|
console.error('Helm: HelmCellRenderer.onMouseMove() error:\n' + errMsg);
|
|
@@ -245,9 +240,7 @@ export class HelmCellRenderer extends DG.GridCellRenderer {
|
|
|
245
240
|
const monomerColor: string = '#404040';
|
|
246
241
|
const frameColor: string = '#C0C0C0';
|
|
247
242
|
|
|
248
|
-
const seq: string = !gridCell.cell.value ? '' : gridCell.cell.value
|
|
249
|
-
.replaceAll(helmGapStartRe, '{').replaceAll(helmGapIntRe, '.').replaceAll(helmGapEndRe, '}')
|
|
250
|
-
.replace('{*}', '{}');
|
|
243
|
+
const seq: string = !gridCell.cell.value ? '' : removeGapsFromHelm(gridCell.cell.value);
|
|
251
244
|
const monomerList = parseHelm(seq);
|
|
252
245
|
const monomers: Set<string> = new Set<string>(monomerList);
|
|
253
246
|
const missedMonomers: Set<string> = findMonomers(monomerList);
|
|
@@ -289,7 +282,7 @@ export class HelmCellRenderer extends DG.GridCellRenderer {
|
|
|
289
282
|
g.transform(1, 0, 0, 1, x, y);
|
|
290
283
|
g.font = '12px monospace';
|
|
291
284
|
g.textBaseline = 'top';
|
|
292
|
-
const [allParts,
|
|
285
|
+
const [allParts, _lengths, sumLengths] = helmPlacer.getCellAllPartsLengths(gridCell.tableRowIndex!);
|
|
293
286
|
|
|
294
287
|
for (let i = 0; i < allParts.length; ++i) {
|
|
295
288
|
const part: string = allParts[i];
|
|
@@ -299,7 +292,9 @@ export class HelmCellRenderer extends DG.GridCellRenderer {
|
|
|
299
292
|
monomers.has(part) ? monomerColor :
|
|
300
293
|
frameColor;
|
|
301
294
|
g.fillStyle = color;
|
|
302
|
-
printLeftOrCentered(sumLengths[i], 0, w, h, g, allParts[i], color, 0, true, 1.0
|
|
295
|
+
printLeftOrCentered(sumLengths[i], 0, w, h, g, allParts[i], color, 0, true, 1.0,
|
|
296
|
+
undefined, undefined, undefined, undefined, undefined,
|
|
297
|
+
undefined, undefined, undefined, helmPlacer.monomerTextSizeMap);
|
|
303
298
|
}
|
|
304
299
|
}
|
|
305
300
|
} finally {
|
|
@@ -49,6 +49,7 @@ export class HelmMonomerPlacer {
|
|
|
49
49
|
|
|
50
50
|
public monomerCharWidth: number = 7;
|
|
51
51
|
public leftPadding: number = 5;
|
|
52
|
+
public monomerTextSizeMap: { [p: string]: TextMetrics } = {};
|
|
52
53
|
|
|
53
54
|
constructor(public readonly col: DG.Column<string>) {
|
|
54
55
|
this.col.dataFrame.onDataChanged.subscribe();
|
package/src/package.ts
CHANGED
|
@@ -7,7 +7,7 @@ import $ from 'cash-dom';
|
|
|
7
7
|
|
|
8
8
|
import {errorToConsole} from '@datagrok-libraries/utils/src/to-console';
|
|
9
9
|
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
10
|
-
import {
|
|
10
|
+
import {GapOriginals, SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
|
|
11
11
|
import {IMonomerLib, Monomer} from '@datagrok-libraries/bio/src/types';
|
|
12
12
|
import {IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
|
|
13
13
|
|
|
@@ -156,17 +156,17 @@ export function helmCellRenderer(): HelmCellRenderer {
|
|
|
156
156
|
return new HelmCellRenderer();
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
function checkMonomersAndOpenWebEditor(cell
|
|
159
|
+
function checkMonomersAndOpenWebEditor(cell: DG.Cell, value?: string, units?: string) {
|
|
160
160
|
const cellValue: string = !!cell && units === undefined ? cell.value : value;
|
|
161
161
|
const monomerList: string[] = parseHelm(cellValue);
|
|
162
|
-
const
|
|
163
|
-
if (
|
|
162
|
+
const missedMonomerSet = findMonomers(monomerList);
|
|
163
|
+
if (missedMonomerSet.size === 0)
|
|
164
164
|
webEditor(cell, value, units);
|
|
165
|
-
else if (
|
|
166
|
-
grok.shell.warning(`WebEditor doesn't support Helm with gaps '${
|
|
165
|
+
else if (missedMonomerSet.size === 1 && missedMonomerSet.has(GapOriginals[NOTATION.HELM]))
|
|
166
|
+
grok.shell.warning(`WebEditor doesn't support Helm with gaps '${GapOriginals[NOTATION.HELM]}'.`);
|
|
167
167
|
else {
|
|
168
168
|
grok.shell.warning(
|
|
169
|
-
`Monomers ${Array.from(
|
|
169
|
+
`Monomers ${Array.from(missedMonomerSet).map((m) => `'${m}'`).join(', ')} are absent! <br/>` +
|
|
170
170
|
`Please, upload the monomer library! <br/>` +
|
|
171
171
|
`<a href="https://datagrok.ai/help/domains/bio/macromolecules" target="_blank">Learn more</a>`);
|
|
172
172
|
}
|
|
@@ -187,11 +187,11 @@ export function editMoleculeCell(cell: DG.GridCell): void {
|
|
|
187
187
|
export function openEditor(mol: string): void {
|
|
188
188
|
const df = grok.shell.tv.grid.dataFrame;
|
|
189
189
|
const col = df.columns.bySemType('Macromolecule')!;
|
|
190
|
-
const
|
|
190
|
+
const colSh = SeqHandler.forColumn(col);
|
|
191
191
|
const colUnits = col.getTag(DG.TAGS.UNITS);
|
|
192
192
|
if (colUnits === NOTATION.HELM)
|
|
193
193
|
checkMonomersAndOpenWebEditor(df.currentCell, undefined, undefined);
|
|
194
|
-
const convert =
|
|
194
|
+
const convert = colSh.getConverter(NOTATION.HELM);
|
|
195
195
|
const helmMol = convert(mol);
|
|
196
196
|
checkMonomersAndOpenWebEditor(df.currentCell, helmMol, col.getTag(DG.TAGS.UNITS));
|
|
197
197
|
}
|
|
@@ -204,11 +204,13 @@ export function propertiesWidget(sequence: DG.SemanticValue): DG.Widget {
|
|
|
204
204
|
return getPropertiesWidget(sequence);
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
-
function webEditor(cell
|
|
207
|
+
function webEditor(cell: DG.Cell, value?: string, units?: string) {
|
|
208
208
|
const view = ui.div();
|
|
209
|
-
const df = grok.shell.tv.grid.dataFrame;
|
|
210
|
-
const col = df.columns.bySemType('Macromolecule')!;
|
|
211
|
-
const
|
|
209
|
+
// const df = grok.shell.tv.grid.dataFrame;
|
|
210
|
+
// const col = df.columns.bySemType('Macromolecule')!;
|
|
211
|
+
const col = cell.column;
|
|
212
|
+
const sh = SeqHandler.forColumn(col);
|
|
213
|
+
const rowIdx = cell.rowIndex;
|
|
212
214
|
// @ts-ignore
|
|
213
215
|
org.helm.webeditor.MolViewer.molscale = 0.8;
|
|
214
216
|
// @ts-ignore
|
|
@@ -244,13 +246,13 @@ function webEditor(cell?: DG.Cell, value?: string, units?: string) {
|
|
|
244
246
|
ui.dialog({showHeader: false, showFooter: true})
|
|
245
247
|
.add(view)
|
|
246
248
|
.onOK(() => {
|
|
247
|
-
const helmValue = app.canvas.getHelm(true).replace(/<\/span>/g, '')
|
|
249
|
+
const helmValue: string = app.canvas.getHelm(true).replace(/<\/span>/g, '')
|
|
248
250
|
.replace(/<span style='background:#bbf;'>/g, '');
|
|
249
251
|
if (!!cell) {
|
|
250
252
|
if (units === undefined)
|
|
251
253
|
cell.value = helmValue;
|
|
252
254
|
else {
|
|
253
|
-
const convertedRes =
|
|
255
|
+
const convertedRes = sh.convertHelmToFastaSeparator(helmValue, units!, sh.separator);
|
|
254
256
|
cell.value = convertedRes;
|
|
255
257
|
}
|
|
256
258
|
}
|
|
@@ -3,9 +3,10 @@ import * as ui from 'datagrok-api/ui';
|
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
4
|
|
|
5
5
|
import {after, before, category, delay, expect, expectObject, test} from '@datagrok-libraries/utils/src/test';
|
|
6
|
+
import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
|
|
6
7
|
import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
7
8
|
import {
|
|
8
|
-
getUserLibSettings,
|
|
9
|
+
getUserLibSettings, setUserLibSettings, setUserLibSettingsForTests
|
|
9
10
|
} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
|
|
10
11
|
|
|
11
12
|
import {findMonomers, parseHelm} from '../utils';
|
|
@@ -15,7 +16,7 @@ import {findMonomers, parseHelm} from '../utils';
|
|
|
15
16
|
category('findMonomers', () => {
|
|
16
17
|
let monomerLibHelper: IMonomerLibHelper;
|
|
17
18
|
/** Backup actual user's monomer libraries settings */
|
|
18
|
-
let userLibSettings:
|
|
19
|
+
let userLibSettings: UserLibSettings;
|
|
19
20
|
|
|
20
21
|
before(async () => {
|
|
21
22
|
monomerLibHelper = await getMonomerLibHelper();
|
|
@@ -4,8 +4,9 @@ import * as DG from 'datagrok-api/dg';
|
|
|
4
4
|
|
|
5
5
|
import {after, before, category, delay, expect, test, expectArray, testEvent} from '@datagrok-libraries/utils/src/test';
|
|
6
6
|
import {
|
|
7
|
-
getUserLibSettings,
|
|
7
|
+
getUserLibSettings, setUserLibSettings, setUserLibSettingsForTests
|
|
8
8
|
} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
|
|
9
|
+
import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
|
|
9
10
|
import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
10
11
|
import {MolfileHandler} from '@datagrok-libraries/chem-meta/src/parsing-utils/molfile-handler';
|
|
11
12
|
import {MolfileHandlerBase} from '@datagrok-libraries/chem-meta/src/parsing-utils/molfile-handler-base';
|
|
@@ -16,7 +17,7 @@ import {_package} from '../package-test';
|
|
|
16
17
|
|
|
17
18
|
category('getMolfiles', () => {
|
|
18
19
|
let monomerLibHelper: IMonomerLibHelper;
|
|
19
|
-
let userLibSettings:
|
|
20
|
+
let userLibSettings: UserLibSettings;
|
|
20
21
|
|
|
21
22
|
before(async () => {
|
|
22
23
|
monomerLibHelper = await getMonomerLibHelper();
|
|
@@ -4,7 +4,7 @@ import * as grok from 'datagrok-api/grok';
|
|
|
4
4
|
|
|
5
5
|
import {category, expect, expectObject, test} from '@datagrok-libraries/utils/src/test';
|
|
6
6
|
import {ALPHABET, NOTATION, TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
7
|
-
import {
|
|
7
|
+
import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
|
|
8
8
|
|
|
9
9
|
import {getPropertiesDict} from '../widgets/properties-widget';
|
|
10
10
|
|
|
@@ -75,7 +75,7 @@ function testPropertiesDict(
|
|
|
75
75
|
col.setTag(DG.TAGS.UNITS, units);
|
|
76
76
|
if (separator) col.setTag(bioTAGS.separator, separator);
|
|
77
77
|
if (alphabet) col.setTag(bioTAGS.alphabet, alphabet);
|
|
78
|
-
const uh =
|
|
78
|
+
const uh = SeqHandler.forColumn(col);
|
|
79
79
|
const actPropDict = getPropertiesDict(seq, uh);
|
|
80
80
|
expectObject(actPropDict, expPropDict);
|
|
81
81
|
}
|
package/src/utils/index.ts
CHANGED
|
@@ -11,6 +11,16 @@ import {
|
|
|
11
11
|
SDF_MONOMER_NAME
|
|
12
12
|
} from '../constants';
|
|
13
13
|
|
|
14
|
+
// Global flag is for replaceAll
|
|
15
|
+
const helmGapStartRe = /\{(\*\.)+/g;
|
|
16
|
+
const helmGapIntRe = /\.(\*\.)+/g;
|
|
17
|
+
const helmGapEndRe = /(\.\*)+\}/g;
|
|
18
|
+
|
|
19
|
+
export function removeGapsFromHelm(srcHelm: string): string {
|
|
20
|
+
return srcHelm.replaceAll(helmGapStartRe, '{').replaceAll(helmGapIntRe, '.')
|
|
21
|
+
.replaceAll(helmGapEndRe, '}').replace('{*}', '{}');
|
|
22
|
+
}
|
|
23
|
+
|
|
14
24
|
export function getParts(subParts: string[], s: string): string[] {
|
|
15
25
|
const j = 0;
|
|
16
26
|
const allParts: string[] = [];
|
|
@@ -226,14 +236,14 @@ function unescape(s: string) {
|
|
|
226
236
|
|
|
227
237
|
return s.replace(/[\\]./g, function(m) {
|
|
228
238
|
switch (m) {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
239
|
+
case '\\r':
|
|
240
|
+
return '\r';
|
|
241
|
+
case '\\n':
|
|
242
|
+
return '\n';
|
|
243
|
+
case '\\t':
|
|
244
|
+
return '\t';
|
|
245
|
+
default:
|
|
246
|
+
return m.substring(1);
|
|
237
247
|
}
|
|
238
248
|
});
|
|
239
249
|
}
|
|
@@ -4,14 +4,15 @@ import * as DG from 'datagrok-api/dg';
|
|
|
4
4
|
|
|
5
5
|
import $ from 'cash-dom';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
|
|
8
8
|
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
import {removeGapsFromHelm} from '../utils';
|
|
11
|
+
|
|
12
|
+
export function getPropertiesDict(seq: string, sh: SeqHandler): {} {
|
|
13
|
+
const helmString = sh.isHelm() ? seq : sh.getConverter(NOTATION.HELM)(seq);
|
|
12
14
|
// Remove gap symbols for compatibility with WebEditor
|
|
13
|
-
const helmString2 = helmString
|
|
14
|
-
.replaceAll(/\{(\*\.)+/g, '{').replaceAll(/(\.\*)+}/g, '}');
|
|
15
|
+
const helmString2 = removeGapsFromHelm(helmString);
|
|
15
16
|
|
|
16
17
|
const host = ui.div([], {style: {width: '0', height: '0'}});
|
|
17
18
|
document.documentElement.appendChild(host);
|
|
@@ -35,8 +36,8 @@ export function getPropertiesDict(seq: string, uh: UnitsHandler): {} {
|
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
export function getPropertiesWidget(value: DG.SemanticValue): DG.Widget {
|
|
38
|
-
const
|
|
39
|
-
const propDict = getPropertiesDict(value.value,
|
|
39
|
+
const sh = SeqHandler.forColumn(value.cell.column);
|
|
40
|
+
const propDict = getPropertiesDict(value.value, sh);
|
|
40
41
|
return new DG.Widget(
|
|
41
42
|
ui.tableFromMap(propDict)
|
|
42
43
|
);
|