@datagrok/bio 2.13.2 → 2.13.5
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 +26 -0
- package/detectors.js +52 -38
- package/dist/111.js +2 -0
- package/dist/111.js.map +1 -0
- package/dist/234.js +2 -0
- package/dist/234.js.map +1 -0
- package/dist/242.js +2 -0
- package/dist/242.js.map +1 -0
- package/dist/{286.js → 248.js} +1 -1
- package/dist/248.js.map +1 -0
- package/dist/284.js +3 -0
- package/dist/284.js.map +1 -0
- package/dist/317.js +2 -0
- package/dist/317.js.map +1 -0
- package/dist/589.js +2 -0
- package/dist/589.js.map +1 -0
- package/dist/603.js +2 -0
- package/dist/603.js.map +1 -0
- package/dist/682.js +2 -0
- package/dist/682.js.map +1 -0
- package/dist/705.js +2 -0
- package/dist/705.js.map +1 -0
- package/dist/{590.js → 731.js} +2 -2
- package/dist/731.js.map +1 -0
- package/dist/778.js +2 -0
- package/dist/778.js.map +1 -0
- package/dist/793.js +2 -0
- package/dist/793.js.map +1 -0
- package/dist/950.js +2 -0
- package/dist/950.js.map +1 -0
- package/dist/package-test.js +6 -7
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +6 -7
- package/dist/package.js.map +1 -1
- package/files/cache_config.json +7 -0
- package/package.json +17 -23
- package/src/analysis/sequence-activity-cliffs.ts +1 -1
- package/src/function-edtiors/split-to-monomers-editor.ts +6 -7
- package/src/package-types.ts +19 -19
- package/src/package.ts +23 -16
- package/src/substructure-search/substructure-search.ts +9 -10
- package/src/tests/WebLogo-positions-test.ts +6 -6
- package/src/tests/activity-cliffs-tests.ts +5 -2
- package/src/tests/bio-tests.ts +6 -6
- package/src/tests/checkInputColumn-tests.ts +3 -3
- package/src/tests/converters-test.ts +1 -1
- package/src/tests/detectors-tests.ts +25 -13
- package/src/tests/fasta-export-tests.ts +2 -2
- package/src/tests/mm-distance-tests.ts +1 -1
- package/src/tests/msa-tests.ts +2 -2
- package/src/tests/renderers-test.ts +5 -5
- package/src/tests/scoring.ts +26 -5
- package/src/tests/seq-handler-get-region.ts +4 -4
- package/src/tests/sequence-space-test.ts +1 -1
- package/src/tests/substructure-filters-tests.ts +4 -1
- package/src/tests/to-atomic-level-tests.ts +1 -1
- package/src/utils/cell-renderer-consts.ts +3 -11
- package/src/utils/cell-renderer.ts +15 -17
- package/src/utils/context-menu.ts +1 -1
- package/src/utils/convert.ts +7 -4
- package/src/utils/get-region-func-editor.ts +11 -16
- package/src/utils/get-region.ts +5 -5
- package/src/utils/macromolecule-column-widget.ts +1 -1
- package/src/utils/monomer-lib/lib-manager.ts +20 -8
- package/src/utils/monomer-lib/library-file-manager/file-manager.ts +28 -24
- package/src/utils/monomer-lib/library-file-manager/file-validator.ts +2 -1
- package/src/utils/monomer-lib/library-file-manager/ui.ts +3 -6
- package/src/utils/multiple-sequence-alignment-ui.ts +10 -11
- package/src/utils/multiple-sequence-alignment.ts +2 -2
- package/src/utils/pepsea.ts +1 -1
- package/src/utils/save-as-fasta.ts +5 -5
- package/src/viewers/vd-regions-viewer.ts +2 -2
- package/src/widgets/bio-substructure-filter.ts +7 -7
- package/src/widgets/package-settings-editor-widget.ts +27 -27
- package/src/widgets/representations.ts +57 -61
- package/tsconfig.json +4 -4
- package/webpack.config.js +1 -1
- package/dist/23.js +0 -2
- package/dist/23.js.map +0 -1
- package/dist/231.js +0 -2
- package/dist/231.js.map +0 -1
- package/dist/282.js +0 -2
- package/dist/282.js.map +0 -1
- package/dist/286.js.map +0 -1
- package/dist/356.js +0 -2
- package/dist/356.js.map +0 -1
- package/dist/36.js +0 -2
- package/dist/36.js.map +0 -1
- package/dist/40.js +0 -2
- package/dist/40.js.map +0 -1
- package/dist/413.js +0 -2
- package/dist/413.js.map +0 -1
- package/dist/42.js +0 -2
- package/dist/42.js.map +0 -1
- package/dist/427.js +0 -2
- package/dist/427.js.map +0 -1
- package/dist/545.js +0 -3
- package/dist/545.js.map +0 -1
- package/dist/590.js.map +0 -1
- package/dist/65.js +0 -2
- package/dist/65.js.map +0 -1
- package/dist/796.js +0 -2
- package/dist/796.js.map +0 -1
- package/dist/package-test.js.LICENSE.txt +0 -1
- package/dist/package.js.LICENSE.txt +0 -1
- /package/dist/{545.js.LICENSE.txt → 284.js.LICENSE.txt} +0 -0
package/src/tests/msa-tests.ts
CHANGED
|
@@ -125,14 +125,14 @@ async function _testMSAOnColumn(
|
|
|
125
125
|
const tgtCol = tgtDf.getCol('seq')!;
|
|
126
126
|
const srcCol: DG.Column = srcDf.getCol('seq')!;
|
|
127
127
|
expect(srcCol.semType, DG.SEMTYPE.MACROMOLECULE);
|
|
128
|
-
expect(srcCol.
|
|
128
|
+
expect(srcCol.meta.units, srcNotation);
|
|
129
129
|
if (alphabet)
|
|
130
130
|
expect(srcCol.getTag(bioTAGS.alphabet), alphabet);
|
|
131
131
|
|
|
132
132
|
const msaSeqCol = await multipleSequenceAlignmentUI({col: srcCol, pepsea: {method: pepseaMethod}});
|
|
133
133
|
expect(msaSeqCol.semType, DG.SEMTYPE.MACROMOLECULE);
|
|
134
134
|
expect(msaSeqCol.semType, DG.SEMTYPE.MACROMOLECULE);
|
|
135
|
-
expect(msaSeqCol.
|
|
135
|
+
expect(msaSeqCol.meta.units, tgtNotation);
|
|
136
136
|
expect(msaSeqCol.getTag(bioTAGS.aligned), ALIGNMENT.SEQ_MSA);
|
|
137
137
|
if (alphabet)
|
|
138
138
|
expect(msaSeqCol.getTag(bioTAGS.alphabet), alphabet);
|
|
@@ -103,7 +103,7 @@ category('renderers', () => {
|
|
|
103
103
|
async function _rendererMacromoleculeDifference() {
|
|
104
104
|
const seqDiffCol: DG.Column = DG.Column.fromStrings('SequencesDiff',
|
|
105
105
|
['meI/hHis/Aca/N/T/dK/Thr_PO3H2/Aca#D-Tyr_Et/Tyr_ab-dehydroMe/meN/E/N/dV']);
|
|
106
|
-
seqDiffCol.
|
|
106
|
+
seqDiffCol.meta.units = NOTATION.SEPARATOR;
|
|
107
107
|
seqDiffCol.setTag(bioTAGS.separator, '/');
|
|
108
108
|
seqDiffCol.setTag(bioTAGS.aligned, 'SEQ');
|
|
109
109
|
seqDiffCol.setTag(bioTAGS.alphabet, 'UN');
|
|
@@ -140,10 +140,10 @@ category('renderers', () => {
|
|
|
140
140
|
expect(tv.grid.dataFrame.id, df.id);
|
|
141
141
|
|
|
142
142
|
console.log('Bio: tests/renderers/afterMsa, src before test ' +
|
|
143
|
-
`semType="${srcSeqCol!.semType}", units="${srcSeqCol!.
|
|
143
|
+
`semType="${srcSeqCol!.semType}", units="${srcSeqCol!.meta.units}", ` +
|
|
144
144
|
`cell.renderer="${srcSeqCol!.getTag(DG.TAGS.CELL_RENDERER)}"`);
|
|
145
145
|
expect(srcSeqCol.semType, DG.SEMTYPE.MACROMOLECULE);
|
|
146
|
-
expect(srcSeqCol.
|
|
146
|
+
expect(srcSeqCol.meta.units, NOTATION.FASTA);
|
|
147
147
|
expect(srcSeqCol.getTag(bioTAGS.aligned), ALIGNMENT.SEQ);
|
|
148
148
|
expect(srcSeqCol.getTag(bioTAGS.alphabet), ALPHABET.PT);
|
|
149
149
|
expect(srcSeqCol.getTag(DG.TAGS.CELL_RENDERER), 'sequence');
|
|
@@ -153,7 +153,7 @@ category('renderers', () => {
|
|
|
153
153
|
expect(tv.grid.dataFrame.id, df.id);
|
|
154
154
|
|
|
155
155
|
expect(msaSeqCol.semType, DG.SEMTYPE.MACROMOLECULE);
|
|
156
|
-
expect(msaSeqCol.
|
|
156
|
+
expect(msaSeqCol.meta.units, NOTATION.FASTA);
|
|
157
157
|
expect(msaSeqCol.getTag(bioTAGS.aligned), ALIGNMENT.SEQ_MSA);
|
|
158
158
|
expect(msaSeqCol.getTag(bioTAGS.alphabet), ALPHABET.PT);
|
|
159
159
|
expect(msaSeqCol.getTag(DG.TAGS.CELL_RENDERER), 'sequence');
|
|
@@ -205,7 +205,7 @@ category('renderers', () => {
|
|
|
205
205
|
/**/
|
|
206
206
|
const seqDiffCol: DG.Column = DG.Column.fromStrings('SequencesDiff',
|
|
207
207
|
['meI/hHis/Aca/N/T/dK/Thr_PO3H2/Aca#D-Tyr_Et/Tyr_ab-dehydroMe/meN/E/N/dV']);
|
|
208
|
-
seqDiffCol.
|
|
208
|
+
seqDiffCol.meta.units = NOTATION.SEPARATOR;
|
|
209
209
|
seqDiffCol.setTag(bioTAGS.separator, '/');
|
|
210
210
|
seqDiffCol.setTag(bioTAGS.aligned, 'SEQ');
|
|
211
211
|
seqDiffCol.setTag(bioTAGS.alphabet, 'UN');
|
package/src/tests/scoring.ts
CHANGED
|
@@ -2,7 +2,9 @@ import * as grok from 'datagrok-api/grok';
|
|
|
2
2
|
import * as ui from 'datagrok-api/ui';
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import wu from 'wu';
|
|
6
|
+
|
|
7
|
+
import {category, test, expectFloat, before, after, expect} from '@datagrok-libraries/utils/src/test';
|
|
6
8
|
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
7
9
|
import {IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
8
10
|
|
|
@@ -13,6 +15,7 @@ import {
|
|
|
13
15
|
import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
|
|
14
16
|
|
|
15
17
|
category('Scoring', () => {
|
|
18
|
+
/* eslint-disable max-len */
|
|
16
19
|
const sequence = 'sequence';
|
|
17
20
|
const expectedSimilarity = 'expected_similarity';
|
|
18
21
|
const expectedIdentity = 'expected_identity';
|
|
@@ -22,11 +25,13 @@ PEPTIDE1{Aca.Orn.gGlu.Pqa.D-His_1Bn.dH.hHis.4Abz.D-Tic.D-Dap.Y.Iva.meS.F.P.F.D-1
|
|
|
22
25
|
PEPTIDE1{Iva.Gly_allyl.gGlu.Pqa.D-Dip.dH.hHis.4Abz.D-aHyp.D-Dap.Y.Iva.I.Tyr_26diMe.P.Asu.meC}$$$$,0.68,0.53
|
|
23
26
|
PEPTIDE1{[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal]}$$$$V2.0,0.34,0.0`
|
|
24
27
|
);
|
|
25
|
-
/* eslint-enable max-len */
|
|
26
28
|
const seqCol: DG.Column<string> = table.getCol(sequence);
|
|
27
|
-
seqCol.
|
|
29
|
+
seqCol.meta.units = NOTATION.HELM;
|
|
28
30
|
seqCol.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
29
31
|
const reference = seqCol.get(0)!;
|
|
32
|
+
const shortReference = 'PEPTIDE1{Iva.Gly_allyl.gGlu.Pqa.D-Dip.dH.hHis.4Abz.D-aHyp.D-Dap.Y.Iva}$$$$';
|
|
33
|
+
const longReference = 'PEPTIDE1{Iva.Gly_allyl.gGlu.Pqa.D-Dip.dH.hHis.4Abz.D-aHyp.D-Dap.Y.Iva.I.Tyr_26diMe.P.Asu.meC.I.Tyr_26diMe.P.Asu.meC}$$$$';
|
|
34
|
+
/* eslint-enable max-len */
|
|
30
35
|
|
|
31
36
|
let monomerLibHelper: IMonomerLibHelper;
|
|
32
37
|
/** Backup actual user's monomer libraries settings */
|
|
@@ -49,15 +54,31 @@ PEPTIDE1{[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[
|
|
|
49
54
|
test('Identity', async () => {
|
|
50
55
|
const scoresCol = await sequenceIdentityScoring(table, seqCol, reference);
|
|
51
56
|
for (let i = 0; i < scoresCol.length; i++) {
|
|
52
|
-
|
|
57
|
+
const resScore = scoresCol.get(i)!;
|
|
58
|
+
const tgtScore = table.get(expectedIdentity, i);
|
|
59
|
+
expectFloat(resScore, tgtScore, 0.01,
|
|
53
60
|
`Wrong identity score for sequence at position ${i}`);
|
|
54
61
|
}
|
|
55
62
|
});
|
|
56
63
|
|
|
64
|
+
test('Identity-shortReference', async () => {
|
|
65
|
+
const scoresCol = await sequenceIdentityScoring(table, seqCol, shortReference);
|
|
66
|
+
expect(wu.count(0).take(scoresCol.length).map((rowI) => scoresCol.get(rowI))
|
|
67
|
+
.every((v) => v != null && !isNaN(v)), true);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test('Identity-longReference', async () => {
|
|
71
|
+
const scoresCol = await sequenceIdentityScoring(table, seqCol, longReference);
|
|
72
|
+
expect(wu.count(0).take(scoresCol.length).map((rowI) => scoresCol.get(rowI))
|
|
73
|
+
.every((v) => v != null && !isNaN(v)), true);
|
|
74
|
+
});
|
|
75
|
+
|
|
57
76
|
test('Similarity', async () => {
|
|
58
77
|
const scoresCol = await sequenceSimilarityScoring(table, seqCol, reference);
|
|
59
78
|
for (let i = 0; i < scoresCol.length; i++) {
|
|
60
|
-
|
|
79
|
+
const resScore = scoresCol.get(i)!;
|
|
80
|
+
const tgtScore = table.get(expectedSimilarity, i);
|
|
81
|
+
expectFloat(resScore, tgtScore, 0.01,
|
|
61
82
|
`Wrong similarity score for sequence at position ${i}`);
|
|
62
83
|
}
|
|
63
84
|
});
|
|
@@ -82,8 +82,8 @@ PEPTIDE1{[Cys_SEt].T.*.*}$$$$`,
|
|
|
82
82
|
const tgtDf = DG.DataFrame.fromCsv(testData.tgtCsv);
|
|
83
83
|
const tgtSeqCol = tgtDf.getCol('seq');
|
|
84
84
|
|
|
85
|
-
expect(srcSeqCol.
|
|
86
|
-
expect(resSeqCol.
|
|
85
|
+
expect(srcSeqCol.meta.units, testData.units);
|
|
86
|
+
expect(resSeqCol.meta.units, testData.units);
|
|
87
87
|
expect(srcSeqCol.getTag(TAGS.alphabet), testData.alphabet);
|
|
88
88
|
expect(resSeqCol.getTag(TAGS.alphabet), testData.alphabet);
|
|
89
89
|
expectArray(resSeqCol.toList(), tgtSeqCol.toList());
|
|
@@ -105,8 +105,8 @@ PEPTIDE1{[Cys_SEt].T.*.*}$$$$`,
|
|
|
105
105
|
const tgtDf = DG.DataFrame.fromCsv(testData.tgtCsv);
|
|
106
106
|
const tgtSeqCol = tgtDf.getCol('seq');
|
|
107
107
|
|
|
108
|
-
expect(srcSeqCol.
|
|
109
|
-
expect(resSeqCol.
|
|
108
|
+
expect(srcSeqCol.meta.units, testData.units);
|
|
109
|
+
expect(resSeqCol.meta.units, testData.units);
|
|
110
110
|
expect(srcSeqCol.getTag(TAGS.alphabet), testData.alphabet);
|
|
111
111
|
expect(resSeqCol.getTag(TAGS.alphabet), testData.alphabet);
|
|
112
112
|
expectArray(resSeqCol.toList(), tgtSeqCol.toList());
|
|
@@ -21,7 +21,7 @@ category('sequenceSpace', async () => {
|
|
|
21
21
|
await _testSequenceSpaceReturnsResult(testFastaDf, DimReductionMethods.UMAP, 'sequence');
|
|
22
22
|
//grok.shell.closeTable(testFastaDf);
|
|
23
23
|
//testFastaTableView.close();
|
|
24
|
-
});
|
|
24
|
+
}, {benchmark: true});
|
|
25
25
|
|
|
26
26
|
test('sequenceSpaceWithEmptyRows', async () => {
|
|
27
27
|
testHelmWithEmptyRows = await readDataframe('tests/100_3_clustests_empty_vals.csv');
|
|
@@ -5,15 +5,16 @@ import * as DG from 'datagrok-api/dg';
|
|
|
5
5
|
import $ from 'cash-dom';
|
|
6
6
|
import wu from 'wu';
|
|
7
7
|
|
|
8
|
-
|
|
9
8
|
import {after, before, category, test, expect, delay, testEvent, awaitCheck} from '@datagrok-libraries/utils/src/test';
|
|
10
9
|
import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
11
10
|
import {
|
|
12
11
|
getUserLibSettings, setUserLibSettings, setUserLibSettingsForTests
|
|
13
12
|
} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
|
|
14
13
|
import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
|
|
14
|
+
import {getHelmHelper, IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
|
|
15
15
|
|
|
16
16
|
import {awaitGrid, readDataframe} from './utils';
|
|
17
|
+
|
|
17
18
|
import {
|
|
18
19
|
BioSubstructureFilter, FastaBioFilter, SeparatorBioFilter, SeparatorFilterProps
|
|
19
20
|
} from '../widgets/bio-substructure-filter';
|
|
@@ -24,11 +25,13 @@ import {_package} from '../package-test';
|
|
|
24
25
|
|
|
25
26
|
|
|
26
27
|
category('bio-substructure-filters', async () => {
|
|
28
|
+
let helmHelper: IHelmHelper;
|
|
27
29
|
let monomerLibHelper: IMonomerLibHelper;
|
|
28
30
|
/** Backup actual user's monomer libraries settings */
|
|
29
31
|
let userLibSettings: UserLibSettings;
|
|
30
32
|
|
|
31
33
|
before(async () => {
|
|
34
|
+
helmHelper = await getHelmHelper(); // init Helm package
|
|
32
35
|
monomerLibHelper = await getMonomerLibHelper();
|
|
33
36
|
userLibSettings = await getUserLibSettings();
|
|
34
37
|
|
|
@@ -205,7 +205,7 @@ PEPTIDE1{Lys_Boc.hHis.Aca.Cys_SEt.T.dK.Thr_PO3H2.Aca.Tyr_PO3H2.Thr_PO3H2.Aca.Tyr
|
|
|
205
205
|
const srcDf = DG.DataFrame.fromCsv(srcCsv);
|
|
206
206
|
const seqCol = srcDf.getCol('seq');
|
|
207
207
|
seqCol.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
208
|
-
seqCol.
|
|
208
|
+
seqCol.meta.units = NOTATION.FASTA;
|
|
209
209
|
seqCol.setTag(bioTAGS.alphabet, ALPHABET.PT);
|
|
210
210
|
const sh = SeqHandler.forColumn(seqCol);
|
|
211
211
|
const resCol = (await _testToAtomicLevel(srcDf, 'seq', monomerLibHelper))!;
|
|
@@ -2,33 +2,25 @@ import * as grok from 'datagrok-api/grok';
|
|
|
2
2
|
import * as ui from 'datagrok-api/ui';
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
4
|
|
|
5
|
-
export enum MonomerWidthMode {
|
|
6
|
-
long = 'long',
|
|
7
|
-
short = 'short',
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export const enum Tags {
|
|
11
|
-
RendererSettingsChanged = '.mm.cellRenderer.settingsChanged',
|
|
12
|
-
}
|
|
13
|
-
|
|
14
5
|
export const rendererSettingsChangedState = {
|
|
15
6
|
true: '1',
|
|
16
7
|
false: '0',
|
|
17
8
|
};
|
|
18
9
|
|
|
19
10
|
export const enum Temps {
|
|
20
|
-
|
|
11
|
+
maxMonomerLength = '.mm.cellRenderer.maxMonomerLength',
|
|
21
12
|
colorCode = '.mm.cellRenderer.colorCode',
|
|
22
13
|
compareWithCurrent = '.mm.cellRenderer.compareWithCurrent',
|
|
23
14
|
highlightDifference = '.mm.cellRenderer.highlightDifference',
|
|
24
15
|
gapLength = '.mm.cellRenderer.gapLength',
|
|
25
16
|
monomerPlacer = '.mm.cellRenderer.monomerPlacer',
|
|
17
|
+
|
|
18
|
+
rendererSettingsChanged = '.mm.cellRenderer.settingsChanged',
|
|
26
19
|
}
|
|
27
20
|
|
|
28
21
|
export const enum tempTAGS {
|
|
29
22
|
referenceSequence = 'reference-sequence',
|
|
30
23
|
currentWord = 'current-word',
|
|
31
|
-
monomerWidthMode = 'monomer-width-mode',
|
|
32
24
|
}
|
|
33
25
|
|
|
34
26
|
// export const MacromoleculeCellRendererDefaults = new class {
|
|
@@ -25,8 +25,8 @@ import {alphabetPolymerTypes, IMonomerLib} from '@datagrok-libraries/bio/src/typ
|
|
|
25
25
|
import {getGridCellRendererBack} from '@datagrok-libraries/bio/src/utils/cell-renderer-back-base';
|
|
26
26
|
|
|
27
27
|
import {
|
|
28
|
-
Temps as mmcrTemps,
|
|
29
|
-
tempTAGS, rendererSettingsChangedState,
|
|
28
|
+
Temps as mmcrTemps,
|
|
29
|
+
tempTAGS, rendererSettingsChangedState, Temps
|
|
30
30
|
} from '../utils/cell-renderer-consts';
|
|
31
31
|
import * as C from './constants';
|
|
32
32
|
|
|
@@ -152,18 +152,16 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
152
152
|
|
|
153
153
|
let gapLength = 0;
|
|
154
154
|
const msaGapLength = 8;
|
|
155
|
-
let maxLengthOfMonomer = 50; // in case of long monomer representation, do not limit max length
|
|
156
155
|
|
|
157
156
|
// Cell renderer settings
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const
|
|
165
|
-
maxLengthOfMonomer =
|
|
166
|
-
(!isNaN(tagMaxMonomerLength) ? tagMaxMonomerLength : _package.properties?.MaxMonomerLength) ?? 4;
|
|
157
|
+
let maxLengthOfMonomer: number = (_package.properties ? _package.properties.maxMonomerLength : 4) ?? 50;
|
|
158
|
+
if (mmcrTAGS.maxMonomerLength in tableCol.tags) {
|
|
159
|
+
const v = parseInt(tableCol.getTag(mmcrTAGS.maxMonomerLength));
|
|
160
|
+
maxLengthOfMonomer = !isNaN(v) && v ? v : 50;
|
|
161
|
+
}
|
|
162
|
+
if (Temps.maxMonomerLength in tableColTemp) {
|
|
163
|
+
const v = tableColTemp[Temps.maxMonomerLength];
|
|
164
|
+
maxLengthOfMonomer = !isNaN(v) && v ? v : 50;
|
|
167
165
|
}
|
|
168
166
|
|
|
169
167
|
const [_gc, _tc, temp] =
|
|
@@ -184,7 +182,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
184
182
|
g.save();
|
|
185
183
|
try {
|
|
186
184
|
if (
|
|
187
|
-
tableCol.
|
|
185
|
+
tableCol.temp[Temps.rendererSettingsChanged] === rendererSettingsChangedState.true ||
|
|
188
186
|
seqColTemp.monomerLengthLimit != maxLengthOfMonomer
|
|
189
187
|
) {
|
|
190
188
|
gapLength = tableColTemp[mmcrTemps.gapLength] as number ?? gapLength;
|
|
@@ -192,7 +190,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
192
190
|
// particularly monomer representation and max width.
|
|
193
191
|
seqColTemp.setMonomerLengthLimit(maxLengthOfMonomer);
|
|
194
192
|
seqColTemp.setSeparatorWidth(seqColTemp.isMsa() ? msaGapLength : gapLength);
|
|
195
|
-
tableCol.
|
|
193
|
+
tableCol.temp[Temps.rendererSettingsChanged] = rendererSettingsChangedState.false;
|
|
196
194
|
}
|
|
197
195
|
|
|
198
196
|
const [maxLengthWords, maxLengthWordsSum]: [number[], number[]] =
|
|
@@ -211,7 +209,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
211
209
|
g.textBaseline = 'top';
|
|
212
210
|
|
|
213
211
|
//TODO: can this be replaced/merged with splitSequence?
|
|
214
|
-
const units = tableCol.
|
|
212
|
+
const units = tableCol.meta.units;
|
|
215
213
|
const aligned: string = tableCol.getTag(bioTAGS.aligned);
|
|
216
214
|
|
|
217
215
|
const palette = getPaletteByType(paletteType);
|
|
@@ -300,7 +298,7 @@ export class MacromoleculeDifferenceCellRenderer extends DG.GridCellRenderer {
|
|
|
300
298
|
const tableCol = gridCell.tableColumn as DG.Column<string>;
|
|
301
299
|
const s: string = cell.value ?? '';
|
|
302
300
|
const separator = tableCol.tags[bioTAGS.separator];
|
|
303
|
-
const units: string = tableCol.
|
|
301
|
+
const units: string = tableCol.meta.units!;
|
|
304
302
|
w = getUpdatedWidth(grid, g, x, w, dpr);
|
|
305
303
|
//TODO: can this be replaced/merged with splitSequence?
|
|
306
304
|
const [s1, s2] = s.split('#');
|
|
@@ -347,7 +345,7 @@ export function drawMoleculeDifferenceOnCanvas(
|
|
|
347
345
|
g.textBaseline = 'top';
|
|
348
346
|
|
|
349
347
|
let palette: SeqPalette = UnknownSeqPalettes.Color;
|
|
350
|
-
if (units
|
|
348
|
+
if (units !== 'HELM')
|
|
351
349
|
palette = getPaletteByType(units.substring(units.length - 2));
|
|
352
350
|
|
|
353
351
|
const vShift = 7;
|
|
@@ -17,7 +17,7 @@ export function addCopyMenuUI(cell: DG.Cell, menu: DG.Menu): void {
|
|
|
17
17
|
const srcCol = cell.column;
|
|
18
18
|
const srcRowIdx = cell.rowIndex;
|
|
19
19
|
const srcSh = SeqHandler.forColumn(srcCol);
|
|
20
|
-
const separator = tgtNotation === NOTATION.SEPARATOR ? _package.properties.
|
|
20
|
+
const separator = tgtNotation === NOTATION.SEPARATOR ? _package.properties.defaultSeparator : undefined;
|
|
21
21
|
const joiner = srcSh.getJoiner({notation: tgtNotation as NOTATION, separator});
|
|
22
22
|
const srcSS = srcSh.getSplitted(srcRowIdx);
|
|
23
23
|
const tgtSeq = joiner(srcSS);
|
package/src/utils/convert.ts
CHANGED
|
@@ -52,7 +52,8 @@ export function convert(col?: DG.Column): void {
|
|
|
52
52
|
separatorInput.value = '/'; // helm monomers can have - in the name like D-aThr;
|
|
53
53
|
dialogHeader.textContent = 'Current notation: ' + currentNotation;
|
|
54
54
|
filteredNotations = notations.filter((e) => e !== currentNotation);
|
|
55
|
-
targetNotationInput = ui.
|
|
55
|
+
targetNotationInput = ui.input.choice('Convert to', {value: filteredNotations[0], items: filteredNotations,
|
|
56
|
+
onValueChanged: toggleSeparator});
|
|
56
57
|
toggleSeparator();
|
|
57
58
|
convertDialog?.clear();
|
|
58
59
|
convertDialog?.add(ui.div([
|
|
@@ -63,12 +64,13 @@ export function convert(col?: DG.Column): void {
|
|
|
63
64
|
]));
|
|
64
65
|
};
|
|
65
66
|
|
|
66
|
-
const targetColumnInput = ui.
|
|
67
|
+
const targetColumnInput = ui.input.column('Column', {table: grok.shell.t, value: srcCol,
|
|
68
|
+
onValueChanged: (input) => toggleColumn(input.value)});
|
|
67
69
|
|
|
68
70
|
const separatorArray = ['-', '.', '/'];
|
|
69
71
|
let filteredNotations = notations.filter((e) => e !== currentNotation);
|
|
70
72
|
|
|
71
|
-
const separatorInput = ui.
|
|
73
|
+
const separatorInput = ui.input.choice('Separator', {value: separatorArray[0], items: separatorArray});
|
|
72
74
|
|
|
73
75
|
// hide the separator input for non-SEPARATOR target notations
|
|
74
76
|
const toggleSeparator = () => {
|
|
@@ -77,7 +79,8 @@ export function convert(col?: DG.Column): void {
|
|
|
77
79
|
else
|
|
78
80
|
$(separatorInput.root).show();
|
|
79
81
|
};
|
|
80
|
-
let targetNotationInput = ui.
|
|
82
|
+
let targetNotationInput = ui.input.choice('Convert to', {value: filteredNotations[0], items: filteredNotations,
|
|
83
|
+
onValueChanged: toggleSeparator});
|
|
81
84
|
|
|
82
85
|
// set correct visibility on init
|
|
83
86
|
toggleSeparator();
|
|
@@ -37,25 +37,20 @@ export class GetRegionFuncEditor {
|
|
|
37
37
|
) {
|
|
38
38
|
const getDesc = (paramName: string) => this.call.inputParams[paramName].property.description;
|
|
39
39
|
|
|
40
|
-
this.inputs.table = ui.
|
|
41
|
-
this.call.inputParams['table'].value ?? grok.shell.tv.dataFrame, undefined,
|
|
42
|
-
() => {});
|
|
40
|
+
this.inputs.table = ui.input.table('Table', {value: this.call.inputParams['table'].value ?? grok.shell.tv.dataFrame});
|
|
43
41
|
|
|
44
42
|
const seqColValue = this.call.inputParams['sequence'].value ??
|
|
45
43
|
this.inputs.table.value!.columns.bySemType(DG.SEMTYPE.MACROMOLECULE);
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
this.inputs.
|
|
50
|
-
|
|
51
|
-
this.inputs.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
this.inputs.
|
|
55
|
-
this.
|
|
56
|
-
|
|
57
|
-
this.inputs.name = ui.stringInput('Column name', this.getDefaultName(),
|
|
58
|
-
this.nameInputChanged.bind(this), {clearIcon: true});
|
|
44
|
+
this.inputs.sequence = ui.input.column('Sequence', {table: grok.shell.tv.dataFrame, value: seqColValue,
|
|
45
|
+
onValueChanged: this.sequenceInputChanged.bind(this), filter: (col: DG.Column) => col.semType === DG.SEMTYPE.MACROMOLECULE});
|
|
46
|
+
this.inputs.start = ui.input.choice('Start', {onValueChanged: this.startInputChanged.bind(this)}) as unknown as DG.InputBase<string>;
|
|
47
|
+
this.inputs.end = ui.input.choice('End', {onValueChanged: this.endInputChanged.bind(this)}) as unknown as DG.InputBase<string>;
|
|
48
|
+
|
|
49
|
+
this.inputs.region = ui.input.choice<SeqRegion>('Region', {value: null as unknown as SeqRegion, items: [],
|
|
50
|
+
onValueChanged: this.regionInputChanged.bind(this)}) as DG.InputBase<SeqRegion>;
|
|
51
|
+
|
|
52
|
+
this.inputs.name = ui.input.string('Column name', {value: this.getDefaultName(),
|
|
53
|
+
onValueChanged: this.nameInputChanged.bind(this), clearIcon: true});
|
|
59
54
|
this.inputs.name.onInput(this.nameInputInput.bind(this)); // To catch clear event
|
|
60
55
|
|
|
61
56
|
// tooltips
|
package/src/utils/get-region.ts
CHANGED
|
@@ -8,11 +8,11 @@ import {TaskBarProgressIndicator} from 'datagrok-api/dg';
|
|
|
8
8
|
export function getRegionUI(col: DG.Column<string>): void {
|
|
9
9
|
const sh = SeqHandler.forColumn(col);
|
|
10
10
|
|
|
11
|
-
const nameInput = ui.
|
|
12
|
-
const startPositionInput = ui.
|
|
13
|
-
() => { /* TODO: update name placeholder with getDefaultName() */ });
|
|
14
|
-
const endPositionInput = ui.
|
|
15
|
-
() => { /* TODO: update name placeholder with getDefaultName() */ });
|
|
11
|
+
const nameInput = ui.input.string('Name', {value: ''});
|
|
12
|
+
const startPositionInput = ui.input.choice('Start Position', {value: sh.posList[0], items: sh.posList,
|
|
13
|
+
onValueChanged: () => { /* TODO: update name placeholder with getDefaultName() */ }});
|
|
14
|
+
const endPositionInput = ui.input.choice('End Position', {value: sh.posList[sh.posList.length], items: sh.posList,
|
|
15
|
+
onValueChanged: () => { /* TODO: update name placeholder with getDefaultName() */ }});
|
|
16
16
|
|
|
17
17
|
const getDefaultName = (): string => {
|
|
18
18
|
return `${col.name}:${startPositionInput.value}-${endPositionInput.value}`;
|
|
@@ -25,7 +25,7 @@ export class MacromoleculeColumnWidget extends DG.Widget {
|
|
|
25
25
|
|
|
26
26
|
async init(): Promise<void> {
|
|
27
27
|
const sh = SeqHandler.forColumn(this.seqCol);
|
|
28
|
-
const pkgTooltipWebLogo = _package.properties.
|
|
28
|
+
const pkgTooltipWebLogo = _package.properties.tooltipWebLogo;
|
|
29
29
|
const colTooltipWebLogo = this.seqCol.getTag(wlTAGS.tooltipWebLogo);
|
|
30
30
|
|
|
31
31
|
if (pkgTooltipWebLogo !== false && !['false', 'off', 'disable', 'disabled'].includes(colTooltipWebLogo)) {
|
|
@@ -4,6 +4,7 @@ import * as ui from 'datagrok-api/ui';
|
|
|
4
4
|
import * as DG from 'datagrok-api/dg';
|
|
5
5
|
|
|
6
6
|
import {delay} from '@datagrok-libraries/utils/src/test';
|
|
7
|
+
import {ILogger} from '@datagrok-libraries/bio/src/utils/logger';
|
|
7
8
|
import {IMonomerLib} from '@datagrok-libraries/bio/src/types';
|
|
8
9
|
import {
|
|
9
10
|
getUserLibSettings, setUserLibSettings, LIB_PATH
|
|
@@ -49,7 +50,9 @@ export class MonomerLibManager implements IMonomerLibHelper {
|
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
/** Protect constructor to prevent multiple instantiation. */
|
|
52
|
-
protected constructor(
|
|
53
|
+
protected constructor(
|
|
54
|
+
private readonly logger: ILogger,
|
|
55
|
+
) {}
|
|
53
56
|
|
|
54
57
|
/** Singleton monomer library
|
|
55
58
|
* @return {MonomerLibManager} MonomerLibHelper instance
|
|
@@ -64,7 +67,8 @@ export class MonomerLibManager implements IMonomerLibHelper {
|
|
|
64
67
|
async getFileManager(): Promise<MonomerLibFileManager> {
|
|
65
68
|
if (this._fileManagerPromise === undefined) {
|
|
66
69
|
this._fileManagerPromise = (async () => {
|
|
67
|
-
const fileManager: MonomerLibFileManager =
|
|
70
|
+
const fileManager: MonomerLibFileManager =
|
|
71
|
+
await MonomerLibFileManager.create(this, this._eventManager, this.logger);
|
|
68
72
|
return fileManager;
|
|
69
73
|
})();
|
|
70
74
|
}
|
|
@@ -82,6 +86,7 @@ export class MonomerLibManager implements IMonomerLibHelper {
|
|
|
82
86
|
// WARNING: This function is not allowed to throw any exception,
|
|
83
87
|
// because it will prevent further handling monomer library settings
|
|
84
88
|
// through blocking this.loadLibrariesPromise
|
|
89
|
+
const pi = DG.TaskBarProgressIndicator.create('Loading monomers ...');
|
|
85
90
|
try {
|
|
86
91
|
const [libFileNameList, settings]: [string[], UserLibSettings] = await Promise.all([
|
|
87
92
|
(await this.getFileManager()).getValidLibraryPaths(),
|
|
@@ -95,14 +100,19 @@ export class MonomerLibManager implements IMonomerLibHelper {
|
|
|
95
100
|
return isFileIncluded && isExplicit;
|
|
96
101
|
});
|
|
97
102
|
|
|
103
|
+
let completedLibCount: number = 0;
|
|
98
104
|
const libs: IMonomerLib[] = await Promise.all(filteredLibFnList
|
|
99
105
|
.map((libFileName) => {
|
|
100
106
|
//TODO handle whether files are in place
|
|
101
|
-
return this.readLibrary(LIB_PATH, libFileName)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
107
|
+
return this.readLibrary(LIB_PATH, libFileName)
|
|
108
|
+
.catch((err: any) => {
|
|
109
|
+
const errMsg: string = `Loading monomers from '${libFileName}' error: ` +
|
|
110
|
+
`${err instanceof Error ? err.message : err.toString()}`;
|
|
111
|
+
return new MonomerLib({}, libFileName, errMsg);
|
|
112
|
+
}).finally(() => {
|
|
113
|
+
pi.update(Math.round(100 * (++completedLibCount) / filteredLibFnList.length),
|
|
114
|
+
`Loading monomer libs ${completedLibCount}/${filteredLibFnList.length}`);
|
|
115
|
+
});
|
|
106
116
|
}));
|
|
107
117
|
this._monomerLib.updateLibs(libs, reload);
|
|
108
118
|
} catch (err: any) {
|
|
@@ -112,6 +122,8 @@ export class MonomerLibManager implements IMonomerLibHelper {
|
|
|
112
122
|
|
|
113
123
|
const errStack = err instanceof Error ? err.stack : undefined;
|
|
114
124
|
_package.logger.error(errMsg, undefined, errStack);
|
|
125
|
+
} finally {
|
|
126
|
+
pi.close();
|
|
115
127
|
}
|
|
116
128
|
});
|
|
117
129
|
}
|
|
@@ -149,7 +161,7 @@ export class MonomerLibManager implements IMonomerLibHelper {
|
|
|
149
161
|
let res = window.$monomerLibHelperPromise;
|
|
150
162
|
if (res === undefined) {
|
|
151
163
|
res = window.$monomerLibHelperPromise = (async () => {
|
|
152
|
-
const instance = new MonomerLibManager();
|
|
164
|
+
const instance = new MonomerLibManager(_package.logger);
|
|
153
165
|
instance._eventManager = MonomerLibFileEventManager.getInstance();
|
|
154
166
|
return instance;
|
|
155
167
|
})();
|
|
@@ -6,6 +6,7 @@ import * as DG from 'datagrok-api/dg';
|
|
|
6
6
|
import {JSONSchemaType} from 'ajv';
|
|
7
7
|
|
|
8
8
|
import {IMonomerLib, Monomer} from '@datagrok-libraries/bio/src/types';
|
|
9
|
+
import {ILogger} from '@datagrok-libraries/bio/src/utils/logger';
|
|
9
10
|
import {LIB_PATH} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
|
|
10
11
|
import {
|
|
11
12
|
HELM_REQUIRED_FIELD as REQ,
|
|
@@ -31,6 +32,7 @@ export class MonomerLibFileManager implements IMonomerLibFileManager {
|
|
|
31
32
|
private readonly fileValidator: MonomerLibFileValidator,
|
|
32
33
|
private readonly libHelper: IMonomerLibHelper,
|
|
33
34
|
public readonly eventManager: MonomerLibFileEventManager,
|
|
35
|
+
private readonly logger: ILogger,
|
|
34
36
|
) {
|
|
35
37
|
this.eventManager.updateValidLibraryFileListRequested$.subscribe(async () => {
|
|
36
38
|
await this.updateValidLibraryList();
|
|
@@ -46,19 +48,20 @@ export class MonomerLibFileManager implements IMonomerLibFileManager {
|
|
|
46
48
|
|
|
47
49
|
/** For internal use only, get {@link IMonomerLibHelper.getFileManager} */
|
|
48
50
|
public static async create(
|
|
49
|
-
libHelper: IMonomerLibHelper, eventManager: MonomerLibFileEventManager
|
|
51
|
+
libHelper: IMonomerLibHelper, eventManager: MonomerLibFileEventManager, logger: ILogger,
|
|
50
52
|
): Promise<MonomerLibFileManager> {
|
|
51
53
|
const helmSchemaRaw = await grok.dapi.files.readAsText(HELM_JSON_SCHEMA_PATH);
|
|
52
54
|
const helmSchema = JSON.parse(helmSchemaRaw) as JSONSchemaType<any>;
|
|
53
55
|
|
|
54
56
|
const fileValidator = new MonomerLibFileValidator(helmSchema);
|
|
55
|
-
return new MonomerLibFileManager(fileValidator, libHelper, eventManager);
|
|
57
|
+
return new MonomerLibFileManager(fileValidator, libHelper, eventManager, logger);
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
/** Add standard .json monomer library */
|
|
59
61
|
async addLibraryFile(fileContent: string, fileName: string): Promise<void> {
|
|
60
62
|
try {
|
|
61
|
-
|
|
63
|
+
const alreadyFileExists = await grok.dapi.files.exists(LIB_PATH + `${fileName}`);
|
|
64
|
+
if (alreadyFileExists) {
|
|
62
65
|
grok.shell.error(`File ${fileName} already exists`);
|
|
63
66
|
return;
|
|
64
67
|
}
|
|
@@ -122,21 +125,17 @@ export class MonomerLibFileManager implements IMonomerLibFileManager {
|
|
|
122
125
|
return await this.eventManager.getValidLibraryPathsAsynchronously();
|
|
123
126
|
}
|
|
124
127
|
|
|
125
|
-
private async libraryFileExists(fileName: string): Promise<boolean> {
|
|
126
|
-
return await grok.dapi.files.exists(LIB_PATH + `${fileName}`);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
128
|
private async updateValidLibraryList(): Promise<void> {
|
|
130
129
|
const logPrefix: string = `${this.toLog()}.updateValidLibraryList()`;
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
130
|
+
this.logger.debug(`${logPrefix}, start`);
|
|
131
|
+
this.filesPromise = this.filesPromise.then(async () => {
|
|
132
|
+
this.logger.debug(`${logPrefix}, IN`);
|
|
134
133
|
const invalidFiles = [] as string[];
|
|
135
134
|
// console.log(`files before validation:`, this.libraryEventManager.getValidFilesPathList());
|
|
136
135
|
const filePaths = await this.getFilePathsAtDefaultLocation();
|
|
137
136
|
|
|
138
137
|
if (!this.fileListHasChanged(filePaths)) {
|
|
139
|
-
|
|
138
|
+
this.logger.debug(`${logPrefix}, end, not changed`);
|
|
140
139
|
return;
|
|
141
140
|
}
|
|
142
141
|
|
|
@@ -160,18 +159,19 @@ export class MonomerLibFileManager implements IMonomerLibFileManager {
|
|
|
160
159
|
// console.log(`files after validation:`, this.libraryEventManager.getValidFilesPathList());
|
|
161
160
|
|
|
162
161
|
if (validLibraryPaths.some((el) => !el.endsWith('.json')))
|
|
163
|
-
|
|
162
|
+
this.logger.warning(`Wrong validation: ${validLibraryPaths}`);
|
|
164
163
|
|
|
165
164
|
if (invalidFiles.length > 0) {
|
|
166
165
|
const message = `Invalid monomer library files in ${LIB_PATH}` +
|
|
167
166
|
`, consider fixing or removing them: ${invalidFiles.join(', ')}`;
|
|
168
167
|
|
|
169
|
-
|
|
168
|
+
this.logger.warning(message);
|
|
170
169
|
// grok.shell.warning(message);
|
|
171
170
|
}
|
|
172
|
-
|
|
171
|
+
this.logger.debug(`${logPrefix}, OUT`);
|
|
173
172
|
});
|
|
174
|
-
|
|
173
|
+
this.logger.debug(`${logPrefix}, end`);
|
|
174
|
+
return this.filesPromise;
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
private fileListHasChanged(newList: string[]): boolean {
|
|
@@ -191,21 +191,25 @@ export class MonomerLibFileManager implements IMonomerLibFileManager {
|
|
|
191
191
|
|
|
192
192
|
/** Get relative paths for files in LIB_PATH */
|
|
193
193
|
private async getFilePathsAtDefaultLocation(): Promise<string[]> {
|
|
194
|
+
const logPrefix = `${this.toLog()}.getFilePathsAtDefaultLocation()`;
|
|
195
|
+
this.logger.debug(`${logPrefix}, start`);
|
|
194
196
|
const list = await grok.dapi.files.list(LIB_PATH);
|
|
195
197
|
const paths = list.map((fileInfo) => {
|
|
196
198
|
return fileInfo.fullPath;
|
|
197
199
|
});
|
|
198
200
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
// WARNING: an extra sanity check,
|
|
202
|
-
// caused by unexpected behavior of grok.dapi.files.list() when it returns non-existent paths
|
|
201
|
+
const checkForUi = false;
|
|
203
202
|
const existingPaths = [] as string[];
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
203
|
+
if (checkForUi) {
|
|
204
|
+
// WARNING: an extra sanity check,
|
|
205
|
+
// caused by unexpected behavior of grok.dapi.files.list() when it returns non-existent paths
|
|
206
|
+
for (const path of paths) {
|
|
207
|
+
const exists = await grok.dapi.files.exists(path);
|
|
208
|
+
if (exists)
|
|
209
|
+
existingPaths.push(path);
|
|
210
|
+
}
|
|
211
|
+
} else
|
|
212
|
+
existingPaths.push(...paths);
|
|
209
213
|
|
|
210
214
|
return existingPaths.map((path) => {
|
|
211
215
|
// Get relative path (to LIB_PATH)
|