export function couldBeSaved()

in packages/ketcher-react/src/script/ui/data/convert/structConverter.ts [27:186]


export function couldBeSaved(
  struct: Struct,
  format: SupportedFormat,
): string | null {
  const warnings: Array<string> = [];
  const formatName: string = getPropertiesByFormat(format).name;

  const rxnArrowsSize = struct.rxnArrows.size;
  const hasRxnArrow = struct.hasRxnArrow();

  if (format === 'smarts') {
    const arrayOfAtoms: Array<Atom> = Array.from(struct.atoms.values());
    const arrayOfBonds: Array<Bond> = Array.from(struct.bonds.values());

    const atomsHaveUnsupportedProperties = arrayOfAtoms.some(
      (atom) =>
        atom.radical ||
        atom.unsaturatedAtom ||
        atom.exactChangeFlag ||
        atom.invRet,
    );
    const bondsHaveUnsupportedProperties = arrayOfBonds.some(
      (bond) =>
        bond.reactingCenterStatus ||
        bond.type === Bond.PATTERN.TYPE.DATIVE ||
        bond.type === Bond.PATTERN.TYPE.HYDROGEN,
    );
    if (bondsHaveUnsupportedProperties || atomsHaveUnsupportedProperties) {
      warnings.push(
        `Structure contains query properties of atoms and bonds that are not supported in the SMARTS. Query properties will not be reflected in the file saved.`,
      );
    }
  }

  if (format === 'smiles') {
    const arrayOfAtoms: Array<any> = Array.from(struct.atoms.values());
    const hasGenerics = arrayOfAtoms.some((atom) => atom.pseudo);
    if (hasGenerics) {
      warnings.push(
        `Structure contains generic atoms. They will be saved as any atom (*).`,
      );
    }
  }

  if (format !== 'ket') {
    if (hasRxnArrow) {
      const arrayOfArrows: Array<any> = Array.from(struct.rxnArrows.values());
      const rxnArrowMode: RxnArrowMode = arrayOfArrows[0].mode;
      if (
        ![RxnArrowMode.OpenAngle, RxnArrowMode.Retrosynthetic].includes(
          rxnArrowMode,
        )
      ) {
        warnings.push(
          `The ${formatName} format does not support drawn elements: the reaction ${rxnArrowMode} arrow will be replaced with the reaction arrow`,
        );
      }
    }

    // TODO: find better solution for case when Arrows > 1
    if (rxnArrowsSize > 1) {
      warnings.push(
        `The ${formatName} format does not support drawn elements: reaction arrows will be lost.`,
      );
    }
  }

  if (
    (
      [
        'inChI',
        'inChIAuxInfo',
        'inChIKey',
        'smiles',
        'smilesExt',
      ] as SupportedFormat[]
    ).includes(format)
  ) {
    if (struct.rgroups.size !== 0)
      warnings.push(
        `In ${formatName} the structure will be saved without R-group fragments`,
      );

    struct = struct.clone(); // need this: .getScaffold()
    const isRg = struct.atoms.find((_ind, atom) => atom.label === 'R#');
    if (isRg !== null)
      warnings.push(
        `In ${formatName} the structure will be saved without R-group members`,
      );

    const isSg = struct.sgroups.find(
      (_ind, sg) =>
        sg.type !== 'MUL' && !/^INDIGO_.+_DESC$/i.test(sg.data.fieldName),
    );
    if (isSg !== null)
      warnings.push(
        `In ${formatName} the structure will be saved without S-groups`,
      );
  }

  if (
    (
      [
        'smiles',
        'smilesExt',
        'smarts',
        'inChI',
        'inChIAuxInfo',
        'inChIKey',
        'cml',
      ] as SupportedFormat[]
    ).includes(format)
  ) {
    const isVal = struct.atoms.find((_ind, atom) => atom.explicitValence >= 0);
    if (isVal !== null)
      warnings.push(`In ${formatName} valence is not supported`);
  }

  if (
    (['mol', 'rxn'] as SupportedFormat[]).includes(format) &&
    Array.from(struct.frags.values()).some((fr) => {
      if (fr?.enhancedStereoFlag) {
        return fr.enhancedStereoFlag !== StereoFlag.Abs;
      }
      return false;
    })
  ) {
    warnings.push(
      `Structure contains enhanced stereochemistry features. Information will be partly lost.`,
    );
  }

  if (
    (
      [
        'inChI',
        'inChIAuxInfo',
        'inChIKey',
        'smiles',
        'smilesExt',
      ] as SupportedFormat[]
    ).includes(format)
  ) {
    if (struct.functionalGroups.size !== 0)
      warnings.push(
        `In ${formatName} the structure will be saved without functional groups.`,
      );
  }

  if ((['cml'] as SupportedFormat[]).includes(format)) {
    if (struct.functionalGroups.size !== 0)
      warnings.push(
        `Structure contains functional groups. In ${formatName} information will be partly lost.`,
      );
  }

  if (warnings.length !== 0) return warnings.join('\n');

  return null;
}