@datagrok/bio 2.23.2 → 2.25.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.
Files changed (63) hide show
  1. package/.eslintrc.json +0 -2
  2. package/CHANGELOG.md +9 -0
  3. package/README.md +1 -1
  4. package/dist/455.js.map +1 -1
  5. package/dist/package-test.js +3 -3
  6. package/dist/package-test.js.map +1 -1
  7. package/dist/package.js +2 -2
  8. package/dist/package.js.map +1 -1
  9. package/files/samples/HELM_CHEMS.csv +11 -0
  10. package/package.json +2 -2
  11. package/src/analysis/sequence-space.ts +1 -1
  12. package/src/demo/bio03-atomic-level.ts +1 -1
  13. package/src/package-types.ts +2 -2
  14. package/src/package.ts +10 -4
  15. package/src/tests/activity-cliffs-tests.ts +2 -2
  16. package/src/tests/monomer-libraries-tests.ts +9 -7
  17. package/src/tests/renderers-monomer-placer-tests.ts +1 -1
  18. package/src/tests/scoring.ts +1 -1
  19. package/src/tests/seq-handler-get-helm-tests.ts +1 -1
  20. package/src/tests/splitters-test.ts +2 -2
  21. package/src/tests/substructure-filters-tests.ts +11 -11
  22. package/src/tests/to-atomic-level-tests.ts +2 -2
  23. package/src/tests/to-atomic-level-ui-tests.ts +13 -14
  24. package/src/utils/cell-renderer.ts +1 -1
  25. package/src/utils/get-region.ts +2 -2
  26. package/src/utils/helm-to-molfile/converter/const.ts +0 -1
  27. package/src/utils/helm-to-molfile/converter/converter.ts +4 -4
  28. package/src/utils/helm-to-molfile/converter/helm.ts +14 -6
  29. package/src/utils/helm-to-molfile/converter/mol-bonds.ts +2 -2
  30. package/src/utils/helm-to-molfile/converter/mol-wrapper.ts +2 -2
  31. package/src/utils/helm-to-molfile/converter/monomer-wrapper.ts +1 -1
  32. package/src/utils/helm-to-molfile/converter/polymer.ts +1 -1
  33. package/src/utils/helm-to-molfile/converter/r-group-handler.ts +2 -2
  34. package/src/utils/helm-to-molfile/utils.ts +3 -2
  35. package/src/utils/monomer-cell-renderer-base.ts +1 -2
  36. package/src/utils/monomer-lib/consts.ts +1 -6
  37. package/src/utils/monomer-lib/lib-manager.ts +239 -112
  38. package/src/utils/monomer-lib/library-file-manager/file-validator.ts +1 -1
  39. package/src/utils/monomer-lib/library-file-manager/monomers-lib-provider.ts +378 -0
  40. package/src/utils/monomer-lib/library-file-manager/ui.ts +120 -81
  41. package/src/utils/monomer-lib/monomer-colors.ts +37 -39
  42. package/src/utils/monomer-lib/monomer-lib-base.ts +34 -7
  43. package/src/utils/monomer-lib/monomer-lib.ts +7 -33
  44. package/src/utils/monomer-lib/monomer-manager/duplicate-monomer-manager.ts +3 -3
  45. package/src/utils/monomer-lib/monomer-manager/monomer-manager.ts +91 -82
  46. package/src/utils/monomer-lib/smiles2Monomer.ts +128 -0
  47. package/src/utils/monomer-lib/web-editor-monomer-dummy.ts +15 -1
  48. package/src/utils/monomer-lib/web-editor-monomer-of-library.ts +2 -1
  49. package/src/utils/multiple-sequence-alignment-ui.ts +1 -1
  50. package/src/utils/multiple-sequence-alignment.ts +1 -1
  51. package/src/utils/seq-helper/seq-handler.ts +26 -13
  52. package/src/utils/seq-helper/seq-helper.ts +1 -2
  53. package/src/utils/sequence-to-mol.ts +1 -1
  54. package/src/utils/ui-utils.ts +1 -1
  55. package/src/viewers/web-logo-viewer.ts +20 -9
  56. package/src/widgets/composition-analysis-widget.ts +1 -1
  57. package/src/widgets/sequence-scrolling-widget.ts +1 -2
  58. package/test-console-output-1.log +670 -721
  59. package/test-record-1.mp4 +0 -0
  60. package/src/utils/monomer-lib/library-file-manager/custom-monomer-lib-handlers.ts +0 -41
  61. package/src/utils/monomer-lib/library-file-manager/event-manager.ts +0 -93
  62. package/src/utils/monomer-lib/library-file-manager/file-manager.ts +0 -317
  63. package/src/utils/monomer-lib/monomer-set.ts +0 -61
