{"version":3,"file":"sdf-parser.min.js","sources":["../node_modules/ensure-string/lib-esm/index.js","../node_modules/isutf8/dist/index.esm.js","../src/util/getMolecule.js","../node_modules/dynamic-typing/lib-esm/parseString.js","../src/MolfileStream.js","../src/iterator.js","../src/parse.js","../src/getEntriesBoundaries.js"],"sourcesContent":["import isutf8 from 'isutf8';\n/**\n * Ensure that the data is string. If it is an ArrayBuffer it will be converted to string using TextDecoder.\n * @param blob\n * @param options\n * @returns\n */\nexport function ensureString(blob, options = {}) {\n    if (typeof blob === 'string') {\n        return blob;\n    }\n    if (ArrayBuffer.isView(blob) || blob instanceof ArrayBuffer) {\n        const { encoding = guessEncoding(blob) } = options;\n        const decoder = new TextDecoder(encoding);\n        return decoder.decode(blob);\n    }\n    throw new TypeError(`blob must be a string, ArrayBuffer or ArrayBufferView`);\n}\nfunction guessEncoding(blob) {\n    const uint8 = ArrayBuffer.isView(blob)\n        ? new Uint8Array(blob.buffer, blob.byteOffset, blob.byteLength)\n        : new Uint8Array(blob);\n    if (uint8.length >= 2) {\n        if (uint8[0] === 0xfe && uint8[1] === 0xff) {\n            return 'utf-16be';\n        }\n        if (uint8[0] === 0xff && uint8[1] === 0xfe) {\n            return 'utf-16le';\n        }\n    }\n    //@ts-expect-error an ArrayBuffer is also ok\n    if (!isutf8(blob))\n        return 'latin1';\n    return 'utf-8';\n}\n//# sourceMappingURL=index.js.map","/*\n    https://tools.ietf.org/html/rfc3629\n\n    UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4\n\n    UTF8-1    = %x00-7F\n\n    UTF8-2    = %xC2-DF UTF8-tail\n\n    UTF8-3    = %xE0 %xA0-BF UTF8-tail\n                %xE1-EC 2( UTF8-tail )\n                %xED %x80-9F UTF8-tail\n                %xEE-EF 2( UTF8-tail )\n\n    UTF8-4    = %xF0 %x90-BF 2( UTF8-tail )\n                %xF1-F3 3( UTF8-tail )\n                %xF4 %x80-8F 2( UTF8-tail )\n\n    UTF8-tail = %x80-BF\n*/\n/**\n * Check if a Node.js Buffer or Uint8Array is UTF-8.\n */\nfunction isUtf8(buf) {\n    if (!buf) {\n        return false;\n    }\n    var i = 0;\n    var len = buf.length;\n    while (i < len) {\n        // UTF8-1 = %x00-7F\n        if (buf[i] <= 0x7F) {\n            i++;\n            continue;\n        }\n        // UTF8-2 = %xC2-DF UTF8-tail\n        if (buf[i] >= 0xC2 && buf[i] <= 0xDF) {\n            // if(buf[i + 1] >= 0x80 && buf[i + 1] <= 0xBF) {\n            if (buf[i + 1] >> 6 === 2) {\n                i += 2;\n                continue;\n            }\n            else {\n                return false;\n            }\n        }\n        // UTF8-3 = %xE0 %xA0-BF UTF8-tail\n        // UTF8-3 = %xED %x80-9F UTF8-tail\n        if (((buf[i] === 0xE0 && buf[i + 1] >= 0xA0 && buf[i + 1] <= 0xBF) ||\n            (buf[i] === 0xED && buf[i + 1] >= 0x80 && buf[i + 1] <= 0x9F)) && buf[i + 2] >> 6 === 2) {\n            i += 3;\n            continue;\n        }\n        // UTF8-3 = %xE1-EC 2( UTF8-tail )\n        // UTF8-3 = %xEE-EF 2( UTF8-tail )\n        if (((buf[i] >= 0xE1 && buf[i] <= 0xEC) ||\n            (buf[i] >= 0xEE && buf[i] <= 0xEF)) &&\n            buf[i + 1] >> 6 === 2 &&\n            buf[i + 2] >> 6 === 2) {\n            i += 3;\n            continue;\n        }\n        // UTF8-4 = %xF0 %x90-BF 2( UTF8-tail )\n        //          %xF1-F3 3( UTF8-tail )\n        //          %xF4 %x80-8F 2( UTF8-tail )\n        if (((buf[i] === 0xF0 && buf[i + 1] >= 0x90 && buf[i + 1] <= 0xBF) ||\n            (buf[i] >= 0xF1 && buf[i] <= 0xF3 && buf[i + 1] >> 6 === 2) ||\n            (buf[i] === 0xF4 && buf[i + 1] >= 0x80 && buf[i + 1] <= 0x8F)) &&\n            buf[i + 2] >> 6 === 2 &&\n            buf[i + 3] >> 6 === 2) {\n            i += 4;\n            continue;\n        }\n        return false;\n    }\n    return true;\n}\n\nexport { isUtf8 as default };\n","/**\n * Parse the molfile and the properties with > < labels >\n * @param {string} sdfPart\n * @param {*} labels\n * @param {*} currentLabels\n * @param {object} options\n * @returns\n */\nexport function getMolecule(sdfPart, labels, currentLabels, options) {\n  let parts = sdfPart.split(`${options.eol}>`);\n  if (parts.length === 0 || parts[0].length <= 5) return;\n  let molecule = {};\n  molecule.molfile = parts[0] + options.eol;\n  for (let j = 1; j < parts.length; j++) {\n    let lines = parts[j].split(options.eol);\n    let from = lines[0].indexOf('<');\n    let to = lines[0].indexOf('>');\n    let label = lines[0].slice(from + 1, to);\n    currentLabels.push(label);\n    if (!labels[label]) {\n      labels[label] = {\n        counter: 0,\n        isNumeric: options.dynamicTyping,\n        keep: false,\n      };\n      if (\n        (!options.exclude || !options.exclude.includes(label)) &&\n        (!options.include || options.include.includes(label))\n      ) {\n        labels[label].keep = true;\n        if (options.modifiers[label]) {\n          labels[label].modifier = options.modifiers[label];\n        }\n        if (options.forEach[label]) {\n          labels[label].forEach = options.forEach[label];\n        }\n      }\n    }\n    if (labels[label].keep) {\n      for (let k = 1; k < lines.length - 1; k++) {\n        if (molecule[label]) {\n          molecule[label] += options.eol + lines[k];\n        } else {\n          molecule[label] = lines[k];\n        }\n      }\n      if (labels[label].modifier) {\n        let modifiedValue = labels[label].modifier(molecule[label]);\n        if (modifiedValue === undefined || modifiedValue === null) {\n          delete molecule[label];\n        } else {\n          molecule[label] = modifiedValue;\n        }\n      }\n      if (\n        labels[label].isNumeric &&\n        (!Number.isFinite(+molecule[label]) || molecule[label].match(/^0[0-9]/))\n      ) {\n        labels[label].isNumeric = false;\n      }\n    }\n  }\n  return molecule;\n}\n","export function parseString(value) {\n    if (value.length === 4 || value.length === 5) {\n        const lowercase = value.toLowerCase();\n        if (lowercase === 'true')\n            return true;\n        if (lowercase === 'false')\n            return false;\n    }\n    const number = Number(value);\n    if (number === 0 && !value.includes('0')) {\n        return value;\n    }\n    if (!Number.isNaN(number))\n        return number;\n    return value;\n}\n//# sourceMappingURL=parseString.js.map","export class MolfileStream extends TransformStream {\n  #buffer = '';\n\n  constructor() {\n    super({\n      transform: (chunk, controller) => {\n        this.#buffer += chunk;\n        let begin = 0;\n        let index = 0;\n        while ((index = this.#buffer.indexOf('$$$$', index)) !== -1) {\n          // we need to check if the delimiter '\\n' is in the current buffer\n          // if it is not we need to wait for the next chunk\n          const endOfDelimiter = this.#buffer.indexOf('\\n', index);\n          if (endOfDelimiter === -1) {\n            index = begin;\n            break;\n          }\n          const eolLength = this.#buffer[endOfDelimiter - 1] === '\\r' ? 2 : 1;\n          // need to remove the last eol because we will split on eol+'>' in getMolecule\n          if (index - eolLength - begin > 40) {\n            controller.enqueue(this.#buffer.slice(begin, index - eolLength));\n          }\n          index = endOfDelimiter + eolLength;\n          begin = index;\n        }\n        this.#buffer = this.#buffer.slice(begin);\n      },\n      flush: (controller) => {\n        if (this.#buffer && this.#buffer.length > 40) {\n          controller.enqueue(this.#buffer);\n        }\n      },\n    });\n  }\n}\n","import { parseString } from 'dynamic-typing';\n\nimport { MolfileStream } from './MolfileStream.js';\n\n/**\n *  Parse a SDF file as an iterator\n * @param {ReadableStream} readStream - SDF file to parse\n * @param {object} [options={}] - iterator options\n * @param {Function} [options.filter] - Callback allowing to filter the molecules\n * @param {string} [options.eol='\\n'] - End of line character\n * @param {boolean} [options.dynamicTyping] - Dynamically type the data\n * @yields {object} - Molecule object\n */\nexport async function* iterator(readStream, options = {}) {\n  const { eol = '\\n', dynamicTyping = true } = options;\n\n  const moleculeStream = readStream.pipeThrough(new MolfileStream({ eol }));\n  for await (const entry of moleculeStream) {\n    const molecule = getMolecule(entry, {\n      eol,\n      dynamicTyping,\n    });\n    if (!options.filter || options.filter(molecule)) {\n      yield molecule;\n    }\n  }\n}\n\n/**\n * Convert a SDF part to an object\n * @param {string} sdfPart - text containing the molfile\n * @param {object} options - options\n * @param {string} options.eol - end of line character\n * @param {boolean} options.dynamicTyping - Dynamically type the data (create numbers and booleans)\n * @returns\n */\nfunction getMolecule(sdfPart, options) {\n  const { eol, dynamicTyping } = options;\n  let parts = sdfPart.split(`${eol}>`);\n  if (parts.length === 0 || parts[0].length <= 5) return;\n  let molecule = {};\n  molecule.molfile = parts[0] + eol;\n  for (let j = 1; j < parts.length; j++) {\n    let lines = parts[j].split(eol);\n    let from = lines[0].indexOf('<');\n    let to = lines[0].indexOf('>');\n    let label = lines[0].slice(from + 1, to);\n    for (let k = 1; k < lines.length - 1; k++) {\n      if (molecule[label]) {\n        molecule[label] += eol + lines[k];\n      } else {\n        molecule[label] = lines[k];\n      }\n    }\n    if (dynamicTyping) {\n      molecule[label] = parseString(molecule[label]);\n    }\n  }\n  return molecule;\n}\n","import { ensureString } from 'ensure-string';\n\nimport { getEntriesBoundaries } from './getEntriesBoundaries';\nimport { getMolecule } from './util/getMolecule';\n/**\n *  Parse a SDF file\n * @param {string|ArrayBuffer|Uint8Array} sdf - SDF file to parse\n * @param {object} [options={}]\n * @param {string[]} [options.include] - List of fields to include\n * @param {string[]} [options.exclude] - List of fields to exclude\n * @param {Function} [options.filter] - Callback allowing to filter the molecules\n * @param {boolean} [options.dynamicTyping] - Dynamically type the data\n * @param {object} [options.modifiers] - Object containing callbacks to apply on some specific fields\n * @param {boolean} [options.mixedEOL=false] - Set to true if you know there is a mixture between \\r\\n and \\n\n * @param {string} [options.eol] - Specify the end of line character. Default will be the one found in the file\n * @returns {object} - Object containing the molecules, the labels and the statistics\n */\nexport function parse(sdf, options = {}) {\n  options = { ...options };\n  if (options.modifiers === undefined) options.modifiers = {};\n  if (options.forEach === undefined) options.forEach = {};\n  if (options.dynamicTyping === undefined) options.dynamicTyping = true;\n\n  sdf = ensureString(sdf);\n  if (typeof sdf !== 'string') {\n    throw new TypeError('Parameter \"sdf\" must be a string');\n  }\n\n  if (options.eol === undefined) {\n    options.eol = '\\n';\n    if (options.mixedEOL) {\n      sdf = sdf.replaceAll('\\r\\n', '\\n');\n      sdf = sdf.replaceAll('\\r', '\\n');\n    } else {\n      // we will find the delimiter in order to be much faster and not use regular expression\n      let header = new Set(sdf.slice(0, 1000));\n      if (header.has('\\r\\n')) {\n        options.eol = '\\r\\n';\n      } else if (header.has('\\r')) {\n        options.eol = '\\r';\n      }\n    }\n  }\n\n  let entriesBoundaries = getEntriesBoundaries(\n    sdf,\n    `${options.eol}$$$$`,\n    options.eol,\n  );\n  let molecules = [];\n  let labels = {};\n\n  let start = Date.now();\n\n  for (let i = 0; i < entriesBoundaries.length; i++) {\n    let sdfPart = sdf.slice(...entriesBoundaries[i]);\n    if (sdfPart.length < 40) continue;\n    let currentLabels = [];\n    const molecule = getMolecule(sdfPart, labels, currentLabels, options);\n    if (!molecule) continue;\n    if (!options.filter || options.filter(molecule)) {\n      molecules.push(molecule);\n      // only now we can increase the counter\n      for (let j = 0; j < currentLabels.length; j++) {\n        labels[currentLabels[j]].counter++;\n      }\n    }\n  }\n  // all numeric fields should be converted to numbers\n  for (let label in labels) {\n    let currentLabel = labels[label];\n    if (currentLabel.isNumeric) {\n      currentLabel.minValue = Infinity;\n      currentLabel.maxValue = -Infinity;\n      for (let j = 0; j < molecules.length; j++) {\n        if (molecules[j][label]) {\n          let value = Number.parseFloat(molecules[j][label]);\n          molecules[j][label] = value;\n          if (value > currentLabel.maxValue) {\n            currentLabel.maxValue = value;\n          }\n          if (value < currentLabel.minValue) {\n            currentLabel.minValue = value;\n          }\n        }\n      }\n    }\n  }\n\n  // we check that a label is in all the records\n  for (let key in labels) {\n    if (labels[key].counter === molecules.length) {\n      labels[key].always = true;\n    } else {\n      labels[key].always = false;\n    }\n  }\n\n  let statistics = [];\n  for (let key in labels) {\n    let statistic = labels[key];\n    statistic.label = key;\n    statistics.push(statistic);\n  }\n\n  return {\n    time: Date.now() - start,\n    molecules,\n    labels: Object.keys(labels),\n    statistics,\n  };\n}\n","/**\n *\n * @param {*} string\n * @param {*} substring\n * @param {*} eol\n * @returns\n */\nexport function getEntriesBoundaries(string, substring, eol) {\n  const res = [];\n  let previous = 0;\n  let next = 0;\n  while (next !== -1) {\n    next = string.indexOf(substring, previous);\n    if (next !== -1) {\n      res.push([previous, next]);\n      const nextMatch = string.indexOf(eol, next + substring.length);\n      if (nextMatch === -1) {\n        next = -1;\n      } else {\n        previous = nextMatch + eol.length;\n        next = previous;\n      }\n    } else {\n      res.push([previous, string.length]);\n    }\n  }\n  return res;\n}\n"],"names":["guessEncoding","blob","uint8","ArrayBuffer","isView","Uint8Array","buffer","byteOffset","byteLength","length","buf","i","len","isutf8","getMolecule","sdfPart","labels","currentLabels","options","parts","split","eol","molecule","molfile","j","lines","from","indexOf","to","label","slice","push","counter","isNumeric","dynamicTyping","keep","exclude","includes","include","modifiers","modifier","forEach","k","modifiedValue","Number","isFinite","match","parseString","value","lowercase","toLowerCase","number","isNaN","MolfileStream","TransformStream","constructor","super","transform","chunk","controller","this","begin","index","endOfDelimiter","eolLength","enqueue","flush","async","readStream","moleculeStream","pipeThrough","entry","filter","sdf","undefined","encoding","TextDecoder","decode","TypeError","ensureString","mixedEOL","replaceAll","header","Set","has","entriesBoundaries","string","substring","res","previous","next","nextMatch","getEntriesBoundaries","molecules","start","Date","now","currentLabel","minValue","Infinity","maxValue","parseFloat","key","always","statistics","statistic","time","Object","keys"],"mappings":"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","x_google_ignoreList":[0,1,3]}