openchemlib 9.8.0 → 9.10.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.
@@ -36,6 +36,44 @@ export interface MoleculeFromSmilesOptions {
36
36
  noStereo?: boolean;
37
37
  }
38
38
 
39
+ interface FromMolfileOptions {
40
+ /**
41
+ * If set to 'superscript', it will add a ']' at the beginning of the custom label to be
42
+ * compatible with the way to represent superscript in OCL
43
+ * If set to 'normal', it will remove the ']' at the beginning of the custom label if present
44
+ * If set to 'auto', it will set normal for 'C' and superscript for everything else
45
+ * If not set, it will keep the label as is
46
+ * Default: undefined (keep as is)
47
+ * @default undefined
48
+ */
49
+ customLabelPosition?: 'normal' | 'superscript' | 'auto' | undefined;
50
+ }
51
+
52
+ interface ToMolfileOptions {
53
+ /**
54
+ * Include custom atom labels as A lines
55
+ */
56
+ includeCustomAtomLabelsAsALines?: boolean;
57
+ /**
58
+ * Include custom atom labels as V lines
59
+ */
60
+ includeCustomAtomLabelsAsVLines?: boolean;
61
+ /**
62
+ * If set to 'superscript', it will add a ']' at the beginning of the custom label to be
63
+ * compatible with the way to represent superscript in OCL
64
+ * If set to 'normal', it will remove the ']' at the beginning of the custom label if present
65
+ * If not set, it will keep the label as is
66
+ * Default: undefined (keep as is)
67
+ * @default undefined
68
+ */
69
+ customLabelPosition?: 'normal' | 'superscript' | 'auto' | undefined;
70
+ /**
71
+ * Remove custom atom labels
72
+ * @default false
73
+ */
74
+ removeCustomAtomLabels?: boolean;
75
+ }
76
+
39
77
  export interface AtomQueryFeatures {
40
78
  aromatic: boolean;
41
79
  notAromatic: boolean;
@@ -480,7 +518,7 @@ export declare class Molecule {
480
518
  * Parse the provided `molfile` and return a `Molecule`.
481
519
  * @param molfile - MDL Molfile string in V2000 or V3000
482
520
  */
483
- static fromMolfile(molfile: string): Molecule;
521
+ static fromMolfile(molfile: string, options?: FromMolfileOptions): Molecule;
484
522
 
485
523
  /**
486
524
  * Parse the provided `molfile` and return an object with `Molecule` and map.
@@ -557,9 +595,13 @@ export declare class Molecule {
557
595
  toIsomericSmiles(options?: SmilesGeneratorOptions): string;
558
596
 
559
597
  /**
560
- * Returns a MDL Molfile V2000 string.
598
+ * Returns a molfile V2000 with the possibility to add A and V lines to set custom atom labels
599
+ * Those fileds only exists in molfiles V2000
600
+ * @param molecule - the molecule to convert
601
+ * @param options - options to include A or V lines
602
+ * @returns the molfile as a string
561
603
  */
562
- toMolfile(): string;
604
+ toMolfile(options?: ToMolfileOptions): string;
563
605
 
564
606
  /**
565
607
  * Returns a MDL Molfile V3000 string.
@@ -1288,6 +1288,141 @@ function init(OCL) {
1288
1288
  delete OCL.GenericUIHelper;
1289
1289
  }
1290
1290
 
1291
+ // lib/extend/utils/changeMolfileCustomLabelPosition.js
1292
+ function changeMolfileCustomLabelPosition(molecule, customLabelPosition) {
1293
+ switch (customLabelPosition) {
1294
+ case "superscript":
1295
+ for (let i = 0; i < molecule.getAllAtoms(); i++) {
1296
+ const customLabel = molecule.getAtomCustomLabel(i);
1297
+ if (customLabel && !customLabel.startsWith("]")) {
1298
+ molecule.setAtomCustomLabel(i, `]${customLabel}`);
1299
+ }
1300
+ }
1301
+ break;
1302
+ case "normal":
1303
+ for (let i = 0; i < molecule.getAllAtoms(); i++) {
1304
+ const customLabel = molecule.getAtomCustomLabel(i);
1305
+ if (customLabel?.startsWith("]")) {
1306
+ molecule.setAtomCustomLabel(i, customLabel.slice(1));
1307
+ }
1308
+ }
1309
+ break;
1310
+ case "auto":
1311
+ for (let i = 0; i < molecule.getAllAtoms(); i++) {
1312
+ const customLabel = molecule.getAtomCustomLabel(i);
1313
+ if (customLabel) {
1314
+ const atomLabel = molecule.getAtomLabel(i);
1315
+ if (atomLabel === "C") {
1316
+ if (customLabel.startsWith("]")) {
1317
+ molecule.setAtomCustomLabel(i, customLabel.slice(1));
1318
+ }
1319
+ } else if (!customLabel.startsWith("]")) {
1320
+ molecule.setAtomCustomLabel(i, `]${customLabel}`);
1321
+ }
1322
+ }
1323
+ }
1324
+ break;
1325
+ case void 0:
1326
+ break;
1327
+ default:
1328
+ break;
1329
+ }
1330
+ }
1331
+
1332
+ // lib/extend/extendFromMolfile.js
1333
+ function extendFromMolfile(Molecule2) {
1334
+ const _fromMolfile = Molecule2.fromMolfile;
1335
+ Molecule2.fromMolfile = function fromMolfile(molfile, options = {}) {
1336
+ const { customLabelPosition } = options;
1337
+ const molecule = _fromMolfile.call(this, molfile);
1338
+ const lines = molfile.split("\n");
1339
+ if (lines.length < 4 || !lines[3].includes("V2000")) {
1340
+ return molecule;
1341
+ }
1342
+ const possibleLines = lines.slice(
1343
+ 4 + molecule.getAllAtoms() + molecule.getAllBonds()
1344
+ );
1345
+ for (let i = 0; i < possibleLines.length; i++) {
1346
+ const line = possibleLines[i];
1347
+ if (line.startsWith("A ")) {
1348
+ const atom = Number(line.slice(3));
1349
+ const valueLine = possibleLines[i + 1]?.trim();
1350
+ i++;
1351
+ if (!Number.isNaN(atom) && atom <= molecule.getAllAtoms() && valueLine && !molecule.getAtomCustomLabel(atom - 1)) {
1352
+ molecule.setAtomCustomLabel(atom - 1, valueLine);
1353
+ }
1354
+ }
1355
+ if (line.startsWith("V ")) {
1356
+ const parts = line.split(" ").filter(Boolean);
1357
+ if (parts.length >= 3) {
1358
+ const atom = Number(parts[1]);
1359
+ const label = parts.slice(2).join(" ");
1360
+ if (!Number.isNaN(atom) && atom <= molecule.getAllAtoms() && !molecule.getAtomCustomLabel(atom - 1)) {
1361
+ molecule.setAtomCustomLabel(atom - 1, label);
1362
+ }
1363
+ }
1364
+ }
1365
+ }
1366
+ changeMolfileCustomLabelPosition(molecule, customLabelPosition);
1367
+ return molecule;
1368
+ };
1369
+ }
1370
+
1371
+ // lib/extend/extendToMolfile.js
1372
+ var CUSTOM_ATOMS_LABELS_TAGS = [
1373
+ "M STY",
1374
+ "M SLB",
1375
+ "M SAL",
1376
+ "M SDT",
1377
+ "M SDD",
1378
+ "M SED"
1379
+ ];
1380
+ function extendToMolfile(Molecule2) {
1381
+ const _toMolfile = Molecule2.prototype.toMolfile;
1382
+ Molecule2.prototype.toMolfile = function toMolfile(options = {}) {
1383
+ let molecule = this.getCompactCopy();
1384
+ const {
1385
+ includeCustomAtomLabelsAsALines = false,
1386
+ includeCustomAtomLabelsAsVLines = false,
1387
+ customLabelPosition,
1388
+ removeCustomAtomLabels = false
1389
+ } = options;
1390
+ changeMolfileCustomLabelPosition(molecule, customLabelPosition);
1391
+ const molfile = _toMolfile.call(this);
1392
+ if (!includeCustomAtomLabelsAsALines && !includeCustomAtomLabelsAsVLines && !removeCustomAtomLabels) {
1393
+ return molfile;
1394
+ }
1395
+ let lines = molfile.split("\n");
1396
+ if (removeCustomAtomLabels) {
1397
+ lines = lines.filter(
1398
+ (line) => !CUSTOM_ATOMS_LABELS_TAGS.some((tag) => line.startsWith(tag))
1399
+ );
1400
+ }
1401
+ if (lines.length < 4 || !lines[3].includes("V2000")) {
1402
+ return molfile;
1403
+ }
1404
+ const newLines = [];
1405
+ for (let i = 0; i < molecule.getAllAtoms(); i++) {
1406
+ const label = molecule.getAtomCustomLabel(i);
1407
+ if (label) {
1408
+ const paddedAtomNumber = String(i + 1).padStart(3, " ");
1409
+ if (includeCustomAtomLabelsAsALines) {
1410
+ newLines.push(`A ${paddedAtomNumber}`, label);
1411
+ }
1412
+ if (includeCustomAtomLabelsAsVLines) {
1413
+ newLines.push(`V ${paddedAtomNumber} ${label}`);
1414
+ }
1415
+ }
1416
+ }
1417
+ const mEndIndex = lines.findIndex((line) => line.startsWith("M END"));
1418
+ if (mEndIndex === -1) {
1419
+ return molfile;
1420
+ }
1421
+ lines.splice(mEndIndex, 0, ...newLines);
1422
+ return lines.join("\n");
1423
+ };
1424
+ }
1425
+
1291
1426
  // lib/extend/index.js
1292
1427
  function extendOCL(OCL) {
1293
1428
  const { ConformerGenerator: ConformerGenerator2, ForceFieldMMFF94: ForceFieldMMFF942, Molecule: Molecule2 } = OCL;
@@ -1313,6 +1448,8 @@ function extendOCL(OCL) {
1313
1448
  options.funcTol
1314
1449
  );
1315
1450
  };
1451
+ extendFromMolfile(Molecule2);
1452
+ extendToMolfile(Molecule2);
1316
1453
  function parseMoleculeFromText(text) {
1317
1454
  if (!text) {
1318
1455
  return null;
@@ -71020,7 +71157,7 @@ function getExports($wnd) {
71020
71157
  $sendStats("moduleStartup", "end");
71021
71158
  $gwt && $gwt.permProps && __gwtModuleFunction.__moduleStartupDone($gwt.permProps);
71022
71159
  const toReturn = $wnd["OCL"];
71023
- toReturn.version = "9.8.0";
71160
+ toReturn.version = "9.10.0";
71024
71161
  return toReturn;
71025
71162
  }
71026
71163
  var isBrowserWindow = typeof window !== "undefined" && typeof window.document !== "undefined";
@@ -71164,8 +71301,8 @@ export {
71164
71301
  };
71165
71302
  /**
71166
71303
  * openchemlib - Manipulate molecules
71167
- * @version v9.8.0
71168
- * @date 2025-09-15T09:15:58.106Z
71304
+ * @version v9.10.0
71305
+ * @date 2025-10-08T14:06:44.519Z
71169
71306
  * @link https://github.com/cheminfo/openchemlib-js
71170
71307
  * @license BSD-3-Clause
71171
71308
  */