@@ -1,3 +1,4 @@
1
+ /* eslint-disable max-len */
1
2
  /* Do not change these import lines to match external modules in webpack configuration */
2
3
  import * as grok from 'datagrok-api/grok';
3
4
  import * as ui from 'datagrok-api/ui';
@@ -5,22 +6,20 @@ import * as DG from 'datagrok-api/dg';
5
6
 
6
7
  import {delay} from '@datagrok-libraries/utils/src/test';
7
8
  import {ILogger} from '@datagrok-libraries/bio/src/utils/logger';
8
- import {IMonomerLib, IMonomerSet} from '@datagrok-libraries/bio/src/types';
9
+ import {DEFAULT_FILES_LIB_PROVIDER_NAME, findProviderWithLibraryName, IMonomerLib, IMonomerSet} from '@datagrok-libraries/bio/src/types/monomer-library';
9
10
  import {
10
11
  getUserLibSettings, setUserLibSettings,
11
12
  } from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
12
13
  import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
13
- import {
14
- IMonomerLibFileEventManager, IMonomerLibHelper,
15
- } from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
16
14
 
17
15
  import {MonomerLib} from './monomer-lib';
18
- import {MonomerSet} from './monomer-set';
19
- import {MonomerLibFileManager} from './library-file-manager/file-manager';
20
- import {MonomerLibFileEventManager} from './library-file-manager/event-manager';
21
- import {LIB_PATH, LIB_SETTINGS_FOR_TESTS, SETS_PATH} from './consts';
16
+ import {MonomerSet} from '@datagrok-libraries/bio/src/types/monomer-library';
17
+ import {LIB_SETTINGS_FOR_TESTS} from './consts';
22
18
 
23
19
  import {_package} from '../../package';
20
+ import {IMonomerLibHelper, IMonomerLibProvider} from '@datagrok-libraries/bio/src/types/monomer-library';
21
+ import {merge, Observable, Subject} from 'rxjs';
22
+ import {MonomerLibFromFilesProvider} from './library-file-manager/monomers-lib-provider';
24
23
 
25
24
  type MonomerLibWindowType = Window & { $monomerLibHelperPromise?: Promise<MonomerLibManager> };
26
25
  declare const window: MonomerLibWindowType;
