ChemPal Documentation - v1.6.0
    Preparing search index...

    Function parseChemicalSpecs

    • Extracts structured chemical properties (purity, molecular formula, molecular weight, SMILES) from a supplier's free-form, HTML-laced product copy. Built for Wix suppliers whose specs live inside descriptions and additional-info accordions as loosely-labelled bullet lists — labels and separators vary wildly (MW -, Molecular mass :, Formula:), so each field is matched tolerantly and validated before being returned. CAS numbers are intentionally left to findCAS (in helpers/cas), which already searches free text robustly.

      Parameters

      • html: string

        Raw product copy, possibly containing HTML markup

      Returns ChemicalSpecs

      The chemical properties found; fields absent or invalid are omitted

      parseChemicalSpecs("<p>Purity: 98%+</p><p>Formula: C5H9KO2</p><p>MW: 140.22g/mol</p>")
      // { purity: 98, formula: "C5H9KO2", molecularWeight: 140.22 }
      parseChemicalSpecs("<li>MW - 136.169 G/MOL</li><li>SMILES: [K+].CCCCC([O-])=O</li>")
      // { molecularWeight: 136.169, smiles: "[K+].CCCCC([O-])=O" }
      parseChemicalSpecs("Ships in 4-6 business days") // {}
      export const parseChemicalSpecs = (html: string): ChemicalSpecs => {
      if (!html || typeof html !== 'string') return {};

      const text = normalizeSpecText(html);
      const lines = text.split('\n').map((line) => line.trim());
      const specs: ChemicalSpecs = {};

      const purity = extractPurity(lines);
      const grade = extractGrade(lines);

      if (purity !== undefined) specs.purity = purity;
      if (grade !== undefined) specs.grade = grade;

      // Iterate every "…formula…" match and keep the first candidate that validates: the copy may say
      // "the rough formula is C6H15NO3" (capturing the word "is") before the real "Empirical formula
      // C6H15NO3", and a single match would stop at the bogus first hit. Clean single formulas (e.g.
      // "NaOH") are kept verbatim; salts/adducts joined by a dot (e.g. "C6H15NO3.H3PO4") aren't valid
      // isMoleForm, so fall back to the tolerant finder.
      for (const formulaMatch of text.matchAll(new RegExp(FORMULA_REGEX.source, 'gi'))) {
      const rawFormula = formulaMatch[1];
      const formula = isMoleForm(rawFormula) ? rawFormula : findFormulaInText(rawFormula);
      if (formula) {
      specs.formula = formatFormula(formula);
      break;
      }
      }

      const molecularWeight = findMolarMass(text);
      if (molecularWeight !== undefined) specs.molecularWeight = molecularWeight;

      const smilesMatch = text.match(SMILES_LABEL_REGEX);
      if (smilesMatch && looksLikeSmiles(smilesMatch[1])) specs.smiles = smilesMatch[1];

      return specs;
      };