{"version":3,"file":"sdf-parser.umd.min.js","sources":["../node_modules/ensure-string/lib/index.js","../lib/util/getMolecule.js","../node_modules/dynamic-typing/lib/parseString.js","../lib/MolfileStream.js","../lib/iterator.js","../lib/parse.js","../lib/getEntriesBoundaries.js"],"sourcesContent":["/**\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        if (options.encoding) {\n            return new TextDecoder(options.encoding).decode(blob);\n        }\n        else {\n            return decodeText(blob);\n        }\n    }\n    throw new TypeError(`blob must be a string, ArrayBuffer or ArrayBufferView`);\n}\nfunction decodeText(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 new TextDecoder('utf-16be').decode(uint8);\n        }\n        if (uint8[0] === 0xff && uint8[1] === 0xfe) {\n            return new TextDecoder('utf-16le').decode(uint8);\n        }\n    }\n    try {\n        return new TextDecoder('utf-8', { fatal: true }).decode(uint8);\n    }\n    catch {\n        return new TextDecoder('latin1').decode(uint8);\n    }\n}\n//# sourceMappingURL=index.js.map","/**\n * Parse a single SDF entry string into a molecule object.\n * @param sdfPart - A single SDF record (everything before the `$$$$` line).\n * @param labels - Shared label tracking object, mutated in place.\n * @param currentLabels - Array to collect label names found in this entry.\n * @param options - Resolved parse options.\n * @returns The molecule object, or `undefined` if the entry is too short.\n */\nexport function getMolecule(sdfPart, labels, currentLabels, options) {\n    const { eol, dynamicTyping, include, exclude, modifiers, forEach } = options;\n    const parts = sdfPart.split(`${eol}>`);\n    if (parts.length === 0 || parts[0].length <= 5)\n        return undefined;\n    const molecule = { molfile: parts[0] + eol };\n    for (let j = 1; j < parts.length; j++) {\n        const lines = parts[j].split(eol);\n        const from = lines[0].indexOf('<');\n        const to = lines[0].indexOf('>');\n        const label = lines[0].slice(from + 1, to);\n        currentLabels.push(label);\n        if (!labels[label]) {\n            labels[label] = {\n                counter: 0,\n                isNumeric: dynamicTyping,\n                keep: false,\n            };\n            if (!exclude?.includes(label) && (!include || include.includes(label))) {\n                labels[label].keep = true;\n                if (modifiers[label])\n                    labels[label].modifier = modifiers[label];\n                if (forEach[label])\n                    labels[label].forEach = forEach[label];\n            }\n        }\n        if (labels[label].keep) {\n            for (let k = 1; k < lines.length - 1; k++) {\n                if (molecule[label]) {\n                    molecule[label] = `${molecule[label]}${eol}${lines[k]}`;\n                }\n                else {\n                    molecule[label] = lines[k];\n                }\n            }\n            if (labels[label].modifier) {\n                const modifiedValue = labels[label].modifier(molecule[label]);\n                if (modifiedValue === undefined || modifiedValue === null) {\n                    // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n                    delete molecule[label];\n                }\n                else {\n                    molecule[label] = modifiedValue;\n                }\n            }\n            if (labels[label].isNumeric &&\n                (!Number.isFinite(+molecule[label]) ||\n                    molecule[label].match(/^0[0-9]/))) {\n                labels[label].isNumeric = false;\n            }\n        }\n    }\n    return molecule;\n}\n//# sourceMappingURL=getMolecule.js.map","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","/**\n * A Web Streams API `TransformStream` that splits an incoming text stream on\n * the `$$$$` SDF record delimiter and emits individual molfile strings.\n *\n * Entries shorter than 40 characters are discarded.\n * @example\n * ```ts\n * const stream = readStream.pipeThrough(new MolfileStream());\n * for await (const molfile of stream) {\n *   console.log(molfile);\n * }\n * ```\n */\nexport class MolfileStream extends TransformStream {\n    #buffer = [];\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars\n    constructor(_options) {\n        super({\n            transform: (chunk, controller) => {\n                this.#buffer.push(chunk);\n                const combined = this.#buffer.join('');\n                this.#buffer.length = 0;\n                let begin = 0;\n                let index = 0;\n                while ((index = combined.indexOf('$$$$', index)) !== -1) {\n                    const endOfDelimiter = combined.indexOf('\\n', index);\n                    if (endOfDelimiter === -1) {\n                        index = begin;\n                        break;\n                    }\n                    const eolLength = combined[endOfDelimiter - 1] === '\\r' ? 2 : 1;\n                    // Remove the last eol before enqueuing\n                    if (index - eolLength - begin > 40) {\n                        controller.enqueue(combined.slice(begin, index - eolLength));\n                    }\n                    index = endOfDelimiter + eolLength;\n                    begin = index;\n                }\n                if (begin < combined.length) {\n                    this.#buffer.push(combined.slice(begin));\n                }\n            },\n            flush: (controller) => {\n                const remaining = this.#buffer.join('');\n                if (remaining && remaining.length > 40) {\n                    controller.enqueue(remaining);\n                }\n            },\n        });\n    }\n}\n//# sourceMappingURL=MolfileStream.js.map","import { parseString } from 'dynamic-typing';\nimport { MolfileStream } from \"./MolfileStream.js\";\n/**\n * Asynchronously iterate over molecules from a text-decoded SDF stream.\n * @param readStream - A `ReadableStream<string>` supplying SDF text content.\n * @param options - Iterator options.\n * @yields {IteratorMolecule} Individual molecule objects.\n * @example\n * ```ts\n * import { openAsBlob } from 'node:fs';\n * import { iterator } from 'sdf-parser';\n *\n * const blob = await openAsBlob('compounds.sdf');\n * const textDecoder = new TextDecoderStream();\n * for await (const molecule of iterator(blob.stream().pipeThrough(textDecoder))) {\n *   console.log(molecule.molfile);\n * }\n * ```\n */\nexport async function* iterator(readStream, options = {}) {\n    const { eol = '\\n', dynamicTyping = true } = options;\n    const moleculeStream = readStream.pipeThrough(new MolfileStream({ eol }));\n    for await (const entry of moleculeStream) {\n        const molecule = parseMolecule(entry, { eol, dynamicTyping });\n        if (!options.filter || options.filter(molecule)) {\n            yield molecule;\n        }\n    }\n}\nfunction parseMolecule(sdfPart, options) {\n    const { eol, dynamicTyping } = options;\n    const parts = sdfPart.split(`${eol}>`);\n    const molecule = {\n        molfile: parts.length > 0 && parts[0].length > 5 ? parts[0] + eol : '',\n    };\n    for (let j = 1; j < parts.length; j++) {\n        const lines = parts[j].split(eol);\n        const from = lines[0].indexOf('<');\n        const to = lines[0].indexOf('>');\n        const label = lines[0].slice(from + 1, to);\n        for (let k = 1; k < lines.length - 1; k++) {\n            if (molecule[label]) {\n                molecule[label] = `${molecule[label]}${eol}${lines[k]}`;\n            }\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//# sourceMappingURL=iterator.js.map","import { ensureString } from 'ensure-string';\nimport { getEntriesBoundaries } from \"./getEntriesBoundaries.js\";\nimport { getMolecule } from \"./util/getMolecule.js\";\n/**\n * Synchronously parse an SDF file into an array of molecule objects.\n * @param sdf - The SDF content as a string, `ArrayBuffer`, or `ArrayBufferView`.\n * @param options - Parsing options.\n * @returns A {@link ParseResult} containing molecules and statistics.\n * @example\n * ```ts\n * import { readFileSync } from 'node:fs';\n * import { parse } from 'sdf-parser';\n *\n * const sdf = readFileSync('compounds.sdf', 'utf8');\n * const { molecules, statistics } = parse(sdf);\n * ```\n */\nexport function parse(sdf, options = {}) {\n    options = { ...options };\n    if (options.modifiers === undefined)\n        options.modifiers = {};\n    if (options.forEach === undefined)\n        options.forEach = {};\n    if (options.dynamicTyping === undefined)\n        options.dynamicTyping = true;\n    // ensureString converts ArrayBuffer/ArrayBufferView to string\n    const sdfString = ensureString(sdf);\n    if (typeof sdfString !== 'string') {\n        throw new TypeError('Parameter \"sdf\" must be a string');\n    }\n    if (options.eol === undefined) {\n        options.eol = '\\n';\n        if (options.mixedEOL) {\n            // Normalize all line endings to \\n\n            // We work on a local variable so no issue here\n        }\n        else {\n            // Note: new Set(string) creates a Set of individual characters.\n            // '\\r\\n' is two characters so header.has('\\r\\n') would always be false.\n            // This preserves the original detection behaviour.\n            const header = new Set(sdfString.slice(0, 1000));\n            if (header.has('\\r\\n')) {\n                options.eol = '\\r\\n';\n            }\n            else if (header.has('\\r')) {\n                options.eol = '\\r';\n            }\n        }\n    }\n    let workingSdf = sdfString;\n    if (options.mixedEOL) {\n        workingSdf = workingSdf.replaceAll('\\r\\n', '\\n');\n        workingSdf = workingSdf.replaceAll('\\r', '\\n');\n    }\n    const eol = options.eol;\n    const modifiers = options.modifiers;\n    const forEachMap = options.forEach;\n    const dynamicTyping = options.dynamicTyping;\n    const entriesBoundaries = getEntriesBoundaries(workingSdf, `${eol}$$$$`, eol);\n    const molecules = [];\n    const labels = {};\n    const start = Date.now();\n    for (const boundary of entriesBoundaries) {\n        const sdfPart = workingSdf.slice(...boundary);\n        if (sdfPart.length < 40)\n            continue;\n        const currentLabels = [];\n        const molecule = getMolecule(sdfPart, labels, currentLabels, {\n            eol,\n            dynamicTyping,\n            modifiers,\n            forEach: forEachMap,\n            include: options.include,\n            exclude: options.exclude,\n        });\n        if (!molecule)\n            continue;\n        if (!options.filter || options.filter(molecule)) {\n            molecules.push(molecule);\n            for (const label of currentLabels) {\n                labels[label].counter++;\n            }\n        }\n    }\n    // Convert all numeric fields and compute min/max\n    for (const label in labels) {\n        const currentLabel = labels[label];\n        if (currentLabel.isNumeric) {\n            currentLabel.minValue = Infinity;\n            currentLabel.maxValue = -Infinity;\n            for (const molecule of molecules) {\n                if (molecule[label]) {\n                    const value = Number.parseFloat(molecule[label]);\n                    molecule[label] = value;\n                    if (value > (currentLabel.maxValue ?? -Infinity)) {\n                        currentLabel.maxValue = value;\n                    }\n                    if (value < (currentLabel.minValue ?? Infinity)) {\n                        currentLabel.minValue = value;\n                    }\n                }\n            }\n        }\n    }\n    for (const key in labels) {\n        labels[key].always = labels[key].counter === molecules.length;\n    }\n    const statistics = [];\n    for (const key in labels) {\n        const info = labels[key];\n        statistics.push({\n            label: key,\n            counter: info.counter,\n            isNumeric: info.isNumeric,\n            keep: info.keep,\n            minValue: info.minValue,\n            maxValue: info.maxValue,\n            always: info.always ?? false,\n        });\n    }\n    return {\n        time: Date.now() - start,\n        molecules,\n        labels: Object.keys(labels),\n        statistics,\n    };\n}\n//# sourceMappingURL=parse.js.map","/**\n * Get the [start, end] boundaries of each SDF entry in a string.\n *\n * Uses `indexOf` for fast splitting without regex overhead.\n * @param string - The full SDF string.\n * @param substring - The delimiter to search for (e.g. `'\\n$$$$'`).\n * @param eol - The end-of-line character used to skip past the delimiter line.\n * @returns An array of `[start, end]` index pairs, one per SDF entry.\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            }\n            else {\n                previous = nextMatch + eol.length;\n                next = previous;\n            }\n        }\n        else {\n            res.push([previous, string.length]);\n        }\n    }\n    return res;\n}\n//# sourceMappingURL=getEntriesBoundaries.js.map"],"names":["ensureString","blob","options","ArrayBuffer","isView","encoding","TextDecoder","decode","uint8","Uint8Array","buffer","byteOffset","byteLength","length","fatal","decodeText","TypeError","getMolecule","sdfPart","labels","currentLabels","eol","dynamicTyping","include","exclude","modifiers","forEach","parts","split","molecule","molfile","j","lines","from","indexOf","to","label","slice","push","counter","isNumeric","keep","includes","modifier","k","modifiedValue","Number","isFinite","match","parseString","value","lowercase","toLowerCase","number","isNaN","MolfileStream","TransformStream","constructor","_options","super","transform","chunk","controller","this","combined","join","begin","index","endOfDelimiter","eolLength","enqueue","flush","remaining","parseMolecule","async","readStream","moleculeStream","pipeThrough","entry","filter","sdf","undefined","sdfString","mixedEOL","header","Set","has","workingSdf","replaceAll","forEachMap","entriesBoundaries","string","substring","res","previous","next","nextMatch","getEntriesBoundaries","molecules","start","Date","now","boundary","currentLabel","minValue","Infinity","maxValue","parseFloat","key","always","statistics","info","time","Object","keys"],"mappings":"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","x_google_ignoreList":[0,2]}