@@ -32,16 +31,63 @@ export class MonomerLibManager implements IMonomerLibHelper {
32
31
  private readonly _monomerSets = new MonomerSet('MAIN', []);
33
32
  private _initialLoadCompleted: boolean = false;
34
33
  public get initialLoadCompleted(): boolean { return this._initialLoadCompleted; }
35
- private _eventManager: MonomerLibFileEventManager;
36
34
 
37
- public get eventManager(): IMonomerLibFileEventManager { return this._eventManager; }
35
+ private _providersDataChanged = new Subject<void>();
36
+ public get providersDataChanged(): Observable<void> {
37
+ return this._providersDataChanged;
38
+ }
39
+
40
+ private _fileUploadRequested = new Subject<void>();
41
+ public get fileUploadRequested(): Observable<void> {
42
+ return this._fileUploadRequested;
43
+ }
44
+ public requestFileUpload(): void {
45
+ this._fileUploadRequested.next();
46
+ }
47
+
48
+ private _selectionChanged = new Subject<void>();
49
+ public get librarySelectionChanged(): Observable<void> {
50
+ return this._selectionChanged;
51
+ }
52
+ public notifyLibrarySelectionChanged(): void {
53
+ this._selectionChanged.next();
54
+ }
55
+
56
+ async getAvaliableLibraryNames(refresh: boolean = false): Promise<string[]> {
57
+ const providers = await this.getProviders();
58
+ const libNames: string[] = [];
59
+ for (const provider of providers) {
60
+ if (refresh)
61
+ await provider.refreshLists();
62
+ const names = await provider.listLibraries();
63
+ libNames.push(...names);
64
+ }
65
+ return libNames;
66
+ }
67
+
68
+ async refreshValidLibraryLists(): Promise<void> {
69
+ const providers = await this.getProviders();
70
+ await Promise.all(providers.map(async (provider) => provider.refreshLists()));
71
+ }
72
+
73
+ async getAvailableLibrariesPerProvider(): Promise<Map<string, string[]>> {
74
+ const providers = await this.getProviders();
75
+ const libNamesMap: Map<string, string[]> = new Map();
76
+ for (const provider of providers) {
77
+ const names = await provider.listLibraries();
78
+ libNamesMap.set(provider.name, names);
79
+ }
80
+ return libNamesMap;
81
+ }
82
+
38
83
 
39
84
  public async awaitLoaded(timeout: number = Infinity): Promise<void> {
40
85
  timeout = timeout === Infinity ? 1 * 60000 : timeout; // Limit the max lib loaded timeout
41
86
  return await Promise.race([
42
87
  (async () => {
43
- const fileManager = await this.getFileManager();
44
- await fileManager.filesPromise;
88
+ const providers = await this.getProviders();
89
+ await Promise.all(providers.map(async (provider) => provider.loadPromise));
90
+ await this.loadLibrariesPromise;
45
91
  return true;
46
92
  })(),
47
93
  (async () => {
@@ -54,6 +100,24 @@ export class MonomerLibManager implements IMonomerLibHelper {
54
100
  });
55
101
  }
56
102
 
103
+ private _monomerLibProviders: IMonomerLibProvider[] | null = null;
104
+ public async getProviders(): Promise<IMonomerLibProvider[]> {
105
+ if (this._monomerLibProviders == null) {
106
+ const providerFuncs = DG.Func.find({tags: ['monomer-lib-provider']});
107
+ this._monomerLibProviders = await Promise.all(providerFuncs.map(async (func) => {
108
+ return (await func.apply({})) as IMonomerLibProvider;
109
+ }));
110
+ // hard coded files provider from bio package
111
+ this._monomerLibProviders.push(await MonomerLibFromFilesProvider.getInstance(this, _package.logger));
112
+
113
+ // eslint-disable-next-line rxjs/no-ignored-subscription --- needed for the lifetime of app
114
+ DG.debounce(merge(...this._monomerLibProviders.map((p) => p.onChanged)), 200).subscribe(() => {
115
+ this._providersDataChanged.next();
116
+ });
117
+ }
118
+ return this._monomerLibProviders;
119
+ }
120
+
57
121
  /** Protect constructor to prevent multiple instantiation. */
58
122
  protected constructor(
59
123
  private readonly logger: ILogger,
@@ -101,23 +165,9 @@ export class MonomerLibManager implements IMonomerLibHelper {
101
165
  this._monomerLib.assignDuplicatePreferences(settings);
102
166
  }
103
167
 
104
- /** Instance promise of {@link getFileManager} */
105
- private _fileManagerPromise?: Promise<MonomerLibFileManager>;
106
-
107
- async getFileManager(): Promise<MonomerLibFileManager> {
108
- if (this._fileManagerPromise === undefined) {
109
- this._fileManagerPromise = (async () => {
110
- const fileManager: MonomerLibFileManager =
111
- await MonomerLibFileManager.create(this, this._eventManager, this.logger);
112
- await fileManager.initializedPromise;
113
- return fileManager;
114
- })();
115
- }
116
- return this._fileManagerPromise;
117
- }
118
168
 
119
169
  /** Allows syncing with managing settings/loading libraries */
120
- public loadLibrariesPromise: Promise<void> = Promise.resolve();
170
+ private loadLibrariesPromise: Promise<void> = Promise.resolve();
121
171
 
122
172
  /** Loads libraries based on settings in user storage {@link LIB_STORAGE_NAME}
123
173
  * @param {boolean} reload Clean {@link monomerLib} before load libraries [false]
@@ -130,36 +180,44 @@ export class MonomerLibManager implements IMonomerLibHelper {
130
180
 
131
181
  const pi = DG.TaskBarProgressIndicator.create('Loading monomers ...');
132
182
  try {
133
- const [[libFileNameList,], settings]: [[string[],], UserLibSettings] =
134
- await Promise.all([
135
- await this.getFileManager().then((fileManager) => {
136
- return [fileManager.getValidLibraryPaths(),];
137
- }),
138
- getUserLibSettings(),
139
- ]);
140
-
141
- const filteredLibFnList = libFileNameList.filter((libFileName) => {
142
- const isFileIncluded = !settings.exclude.includes(libFileName);
143
- const isExplicit = settings.explicit.length === 0 || settings.explicit.includes(libFileName);
144
-
145
- return isFileIncluded && isExplicit;
183
+ // const [[libFileNameList,], settings]: [[string[],], UserLibSettings] =
184
+ // await Promise.all([
185
+ // await this.getFileManager().then((fileManager) => {
186
+ // return [fileManager.getValidLibraryPaths(),];
187
+ // }),
188
+ // getUserLibSettings(),
189
+ // ]);
190
+ const settings: UserLibSettings = await getUserLibSettings();
191
+ const providers = await this.getProviders();
192
+ const libNames = await Promise.all(providers.map(async (provider) => provider.listLibraries()));
193
+ libNames.forEach((names, i) => {
194
+ libNames[i] = names.filter((name) => {
195
+ const isFileIncluded = !settings.exclude.includes(name);
196
+ const isExplicit = (settings.explicit?.length ?? 0) === 0 || settings.explicit.includes(name);
197
+ return isFileIncluded && isExplicit;
198
+ });
146
199
  });
147
200
 
148
201
  let completedFileCount: number = 0;
149
- const allCount: number = filteredLibFnList.length;
150
- const [libs,]: [IMonomerLib[],] = await Promise.all([
151
- Promise.all(filteredLibFnList.map((libFileName) => {
152
- return this.readLibrary(LIB_PATH, libFileName)
153
- .catch((err: any) => {
154
- const errMsg: string = `Loading monomers from '${libFileName}' error: ` +
155
- `${err instanceof Error ? err.message : err.toString()}`;
156
- return new MonomerLib({}, libFileName, errMsg);
157
- })
158
- .finally(() => {
159
- pi.update(Math.round(100 * (++completedFileCount) / allCount),
160
- `Loading monomers ${completedFileCount}/${allCount}`);
161
- });
162
- })),]);
202
+ const libs: IMonomerLib[] = [];
203
+ for (let i = 0; i < providers.length; i++) {
204
+ const provider = providers[i];
205
+ const names = libNames[i];
206
+ try {
207
+ const libDatas = await provider.loadLibraries(names);
208
+ for (let j = 0; j < libDatas.length; j++)
209
+ libs.push(new MonomerLib(libDatas[j], names[j]));
210
+ } catch (err: any) {
211
+ grok.shell.warning(`Loading monomer libraries from provider '${provider.name}' failed: ` +
212
+ ``);
213
+ this.logger.error(`Loading monomer libraries from provider '${provider.name}' failed: ` +
214
+ `${err instanceof Error ? err.message : err.toString()}`);
215
+ }
216
+ pi.update(Math.round(100 * (++completedFileCount) / providers.length),
217
+ `Loading monomers ${completedFileCount}/${providers.length}`);
218
+ }
219
+
220
+
163
221
  this._monomerLib.updateLibs(libs, reload);
164
222
  this._initialLoadCompleted = true;
165
223
  } catch (err: any) {
@@ -189,7 +247,7 @@ export class MonomerLibManager implements IMonomerLibHelper {
189
247
 
190
248
  private loadSetsPromise: Promise<void> = Promise.resolve();
191
249
 
192
- async loadMonomerSets(reload: boolean = false): Promise<void> {
250
+ async loadMonomerSets(_reload: boolean = false): Promise<void> {
193
251
  const logPrefix = `${this.toLog()}.loadMonomerSets()`;
194
252
 
195
253
  this.logger.debug(`${logPrefix}, start`);
@@ -197,31 +255,53 @@ export class MonomerLibManager implements IMonomerLibHelper {
197
255
  this.logger.debug(`${logPrefix}, IN`);
198
256
  const pi = DG.TaskBarProgressIndicator.create(`Loading monomer sets ...`);
199
257
  try {
200
- const [[setFileNameList,]]: [[string[],],] = await Promise.all([
201
- await this.getFileManager().then((fileManager) => {
202
- return [fileManager.getValidSetPaths(),];
203
- })
204
- ]);
258
+ // const [[setFileNameList,]]: [[string[],],] = await Promise.all([
259
+ // await this.getFileManager().then((fileManager) => {
260
+ // return [fileManager.getValidSetPaths(),];
261
+ // })
262
+ // ]);
263
+
264
+ // // TODO: Filter for settings
265
+ // const filteredSetFnList = setFileNameList.filter((setFileName) => true);
266
+
267
+ // let completedFileCount: number = 0;
268
+ // const allCount: number = filteredSetFnList.length;
269
+ // const [sets,]: [IMonomerSet[],] = await Promise.all([
270
+ // Promise.all(filteredSetFnList.map((setFileName) => {
271
+ // // TODO: handle whether files are in place
272
+ // return this.readSet(SETS_PATH, setFileName)
273
+ // .catch((err: any) => {
274
+ // const errMsg: string = `Loading monomer sets from '${setFileName}' error: ` +
275
+ // `${err instanceof Error ? err.message : err.toString()}`;
276
+ // return new MonomerSet('Broken monomer set', [], setFileName, errMsg);
277
+ // })
278
+ // .finally(() => {
279
+ // pi.update(Math.round(100 * (++completedFileCount) / allCount),
280
+ // `Loading monomers ${completedFileCount}/${allCount}`);
281
+ // });
282
+ // })),]);
283
+ const providers = await this.getProviders();
284
+ const setNames = await Promise.all(providers.map(async (provider) => provider.listSets()));
285
+ const sets: IMonomerSet[] = [];
286
+ let completedFileCount: number = 0;
287
+ for (let i = 0; i < providers.length; i++) {
288
+ const provider = providers[i];
289
+ const names = setNames[i];
290
+ try {
291
+ const setDatas = await provider.loadSets(names);
292
+ for (let j = 0; j < setDatas.length; j++)
293
+ sets.push(setDatas[j]);
294
+ } catch (err: any) {
295
+ grok.shell.warning(`Loading monomer sets from provider '${provider.name}' failed: ` +
296
+ ``);
297
+ this.logger.error(`Loading monomer sets from provider '${provider.name}' failed: ` +
298
+ `${err instanceof Error ? err.message : err.toString()}`);
299
+ }
300
+ pi.update(Math.round(100 * (++completedFileCount) / providers.length),
301
+ `Loading monomer sets ${completedFileCount}/${providers.length}`);
302
+ }
205
303
 
206
- // TODO: Filter for settings
207
- const filteredSetFnList = setFileNameList.filter((setFileName) => true);
208
304
 
209
- let completedFileCount: number = 0;
210
- const allCount: number = filteredSetFnList.length;
211
- const [sets,]: [IMonomerSet[],] = await Promise.all([
212
- Promise.all(filteredSetFnList.map((setFileName) => {
213
- // TODO: handle whether files are in place
214
- return this.readSet(SETS_PATH, setFileName)
215
- .catch((err: any) => {
216
- const errMsg: string = `Loading monomer sets from '${setFileName}' error: ` +
217
- `${err instanceof Error ? err.message : err.toString()}`;
218
- return new MonomerSet('Broken monomer set', [], setFileName, errMsg);
219
- })
220
- .finally(() => {
221
- pi.update(Math.round(100 * (++completedFileCount) / allCount),
222
- `Loading monomers ${completedFileCount}/${allCount}`);
223
- });
224
- })),]);
225
305
  this._monomerSets.updateSets(sets);
226
306
  } catch (err: any) {
227
307
  const errMsg: string = 'Loading monomer sets error: ' +
@@ -239,47 +319,95 @@ export class MonomerLibManager implements IMonomerLibHelper {
239
319
  return this.loadSetsPromise;
240
320
  }
241
321
 
242
- /** Reads library from file shares, handles .json and .sdf
243
- * @param {string} path Path to library file
244
- * @param {string} fileName Name of library file
245
- * @return {Promise<IMonomerLib>} Promise of IMonomerLib
246
- */
247
- async readLibrary(path: string, fileName: string): Promise<IMonomerLib> {
248
- const fileManager = await this.getFileManager();
249
- const lib: IMonomerLib = await fileManager.loadLibraryFromFile(path, fileName);
250
- return lib;
251
- }
322
+ // /** Reads library from file shares, handles .json and .sdf
323
+ // * @param {string} path Path to library file
324
+ // * @param {string} fileName Name of library file
325
+ // * @return {Promise<IMonomerLib>} Promise of IMonomerLib
326
+ // */
327
+ // async readLibrary(path: string, fileName: string): Promise<IMonomerLib> {
328
+ // const fileManager = await this.getFileManager();
329
+ // const lib: IMonomerLib = await fileManager.loadLibraryFromFile(path, fileName);
330
+ // return lib;
331
+ // }
332
+
333
+ // async readSet(path: string, fileName: string): Promise<IMonomerSet> {
334
+ // const fileManager = await this.getFileManager();
335
+ // const set: IMonomerSet = await fileManager.loadSetFromFile(this._monomerLib, path, fileName);
336
+ // return set;
337
+ // }
338
+ // -- Settings --
252
339
 
253
- async readSet(path: string, fileName: string): Promise<IMonomerSet> {
254
- const fileManager = await this.getFileManager();
255
- const set: IMonomerSet = await fileManager.loadSetFromFile(this._monomerLib, path, fileName);
256
- return set;
340
+ /** Changes userLibSettings set only HELMCoreLibrary.json, polytool-lib.json */
341
+ async loadMonomerLibForTests(): Promise<void> {
342
+ await setUserLibSettings(LIB_SETTINGS_FOR_TESTS);
343
+ await this.awaitLoaded(10000);
344
+ await this.loadMonomerLib(true); // load default libraries
257
345
  }
258
346
 
259
- /** Reset user settings to the specified library. WARNING: clears user * settings */
260
- public async selectSpecifiedLibraries(libFileNameList: string[]): Promise<void> {
261
- const invalidNames = await this.getInvalidFileNames(libFileNameList);
262
- if (invalidNames.length > 0)
263
- throw new Error(`Cannot select libraries ${invalidNames}: no such library in the list`);
264
- const settings = await getUserLibSettings();
265
- settings.exclude = ((await this.getFileManager()).getValidLibraryPaths())
266
- .filter((fileName) => !libFileNameList.includes(fileName));
267
- await setUserLibSettings(settings);
347
+ async readSingleLibrary(providerName: string, libraryName: string): Promise<IMonomerLib | null> {
348
+ const providers = await this.getProviders();
349
+ const provider = providers.find((p) => p.name === providerName);
350
+ if (!provider) {
351
+ this.logger.error(`Provider '${providerName}' not found.`);
352
+ return null;
353
+ }
354
+ try {
355
+ const libDatas = await provider.loadLibraries([libraryName]);
356
+ if (libDatas.length === 0) {
357
+ this.logger.error(`Library '${libraryName}' not found in provider '${providerName}'.`);
358
+ return null;
359
+ }
360
+ return new MonomerLib(libDatas[0], libraryName);
361
+ } catch (err: any) {
362
+ this.logger.error(`Loading monomer library '${libraryName}' from provider '${provider.name}' failed: ` +
363
+ `${err instanceof Error ? err.message : err.toString()}`);
364
+ return null;
365
+ }
268
366
  }
269
367
 
270
- private async getInvalidFileNames(libFileNameList: string[]): Promise<string[]> {
271
- const availableFileNames = (await this.getFileManager()).getValidLibraryPaths();
272
- const invalidNames = libFileNameList.filter((fileName) => !availableFileNames.includes(fileName));
273
- return invalidNames;
368
+
369
+ async readLibraryFromFilePath(filePath: string): Promise<IMonomerLib> {
370
+ const provider: MonomerLibFromFilesProvider = (await this.getProviders()).find((p) => p.name === DEFAULT_FILES_LIB_PROVIDER_NAME) as MonomerLibFromFilesProvider;
371
+ if (!provider) {
372
+ // Just in case, but this should never happen
373
+ throw new Error(`Provider '${DEFAULT_FILES_LIB_PROVIDER_NAME}' not found.`);
374
+ }
375
+
376
+ const res = await provider.getSingleLibraryWithFullPath(filePath);
377
+ if (!res)
378
+ throw new Error(`Library at path '${filePath}' not found.`);
379
+ return new MonomerLib(res, filePath);
274
380
  }
275
381
 
276
- // -- Settings --
382
+ async readSingleLibraryByName(libraryName: string): Promise<IMonomerLib | null> {
383
+ const providers = await this.getProviders();
384
+ const provider = await findProviderWithLibraryName(providers, libraryName);
385
+ if (!provider) {
386
+ this.logger.error(`No provider found for library '${libraryName}'.`);
387
+ return null;
388
+ }
389
+ return this.readSingleLibrary(provider.name, libraryName);
390
+ }
277
391
 
278
- /** Changes userLibSettings set only HELMCoreLibrary.json, polytool-lib.json */
279
- async loadMonomerLibForTests(): Promise<void> {
280
- await setUserLibSettings(LIB_SETTINGS_FOR_TESTS);
281
- await this.awaitLoaded(10000);
282
- await this.loadMonomerLib(true); // load default libraries
392
+ async readSingleSet(providerName: string, setName: string): Promise<IMonomerSet | null> {
393
+ const providers = await this.getProviders();
394
+ const provider = providers.find((p) => p.name === providerName);
395
+ if (!provider) {
396
+ this.logger.error(`Provider '${providerName}' not found.`);
397
+ return null;
398
+ }
399
+ try {
400
+ const setDatas = await provider.loadSets([setName]);
401
+ if (setDatas.length === 0) {
402
+ this.logger.error(`Set '${setName}' not found in provider '${providerName}'.`);
403
+ return null;
404
+ }
405
+ return setDatas[0];
406
+ } catch (err: any) {
407
+ this.logger.error(`Loading monomer set '${setName}' from provider '${provider.name}' failed: ` +
408
+ `${err instanceof Error ? err.message : err.toString()}`);
409
+ return null;
410
+ }
283
411
  }
284
412
 
285
413
  // -- Instance singleton --
@@ -288,7 +416,6 @@ export class MonomerLibManager implements IMonomerLibHelper {
288
416
  if (res == undefined) {
289
417
  res = window.$monomerLibHelperPromise = (async () => {
290
418
  const instance = new MonomerLibManager(_package.logger);
291
- instance._eventManager = MonomerLibFileEventManager.getInstance();
292
419
  return instance;
293
420
  })();
294
421
  }
@@ -22,7 +22,7 @@ export class MonomerLibFileValidator {
22
22
 
23
23
  validateFile(fileContent: string, fileName: string): boolean {
24
24
  const jsonContent = this.parseJson(fileContent, fileName);
25
- if (jsonContent === null)
25
+ if (jsonContent == null)
26
26
  return false;
27
27
 
28
28
  if (!Array.isArray(jsonContent)) {