/**************************************************************************** * Copyright 2017 EPAM Systems * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ***************************************************************************/ import molfile from '../chem/molfile'; export const map = { 'mol': { name: 'MDL Molfile', mime: 'chemical/x-mdl-molfile', ext: ['.mol'], supportsCoords: true }, 'rxn': { name: 'MDL Rxnfile', mime:'chemical/x-mdl-rxnfile', ext: ['.rxn'], supportsCoords: true }, 'cml': { name: 'CML', mime: 'chemical/x-cml', ext: ['.cml', '.mrv'], supportsCoords: true }, 'smiles': { name: 'Daylight SMILES', mime: 'chemical/x-daylight-smiles', ext: ['.smi', '.smiles'] }, 'smarts': { name: 'Daylight SMARTS', mime: 'chemical/x-daylight-smarts', ext: ['.smarts'] }, 'inchi': { name: 'InChI String', mime: 'chemical/x-inchi', ext: ['.inchi'] } }; export function guess (structStr, strict) { // Mimic Indigo/molecule_auto_loader.cpp as much as possible const molStr = structStr.trim(); if (molStr.indexOf('$RXN') !== -1) return 'rxn'; const molMatch = molStr.match(/^(M END|\$END MOL)$/m); if (molMatch) { const end = molMatch.index + molMatch[0].length; if (end === molStr.length || molStr.slice(end, end + 20).search(/^\$(MOL|END CTAB)$/m) !== -1) return 'mol'; } if (molStr[0] === '<' && molStr.indexOf(' { var moldata = molfile.stringify(struct); if (format === 'mol' || format === 'rxn') resolve(moldata); else resolve(server.then(() => ( server.convert({ struct: moldata, output_format: map[format].mime }, serverOpts) ), () => { throw Error(map[format].name + ' is not supported in the standalone mode'); }).then(res => res.struct)); }); } export function fromString (structStr, opts, server, serverOpts) { return new Promise(function (resolve, reject) { const format = guess(structStr); console.assert(map[format], 'No such format'); if (format === 'mol' || format === 'rxn') { const struct = molfile.parse(structStr, opts); resolve(struct); } else { let withCoords = map[format].supportsCoords; resolve(server.then(() => ( withCoords ? server.convert({ struct: structStr, output_format: map['mol'].mime }, serverOpts) : server.layout({ struct: structStr.trim(), output_format: map['mol'].mime }, serverOpts) ), () => { throw Error(map[format].name + ' is not supported in the standalone mode'); }).then(res => { let struct = molfile.parse(res.struct); if (!withCoords) struct.rescale(); return struct; })); } }); } // Pretty stupid Inchi check (extract from save) export function couldBeSaved(struct, format) { if (format === 'inchi') { if (struct.rgroups.count() !== 0) throw 'R-group fragments are not supported and will be discarded'; struct = struct.clone(); // need this: .getScaffold() struct.sgroups.each((sgid, sg) => { // ? Not sure we should check it client side if (sg.type !== 'MUL' && !/^INDIGO_.+_DESC$/i.test(sg.data.fieldName)) throw Error('InChi data format doesn\'t support s-groups'); }); } }