diff --git a/.github/workflows/dev-build.yml b/.github/workflows/dev-build.yml index 0bea825..5d06f93 100644 --- a/.github/workflows/dev-build.yml +++ b/.github/workflows/dev-build.yml @@ -1,5 +1,5 @@ -# This worklflow will perform following actions when the code is pushed to development branch: +# This worklflow will perform following actions when the code is pushed to the development branch: # - Build the latest docker image in development which needs test to pass first. # - Push the docker image to Docker Hub under namespace - nfdi4chem with tag:dev-latest. # @@ -16,7 +16,8 @@ on: env: DOCKER_HUB_USERNAME : ${{ secrets.DOCKER_USERNAME }} DOCKER_HUB_PASSWORD : ${{ secrets.DOCKER_PASSWORD }} - REPOSITORY_NAME: nmrkit + NMRKIT_REPOSITORY_NAME: nmrkit + NMR_CLI_REPOSITORY_NAME: nmr-cli REPOSITORY_NAMESPACE: nfdi4chem RELEASE_TAG: dev-latest @@ -27,7 +28,7 @@ jobs: push_to_registry: name: Push Docker image to Docker Hub runs-on: ubuntu-latest - needs: test_and_lint + #needs: test_and_lint steps: - name: Check out the repo uses: actions/checkout@v3 @@ -38,7 +39,7 @@ jobs: username: ${{ env.DOCKER_HUB_USERNAME }} password: ${{ env.DOCKER_HUB_PASSWORD }} - - name: Build and push Docker image + - name: Build and push nmrKit Docker image uses: docker/build-push-action@v4 with: context: . @@ -46,6 +47,18 @@ jobs: push: true build-args: | RELEASE_VERSION=dev-latest - tags: ${{ env.REPOSITORY_NAMESPACE }}/${{ env.REPOSITORY_NAME }}:${{ env.RELEASE_TAG }} + tags: ${{ env.REPOSITORY_NAMESPACE }}/${{ env.NMRKIT_REPOSITORY_NAME }}:${{ env.RELEASE_TAG }} + username: ${{ env.DOCKER_HUB_USERNAME }} + password: ${{ env.DOCKER_HUB_PASSWORD }} + + - name: Build and push nmr-cli Docker image + uses: docker/build-push-action@v4 + with: + context: ./app/scripts/nmr-cli/ + file: ./app/scripts/nmr-cli/Dockerfile + push: true + build-args: | + RELEASE_VERSION=dev-latest + tags: ${{ env.REPOSITORY_NAMESPACE }}/${{ env.NMR_CLI_REPOSITORY_NAME }}:${{ env.RELEASE_TAG }} username: ${{ env.DOCKER_HUB_USERNAME }} password: ${{ env.DOCKER_HUB_PASSWORD }} \ No newline at end of file diff --git a/app/scripts/nmr-cli/.gitignore b/app/scripts/nmr-cli/.gitignore new file mode 100644 index 0000000..b38db2f --- /dev/null +++ b/app/scripts/nmr-cli/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +build/ diff --git a/app/scripts/nmr-cli/Dockerfile b/app/scripts/nmr-cli/Dockerfile index a6b0393..6b0c237 100644 --- a/app/scripts/nmr-cli/Dockerfile +++ b/app/scripts/nmr-cli/Dockerfile @@ -1,15 +1,16 @@ # build the image ` docker build --tag nmr-cli . ` # run the container ` docker run -it nmr-cli bash ` -FROM mcr.microsoft.com/playwright:v1.40.0-jammy +FROM mcr.microsoft.com/playwright:v1.56.1-noble SHELL ["/bin/bash", "-o", "pipefail", "-c"] + WORKDIR /app #ENV BASE_NMRIUM_URL=https://nmrium.nmrxiv.org/ ENV BASE_NMRIUM_URL=https://nmriumdev.nmrxiv.org/ - +ENV NMR_PREDICTION_URL=https://nmrshiftdb.nmr.uni-koeln.de/NmrshiftdbServlet/nmrshiftdbaction/quickcheck COPY package.json ./ COPY package-lock.json ./ @@ -18,8 +19,11 @@ RUN npm install COPY . ./ +RUN npm run build + #install the nmr-cli as a global package -# for example, nmr-cli -u https://cheminfo.github.io/bruker-data-test/data/zipped/aspirin-1h.zip +# for example, nmr-cli parse-spectra -u https://cheminfo.github.io/bruker-data-test/data/zipped/aspirin-1h.zip +# nmr-cli predict -n "1H" --id 1 --type "nmr;1H;1d" --shifts "1" --solvent "Dimethylsulphoxide-D6 (DMSO-D6, C2D6SO)" -m $"\n Ketcher 6122516162D 1 1.00000 0.00000 0\n\n 16 17 0 0 0 0 0 0 0 0999 V2000\n 1.1954 -4.6484 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 2.9258 -4.6479 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 2.0622 -4.1483 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 2.9258 -5.6488 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 1.1954 -5.6533 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 2.0644 -6.1483 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 3.7902 -4.1495 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n 4.6574 -4.6498 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 3.7964 -6.1512 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n 4.6596 -5.6458 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 5.5228 -4.1488 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 5.5277 -6.1421 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n 6.3895 -4.6477 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n 5.5216 -3.1488 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n 7.2548 -4.1466 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 8.1215 -4.6455 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 3 1 2 0 0 0 0\n 1 5 1 0 0 0 0\n 5 6 2 0 0 0 0\n 6 4 1 0 0 0 0\n 4 2 1 0 0 0 0\n 2 3 1 0 0 0 0\n 4 9 1 0 0 0 0\n 9 10 2 0 0 0 0\n 10 8 1 0 0 0 0\n 8 7 2 0 0 0 0\n 7 2 1 0 0 0 0\n 8 11 1 0 0 0 0\n 10 12 1 0 0 0 0\n 11 13 1 0 0 0 0\n 11 14 2 0 0 0 0\n 13 15 1 0 0 0 0\n 15 16 1 0 0 0 0\nM END" RUN npm install . -g diff --git a/app/scripts/nmr-cli/bin/index.js b/app/scripts/nmr-cli/bin/index.js deleted file mode 100755 index a8a895b..0000000 --- a/app/scripts/nmr-cli/bin/index.js +++ /dev/null @@ -1,167 +0,0 @@ -#!/usr/bin/env node -const { join, isAbsolute } = require("path"); -const yargs = require("yargs"); -const loader = require("nmr-load-save"); -const fileUtils = require("filelist-utils"); -const playwright = require('playwright'); - -const usageMessage = "Usage: nmr-cli -u or -p -s" - - -/** - * How to Use the Command Line Tool: - * Example 1: Process spectra files from a URL - * Usage: nmr-cli -u https://example.com/file.zip - * ------------------------------------------------------------------------- - * Example 2: process a spectra files from a directory - * Usage: nmr-cli -p /path/to/directory - * ------------------------------------------------------------------------- - * you could also combine the above examples with an optional parameter to capturing a snapshot using the -s option - * - */ - -const options = yargs - .usage(usageMessage) - .option("u", { alias: "url", describe: "File URL", type: "string", nargs: 1 }) - .option("p", { alias: "path", describe: "Directory path", type: "string", nargs: 1 }) - .option("s", { alias: "capture-snapshot", describe: "Capture snapshot", type: "boolean" }).showHelpOnFail(); - - - - -function generateNMRiumURL() { - const baseURL = process.env['BASE_NMRIUM_URL']; - const url = new URL(baseURL) - url.searchParams.append('workspace', "embedded") - return url.toString() -} - -async function captureSpectraViewAsBase64(nmriumState) { - const { data: { spectra }, version } = nmriumState; - const browser = await playwright.chromium.launch() - const context = await browser.newContext(playwright.devices['Desktop Chrome HiDPI']) - const page = await context.newPage() - - const url = generateNMRiumURL() - - await page.goto(url) - - await page.locator('text=Loading').waitFor({ state: 'hidden' }); - - let snapshots = [] - - for (const spectrum of spectra || []) { - const spectrumObject = { - version, - data: { - spectra: [{ ...spectrum }], - } - - } - - // convert typed array to array - const stringObject = JSON.stringify(spectrumObject, (key, value) => { - return ArrayBuffer.isView(value) ? Array.from(value) : value - }) - - // load the spectrum into NMRium using the custom event - await page.evaluate( - ` - window.postMessage({ type: "nmr-wrapper:load", data:{data: ${stringObject},type:"nmrium"}}, '*'); - ` - ) - - //wait for NMRium process and load spectra - await page.locator('text=Loading').waitFor({ state: 'hidden' }); - - // take a snapshot for the spectrum - try { - const snapshot = await page.locator('#nmrSVG .container').screenshot() - - snapshots.push({ - image: snapshot.toString('base64'), - id: spectrum.id, - }) - } catch (e) { - console.log(e) - } - } - - await context.close() - await browser.close() - - return snapshots; -} - -async function loadSpectrumFromURL(url, enableSnapshot = false) { - const { pathname: relativePath, origin: baseURL } = new URL(url); - const source = { - entries: [ - { - relativePath, - } - ], - baseURL - }; - const fileCollection = await fileUtils.fileCollectionFromWebSource(source, {}); - - const { - nmriumState: { data, version }, - } = await loader.read(fileCollection); - - let images = [] - - if (enableSnapshot) { - images = await captureSpectraViewAsBase64({ data, version }); - } - - - return { data, version, images }; -} - - -async function loadSpectrumFromFilePath(path, enableSnapshot = false) { - const dirPath = isAbsolute(path) ? path : join(process.cwd(), path) - - const fileCollection = await fileUtils.fileCollectionFromPath(dirPath, {}); - - const { - nmriumState: { data, version } - } = await loader.read(fileCollection); - - let images = [] - - if (enableSnapshot) { - images = await captureSpectraViewAsBase64({ data, version }); - } - - - return { data, version, images }; -} - - -const parameters = options.argv; - -if (parameters.u && parameters.p) { - options.showHelp(); -} else { - - if (parameters.u) { - loadSpectrumFromURL(parameters.u, parameters.s).then((result) => { - console.log(JSON.stringify(result)) - }) - - } - - if (parameters.p) { - loadSpectrumFromFilePath(parameters.p, parameters.s).then((result) => { - console.log(JSON.stringify(result)) - }) - } - -} - - - - - diff --git a/app/scripts/nmr-cli/package-lock.json b/app/scripts/nmr-cli/package-lock.json index 2497fcf..37ab0fb 100644 --- a/app/scripts/nmr-cli/package-lock.json +++ b/app/scripts/nmr-cli/package-lock.json @@ -1,155 +1,350 @@ { - "name": "test-node", + "name": "nmr-cli", "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "test-node", + "name": "nmr-cli", "version": "1.0.0", "license": "ISC", "dependencies": { - "filelist-utils": "^1.10.2", - "nmr-load-save": "^0.23.11", - "playwright": "^1.40.1", - "yargs": "^17.7.2" + "@zakodium/nmr-types": "^0.4.0", + "@zakodium/nmrium-core": "^0.4.2", + "@zakodium/nmrium-core-plugins": "^0.5.3", + "axios": "^1.13.0", + "file-collection": "^5.4.0", + "lodash.merge": "^4.6.2", + "mf-parser": "^3.6.0", + "ml-spectra-processing": "^14.18.0", + "nmr-processing": "^20.1.0", + "playwright": "^1.56.1", + "yargs": "^18.0.0" }, "bin": { - "nmr-cli": "bin/index.js" + "nmr-cli": "build/index.js" + }, + "devDependencies": { + "@types/lodash.merge": "^4.6.9", + "@types/node": "^24.9.1", + "@types/yargs": "^17.0.34", + "ts-node": "^10.9.2", + "typescript": "^5.9.3" } }, - "node_modules/@lukeed/csprng": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", - "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/@lukeed/uuid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@lukeed/uuid/-/uuid-2.0.1.tgz", - "integrity": "sha512-qC72D4+CDdjGqJvkFMMEAtancHUQ7/d/tAiHf64z8MopFDmcrtbcJuerDtFceuAfQJ2pDSfCKCtbqoGBNnwg0w==", - "dependencies": { - "@lukeed/csprng": "^1.1.0" - }, + "node_modules/@date-fns/utc": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@date-fns/utc/-/utc-2.1.1.tgz", + "integrity": "sha512-SlJDfG6RPeEX8wEVv6ZB3kak4MmbtyiI2qX/5zuKdordbrhB/iaJ58GVMZgJ6P1sJaM1gMgENFYYeg1JWrCFrA==", + "license": "MIT" + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, "engines": { - "node": ">=8" + "node": ">=6.0.0" } }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, "node_modules/@types/lodash": { - "version": "4.14.196", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.196.tgz", - "integrity": "sha512-22y3o88f4a94mKljsZcanlNWPzO0uBsBdzLAngf2tp533LzZcQzb6+eZPJ+vCTt+bqF2XnvT9gejTLsAcJAJyQ==" + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==", + "dev": true, + "license": "MIT" }, "node_modules/@types/lodash.merge": { - "version": "4.6.7", - "resolved": "https://registry.npmjs.org/@types/lodash.merge/-/lodash.merge-4.6.7.tgz", - "integrity": "sha512-OwxUJ9E50gw3LnAefSHJPHaBLGEKmQBQ7CZe/xflHkyy/wH2zVyEIAKReHvVrrn7zKdF58p16We9kMfh7v0RRQ==", + "version": "4.6.9", + "resolved": "https://registry.npmjs.org/@types/lodash.merge/-/lodash.merge-4.6.9.tgz", + "integrity": "sha512-23sHDPmzd59kUgWyKGiOMO2Qb9YtqRO/x4IhkgNUiPQ1+5MUVqi6bCZeq9nBJ17msjIMbEIO5u+XW4Kz6aGUhQ==", + "dev": true, + "license": "MIT", "dependencies": { "@types/lodash": "*" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/@types/node": { + "version": "24.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz", + "integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.34", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.34.tgz", + "integrity": "sha512-KExbHVa92aJpw9WDQvzBaGVE2/Pz+pLZQloT2hjL8IqsZnV62rlPOYvNnLmf/L2dyllfVUOVBj64M0z/46eR2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true + }, + "node_modules/@zakodium/nmr-types": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@zakodium/nmr-types/-/nmr-types-0.4.0.tgz", + "integrity": "sha512-teWfqqfvgI5zhWv9FObbmedrbHWEyau84/NCQk4ykbJ1uVEHU6srmKJFOGngkWTY3/Dbr0sJp2MRm7eBaNlvdA==", + "license": "CC-BY-NC-SA-4.0", + "dependencies": { + "ml-peak-shape-generator": "^4.2.0", + "ml-signal-processing": "^2.1.0", + "ml-spectra-processing": "^14.18.0" + } + }, + "node_modules/@zakodium/nmrium-core": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@zakodium/nmrium-core/-/nmrium-core-0.4.2.tgz", + "integrity": "sha512-Hattb65cahl5o7rJmqI1ZMJsJQCLXNkhAyUYYXqai0Awf0iV1HujlXn5+hmDSpZmKqAIEBlKENqP6aUxLPZq3A==", + "license": "CC-BY-NC-SA-4.0", + "dependencies": { + "cheminfo-types": "^1.8.1", + "fifo-logger": "^2.0.1", + "file-collection": "^5.4.0", + "is-any-array": "^2.0.1", + "lodash.merge": "^4.6.2", + "ml-spectra-processing": "^14.18.0", + "nmr-correlation": "^2.3.5" + } + }, + "node_modules/@zakodium/nmrium-core-plugins": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@zakodium/nmrium-core-plugins/-/nmrium-core-plugins-0.5.3.tgz", + "integrity": "sha512-tbOSouDdwXnvCI39iNQhDo4+cFJnPVPDhSY3B5k4TIzxBi34WYsXpMGM6d35uy9/MIvek+vJ09W/1FsoIcLFhA==", + "license": "CC-BY-NC-SA-4.0", + "dependencies": { + "@date-fns/utc": "^2.1.1", + "@zakodium/nmrium-core": "^0.4.2", + "cheminfo-types": "^1.8.1", + "convert-to-jcamp": "^6.0.0", + "date-fns": "^4.1.0", + "file-collection": "^5.4.0", + "gyromagnetic-ratio": "^2.0.0", + "is-any-array": "^2.0.1", + "jcampconverter": "^12.0.1", + "linear-sum-assignment": "^1.0.9", + "lodash.merge": "^4.6.2", + "ml-spectra-processing": "^14.18.0", + "nmr-processing": "^20.1.0", + "openchemlib": "^9.12.1", + "openchemlib-utils": "^8.7.0", + "sdf-parser": "^7.0.4" + } + }, + "node_modules/@zip.js/zip.js": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.8.8.tgz", + "integrity": "sha512-v0KutehhSAuaoFAFGLp+V4+UiZ1mIxQ8vNOYMD7k9ZJaBbtQV49MYlg568oRLiuwWDg2Di58Iw3Q0ESNWR+5JA==", + "license": "BSD-3-Clause", "engines": { - "node": ">=8" + "bun": ">=0.7.0", + "deno": ">=1.0.0", + "node": ">=18.0.0" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "acorn": "^8.11.0" }, "engines": { - "node": ">=8" + "node": ">=0.4.0" + } + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" }, "node_modules/atom-sorter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/atom-sorter/-/atom-sorter-2.0.0.tgz", - "integrity": "sha512-30O3ccAH+lmysMykyEkBsfB65BU329GatBeYrgzKjDBhaURgvWT7B2+C9gmBFnVmbMO2HaqvyAuce3eMsICluw==" + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/atom-sorter/-/atom-sorter-2.2.1.tgz", + "integrity": "sha512-+Lyyb6iXLHEb/ZYkpuvdEUgZ62+oA96p3rJG5lsttwl9vig1UqD8sAUnGQjrDFcVNUywFBhiW57Nns65M7TXEA==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.1.tgz", + "integrity": "sha512-hU4EGxxt+j7TQijx1oYdAjw4xuIp1wRQSsbMFwSthCWeBQur1eF+qJ5iQ5sN3Tw8YRzQNKb8jszgBdMDVqwJcw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } }, "node_modules/baselines": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/baselines/-/baselines-1.1.6.tgz", - "integrity": "sha512-UxKzVNQlewXopLmYBgmsFTAnCfX1uQzHJRqBpqtiYYVHlGcam2POg855gCh9feVic7x10ZFVw6S7VPZxcAhQrg==", + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/baselines/-/baselines-1.1.9.tgz", + "integrity": "sha512-dFqZSb0EwzmTUyjI3k0HSfsKMKMDHpCILPTsdysFgLf8roGq5f58KrSYAwa9vODk2dbE8NdKgNnKk8TBwXNWAw==", + "license": "MIT", "dependencies": { - "ml-airpls": "^1.0.2", + "ml-airpls": "^2.0.0", "ml-array-sequential-fill": "^1.1.8", - "ml-baseline-correction-regression": "^1.0.2", - "ml-rolling-ball-baseline": "^2.0.2", - "ml-spectra-processing": "^12.5.0" + "ml-baseline-correction-regression": "^2.0.1", + "ml-rolling-ball-baseline": "^2.0.3", + "ml-spectra-processing": "^14.5.0" } }, "node_modules/binary-search": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/binary-search/-/binary-search-1.3.6.tgz", - "integrity": "sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA==" + "integrity": "sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA==", + "license": "CC0-1.0" }, - "node_modules/brukerconverter": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/brukerconverter/-/brukerconverter-6.3.2.tgz", - "integrity": "sha512-+sR1s3uOuZSkxxW06WmHn0X10HFVngRG1a+/4FUZmWypUEFtD+W/7OyNBK3if/1Kx6hX2oJrkL1xwCNH/srwKg==", + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", "dependencies": { - "cheminfo-types": "^1.5.0", - "filelist-utils": "^1.8.0", - "iobuffer": "^5.3.2", - "is-any-array": "^2.0.0", - "jcampconverter": "^9.1.0", - "ml-spectra-processing": "^12.0.0" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" } }, + "node_modules/chemical-elements": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/chemical-elements/-/chemical-elements-2.2.1.tgz", + "integrity": "sha512-Khr3m8RhBbNwDb2MSo9Zb9O+dcUuFourUC0hK+YxNhAtEhOwJPVTMDQeDi1vUwH44tUeNRNKriUs2QQFNQvxgg==", + "license": "MIT" + }, + "node_modules/chemical-groups": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/chemical-groups/-/chemical-groups-2.2.3.tgz", + "integrity": "sha512-rIhA7dC2OJNbQeEFM6+3u81hItYWkaYbWh7awn3hy9RI1qCvhQgdTkrvt7zlLCmcp2nuMzJZUXSju6etBsf6lA==", + "license": "MIT" + }, "node_modules/cheminfo-types": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/cheminfo-types/-/cheminfo-types-1.7.2.tgz", - "integrity": "sha512-Zz7HPnh6wB2beEK7nfsXlNSK1Tpl4O0DpYUod8L6gI/5+INpn/d5UgJLI+3ck6CYY5Qsq34ylyKhERmZ5Wks2A==" + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/cheminfo-types/-/cheminfo-types-1.8.1.tgz", + "integrity": "sha512-FRcpVkox+cRovffgqNdDFQ1eUav+i/Vq/CUd1hcfEl2bevntFlzznL+jE8g4twl6ElB7gZjCko6pYpXyMn+6dA==" }, "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", "dependencies": { - "color-name": "~1.1.4" + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=20" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -158,72 +353,164 @@ } }, "node_modules/convert-to-jcamp": { - "version": "5.4.9", - "resolved": "https://registry.npmjs.org/convert-to-jcamp/-/convert-to-jcamp-5.4.9.tgz", - "integrity": "sha512-6WZ9Whrk7f4TSqepPbBRovnZ+IV+fjncZ8AYfX1OnnILlDQobciiJYFgxawvqpttwrKdmC3eh8shoAjW7CPKMQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/convert-to-jcamp/-/convert-to-jcamp-6.0.0.tgz", + "integrity": "sha512-RktJranOLNxLR9Ef3+aHYgOYf4W3sOysTJKXTN9/SKxmKzkFRPIqfPaPhTPq8u6r+3uQeM2WttDIvg9QEPq9Hg==", + "license": "MIT", "dependencies": { - "cheminfo-types": "^1.7.2", + "cheminfo-types": "^1.7.3", "is-any-array": "^2.0.1", "ml-array-max": "^1.2.4", "ml-array-min": "^1.2.3", - "ml-matrix": "^6.10.4", - "ml-spectra-processing": "^12.5.0" + "ml-matrix": "^6.11.0", + "ml-spectra-processing": "^14.2.2" } }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, - "node_modules/cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", - "dependencies": { - "node-fetch": "^2.6.12" - } + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true }, "node_modules/cuthill-mckee": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/cuthill-mckee/-/cuthill-mckee-1.0.0.tgz", - "integrity": "sha512-ehXCHYXZhZzDZmVQE/P9wQ7XPOn1G3e+pVqcqXvYykBL8Lg7HFm2ewD3TZseOMWiM9bNU0u4UWSV/dAzf+unug==" + "integrity": "sha512-ehXCHYXZhZzDZmVQE/P9wQ7XPOn1G3e+pVqcqXvYykBL8Lg7HFm2ewD3TZseOMWiM9bNU0u4UWSV/dAzf+unug==", + "license": "MIT" }, - "node_modules/d3-array": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-0.7.1.tgz", - "integrity": "sha512-Ifi3fH46Bco+Lb1mOlTxbFEuF3NdyElEVVD+EmoK327I0JzKAP4x57cl+HoxHqFcVd8F/uXLC+wtY3n/R1uO2w==" + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", "engines": { "node": ">=0.4.0" } }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/dynamic-typing": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dynamic-typing/-/dynamic-typing-1.0.0.tgz", - "integrity": "sha512-Jjvr93gCn8+5q9AP+ilq8gInN5xYRaJakmuE11Un8vgCgt0zwWyRqU7lAdRgHEHnf4FwJp/ppymo1GE1+AKw+Q==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dynamic-typing/-/dynamic-typing-1.0.1.tgz", + "integrity": "sha512-KYvDeLd4kPxs5rn/GLDQ2FLrncVVqvUfQKkhbYYaM+51zXjQwyOejP5TuAnAjdX6o+PjdMgcfhr3M7h5hQv4yA==", + "license": "MIT" }, "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==" }, "node_modules/ensure-string": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/ensure-string/-/ensure-string-1.2.0.tgz", "integrity": "sha512-Hvv2Xocfn6CSvCWgIGNzf0D5bgE6fAa65cayGOWsEXz03ej3aDpsogP3zstuLKt43zVuojQFST4XHPt9+PtuGQ==", + "license": "MIT", "dependencies": { "cheminfo-types": "^1.1.0", "isutf8": "^4.0.0" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "engines": { "node": ">=6" } @@ -231,26 +518,57 @@ "node_modules/fft.js": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/fft.js/-/fft.js-4.0.4.tgz", - "integrity": "sha512-f9c00hphOgeQTlDyavwTtu6RiK8AIFjD6+jvXkNkpeQ7rirK3uFWVpalkoS4LAwbdX7mfZ8aoBfFVQX1Re/8aw==" + "integrity": "sha512-f9c00hphOgeQTlDyavwTtu6RiK8AIFjD6+jvXkNkpeQ7rirK3uFWVpalkoS4LAwbdX7mfZ8aoBfFVQX1Re/8aw==", + "license": "MIT" }, - "node_modules/filelist-utils": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/filelist-utils/-/filelist-utils-1.10.2.tgz", - "integrity": "sha512-E4wIKXIXEyON7i6Z/7+hjytm53S0GSE/b+lvPlE5jAbHRV8thv7a4G+aLLFeOPYQK01MCH1l+ti6jHQ3tl/7bg==", + "node_modules/fifo-logger": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fifo-logger/-/fifo-logger-2.0.1.tgz", + "integrity": "sha512-AwCaBK389hl67z4AJ5+8uOsxU07olw0DzowzA6Znr/eaItMCsXXxzA1DjY/KCABWu/4Bq+wrBhn1p7hsjNDv4g==", + "license": "MIT", "dependencies": { - "cheminfo-types": "^1.7.2", - "cross-fetch": "^4.0.0", - "jszip": "^3.10.1", - "pako": "^2.1.0" + "typescript-event-target": "^1.1.1" + } + }, + "node_modules/file-collection": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/file-collection/-/file-collection-5.4.0.tgz", + "integrity": "sha512-xYp3gp244nHg3vccpQjZyxZVIJUGdUbEvDPq/IuFDgx6P0xkU+Zskoc+cOehvJqgo2KZwMaPnVQHnywRHuXJnA==", + "license": "MIT", + "dependencies": { + "@zip.js/zip.js": "^2.8.8", + "cheminfo-types": "^1.8.1" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } } }, "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { @@ -270,6 +588,15 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -278,163 +605,205 @@ "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/get-value": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-3.0.1.tgz", - "integrity": "sha512-mKZj9JLQrwMBtj5wxi6MH8Z5eSKaERpAwjg43dPtlGI1ZVEgH/qC7T8/6R2OBSUA+zzHBZgICsVJaEIV2tKTDA==", - "dependencies": { - "isobject": "^3.0.1" - }, + "node_modules/get-east-asian-width": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", "engines": { - "node": ">=6.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/gyromagnetic-ratio": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/gyromagnetic-ratio/-/gyromagnetic-ratio-1.1.1.tgz", - "integrity": "sha512-M1y9bAhK11moqAPRZ5oUoDCEIQCogjKYXDMlkXJiSjkLFmOAp1qevrjThF+6KrtwkSpmT7Vgy8C/mgBlIdZPSg==" - }, - "node_modules/heap": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", - "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==" - }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/install": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/install/-/install-0.13.0.tgz", - "integrity": "sha512-zDml/jzr2PKU9I8J/xyZBQn8rPCAY//UOYNmR01XwNwyfhEWObo2SWfSl1+0tm1u6PhxLwDnfsT/6jB7OUxqFA==", + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, "engines": { - "node": ">= 0.10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/iobuffer": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/iobuffer/-/iobuffer-5.3.2.tgz", - "integrity": "sha512-kO3CjNfLZ9t+tHxAMd+Xk4v3D/31E91rMs1dHrm7ikEQrlZ8mLDbQ4z3tZfDM48zOkReas2jx8MWSAmN9+c8Fw==" - }, - "node_modules/is-any-array": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-any-array/-/is-any-array-2.0.1.tgz", - "integrity": "sha512-UtilS7hLRu++wb/WBAw9bNuP1Eg04Ivn1vERJck8zJthEvXCBEBpGR/33u/xLKWEQf95803oalHrVDptcAvFdQ==" - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + "node_modules/get-value": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-4.0.1.tgz", + "integrity": "sha512-QTDzwunK3V+VlJJlL0BlCzebAaE8OSlUC+UVd80PiekTw1gpzQSb3cfEQB2LYFWr1lbWfbdqL4pjAoJDPCLxhQ==", + "license": "MIT" }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/isutf8": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/isutf8/-/isutf8-4.0.0.tgz", - "integrity": "sha512-mJtsQGFfAphKdVuRitEpc0eon4v5fuaB6v9ZJIrLnIyybh02sIIwJ2RQbLMp6UICVCfquezllupZIVcqzGzCPg==", - "engines": { - "node": ">= 12" - } + "node_modules/gyromagnetic-ratio": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/gyromagnetic-ratio/-/gyromagnetic-ratio-2.0.0.tgz", + "integrity": "sha512-LrpOHxgnxo0+yqtmA+1FUyl9RkvhTCiIiIPGzo8Yn6TXz6OiY5CJ5k5IqThF61qnkbC+fe6q3kF67OI6d0HyjQ==", + "license": "MIT" }, - "node_modules/jcampconverter": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/jcampconverter/-/jcampconverter-9.5.0.tgz", - "integrity": "sha512-xsuZXcUd+YkF0Rlt0IZa1+4XbMYq/fR6+gewwDJd5M17y2+SbjrgESKZH73+GokzLC7H1KTS0/l5/7cQFFLgiA==", - "dependencies": { - "cheminfo-types": "^1.7.2", - "dynamic-typing": "^1.0.0", - "ensure-string": "^1.2.0", - "gyromagnetic-ratio": "^1.1.1", - "ml-array-median": "^1.1.6" + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jeolconverter": { + "node_modules/has-tostringtag": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/jeolconverter/-/jeolconverter-1.0.2.tgz", - "integrity": "sha512-Oqp4VioharhRkQRSc6WkXc+s42DYLOdLWV7eNi16CJbiBvoaSrFf0KQwJJ5JfbpncYRMzrsjilBFYzYTbREC6g==", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", "dependencies": { - "iobuffer": "^5.3.2" + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/jszip/node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + "node_modules/heap": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", + "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", + "license": "MIT" + }, + "node_modules/is-any-array": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-any-array/-/is-any-array-2.0.1.tgz", + "integrity": "sha512-UtilS7hLRu++wb/WBAw9bNuP1Eg04Ivn1vERJck8zJthEvXCBEBpGR/33u/xLKWEQf95803oalHrVDptcAvFdQ==" + }, + "node_modules/isutf8": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isutf8/-/isutf8-4.0.1.tgz", + "integrity": "sha512-1pk2/2pE+G48eETnp4uOLxQ9WUCxD7oVauYwhFEAGREJPDxEO7iX9qstylrCcx3lNWa1RCS2DxGTxrHdWqS7/w==", + "license": "MIT", + "engines": { + "node": ">= 12" + } }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "node_modules/jcampconverter": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/jcampconverter/-/jcampconverter-12.0.1.tgz", + "integrity": "sha512-CbUP4uFdYXS+K8H0Zuhs9YPhMQnu2xsZ4yo4TIFrymtlH5bW8xrR9JjNn5ehSBWKgYYYbLtnwoH5QnvrvRVJEg==", + "license": "CC-BY-NC-SA-4.0", "dependencies": { - "immediate": "~3.0.5" + "cheminfo-types": "^1.8.1", + "dynamic-typing": "^1.0.1", + "ensure-string": "^1.2.0", + "gyromagnetic-ratio": "^2.0.0", + "ml-array-median": "^1.1.6", + "openchemlib": "^9.12.1" } }, "node_modules/linear-sum-assignment": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/linear-sum-assignment/-/linear-sum-assignment-1.0.5.tgz", - "integrity": "sha512-JiyPEQM+Lb5K0BR9uBkLae9gNKMpici8hOwrWwNnOkABrNn8yWCOd4wwAaLGlu9HzfQFxHcs07zOaGgXgco5Kg==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/linear-sum-assignment/-/linear-sum-assignment-1.0.9.tgz", + "integrity": "sha512-1T2Ek3sxpt2mBHeBFMRJEikiIK/yIOwf+mrxv/DkAU/5ddnCMndZL//hFH7QuHa1tbaQADzsf9t7rkGZKqoFfQ==", + "license": "MIT", "dependencies": { - "cheminfo-types": "^1.4.0", - "install": "^0.13.0", - "ml-matrix": "^6.10.4", - "ml-spectra-processing": "^12.0.0" + "cheminfo-types": "^1.8.1", + "ml-matrix": "^6.12.1", + "ml-spectra-processing": "^14.18.0" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "license": "MIT" }, - "node_modules/lodash.omit": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", - "integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==" + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, "node_modules/median-quickselect": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/median-quickselect/-/median-quickselect-1.0.1.tgz", - "integrity": "sha512-/QL9ptNuLsdA68qO+2o10TKCyu621zwwTFdLvtu8rzRNKsn8zvuGoq/vDxECPyELFG8wu+BpyoMR9BnsJqfVZQ==" + "integrity": "sha512-/QL9ptNuLsdA68qO+2o10TKCyu621zwwTFdLvtu8rzRNKsn8zvuGoq/vDxECPyELFG8wu+BpyoMR9BnsJqfVZQ==", + "license": "ISC" + }, + "node_modules/mf-parser": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/mf-parser/-/mf-parser-3.6.0.tgz", + "integrity": "sha512-vBE7hE8ZB2rtMPxJZHgfuMQIF98ebqXUDTtG/EzapRJ/CDurI/bEo8ZEyQI+ZKznGXr6HGcnBdoE2+U52v/JtA==", + "license": "MIT", + "dependencies": { + "atom-sorter": "^2.2.1", + "chemical-elements": "^2.2.1", + "chemical-groups": "^2.2.3" + } }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -443,6 +812,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -451,17 +821,20 @@ } }, "node_modules/ml-airpls": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ml-airpls/-/ml-airpls-1.0.3.tgz", - "integrity": "sha512-U6D0ahNuCxgfu/bb415tJMAXdtC+5cysUNAS3bWZWQCwQR53vNjby9MJN+6muBiDz6XQk0lULkg+PsW1N+OG6g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ml-airpls/-/ml-airpls-2.0.0.tgz", + "integrity": "sha512-dCFbc2UNnzHkU6PAa1SFjdob/cVNZz//BlLh6BF2jHp56+Oahi02PLytrV4v+X3sW20v2l//8hXuqjZCuv88OQ==", + "license": "MIT", "dependencies": { - "cuthill-mckee": "^1.0.0" + "cuthill-mckee": "^1.0.0", + "ml-spectra-processing": "^14.5.0" } }, "node_modules/ml-array-max": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/ml-array-max/-/ml-array-max-1.2.4.tgz", "integrity": "sha512-BlEeg80jI0tW6WaPyGxf5Sa4sqvcyY6lbSn5Vcv44lp1I2GR6AWojfUvLnGTNsIXrZ8uqWmo8VcG1WpkI2ONMQ==", + "license": "MIT", "dependencies": { "is-any-array": "^2.0.0" } @@ -470,6 +843,7 @@ "version": "1.1.6", "resolved": "https://registry.npmjs.org/ml-array-median/-/ml-array-median-1.1.6.tgz", "integrity": "sha512-V6bV6bTPFRX8v5CaAx/7fuRXC39LLTHfPSVZZafdNaqNz2PFL5zEA7gesjv8dMXh+gwPeUMtB5QPovlTBaa4sw==", + "license": "MIT", "dependencies": { "is-any-array": "^2.0.0", "median-quickselect": "^1.0.1" @@ -479,6 +853,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/ml-array-min/-/ml-array-min-1.2.3.tgz", "integrity": "sha512-VcZ5f3VZ1iihtrGvgfh/q0XlMobG6GQ8FsNyQXD3T+IlstDv85g8kfV0xUG1QPRO/t21aukaJowDzMTc7j5V6Q==", + "license": "MIT", "dependencies": { "is-any-array": "^2.0.0" } @@ -487,6 +862,7 @@ "version": "1.3.7", "resolved": "https://registry.npmjs.org/ml-array-rescale/-/ml-array-rescale-1.3.7.tgz", "integrity": "sha512-48NGChTouvEo9KBctDfHC3udWnQKNKEWN0ziELvY3KG25GR5cA8K8wNVzracsqSW1QEkAXjTNx+ycgAv06/1mQ==", + "license": "MIT", "dependencies": { "is-any-array": "^2.0.0", "ml-array-max": "^1.2.4", @@ -497,25 +873,38 @@ "version": "1.1.8", "resolved": "https://registry.npmjs.org/ml-array-sequential-fill/-/ml-array-sequential-fill-1.1.8.tgz", "integrity": "sha512-8oS9fYn61r61Lo4N0ueXBqjsrraxXMz0oTfKW/waNHOabvKhLMB7hjixUa2Hp5vnVBJHHHNWHqRUm/T00zRhLg==", + "license": "MIT", "dependencies": { "is-any-array": "^2.0.0" } }, "node_modules/ml-baseline-correction-regression": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ml-baseline-correction-regression/-/ml-baseline-correction-regression-1.0.2.tgz", - "integrity": "sha512-dRKbGx49gXhHyvpb9/6OpqySY7cEm8rz0LaQWyAsaMALr3aKHXvtPsjADh5afkzsYRw53QPgwccCo0XTvT3M8w==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ml-baseline-correction-regression/-/ml-baseline-correction-regression-2.0.1.tgz", + "integrity": "sha512-ZPdJogONI5/M7eFuJ4NCrr8NJ1XcSl7OVTUOvZkFr2yjT/o592nd3oqtj+ChyxAJLMO68eFlktNV0OHhvxy1KQ==", + "license": "MIT", "dependencies": { - "ml-regression-polynomial": "^2.2.0" + "ml-regression-polynomial": "^3.0.1" + } + }, + "node_modules/ml-convolution": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ml-convolution/-/ml-convolution-2.0.0.tgz", + "integrity": "sha512-ExW6zVmN2YGuyO3aBiS1ymybme3nVgv2ccCfynSdgtW5sNp4DOHnfow4K/ErTDMQ1s9tINjv7kvzjnVhQHXJBA==", + "license": "MIT", + "dependencies": { + "fft.js": "^4.0.3", + "next-power-of-two": "^1.0.0" } }, "node_modules/ml-direct": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ml-direct/-/ml-direct-0.1.3.tgz", - "integrity": "sha512-3CFuHK4eJrBAiTK9bgwqN5rXr3X66ShC/Acx3+h26kk/aLpQxLRkZ5lPCC72HMG9hTtJIMoSlev8QYpXSBB3OA==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ml-direct/-/ml-direct-1.0.0.tgz", + "integrity": "sha512-DyynbcLIHGCRYiJNRW6qeWpOyV/SCYwSzYDN0VP72ucIx0jn8H4GYKRTY94e0Gk+yKlOjdu3GSNY/j6nxdl9YA==", + "license": "MIT", "dependencies": { - "ml-matrix": "^6.10.4", - "ml-spectra-processing": "^12.0.0" + "ml-matrix": "^6.11.0", + "ml-spectra-processing": "^14.2.0" } }, "node_modules/ml-disjoint-set": { @@ -526,12 +915,14 @@ "node_modules/ml-distance-euclidean": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ml-distance-euclidean/-/ml-distance-euclidean-2.0.0.tgz", - "integrity": "sha512-yC9/2o8QF0A3m/0IXqCTXCzz2pNEzvmcE/9HFKOZGnTjatvBbsn4lWYJkxENkA4Ug2fnYl7PXQxnPi21sgMy/Q==" + "integrity": "sha512-yC9/2o8QF0A3m/0IXqCTXCzz2pNEzvmcE/9HFKOZGnTjatvBbsn4lWYJkxENkA4Ug2fnYl7PXQxnPi21sgMy/Q==", + "license": "MIT" }, "node_modules/ml-distance-matrix": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ml-distance-matrix/-/ml-distance-matrix-2.0.1.tgz", - "integrity": "sha512-6wt3bvK8WzAjyuBt9+wnyGanphrAZyqJGwiEEfuknfu8IQBtHYWpyLhjtQ8R7rjiPyXlF9eP7GcI5L7OA1NLEQ==" + "integrity": "sha512-6wt3bvK8WzAjyuBt9+wnyGanphrAZyqJGwiEEfuknfu8IQBtHYWpyLhjtQ8R7rjiPyXlF9eP7GcI5L7OA1NLEQ==", + "license": "MIT" }, "node_modules/ml-fft": { "version": "1.3.5", @@ -542,27 +933,29 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/ml-floyd-warshall/-/ml-floyd-warshall-3.0.1.tgz", "integrity": "sha512-GrUdw/QuENlOp1HnCNzjaqZJXdXyrOG8YYK7lSvq3fzgOFoaZPY5gUFFmHDSo/T0ZCBLkka9IjcSpEbRGqi/fw==", + "license": "MIT", "dependencies": { "ml-matrix": "^6.10.4" } }, "node_modules/ml-gsd": { - "version": "12.1.3", - "resolved": "https://registry.npmjs.org/ml-gsd/-/ml-gsd-12.1.3.tgz", - "integrity": "sha512-9qTIc3reKSifJ4EpxdFl+9C4pfvm/XKuM+JXBfHdd2hhfD1ZQ9CcrPxm5OBTcZVqJ4e9pKsUDvJnjePX2Yb5YA==", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/ml-gsd/-/ml-gsd-13.1.0.tgz", + "integrity": "sha512-CmUZ/hCPCb6L089Xon1U8xSxTR35DMh3ICfaBuP16mKm7HA8XoonAnjnVOjM4ayewDjgMM3KVqPS/+ti3tFYhA==", + "license": "MIT", "dependencies": { - "@lukeed/uuid": "^2.0.0", - "cheminfo-types": "^1.4.0", - "ml-peak-shape-generator": "^4.1.2", - "ml-savitzky-golay-generalized": "^4.0.1", - "ml-spectra-fitting": "^4.2.1", - "ml-spectra-processing": "^12.0.0" + "cheminfo-types": "^1.8.1", + "ml-peak-shape-generator": "^4.1.4", + "ml-savitzky-golay-generalized": "^4.2.0", + "ml-spectra-fitting": "^5.0.1", + "ml-spectra-processing": "^14.12.0" } }, "node_modules/ml-hash-table": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/ml-hash-table/-/ml-hash-table-1.0.0.tgz", "integrity": "sha512-KV2uRIUbox0xuJ5Gkmr3udX0eNqr+c2HiSqz+sqAtQOnSm46zBmzDJvZX9t4hhcqqyEmGPvxFzx5SnwCfGhXNw==", + "license": "MIT", "dependencies": { "binary-search": "^1.3.5", "num-sort": "^2.0.0" @@ -572,6 +965,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/ml-hclust/-/ml-hclust-3.1.0.tgz", "integrity": "sha512-EI6VCHrPHOsPsgZ1a/auhdxzHpEZ+kV7yjCGGIU+EWtb/XV1ZWSg5GlU32Qt4T05m98wCSQykPBhIg5aW6JjuQ==", + "license": "MIT", "dependencies": { "heap": "^0.2.6", "ml-distance-euclidean": "^2.0.0", @@ -580,18 +974,20 @@ } }, "node_modules/ml-levenberg-marquardt": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ml-levenberg-marquardt/-/ml-levenberg-marquardt-4.1.3.tgz", - "integrity": "sha512-CuR8mg1IIgb5IuDkdJBpnHmx+r6FpRDDPvYhAGq+4WVMLw/lu44P6PniyCrdvk1PNBmxVXN/LwBDMpQ/VaWhgA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ml-levenberg-marquardt/-/ml-levenberg-marquardt-5.0.0.tgz", + "integrity": "sha512-vCFoO2DyYKGZFp+KxofN2cAvSc/3gufJHj/oaDHA2nV+NZH509fD7m35zQR2ZXA8fepxpVrwgCAQ0aAIsV2WtA==", + "license": "MIT", "dependencies": { - "is-any-array": "^2.0.0", - "ml-matrix": "^6.10.4" + "is-any-array": "^2.0.1", + "ml-matrix": "^6.12.1" } }, "node_modules/ml-matrix": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/ml-matrix/-/ml-matrix-6.11.0.tgz", - "integrity": "sha512-7jr9NmFRkaUxbKslfRu3aZOjJd2LkSitCGv+QH9PF0eJoEG7jIpjXra1Vw8/kgao8+kHCSsJONG6vfWmXQ+/Eg==", + "version": "6.12.1", + "resolved": "https://registry.npmjs.org/ml-matrix/-/ml-matrix-6.12.1.tgz", + "integrity": "sha512-TJ+8eOFdp+INvzR4zAuwBQJznDUfktMtOB6g/hUcGh3rcyjxbz4Te57Pgri8Q9bhSQ7Zys4IYOGhFdnlgeB6Lw==", + "license": "MIT", "dependencies": { "is-any-array": "^2.0.1", "ml-array-rescale": "^1.3.7" @@ -615,215 +1011,244 @@ } }, "node_modules/ml-peak-shape-generator": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ml-peak-shape-generator/-/ml-peak-shape-generator-4.1.2.tgz", - "integrity": "sha512-SCVKGZ96JDyzEFgk0payEZKveakfbH7vA4Lysw3eRJEAm8hDnwip2pAFXjcC4jS78WDya4ghwAOSKDBUdHuMBw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ml-peak-shape-generator/-/ml-peak-shape-generator-4.2.0.tgz", + "integrity": "sha512-BDtR0rhUor5/4J9pJOEMRnD+QQ5v6ohx+o6MfRRg2e2IOTeZfp/uJcy5Y852v5CsNec1GmYMkd5PYrY0245qlQ==", + "license": "MIT", "dependencies": { "cheminfo-types": "^1.1.0" } }, "node_modules/ml-regression-base": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/ml-regression-base/-/ml-regression-base-2.1.6.tgz", - "integrity": "sha512-yTckvEc8szc6VrUTJSgAClShvCoPZdNt8pmyRe8aGsIWGjg6bYFotp9mDUwAB0snvKAbQWd6A4trL/PDCASLug==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ml-regression-base/-/ml-regression-base-4.0.0.tgz", + "integrity": "sha512-V2VjB+K/BcgXaX450xvYw36TLOB+piD9G1pHU3VE+ggQUApsVGkYco6UMQykFOwBydHnDTbOiybH/lwrkqFT4g==", + "license": "MIT", "dependencies": { - "is-any-array": "^2.0.0" + "cheminfo-types": "^1.7.3", + "is-any-array": "^2.0.1" + } + }, + "node_modules/ml-regression-exponential": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/ml-regression-exponential/-/ml-regression-exponential-3.0.2.tgz", + "integrity": "sha512-drV4ZSGKMMVNETVa7+/z15Uq9C0F69wNsJbhPvVbERgYRSmoGg+e0X7BYK75TzUvFY8IlYZmvVQOZK334slpbQ==", + "license": "MIT", + "dependencies": { + "ml-regression-base": "^4.0.0", + "ml-regression-simple-linear": "^3.0.0" } }, "node_modules/ml-regression-polynomial": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ml-regression-polynomial/-/ml-regression-polynomial-2.2.0.tgz", - "integrity": "sha512-WxFsEmi6oLxgq9TeaVoAA+vVUJFp1kGarX6WWClR8OmlanoIW5iLMnaeXfQcYuH8xNq4R1Cax2N9hYYmeWWkLg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/ml-regression-polynomial/-/ml-regression-polynomial-3.0.2.tgz", + "integrity": "sha512-RkHQeviEi7q6d2npCeH9MiRTPsBBqqSeqiWV3yctTFXvYgavy5MkpnCqGElHDb62Y3cTXlNQpmD4T7LA7yfGvw==", + "license": "MIT", + "dependencies": { + "ml-matrix": "^6.12.0", + "ml-regression-base": "^4.0.0" + } + }, + "node_modules/ml-regression-simple-linear": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ml-regression-simple-linear/-/ml-regression-simple-linear-3.0.1.tgz", + "integrity": "sha512-SF2oxA+034Co9GVQSFuS3vtACaRAFrEwHi9oX6VTaSY/KtXxseL3d4GApj4jWXMoAgrP7VMoIO1PH0RoZaMR1g==", + "license": "MIT", "dependencies": { - "ml-matrix": "^6.8.0", - "ml-regression-base": "^2.1.3" + "cheminfo-types": "^1.7.3", + "ml-regression-base": "^4.0.0" } }, "node_modules/ml-rolling-ball-baseline": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ml-rolling-ball-baseline/-/ml-rolling-ball-baseline-2.0.2.tgz", - "integrity": "sha512-tZ8ZArQ2XIgkpjMeKUG7Q25Aj+CnMK1Kl0NzXHHvMz1AqtrIm9Y9UP435rRNdqgoGJFpLhzDsoMFa9FDTGOQRQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ml-rolling-ball-baseline/-/ml-rolling-ball-baseline-2.0.3.tgz", + "integrity": "sha512-L7F+BfO4VsxEpPrAGUYWnupf6brodboU0fb3mK8P4k1MbtSDYJJtMGXfxY0PT3mQ+FgOpb6j+X49jzRT1hGShw==", + "license": "MIT", "dependencies": { "is-any-array": "^2.0.1", - "ml-spectra-processing": "^12.5.0" + "ml-spectra-processing": "^14.2.0" } }, "node_modules/ml-savitzky-golay-generalized": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/ml-savitzky-golay-generalized/-/ml-savitzky-golay-generalized-4.0.1.tgz", - "integrity": "sha512-I3z6aEj9f+VaqoqWoTmyXOsIngOCW2JtpcZfoeqnLFFFuIyK4uXOEIRVft3XgQbbtivIvTBJKHpfxyN8sgB5vA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ml-savitzky-golay-generalized/-/ml-savitzky-golay-generalized-4.2.0.tgz", + "integrity": "sha512-Pcn0URPuFbmxNC75SvukByL1Ct+DYQuyo8O5EfmUcHacx+zeODbIoPRgrWwEWZGvZAJ03aS9avTwV0VUNdtAZQ==", + "license": "MIT", "dependencies": { - "cheminfo-types": "^1.0.0", - "is-any-array": "^2.0.0" + "cheminfo-types": "^1.7.3", + "is-any-array": "^2.0.1" } }, "node_modules/ml-signal-processing": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ml-signal-processing/-/ml-signal-processing-1.0.3.tgz", - "integrity": "sha512-fIRgMGmF3kbsW3iiGCVZviwC652nBn+m5CTnweKi8TIyi9X/iEB0njA/TG9whTefEivQL40dqAfVUVAkybgYMw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ml-signal-processing/-/ml-signal-processing-2.1.0.tgz", + "integrity": "sha512-FgZKMMgslSnnT+WKpKwJrInKs0xYmCZb+pz/1Bcr8ks6KQrdNA2xI9jjkr74O5ZSA9RVGjGWt7gG2Ra8UhtrIw==", + "license": "MIT", "dependencies": { - "baselines": "^1.1.5", - "cheminfo-types": "^1.4.0", - "ml-gsd": "^12.1.3", - "ml-savitzky-golay-generalized": "^4.0.1", - "ml-spectra-processing": "^12.0.0" + "baselines": "^1.1.9", + "cheminfo-types": "^1.8.1", + "ml-gsd": "^13.0.1", + "ml-savitzky-golay-generalized": "^4.2.0", + "ml-spectra-processing": "^14.17.1" } }, "node_modules/ml-simple-clustering": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ml-simple-clustering/-/ml-simple-clustering-0.1.0.tgz", - "integrity": "sha512-t1jLL5nzUsNXBcAjcHTkCK2E7i2pEO1qrGzZmzS4BHWWMFxi2OUzBLTpK4MgwxLt0oQLkNGLr6NL4vcDxC2ePw==" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ml-simple-clustering/-/ml-simple-clustering-1.0.0.tgz", + "integrity": "sha512-YTTSKfVHiALLU8NOaaU7J6UhyiUoaroNk3InfLefU7LyQBrctpYcSrAU3tBeE+bVe53w1TxRJqW8JIyDPEnSfg==", + "license": "MIT" }, "node_modules/ml-sparse-matrix": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ml-sparse-matrix/-/ml-sparse-matrix-2.1.0.tgz", - "integrity": "sha512-ukJGbyGv+Zc0llNLVRpegMhRFW14O+i9ZhSEGBxuuSX8g5rA1S+Q+0r2JMKDM9cNM8QsvgtOPG7z/7pbjpoqzg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/ml-sparse-matrix/-/ml-sparse-matrix-3.1.0.tgz", + "integrity": "sha512-oTO38aQ2KeeCzw7u8MTJkI3j5Irn+h9KMc7j7Qi2Dg0AADGWwwhCwrx5BWoYGN3x5b+AfsJ6CKuUOBQnNk9YgA==", + "license": "MIT", "dependencies": { "ml-hash-table": "^1.0.0" } }, "node_modules/ml-spectra-fitting": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ml-spectra-fitting/-/ml-spectra-fitting-4.2.1.tgz", - "integrity": "sha512-vZI98eSK5HKeZTgh8omskRHB8QdnDTaTw1rbMPWTkfBH+6FgEgPvMRqH18BAaSHtxJHrqE6c4tQq9L9J8iYebg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ml-spectra-fitting/-/ml-spectra-fitting-5.0.1.tgz", + "integrity": "sha512-uqSc01tED7PNYYEvtPCAp7QGybZVi1K0HgHlqu5cAxjbpfnDS+XcOc2rTPprf8GoZ9Y3xL/fxyY4Gc5+Dh7e4A==", + "license": "MIT", "dependencies": { - "cheminfo-types": "^1.4.0", - "ml-array-max": "^1.2.4", - "ml-direct": "^0.1.1", - "ml-levenberg-marquardt": "^4.1.0", - "ml-peak-shape-generator": "^4.1.2", - "ml-spectra-processing": "^12.0.0" + "cheminfo-types": "^1.7.2", + "ml-direct": "^1.0.0", + "ml-levenberg-marquardt": "^5.0.0", + "ml-peak-shape-generator": "^4.1.4", + "ml-spectra-processing": "^14.2.0" } }, "node_modules/ml-spectra-processing": { - "version": "12.8.0", - "resolved": "https://registry.npmjs.org/ml-spectra-processing/-/ml-spectra-processing-12.8.0.tgz", - "integrity": "sha512-vu8RiTDWmo9UHUTcaILhH0j61cdsUp2FYiHjvkJQ/JH2ArdOTRJ4KShsiHUgfS4MDLWevcN9kWSalDT5vnwx7g==", + "version": "14.18.0", + "resolved": "https://registry.npmjs.org/ml-spectra-processing/-/ml-spectra-processing-14.18.0.tgz", + "integrity": "sha512-vzk7Lf/21mm9Otjn13xDFsFL4reDViU6GbtAxQfkXtprARxRRoQScbnlDNE11UhOKXy88/FTnR4vf2osMkT4fA==", + "license": "MIT", "dependencies": { "binary-search": "^1.3.6", - "cheminfo-types": "^1.7.2", + "cheminfo-types": "^1.8.1", "fft.js": "^4.0.4", "is-any-array": "^2.0.1", - "ml-matrix": "^6.10.5", - "ml-xsadd": "^2.0.0", - "spline-interpolator": "^1.0.0" + "ml-matrix": "^6.12.1", + "ml-xsadd": "^3.0.1" } }, "node_modules/ml-tree-set": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ml-tree-set/-/ml-tree-set-0.1.1.tgz", - "integrity": "sha512-9XZv+/hSltnsN61Cgb7PCFGxmo1HZn2JxDugnNHZDh0ZryJp7qtmcnPZLw/KrQLgG1JqdkKlfhmAYajSukb8yg==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ml-tree-set/-/ml-tree-set-1.0.1.tgz", + "integrity": "sha512-AoN65YFeZuFTwwu3LUePD3f1IaI3FZ8n6YBgDs3SP9m6XqrtZhxYc/N8mLswLL1lMa6ZeWdzRiq2A5jurD0sgA==", + "license": "MIT" }, "node_modules/ml-xsadd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ml-xsadd/-/ml-xsadd-2.0.0.tgz", - "integrity": "sha512-VoAYUqmPRmzKbbqRejjqceGFp3VF81Qe8XXFGU0UXLxB7Mf4GGvyGq5Qn3k4AiQgDEV6WzobqlPOd+j0+m6IrA==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ml-xsadd/-/ml-xsadd-3.0.1.tgz", + "integrity": "sha512-Fz2q6dwgzGM8wYKGArTUTZDGa4lQFA2Vi6orjGeTVRy22ZnQFKlJuwS9n8NRviqz1KHAHAzdKJwbnYhdo38uYg==", + "license": "MIT" }, - "node_modules/nmr-correlation": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/nmr-correlation/-/nmr-correlation-2.3.3.tgz", - "integrity": "sha512-RSdzZGsE2HeitUEhA7Dc1048eu6Web/SH5UjrbFEpddVNwvPGKQUZfQ5uoygcaTpKfq2lTddi2Ln9MDYjfyOgg==", + "node_modules/multiplet-analysis": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/multiplet-analysis/-/multiplet-analysis-2.1.5.tgz", + "integrity": "sha512-5+CF7qj/ccP+KZquYI2tDEjkGmRL6w1fciAs0OvTzSbAGsi5mEH7oruUipcXh2O6bgZhrY1TduBQkdFVXGJUwQ==", + "license": "MIT", "dependencies": { - "cheminfo-types": "^1.4.0", - "lodash": "^4.17.21", - "ml-matrix-peaks-finder": "^1.0.0", - "ml-peak-shape-generator": "^4.1.1" + "cheminfo-types": "^1.8.1", + "fft.js": "^4.0.4", + "ml-airpls": "^2.0.0", + "ml-spectra-processing": "^14.7.0" } }, - "node_modules/nmr-load-save": { - "version": "0.23.11", - "resolved": "https://registry.npmjs.org/nmr-load-save/-/nmr-load-save-0.23.11.tgz", - "integrity": "sha512-tvZDBfiZYy7xBUdx7MVVoQ3M3DzhsEKZCgkjkVk0tGVNcy1q9C1WYT48nSJXhgTMNslfH8GH9f2ojSTFnHoUDQ==", + "node_modules/next-power-of-two": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-power-of-two/-/next-power-of-two-1.0.0.tgz", + "integrity": "sha512-+z6QY1SxkDk6CQJAeaIZKmcNubBCRP7J8DMQUBglz/sSkNsZoJ1kULjqk9skNPPplzs4i9PFhYrvNDdtQleF/A==", + "license": "MIT" + }, + "node_modules/nmr-correlation": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/nmr-correlation/-/nmr-correlation-2.3.5.tgz", + "integrity": "sha512-WmJXckcF+epK0u2DVv+LBahvtlbFiCbTtXQsYmq07fze6i6XLPHnFcE1q6HKtiYYbePd6ks2PMOmWQEDdU2XbA==", "dependencies": { - "@lukeed/uuid": "^2.0.1", - "@types/lodash.merge": "^4.6.7", - "brukerconverter": "^6.3.2", - "cheminfo-types": "^1.7.2", - "convert-to-jcamp": "^5.4.9", - "filelist-utils": "^1.10.2", - "gyromagnetic-ratio": "^1.1.0", - "is-any-array": "^2.0.1", - "jcampconverter": "^9.5.0", - "jeolconverter": "^1.0.2", - "lodash.merge": "^4.6.2", - "ml-spectra-processing": "^12.8.0", - "nmr-correlation": "^2.3.3", - "nmr-processing": "^11.6.1", - "nmredata": "^0.9.9", - "openchemlib": "^8.7.0", - "openchemlib-utils": "^5.6.0", - "sdf-parser": "^6.0.1", - "varian-converter": "^0.3.3" + "cheminfo-types": "^1.8.1", + "ml-matrix-peaks-finder": "^1.0.0", + "ml-peak-shape-generator": "^4.1.4" } }, "node_modules/nmr-processing": { - "version": "11.6.1", - "resolved": "https://registry.npmjs.org/nmr-processing/-/nmr-processing-11.6.1.tgz", - "integrity": "sha512-NA6uoFbqkqFdrEoEKf3KLeh22opI7torSBi017n4Sqc/jis5/A7MpgunmHVxFYo09BDBIwKM4YvWur86NKXBUw==", + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/nmr-processing/-/nmr-processing-20.1.0.tgz", + "integrity": "sha512-KxNe4JnUB/Rixsl2TmAgxUh9Dqd4PB9FCNiDz7NQFmaC7g6G0IcmdiaDV+rYFf2NhLkDeLIlX6kN3vfW+vSMBw==", + "license": "CC-BY-NC-SA-4.0", "dependencies": { - "@lukeed/uuid": "^2.0.1", "binary-search": "^1.3.6", - "cross-fetch": "^4.0.0", - "form-data": "^4.0.0", - "gyromagnetic-ratio": "^1.1.0", + "d3-color": "3.1.0", + "d3-interpolate": "^3.0.1", + "gyromagnetic-ratio": "^2.0.0", "is-any-array": "^2.0.1", - "linear-sum-assignment": "^1.0.5", - "lodash.omit": "^4.5.0", - "ml-airpls": "^1.0.2", - "ml-baseline-correction-regression": "^1.0.2", - "ml-direct": "^0.1.3", - "ml-gsd": "^12.1.3", + "linear-sum-assignment": "^1.0.9", + "ml-airpls": "^2.0.0", + "ml-convolution": "^2.0.0", + "ml-direct": "^1.0.0", + "ml-gsd": "^13.1.0", "ml-hclust": "^3.1.0", - "ml-levenberg-marquardt": "^4.1.3", - "ml-matrix": "^6.10.7", - "ml-matrix-convolution": "^1.0.0", - "ml-matrix-peaks-finder": "^1.0.0", - "ml-peak-shape-generator": "^4.1.2", - "ml-signal-processing": "^1.0.3", - "ml-simple-clustering": "^0.1.0", - "ml-sparse-matrix": "^2.1.0", - "ml-spectra-processing": "^12.8.0", - "ml-tree-set": "^0.1.1", - "nmr-correlation": "^2.3.3", + "ml-levenberg-marquardt": "^5.0.0", + "ml-matrix": "^6.12.1", + "ml-matrix-convolution": "^2.0.0", + "ml-matrix-peaks-finder": "^2.0.0", + "ml-peak-shape-generator": "^4.2.0", + "ml-regression-base": "^4.0.0", + "ml-regression-exponential": "^3.0.2", + "ml-regression-polynomial": "^3.0.2", + "ml-regression-simple-linear": "^3.0.1", + "ml-savitzky-golay-generalized": "^4.2.0", + "ml-signal-processing": "^2.1.0", + "ml-simple-clustering": "^1.0.0", + "ml-sparse-matrix": "^3.1.0", + "ml-spectra-processing": "^14.18.0", + "ml-tree-set": "^1.0.1", + "multiplet-analysis": "^2.1.5", + "nmr-correlation": "^3.0.0", "numeral": "^2.0.6", - "openchemlib-utils": "^5.4.0", - "spectrum-generator": "^8.0.8" + "openchemlib": "^9.12.1", + "openchemlib-utils": "^8.7.0", + "spectrum-generator": "^8.1.1" } }, - "node_modules/nmredata": { - "version": "0.9.9", - "resolved": "https://registry.npmjs.org/nmredata/-/nmredata-0.9.9.tgz", - "integrity": "sha512-FhqSIN3p37RE/e/8Lf8OG/bpAuT35WtKrhjo6W9YQ1ZvC6QV7xP/1IUYOfOjmMqafaMC8xdzED9aSgHnlE5VUA==", + "node_modules/nmr-processing/node_modules/ml-matrix-convolution": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ml-matrix-convolution/-/ml-matrix-convolution-2.0.0.tgz", + "integrity": "sha512-XuEZf4ZTffAz7oDMG4olkh9aZmsIMr343gPTY+ZvnLWTlMiG+TegRbP4fpA1ju7/IK9q8u3TcC2cxf/N3ydtRA==", + "license": "MIT", "dependencies": { - "filelist-utils": "^1.2.0", - "jszip": "^3.10.1", - "openchemlib": "^8.0.1", - "openchemlib-utils": "^5.2.0" + "ml-fft": "^1.3.5" } }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "node_modules/nmr-processing/node_modules/ml-matrix-peaks-finder": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ml-matrix-peaks-finder/-/ml-matrix-peaks-finder-2.0.0.tgz", + "integrity": "sha512-dbXMpiWFZEMRP4XgD53+vuLJpa/fDXyJDL0A9SXHG0GRZUwq+B+BUYx1OhYrdoCkAROe+b554VCoH1wpQINTiQ==", + "license": "MIT", "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } + "ml-disjoint-set": "^1.0.0", + "ml-matrix-convolution": "^2.0.0" + } + }, + "node_modules/nmr-processing/node_modules/nmr-correlation": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/nmr-correlation/-/nmr-correlation-3.0.1.tgz", + "integrity": "sha512-0iuce3dLBpdcHn0Q/SX3gHvshRCUyN8X6iL6Y97VcK7JS3g8yZSQCIKjft8jsAOUzWP1rX8c1aCxw3BnCjrBEQ==", + "license": "MIT", + "dependencies": { + "cheminfo-types": "^1.8.1", + "ml-matrix-peaks-finder": "^2.0.0", + "ml-peak-shape-generator": "^4.2.0" } }, "node_modules/num-sort": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/num-sort/-/num-sort-2.1.0.tgz", "integrity": "sha512-1MQz1Ed8z2yckoBeSfkQHHO9K1yDRxxtotKSJ9yvcTUUxSvfvzEq5GwBrjjHEpMlq/k5gvXdmJ1SbYxWtpNoVg==", + "license": "MIT", "engines": { "node": ">=8" }, @@ -835,210 +1260,213 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/numeral/-/numeral-2.0.6.tgz", "integrity": "sha512-qaKRmtYPZ5qdw4jWJD6bxEf1FJEqllJrwxCLIm0sQU/A7v2/czigzOb+C2uSiFsa9lBUzeH7M1oK+Q+OLxL3kA==", + "license": "MIT", "engines": { "node": "*" } }, "node_modules/openchemlib": { - "version": "8.7.2", - "resolved": "https://registry.npmjs.org/openchemlib/-/openchemlib-8.7.2.tgz", - "integrity": "sha512-k7LGea1GRLewzO9REarAVrP62hZgImxDZRIU6p29utmYiXL56OmlVMVoTG3FqEule+yx/p96yzv9qYladSC3SA==" + "version": "9.12.1", + "resolved": "https://registry.npmjs.org/openchemlib/-/openchemlib-9.12.1.tgz", + "integrity": "sha512-cODgYX/SMOsT/PkGzw7+DRy//6sZOowkpFyIQYA3dQyNXZU6MXjIvaLMkk5c9j+JTIAiA1JsyARPbKh0AnEcGw==", + "license": "BSD-3-Clause" }, "node_modules/openchemlib-utils": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/openchemlib-utils/-/openchemlib-utils-5.6.1.tgz", - "integrity": "sha512-69dYUKb/vclhxmRwmKdzn5b4CwoKMqnG/O5cA9n4ysJ0A70dv2YCtX5UcC95GD2c3DTS1ALlb32mnmUzcWOGBQ==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/openchemlib-utils/-/openchemlib-utils-8.7.0.tgz", + "integrity": "sha512-UTQnWsxHbSqxor6enmsZUhbh8MGO3ImlilYY2zP+hXo0HGuuSn7B8XkHMRAXHDgURNFM56ezVBtg/RdxX1k9Mg==", + "license": "MIT", "dependencies": { - "atom-sorter": "^2.0.0", + "atom-sorter": "^2.2.1", "ensure-string": "^1.2.0", - "get-value": "^3.0.1", + "get-value": "^4.0.1", "ml-floyd-warshall": "^3.0.1", - "ml-matrix": "^6.11.0", - "papaparse": "^5.4.1", - "sdf-parser": "^6.0.1" + "ml-matrix": "^6.12.1", + "papaparse": "^5.5.3", + "sdf-parser": "^7.0.4" }, "peerDependencies": { - "openchemlib": ">=8.6.2" + "openchemlib": ">=9.12.0" } }, - "node_modules/pako": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", - "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==" - }, "node_modules/papaparse": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz", - "integrity": "sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==" + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.5.3.tgz", + "integrity": "sha512-5QvjGxYVjxO59MGU2lHVYpRWBBtKHnlIAcSe1uNFCkkptUh63NFRj0FJQm7nR67puEruUci/ZkjmEFrjCAyP4A==", + "license": "MIT" }, "node_modules/playwright": { - "version": "1.40.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.40.1.tgz", - "integrity": "sha512-2eHI7IioIpQ0bS1Ovg/HszsN/XKNwEG1kbzSDDmADpclKc7CyqkHw7Mg2JCz/bbCxg25QUPcjksoMW7JcIFQmw==", + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz", + "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==", + "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.40.1" + "playwright-core": "1.56.1" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=16" + "node": ">=18" }, "optionalDependencies": { "fsevents": "2.3.2" } }, "node_modules/playwright-core": { - "version": "1.40.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.40.1.tgz", - "integrity": "sha512-+hkOycxPiV534c4HhpfX6yrlawqVUzITRKwHAmYfmsVreltEl6fAZJ3DPfLMOODw0H3s1Itd6MDCWmP1fl/QvQ==", + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz", + "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==", + "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" }, "engines": { - "node": ">=16" + "node": ">=18" } }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "node_modules/sdf-parser": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/sdf-parser/-/sdf-parser-6.0.1.tgz", - "integrity": "sha512-QorgjqiqTzodCMmYkWYkYJ9nBnOL3w3mWOE9BB1SATUfkFvLOSxHaeZAnJxrHlRkfI7+q3+FsvZOS2OTN74lNA==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/sdf-parser/-/sdf-parser-7.0.4.tgz", + "integrity": "sha512-j4VIBVTVJqs95Asz0lcIku1VjlVgKKWlwDV2JmCIq1exlI9WOSBT9rQvwvTPwl0v2TTgdQLfhYnBmiRg318LoQ==", + "license": "MIT", "dependencies": { - "dynamic-typing": "^1.0.0", + "dynamic-typing": "^1.0.1", "ensure-string": "^1.2.0" } }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" - }, "node_modules/spectrum-generator": { - "version": "8.0.8", - "resolved": "https://registry.npmjs.org/spectrum-generator/-/spectrum-generator-8.0.8.tgz", - "integrity": "sha512-CRCW/ByC9lyRqssRz+S84l/xHhU+p2BzAIQc2OwLqRpmt89bzzr2u8h3WT1GDtXtMnTyDQEH2Yhnpb3PJeZ79Q==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/spectrum-generator/-/spectrum-generator-8.1.1.tgz", + "integrity": "sha512-u5xXYVKV/cZ4gNjFjwcJ4eqMui+XVKEoRWqxdI/Bu0hEx1gRTHzBL4dlJwnhaad+J887X77k03bVAigRXOwKxA==", + "license": "MIT", "dependencies": { - "ml-peak-shape-generator": "^4.1.2", - "ml-spectra-processing": "^12.5.0" - } - }, - "node_modules/spline-interpolator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/spline-interpolator/-/spline-interpolator-1.0.0.tgz", - "integrity": "sha512-s8lowgsWE5wjHGEsk/4VADp7xAHw+pNy3OGp96fYjVTwLSx/83+BBmTFP2wZDRM0kj45q8zSyOV5fUcGn4hLEw==", - "dependencies": { - "d3-array": "^0.7.1" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" + "ml-peak-shape-generator": "^4.1.4", + "ml-spectra-processing": "^14.10.0" } }, "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dependencies": { - "ansi-regex": "^5.0.1" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/varian-converter": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/varian-converter/-/varian-converter-0.3.3.tgz", - "integrity": "sha512-pu2WVuXeqtoy/RC1XIga6E1A4/4m+XhQSVzFdPjxlX2ih53qpHV3fl/g/UVvvJ9m9GQdOExEGKIK3JG4up8Upg==", - "dependencies": { - "filelist-utils": "^1.10.2", - "iobuffer": "^5.3.2", - "ml-spectra-processing": "^12.5.1" + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" } }, - "node_modules/webidl-conversions": { + "node_modules/typescript-event-target": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/typescript-event-target/-/typescript-event-target-1.1.1.tgz", + "integrity": "sha512-dFSOFBKV6uwaloBCCUhxlD3Pr/P1a/tJdcmPrTXCHlEFD3faj0mztjcGn6VBAhQ0/Bdy8K3VWrrqwbt/ffsYsg==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, + "node_modules/v8-compile-cache-lib": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true }, "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" @@ -1053,29 +1481,37 @@ } }, "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", "dependencies": { - "cliui": "^8.0.1", + "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", + "string-width": "^7.2.0", "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "yargs-parser": "^22.0.0" }, "engines": { - "node": ">=12" + "node": "^20.19.0 || ^22.12.0 || >=23" } }, "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", "engines": { - "node": ">=12" + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" } } } -} \ No newline at end of file +} diff --git a/app/scripts/nmr-cli/package.json b/app/scripts/nmr-cli/package.json index 83792f0..53c95a6 100644 --- a/app/scripts/nmr-cli/package.json +++ b/app/scripts/nmr-cli/package.json @@ -1,21 +1,37 @@ { - "name": "test-node", + "name": "nmr-cli", "version": "1.0.0", "description": "", - "main": "bin/index.js", + "main": "./build/index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "build": "tsc", + "start": "node build/index.js", + "dev": "nmr-cli src/index.ts" }, "keywords": [], "author": "", "license": "ISC", "bin": { - "nmr-cli": "./bin/index.js" + "nmr-cli": "./build/index.js" }, "dependencies": { - "filelist-utils": "^1.10.2", - "nmr-load-save": "^0.23.11", - "playwright": "^1.40.1", - "yargs": "^17.7.2" + "@zakodium/nmr-types": "^0.4.0", + "@zakodium/nmrium-core": "^0.4.2", + "@zakodium/nmrium-core-plugins": "^0.5.3", + "axios": "^1.13.0", + "file-collection": "^5.4.0", + "lodash.merge": "^4.6.2", + "mf-parser": "^3.6.0", + "ml-spectra-processing": "^14.18.0", + "nmr-processing": "^20.1.0", + "playwright": "^1.56.1", + "yargs": "^18.0.0" + }, + "devDependencies": { + "@types/lodash.merge": "^4.6.9", + "@types/node": "^24.9.1", + "@types/yargs": "^17.0.34", + "ts-node": "^10.9.2", + "typescript": "^5.9.3" } -} \ No newline at end of file +} diff --git a/app/scripts/nmr-cli/src/index.ts b/app/scripts/nmr-cli/src/index.ts new file mode 100755 index 0000000..4368b21 --- /dev/null +++ b/app/scripts/nmr-cli/src/index.ts @@ -0,0 +1,166 @@ +#!/usr/bin/env node +import yargs, { type Argv, type CommandModule, type Options } from 'yargs' +import { loadSpectrumFromURL, loadSpectrumFromFilePath } from './parse/prase-spectra' +import { generateSpectrumFromPublicationString } from './publication-string' +import { parsePredictionCommand } from './prediction/parsePredictionCommand' +import { hideBin } from 'yargs/helpers' + +const usageMessage = ` +Usage: nmr-cli [options] + +Commands: + parse-spectra Parse a spectra file to NMRium file + parse-publication-string resurrect spectrum from the publication string + predict Predict spectrum from Mol + +Options for 'parse-spectra' command: + -u, --url File URL + -dir, --dir-path Directory path + -s, --capture-snapshot Capture snapshot + -p, --auto-processing Automatic processing of spectrum (FID → FT spectra). + -d, --auto-detection Enable ranges and zones automatic detection. + +Arguments for 'parse-publication-string' command: + publicationString Publication string + +Options for 'predict' command: + -ps,--peakShape Peak shape algorithm (default: "lorentzian") choices: ["gaussian", "lorentzian"] + -n, --nucleus Predicted nucleus, choices: ["1H","13C"] (required) + -i, --id Input ID (default: 1) + -t, --type NMR type (default: "nmr;1H;1d") + -s, --shifts Chemical shifts (default: "1") + --solvent NMR solvent (default: "Dimethylsulphoxide-D6 (DMSO-D6, C2D6SO)") + -m, --molText MOL text (required) + --from From in (ppm) + --to To in (ppm) + --nbPoints Number of points (default: 1024) + --lineWidth Line width (default: 1) + --frequency NMR frequency (MHz) (default: 400) + --tolerance Tolerance to group peaks with close shift (default: 0.001) + + + +Examples: + nmr-cli parse-spectra -u file-url -s // Process spectra files from a URL and capture an image for the spectra + nmr-cli parse-spectra -dir directory-path -s // process a spectra files from a directory and capture an image for the spectra + nmr-cli parse-spectra -u file-url // Process spectra files from a URL + nmr-cli parse-spectra -dir directory-path // Process spectra files from a directory + nmr-cli parse-publication-string "your publication string" +` + +export interface FileOptionsArgs { + /** + * -u, --url + * File URL to load remote spectra or data. + */ + u?: string; + + /** + * -dir, --dir-path + * Local directory path for file input or output. + */ + dir?: string; + + /** + * -s, --capture-snapshot + * Capture a visual snapshot of the current state or spectrum. + */ + s?: boolean; + + /** + * -p, --auto-processing + * Automatically process spectrum from FID to FT spectra. + * Mandatory when automatic detection (`--auto-detection`) is enabled. + */ + p?: boolean; + + /** + * -d, --auto-detection + * Perform automatic ranges and zones detection. + */ + d?: boolean; +} + +// Define options for parsing a spectra file +const fileOptions: { [key in keyof FileOptionsArgs]: Options } = { + u: { + alias: 'url', + describe: 'File URL', + type: 'string', + nargs: 1, + }, + dir: { + alias: 'dir-path', + describe: 'Directory path', + type: 'string', + nargs: 1, + }, + s: { + alias: 'capture-snapshot', + describe: 'Capture snapshot', + type: 'boolean', + }, + p: { + alias: 'auto-processing', + describe: 'Auto processing', + type: 'boolean', + }, + d: { + alias: 'auto-detection', + describe: 'Ranges and zones auto detection', + type: 'boolean', + }, +} as const + +const parseFileCommand: CommandModule<{}, FileOptionsArgs> = { + command: ['parse-spectra', 'ps'], + describe: 'Parse a spectra file to NMRium file', + builder: yargs => { + return yargs + .options(fileOptions) + .conflicts('u', 'dir') as Argv + }, + handler: argv => { + + const { u, dir } = argv; + // Handle parsing the spectra file logic based on argv options + if (u) { + loadSpectrumFromURL({ u, ...argv }).then(result => { + console.log(JSON.stringify(result)) + }) + } + + + if (dir) { + loadSpectrumFromFilePath({ dir, ...argv }).then(result => { + console.log(JSON.stringify(result)) + }) + } + + }, +} + +// Define the parse publication string command +const parsePublicationCommand: CommandModule = { + command: ['parse-publication-string', 'pps'], + describe: 'Parse a publication string', + handler: argv => { + const publicationString = argv._[1] + // Handle parsing publication string + if (typeof publicationString == 'string') { + const nmriumObject = + generateSpectrumFromPublicationString(publicationString) + + console.log(JSON.stringify(nmriumObject)) + } + }, +} + +yargs(hideBin(process.argv)) + .usage(usageMessage) + .command(parseFileCommand) + .command(parsePublicationCommand) + .command(parsePredictionCommand) + .showHelpOnFail(true) + .help() + .parse() diff --git a/app/scripts/nmr-cli/src/parse/data/data1D/convertDataToFloat64Array.ts b/app/scripts/nmr-cli/src/parse/data/data1D/convertDataToFloat64Array.ts new file mode 100644 index 0000000..b0c39d4 --- /dev/null +++ b/app/scripts/nmr-cli/src/parse/data/data1D/convertDataToFloat64Array.ts @@ -0,0 +1,13 @@ +import type { NmrData1D } from 'cheminfo-types'; + +function convert(value: Float64Array | number[] = []): Float64Array { + return !ArrayBuffer.isView(value) && value ? Float64Array.from(value) : value; +} + +export function convertDataToFloat64Array(data: NmrData1D): NmrData1D { + return { + x: convert(data.x), + re: convert(data.re), + im: convert(data?.im), + }; +} diff --git a/app/scripts/nmr-cli/src/parse/data/data1D/detectRanges.ts b/app/scripts/nmr-cli/src/parse/data/data1D/detectRanges.ts new file mode 100644 index 0000000..dd8ddd7 --- /dev/null +++ b/app/scripts/nmr-cli/src/parse/data/data1D/detectRanges.ts @@ -0,0 +1,145 @@ +import { xFindClosestIndex } from "ml-spectra-processing"; +import { isProton } from "../../utility/isProton"; +import { Spectrum1D } from "@zakodium/nmrium-core"; +import { mapRanges, OptionsXYAutoPeaksPicking, updateRangesRelativeValues, xyAutoRangesPicking } from "nmr-processing"; + + +//TODO expose OptionsPeaksToRanges from nmr-processing +interface OptionsPeaksToRanges { + /** + * Number of hydrogens or some number to normalize the integration data. If it's zero return the absolute integration value + * @default 100 + */ + integrationSum?: number; + /** + * if it is true, it will join any overlaped ranges. + * @default true + */ + joinOverlapRanges?: boolean; + /** + * If exits it remove all the signals with integration < clean value + * @default 0.4 + */ + clean?: number; + /** + * If true, the Janalyzer function is run over signals to compile the patterns. + * @default true + */ + compile?: boolean; + /** + * option to chose between approx area with peaks or the sum of the points of given range ('sum', 'peaks') + * @default 'sum' + */ + integralType?: string; + /** + * Observed frequency + * @default 400 + */ + frequency?: number; + /** + * distance limit to clustering peaks. + * @default 16 + */ + frequencyCluster?: number; + /** + * If true, it will keep the peaks for each signal + */ + keepPeaks?: boolean; + /** + * Nucleus + * @default '1H' + */ + nucleus?: string; + /** + * ratio of heights between the extreme peaks + * @default 1.5 + */ + symRatio?: number; +} + + +interface AutoDetectOptions { + from?: number; + to?: number; + minMaxRatio?: number; + lookNegative?: number; +} + + + +export function detectRanges( + spectrum: Spectrum1D, + options: AutoDetectOptions = {}, +) { + + + const { from, to, minMaxRatio = 0.05, lookNegative = false } = options + const { info: { nucleus, solvent, originFrequency }, data } = spectrum; + let { x, re } = data + const windowFromIndex = from ? xFindClosestIndex(x, from) : undefined; + const windowToIndex = to ? xFindClosestIndex(x, to) : undefined; + + const isProtonic = isProton(nucleus); + + const peakPickingOptions: OptionsXYAutoPeaksPicking = { + ...defaultPeakPickingOptions, + smoothY: undefined, + sensitivity: 100, + broadWidth: 0.05, + thresholdFactor: 8, + minMaxRatio, + direction: lookNegative ? 'both' : 'positive', + frequency: originFrequency, + sgOptions: undefined, + + }; + + const rangesOptions: OptionsPeaksToRanges = { + nucleus, + compile: isProtonic, + frequency: originFrequency, + integrationSum: isProtonic ? spectrum.ranges.options.sum : 100, + frequencyCluster: isProtonic ? 16 : 0, + clean: 0.5, + keepPeaks: true, + joinOverlapRanges: isProtonic, + }; + + if (windowFromIndex !== undefined && windowToIndex !== undefined) { + x = x.slice(windowFromIndex, windowToIndex); + re = re.slice(windowFromIndex, windowToIndex); + } + + + const ranges = xyAutoRangesPicking( + { x, y: re }, + { + impurities: nucleus === '13C' ? { solvent: solvent || '' } : undefined, + peakPicking: peakPickingOptions, + ranges: rangesOptions, + }, + ); + + + spectrum.ranges.values = spectrum.ranges.values.concat( + mapRanges(ranges, spectrum), + ); + + updateRangesRelativeValues(spectrum); +} + + +const defaultPeakPickingOptions: OptionsXYAutoPeaksPicking = { + minMaxRatio: 1, + shape: { kind: 'lorentzian' }, + realTopDetection: true, + maxCriteria: true, + smoothY: true, + sensitivity: 100, + broadWidth: 0.25, + broadRatio: 0.0025, + thresholdFactor: 5, + sgOptions: { windowSize: 7, polynomial: 3 }, + frequency: 0 +}; + diff --git a/app/scripts/nmr-cli/src/parse/data/data1D/initSumOptions.ts b/app/scripts/nmr-cli/src/parse/data/data1D/initSumOptions.ts new file mode 100644 index 0000000..d02e573 --- /dev/null +++ b/app/scripts/nmr-cli/src/parse/data/data1D/initSumOptions.ts @@ -0,0 +1,56 @@ +import type { SumOptions } from '@zakodium/nmr-types'; +import { MF } from 'mf-parser'; +import getAtom from '../../utility/getAtom'; +import { MoleculeExtended } from '../../type/MoleculeExtended'; + +export { + updateIntegralsRelativeValues, + updateRangesRelativeValues, +} from 'nmr-processing'; + + +export interface SumParams { + nucleus: string; + molecules: MoleculeExtended[]; +} + +export type SetSumOptions = Omit; + +export function initSumOptions( + options: Partial, + params: SumParams, +) { + let newOptions: SumOptions = { + sum: undefined, + isSumConstant: true, + sumAuto: true, + ...options, + }; + const { molecules, nucleus } = params; + + if (options.sumAuto && Array.isArray(molecules) && molecules.length > 0) { + const { mf, id } = molecules[0]; + newOptions = { ...newOptions, sumAuto: true, mf, moleculeId: id }; + } else { + const { mf, moleculeId, ...resOptions } = newOptions; + newOptions = { ...resOptions, sumAuto: false }; + } + if (!newOptions.sum) { + newOptions.sum = getSum(newOptions.mf || null, nucleus); + } + + return newOptions; +} + +export function getSum(mf: string | null | undefined, nucleus: string) { + const defaultSum = 100; + + if (!mf || !nucleus) return defaultSum; + + const atom = getAtom(nucleus); + const atoms = new MF(mf).getInfo().atoms; + + return atoms[atom] || defaultSum; +} + + diff --git a/app/scripts/nmr-cli/src/parse/data/data1D/initiateDatum1D.ts b/app/scripts/nmr-cli/src/parse/data/data1D/initiateDatum1D.ts new file mode 100644 index 0000000..b8cd347 --- /dev/null +++ b/app/scripts/nmr-cli/src/parse/data/data1D/initiateDatum1D.ts @@ -0,0 +1,77 @@ +import type { + Spectrum1D, +} from '@zakodium/nmrium-core'; +import { Filters1DManager } from 'nmr-processing'; + +import { initSumOptions } from './initSumOptions.js'; +import { initiateRanges } from './initiateRanges.js'; +import { convertDataToFloat64Array } from './convertDataToFloat64Array.js'; +import { initiateFilters } from '../initiateFilters.js'; +import { MoleculeExtended } from '../../type/MoleculeExtended.js'; +import { initiatePeaks } from './initiatePeaks.js'; +import { initiateIntegrals } from './initiateIntegrals.js'; + + +interface InitiateDatum1DOptions { + molecules?: MoleculeExtended[]; +} + +export function initiateDatum1D( + spectrum: any, + options: InitiateDatum1DOptions = {}, +): Spectrum1D { + const { molecules = [] } = options; + + const { integrals, ranges, ...restSpectrum } = spectrum; + const spectrumObj: Spectrum1D = { ...restSpectrum }; + spectrumObj.id = spectrum.id || crypto.randomUUID(); + + spectrumObj.display = { + isVisible: true, + isRealSpectrumVisible: true, + ...spectrum.display, + }; + + spectrumObj.info = { + nucleus: '1H', // 1H, 13C, 19F, ... + isFid: false, + isComplex: false, // if isComplex is true that mean it contains real/ imaginary x set, if not hid re/im button . + dimension: 1, + ...spectrum.info, + }; + + spectrumObj.originalInfo = spectrumObj.info; + + spectrumObj.meta = { ...spectrum.meta }; + + spectrumObj.customInfo = { ...spectrum.customInfo }; + + spectrumObj.data = convertDataToFloat64Array(spectrum.data); + + spectrumObj.originalData = spectrumObj.data; + + spectrumObj.filters = initiateFilters(spectrum?.filters); //array of object {name: "FilterName", options: FilterOptions = {value | object} } + + const { nucleus } = spectrumObj.info; + + spectrumObj.peaks = initiatePeaks(spectrum, spectrumObj); + + const integralsOptions = initSumOptions(integrals?.options || {}, { + nucleus, + molecules, + }); + spectrumObj.integrals = initiateIntegrals( + spectrum, + spectrumObj, + integralsOptions, + ); + + const rangesOptions = initSumOptions(ranges?.options || {}, { + nucleus, + molecules, + }); + spectrumObj.ranges = initiateRanges(spectrum, spectrumObj, rangesOptions); + + + return spectrumObj; +} diff --git a/app/scripts/nmr-cli/src/parse/data/data1D/initiateIntegrals.ts b/app/scripts/nmr-cli/src/parse/data/data1D/initiateIntegrals.ts new file mode 100644 index 0000000..f5953a6 --- /dev/null +++ b/app/scripts/nmr-cli/src/parse/data/data1D/initiateIntegrals.ts @@ -0,0 +1,20 @@ +import type { Integrals } from '@zakodium/nmr-types'; +import type { Spectrum1D } from '@zakodium/nmrium-core'; +import merge from 'lodash.merge'; +import { mapIntegrals } from 'nmr-processing'; + +export function initiateIntegrals( + inputSpectrum: Partial, + spectrum: Spectrum1D, + options: Integrals['options'], +) { + return merge( + { + values: [], + options, + }, + { + values: mapIntegrals(inputSpectrum?.integrals?.values || [], spectrum), + }, + ); +} diff --git a/app/scripts/nmr-cli/src/parse/data/data1D/initiatePeaks.ts b/app/scripts/nmr-cli/src/parse/data/data1D/initiatePeaks.ts new file mode 100644 index 0000000..c998297 --- /dev/null +++ b/app/scripts/nmr-cli/src/parse/data/data1D/initiatePeaks.ts @@ -0,0 +1,13 @@ +import type { Peaks } from '@zakodium/nmr-types'; +import type { Spectrum1D } from '@zakodium/nmrium-core'; +import merge from 'lodash.merge'; +import { mapPeaks } from 'nmr-processing'; + +export function initiatePeaks( + inputSpectrum: Partial, + spectrum: Spectrum1D, +): Peaks { + return merge({ values: [], options: {} }, inputSpectrum.peaks, { + values: mapPeaks(inputSpectrum?.peaks?.values || [], spectrum), + }); +} diff --git a/app/scripts/nmr-cli/src/parse/data/data1D/initiateRanges.ts b/app/scripts/nmr-cli/src/parse/data/data1D/initiateRanges.ts new file mode 100644 index 0000000..529eefe --- /dev/null +++ b/app/scripts/nmr-cli/src/parse/data/data1D/initiateRanges.ts @@ -0,0 +1,20 @@ +import type { Ranges } from '@zakodium/nmr-types'; +import type { Spectrum1D } from '@zakodium/nmrium-core'; +import merge from 'lodash.merge'; +import { mapRanges } from 'nmr-processing'; + +export function initiateRanges( + inputSpectrum: Partial, + spectrum: Spectrum1D, + options: Ranges['options'], +) { + return merge( + { + values: [], + options, + }, + { + values: mapRanges(inputSpectrum?.ranges?.values || [], spectrum), + }, + ); +} diff --git a/app/scripts/nmr-cli/src/parse/data/data2d/detectZones.ts b/app/scripts/nmr-cli/src/parse/data/data2d/detectZones.ts new file mode 100644 index 0000000..62cfe28 --- /dev/null +++ b/app/scripts/nmr-cli/src/parse/data/data2d/detectZones.ts @@ -0,0 +1,24 @@ +import { Spectrum2D } from "@zakodium/nmrium-core"; +import { isFt2DSpectrum } from "./isSpectrum2D"; +import { mapZones } from "nmr-processing"; +import { getDetectionZones } from "./getDetectionZones"; +import { Zone } from "@zakodium/nmr-types"; + +export function detectZones(spectrum: Spectrum2D) { + + if (!isFt2DSpectrum(spectrum)) return; + + const { data } = spectrum; + + const { rr: { minX, maxX, minY, maxY } } = data; + const detectionOptions = { + selectedZone: { fromX: minX, toX: maxX, fromY: minY, toY: maxY }, + thresholdFactor: 1, + maxPercentCutOff: 0.03, + }; + + const zones = getDetectionZones(spectrum, detectionOptions); + spectrum.zones.values = mapZones(zones as Zone[], spectrum); + + +} \ No newline at end of file diff --git a/app/scripts/nmr-cli/src/parse/data/data2d/getDetectionZones.ts b/app/scripts/nmr-cli/src/parse/data/data2d/getDetectionZones.ts new file mode 100644 index 0000000..03c62a4 --- /dev/null +++ b/app/scripts/nmr-cli/src/parse/data/data2d/getDetectionZones.ts @@ -0,0 +1,121 @@ +import type { Spectrum2D } from '@zakodium/nmrium-core'; +import { xyzAutoZonesPicking } from 'nmr-processing'; + +export interface DetectionZonesOptions { + selectedZone: { + fromX: number; + fromY: number; + toX: number; + toY: number; + }; + thresholdFactor: number; + maxPercentCutOff: number; + tolerances?: number[]; + convolutionByFFT?: boolean; + enhanceSymmetry?: boolean; +} + +/** + * + * @param {object} options + * @param {object} options.selectedZone + * @param {number} options.selectedZone.fromX + * @param {number} options.selectedZone.fromY + * @param {number} options.selectedZone.toX + * @param {number} options.selectedZone.toY + * @param {number} options.thresholdFactor + * @param {boolean} options.convolutionByFFT + */ +export function getDetectionZones( + spectrum: Spectrum2D, + options: DetectionZonesOptions, +) { + let dataMatrix = {}; + const { selectedZone } = options; + if (selectedZone) { + options.enhanceSymmetry = false; + dataMatrix = getSubMatrix(spectrum, selectedZone); + } else { + dataMatrix = spectrum.data; + } + + return autoZonesDetection(dataMatrix, { + ...options, + info: spectrum.info, + }); +} + +function autoZonesDetection(data: any, options: any) { + const { + clean, + tolerances, + thresholdFactor, + maxPercentCutOff, + convolutionByFFT, + info: { nucleus: nuclei, originFrequency }, + } = options; + + const { enhanceSymmetry = nuclei[0] === nuclei[1] } = options; + + const zones = xyzAutoZonesPicking(data, { + nuclei, + tolerances, + observedFrequencies: originFrequency, + thresholdFactor, + realTopDetection: true, + clean, + maxPercentCutOff, + enhanceSymmetry, + convolutionByFFT, + }); + + return zones; +} + +function getSubMatrix(datum: any, selectedZone: any) { + const { fromX, toX, fromY, toY } = selectedZone; + const data = datum.data.rr; + const xStep = (data.maxX - data.minX) / (data.z[0].length - 1); + const yStep = (data.maxY - data.minY) / (data.z.length - 1); + let xIndexFrom = Math.max(Math.floor((fromX - data.minX) / xStep), 0); + let yIndexFrom = Math.max(Math.floor((fromY - data.minY) / yStep), 0); + let xIndexTo = Math.min( + Math.floor((toX - data.minX) / xStep), + data.z[0].length - 1, + ); + let yIndexTo = Math.min( + Math.floor((toY - data.minY) / yStep), + data.z.length - 1, + ); + + if (xIndexFrom > xIndexTo) [xIndexFrom, xIndexTo] = [xIndexTo, xIndexFrom]; + if (yIndexFrom > yIndexTo) [yIndexFrom, yIndexTo] = [yIndexTo, yIndexFrom]; + + const dataMatrix: any = { + z: [], + maxX: data.minX + xIndexTo * xStep, + minX: data.minX + xIndexFrom * xStep, + maxY: data.minY + yIndexTo * yStep, + minY: data.minY + yIndexFrom * yStep, + }; + let maxZ = Number.MIN_SAFE_INTEGER; + let minZ = Number.MAX_SAFE_INTEGER; + + const nbXPoints = xIndexTo - xIndexFrom + 1; + + for (let j = yIndexFrom; j < yIndexTo; j++) { + const row = new Float32Array(nbXPoints); + let xIndex = xIndexFrom; + for (let i = 0; i < nbXPoints; i++) { + row[i] = data.z[j][xIndex++]; + } + for (const rowValue of row) { + if (maxZ < rowValue) maxZ = rowValue; + if (minZ > rowValue) minZ = rowValue; + } + dataMatrix.z.push(Array.from(row)); + } + dataMatrix.minZ = minZ; + dataMatrix.maxZ = maxZ; + return dataMatrix; +} diff --git a/app/scripts/nmr-cli/src/parse/data/data2d/initiateDatum2D.ts b/app/scripts/nmr-cli/src/parse/data/data2d/initiateDatum2D.ts new file mode 100644 index 0000000..3676f1e --- /dev/null +++ b/app/scripts/nmr-cli/src/parse/data/data2d/initiateDatum2D.ts @@ -0,0 +1,69 @@ +import type { + Spectrum2D, +} from '@zakodium/nmrium-core'; +import { Filters2DManager } from 'nmr-processing'; + + +import { initiateZones } from './initiateZones.js'; +import { initiateFilters } from '../initiateFilters.js'; + +const defaultMinMax = { z: [], minX: 0, minY: 0, maxX: 0, maxY: 0 }; + + +function initiateDisplay(spectrum: any) { + return { + isPositiveVisible: true, + isNegativeVisible: true, + isVisible: true, + dimension: 2, + ...spectrum.display, + }; +} + +function initiateInfo(spectrum: any) { + return { + nucleus: ['1H', '1H'], + isFt: true, + isFid: false, + isComplex: false, // if isComplex is true that mean it contains real/ imaginary x set, if not hid re/im button . + dimension: 2, + ...spectrum.info, + }; +} + + +export function initiateDatum2D( + spectrum: any, +): Spectrum2D { + const datum: any = { ...spectrum }; + + datum.id = spectrum.id || crypto.randomUUID(); + + datum.display = initiateDisplay(spectrum); + + datum.info = initiateInfo(spectrum); + + datum.originalInfo = datum.info; + + datum.meta = { ...spectrum.meta }; + + datum.customInfo = { ...spectrum.customInfo }; + + datum.data = getData(datum, spectrum); + datum.originalData = datum.data; + datum.filters = initiateFilters(spectrum?.filters); + + datum.zones = initiateZones(spectrum, datum as Spectrum2D); + + //reapply filters after load the original data + + return datum; +} + +function getData(datum: any, options: any) { + if (datum.info.isFid) { + const { re = defaultMinMax, im = defaultMinMax } = options.data; + return { re, im }; + } + return { rr: defaultMinMax, ...options.data }; +} diff --git a/app/scripts/nmr-cli/src/parse/data/data2d/initiateZones.ts b/app/scripts/nmr-cli/src/parse/data/data2d/initiateZones.ts new file mode 100644 index 0000000..cc16095 --- /dev/null +++ b/app/scripts/nmr-cli/src/parse/data/data2d/initiateZones.ts @@ -0,0 +1,24 @@ +import type { Zones } from '@zakodium/nmr-types'; +import type { Spectrum2D } from '@zakodium/nmrium-core'; +import merge from 'lodash.merge'; +import { mapZones } from 'nmr-processing'; + +export function initiateZones( + options: Partial<{ zones: Zones }>, + spectrum: Spectrum2D, +) { + return merge( + { + values: [], + options: { + sum: undefined, + isSumConstant: true, + sumAuto: true, + }, + }, + options.zones, + { + values: mapZones(options?.zones?.values || [], spectrum), + }, + ); +} diff --git a/app/scripts/nmr-cli/src/parse/data/data2d/isSpectrum2D.ts b/app/scripts/nmr-cli/src/parse/data/data2d/isSpectrum2D.ts new file mode 100644 index 0000000..480309b --- /dev/null +++ b/app/scripts/nmr-cli/src/parse/data/data2d/isSpectrum2D.ts @@ -0,0 +1,36 @@ +import type { Spectrum2D, Spectrum } from '@zakodium/nmrium-core'; +import type { NmrData2D, NmrData2DFid, NmrData2DFt } from 'cheminfo-types'; + +export function isSpectrum2D( + spectrum: Spectrum | undefined, +): spectrum is Spectrum2D { + return spectrum?.info.dimension === 2; +} + +function isQuadrantsData(data: NmrData2D): data is NmrData2DFt { + return 'rr' in data && 'ri' in data && 'ir' in data && 'ii' in data; +} +function isFt2DData(data: NmrData2D): data is NmrData2DFt { + return 'rr' in data; +} + +export function isFid2DData(data: NmrData2D): data is NmrData2DFid { + return 're' in data; +} + +export function isFid2DSpectrum( + spectrum: Spectrum, +): spectrum is Spectrum2D & { data: NmrData2DFid } { + return isSpectrum2D(spectrum) && isFid2DData(spectrum.data); +} + +export function isFt2DSpectrum( + spectrum: Spectrum, +): spectrum is Spectrum2D & { data: NmrData2DFt } { + return isSpectrum2D(spectrum) && isFt2DData(spectrum.data); +} +export function isQuadrants2DSpectrum( + spectrum: Spectrum, +): spectrum is Spectrum2D & { data: NmrData2DFt } { + return isSpectrum2D(spectrum) && isQuadrantsData(spectrum.data); +} diff --git a/app/scripts/nmr-cli/src/parse/data/initiateFilters.ts b/app/scripts/nmr-cli/src/parse/data/initiateFilters.ts new file mode 100644 index 0000000..53e1e79 --- /dev/null +++ b/app/scripts/nmr-cli/src/parse/data/initiateFilters.ts @@ -0,0 +1,8 @@ +export function initiateFilters(inputFilters: any): any { + if (!inputFilters || !Array.isArray(inputFilters)) return []; + + return inputFilters.map((filter) => ({ + ...filter, + id: filter?.id || crypto.randomUUID(), + })); +} diff --git a/app/scripts/nmr-cli/src/parse/prase-spectra.ts b/app/scripts/nmr-cli/src/parse/prase-spectra.ts new file mode 100644 index 0000000..36953e9 --- /dev/null +++ b/app/scripts/nmr-cli/src/parse/prase-spectra.ts @@ -0,0 +1,186 @@ +import { join, isAbsolute } from 'path' +import { NmriumData, ParsingOptions, type NmriumState } from '@zakodium/nmrium-core' +import init from '@zakodium/nmrium-core-plugins' +import playwright from 'playwright' +import { FileCollection } from 'file-collection' +import { FileOptionsArgs } from '..' +import { isSpectrum2D } from './data/data2d/isSpectrum2D' +import { initiateDatum2D } from './data/data2d/initiateDatum2D' +import { initiateDatum1D } from './data/data1D/initiateDatum1D' +import { detectZones } from './data/data2d/detectZones' +import { detectRanges } from './data/data1D/detectRanges' +import { Filters1DManager, Filters2DManager } from 'nmr-processing' + +type RequiredKey = Omit & Required>; + +const parsingOptions: ParsingOptions = { + onLoadProcessing: { autoProcessing: true }, + sourceSelector: { general: { dataSelection: 'preferFT' } }, + experimentalFeatures: true +}; + +interface Snapshot { + image: string + id: string +} + +const core = init() + +function generateNMRiumURL() { + const baseURL = process.env['BASE_NMRIUM_URL'] || '' + const url = new URL(baseURL) + url.searchParams.append('workspace', 'embedded') + return url.toString() +} + +async function captureSpectraViewAsBase64(nmriumState: Partial) { + const { data: { spectra } = { spectra: [] }, version } = nmriumState + const browser = await playwright.chromium.launch() + const context = await browser.newContext( + playwright.devices['Desktop Chrome HiDPI'] + ) + const page = await context.newPage() + + const url = generateNMRiumURL() + + await page.goto(url) + + await page.locator('text=Loading').waitFor({ state: 'hidden' }) + + let snapshots: Snapshot[] = [] + + for (const spectrum of spectra || []) { + const spectrumObject = { + version, + data: { + spectra: [{ ...spectrum }], + }, + } + + // convert typed array to array + const stringObject = JSON.stringify( + spectrumObject, + (key, value: unknown) => { + return ArrayBuffer.isView(value) + ? Array.from(value as unknown as Iterable) + : value + } + ) + + // load the spectrum into NMRium using the custom event + await page.evaluate( + ` + window.postMessage({ type: "nmr-wrapper:load", data:{data: ${stringObject},type:"nmrium"}}, '*'); + ` + ) + + //wait for NMRium process and load spectra + await page.locator('text=Loading').waitFor({ state: 'hidden' }) + + // take a snapshot for the spectrum + try { + const snapshot = await page.locator('#nmrSVG .container').screenshot() + + snapshots.push({ + image: snapshot.toString('base64'), + id: spectrum.id, + }) + } catch (e) { + console.log(e) + } + } + + await context.close() + await browser.close() + + return snapshots + +} + +interface ProcessSpectraOptions { + autoDetection: boolean; autoProcessing: boolean; +} + +function processSpectra(data: NmriumData, options: ProcessSpectraOptions) { + + const { autoDetection = false, autoProcessing = false } = options + + for (let index = 0; index < data.spectra.length; index++) { + const inputSpectrum = data.spectra[index] + const is2D = isSpectrum2D(inputSpectrum); + const spectrum = is2D ? initiateDatum2D(inputSpectrum) : initiateDatum1D(inputSpectrum); + + if (autoProcessing) { + isSpectrum2D(spectrum) ? Filters2DManager.reapplyFilters(spectrum) : Filters1DManager.reapplyFilters(spectrum) + } + + if (autoDetection && spectrum.info.isFt) { + isSpectrum2D(spectrum) ? detectZones(spectrum) : detectRanges(spectrum); + } + + data.spectra[index] = spectrum; + } + + +} + +async function loadSpectrumFromURL(options: RequiredKey) { + const { u: url, s: enableSnapshot = false, p: autoProcessing = false, d: autoDetection = false } = options; + + const { pathname: relativePath, origin: baseURL } = new URL(url) + const source = { + entries: [ + { + relativePath, + }, + ], + baseURL, + } + + const [nmriumState] = await core.readFromWebSource(source, parsingOptions); + const { + data, version + } = nmriumState; + + + if (data) { + processSpectra(data, { autoDetection, autoProcessing }); + } + + let images: Snapshot[] = [] + + if (enableSnapshot) { + images = await captureSpectraViewAsBase64({ data, version }) + } + + return { data, version, images } +} + +async function loadSpectrumFromFilePath(options: RequiredKey) { + const { dir: path, s: enableSnapshot = false, p: autoProcessing = false, d: autoDetection = false } = options; + + const dirPath = isAbsolute(path) ? path : join(process.cwd(), path) + + const fileCollection = await FileCollection.fromPath(dirPath, { + unzip: { zipExtensions: ['zip', 'nmredata'] }, + }) + + const { + nmriumState: { data, version }, + } = await core.read(fileCollection, parsingOptions) + + + if (data) { + processSpectra(data, { autoDetection, autoProcessing }) + } + + let images: Snapshot[] = [] + + if (enableSnapshot) { + images = await captureSpectraViewAsBase64({ data, version }) + } + + return { data, version, images } +} + +export { loadSpectrumFromFilePath, loadSpectrumFromURL } diff --git a/app/scripts/nmr-cli/src/parse/type/MoleculeExtended.ts b/app/scripts/nmr-cli/src/parse/type/MoleculeExtended.ts new file mode 100644 index 0000000..7e71a00 --- /dev/null +++ b/app/scripts/nmr-cli/src/parse/type/MoleculeExtended.ts @@ -0,0 +1,11 @@ +import { StateMolecule } from "@zakodium/nmrium-core"; + +export interface MoleculeExtended + extends Required>, + Omit { + mf: string; + em: number; + mw: number; + svg: string; + atoms: Record; +} \ No newline at end of file diff --git a/app/scripts/nmr-cli/src/parse/utility/getAtom.ts b/app/scripts/nmr-cli/src/parse/utility/getAtom.ts new file mode 100644 index 0000000..68e66ec --- /dev/null +++ b/app/scripts/nmr-cli/src/parse/utility/getAtom.ts @@ -0,0 +1,3 @@ +export default function getAtom(nucleus: string): string { + return nucleus?.replaceAll(/\d/g, '') || ''; +} diff --git a/app/scripts/nmr-cli/src/parse/utility/isProton.ts b/app/scripts/nmr-cli/src/parse/utility/isProton.ts new file mode 100644 index 0000000..85f6e6e --- /dev/null +++ b/app/scripts/nmr-cli/src/parse/utility/isProton.ts @@ -0,0 +1,3 @@ +export function isProton(nucleus: string) { + return nucleus === '1H'; +} diff --git a/app/scripts/nmr-cli/src/prediction/generatePredictedSpectrumData.ts b/app/scripts/nmr-cli/src/prediction/generatePredictedSpectrumData.ts new file mode 100644 index 0000000..78a8647 --- /dev/null +++ b/app/scripts/nmr-cli/src/prediction/generatePredictedSpectrumData.ts @@ -0,0 +1,174 @@ +export interface ShiftsItem { + atom: number + prediction: number + real: number + diff: number + status: 'accept' | 'missing' | string + hoseCode: string + spheres: number +} + +type PeakShape = 'gaussian' | 'lorentzian' + +interface PeakShapeOptions { + x: number + fwhm: number +} + +export interface GenerateSpectrumOptions { + from?: number + to?: number + nbPoints?: number + lineWidth?: number + frequency?: number + tolerance?: number + peakShape?: PeakShape +} + +interface GroupItem { + prediction: number + count: number + atoms: number[] +} + +interface Data1D { + x: number[] + re: number[] +} + +const GAUSSIAN_EXP_FACTOR = -4 * Math.LN2 + +function lorentzian(options: PeakShapeOptions) { + const { x, fwhm } = options + return fwhm ** 2 / (4 * x ** 2 + fwhm ** 2) +} + +function gaussian(options: PeakShapeOptions) { + const { x, fwhm } = options + return Math.exp(GAUSSIAN_EXP_FACTOR * Math.pow(x / fwhm, 2)) +} + +function erfinv(x: number): number { + let a = 0.147 + if (x === 0) return 0 + let ln1MinusXSqrd = Math.log(1 - x * x) + let lnEtcBy2Plus2 = ln1MinusXSqrd / 2 + 2 / (Math.PI * a) + let firstSqrt = Math.sqrt(lnEtcBy2Plus2 ** 2 - ln1MinusXSqrd / a) + let secondSqrt = Math.sqrt(firstSqrt - lnEtcBy2Plus2) + return secondSqrt * (x > 0 ? 1 : -1) +} + +function getGaussianFactor(area = 0.9999) { + if (area >= 1) { + throw new Error('area should be (0 - 1)') + } + + return Math.sqrt(2) * erfinv(area) +} + +function getLorentzianFactor(area = 0.9999) { + if (area >= 1) { + throw new Error('area should be (0 - 1)') + } + const halfResidual = (1 - area) * 0.5 + const quantileFunction = (p: number) => Math.tan(Math.PI * (p - 0.5)) + return ( + (quantileFunction(1 - halfResidual) - quantileFunction(halfResidual)) / 2 + ) +} + +function peakShapeFunction(options: PeakShapeOptions, shape: PeakShape) { + if (shape === 'lorentzian') { + return lorentzian(options) + } + + return gaussian(options) +} + +function getPeakShapeFactor(area: number, shape: PeakShape) { + if (shape === 'lorentzian') { + return getLorentzianFactor(area) + } + + return getGaussianFactor(area) +} + +function groupEquivalentShifts(shifts: ShiftsItem[], tolerance = 0.001) { + const groups: GroupItem[] = [] + + for (const shift of shifts) { + const match = groups.find( + g => Math.abs(g.prediction - shift.prediction) < tolerance + ) + if (match) { + match.count += 1 + match.atoms.push(shift.atom) + } else { + groups.push({ + prediction: shift.prediction, + count: 1, + atoms: [shift.atom], + }) + } + } + + return groups +} + +export function generatePredictedSpectrumData( + shifts: ShiftsItem[], + options: GenerateSpectrumOptions = {} +) { + let { from, to } = options + const { + nbPoints = 10240, + frequency = 400, + lineWidth = 1, + tolerance = 0.001, + peakShape = 'lorentzian', + } = options + + if (!shifts || shifts.length === 0) return [] + + const sortedShifts = shifts + .slice(0) + .sort((a, b) => a.prediction - b.prediction) + + // const acceptedShifts = sortedShifts.filter(shift => + // shift.status === 'accept' + // ); + + const acceptedShifts = sortedShifts + + if (acceptedShifts.length === 0) return [] + from = from ?? acceptedShifts[0].prediction - 1 + to = to ?? (acceptedShifts.at(-1) as ShiftsItem).prediction + 1 + + if (from >= to) { + throw new Error("Invalid range: 'from' is greater or equal then 'to'") + } + + const data: Data1D = { x: [], re: [] } + const stepSize = (to - from) / (nbPoints - 1) + const groupedShifts = groupEquivalentShifts(acceptedShifts, tolerance) + + const limit = (lineWidth * getPeakShapeFactor(0.99, peakShape)) / frequency + for (let i = 0; i < nbPoints; i++) { + const x = from + i * stepSize + let intensity = 0 + for (const { prediction, count } of groupedShifts) { + if (Math.abs(x - prediction) <= limit) { + intensity += + peakShapeFunction( + { x: x - prediction, fwhm: lineWidth / frequency }, + peakShape + ) * count + } + } + + data.x.push(x) + data.re.push(intensity) + } + + return data +} diff --git a/app/scripts/nmr-cli/src/prediction/parsePredictionCommand.ts b/app/scripts/nmr-cli/src/prediction/parsePredictionCommand.ts new file mode 100644 index 0000000..4387a18 --- /dev/null +++ b/app/scripts/nmr-cli/src/prediction/parsePredictionCommand.ts @@ -0,0 +1,248 @@ +import { Argv, CommandModule, Options } from 'yargs' +import { + generatePredictedSpectrumData, + GenerateSpectrumOptions, + ShiftsItem, +} from './generatePredictedSpectrumData' +import { CURRENT_EXPORT_VERSION } from '@zakodium/nmrium-core' + +import https from 'https' +import axios from 'axios' + +interface PredictionParameters { + molText: string + id: number + type: string + shifts: string + solvent: string + nucleus: string +} + +const predictionOptions: { [key in keyof GenerateSpectrumOptions]: Options } = { + from: { + type: 'number', + description: 'From in (ppm)', + }, + to: { + type: 'number', + description: 'To in (ppm)', + }, + nbPoints: { + type: 'number', + description: 'Number of points', + default: 2 ** 18, // 256k points + }, + lineWidth: { + type: 'number', + description: 'Line width', + default: 1, + }, + frequency: { + type: 'number', + description: 'NMR frequency (MHz)', + default: 400, + }, + tolerance: { + type: 'number', + description: 'Tolerance', + default: 0.001, + }, + peakShape: { + alias: 'ps', + type: 'string', + description: 'Peak shape algorithm', + default: 'lorentzian', + choices: ['gaussian', 'lorentzian'], + }, +} as const + +const nmrOptions: { [key in keyof PredictionParameters]: Options } = { + id: { + alias: 'i', + type: 'number', + description: 'Input ID', + default: 1, + }, + type: { + alias: 't', + type: 'string', + description: 'NMR type', + default: 'nmr;1H;1d', + choices: ['nmr;1H;1d', 'nmr;13C;1d'], + }, + shifts: { + alias: 's', + type: 'string', + description: 'Chemical shifts', + default: '1', + }, + solvent: { + type: 'string', + description: 'NMR solvent', + default: 'Dimethylsulphoxide-D6 (DMSO-D6, C2D6SO)', + choices: [ + 'Any', + 'Chloroform-D1 (CDCl3)', + 'Dimethylsulphoxide-D6 (DMSO-D6, C2D6SO)', + 'Methanol-D4 (CD3OD)', + 'Deuteriumoxide (D2O)', + 'Acetone-D6 ((CD3)2CO)', + 'TETRACHLORO-METHANE (CCl4)', + 'Pyridin-D5 (C5D5N)', + 'Benzene-D6 (C6D6)', + 'neat', + 'Tetrahydrofuran-D8 (THF-D8, C4D4O)', + ], + }, + molText: { + alias: 'm', + type: 'string', + description: 'MOL file content', + requiresArg: true, + }, + nucleus: { + alias: 'n', + type: 'string', + description: 'Predicted nucleus', + requiresArg: true, + choices: ['1H', '13C'], + }, +} as const + +interface PredictionResponseItem { + id: number + type: string + statistics: { + accept: number + warning: number + reject: number + missing: number + total: number + } + shifts: ShiftsItem[] +} +interface PredictionResponse { + result: PredictionResponseItem[] +} + +async function predictNMR(options: PredictionArgs): Promise { + const url = process.env['NMR_PREDICTION_URL'] + + if (!url) { + throw new Error('Environment variable NMR_PREDICTION_URL is not defined.') + } + + try { + new URL(url).toString() + } catch { + throw new Error(`Invalid URL in NMR_PREDICTION_URL: "${url}"`) + } + + try { + const { + id, + type, + shifts, + solvent, + from, + to, + nbPoints = 2 ** 18, // 256K + frequency = 400, + lineWidth = 1, + tolerance = 0.001, + molText, + nucleus, + peakShape = 'lorentzian', + } = options + + const payload: any = { + inputs: [ + { + id, + type, + shifts, + solvent, + }, + ], + moltxt: molText.replaceAll(/\\n/g, '\n'), + } + + const httpsAgent = new https.Agent({ + rejectUnauthorized: false, + }) + + // Axios POST request with httpsAgent + const response = await axios.post(url, payload, { + headers: { + 'Content-Type': 'application/json', + }, + httpsAgent, + }) + + const responseResult: PredictionResponse = response.data + const spectra = [] + + for (const result of responseResult.result) { + const name = crypto.randomUUID() + const data = generatePredictedSpectrumData(result.shifts, { + from, + to, + nbPoints, + lineWidth, + frequency, + tolerance, + peakShape, + }) + + const info = { + isFid: false, + isComplex: false, + dimension: 1, + originFrequency: frequency, + baseFrequency: frequency, + pulseSequence: '', + solvent, + isFt: true, + name, + nucleus, + } + + spectra.push({ + id: crypto.randomUUID(), + data, + info, + }) + } + + const nmrium = { data: { spectra }, version: CURRENT_EXPORT_VERSION } + console.log(JSON.stringify(nmrium, null, 2)) + } catch (error) { + console.error( + 'Error:', + error instanceof Error ? error.message : String(error) + ) + + if (axios.isAxiosError(error) && error.response) { + console.error('Response data:', error.response.data) + } else if (error instanceof Error && error.cause) { + console.error('Network Error:', error.cause) + } + } +} + +type PredictionArgs = PredictionParameters & GenerateSpectrumOptions + +// Define the prediction string command +export const parsePredictionCommand: CommandModule<{}, PredictionArgs> = { + command: ['predict', 'p'], + describe: 'Predict NMR spectrum from mol text', + builder: (yargs: Argv<{}>): Argv => { + return yargs.options({ + ...nmrOptions, + ...predictionOptions, + }) as Argv + }, + handler: async argv => { + await predictNMR(argv) + }, +} diff --git a/app/scripts/nmr-cli/src/publication-string.ts b/app/scripts/nmr-cli/src/publication-string.ts new file mode 100644 index 0000000..e8a719a --- /dev/null +++ b/app/scripts/nmr-cli/src/publication-string.ts @@ -0,0 +1,75 @@ +import { + resurrect, + rangesToXY, +} from 'nmr-processing' +import { CURRENT_EXPORT_VERSION } from '@zakodium/nmrium-core' +import { castToArray } from './utilities/castToArray' +import { NMRRange } from '@zakodium/nmr-types' + +interface Info { + nucleus: string + solvent: string + name: string +} + +function generateSpectrumFromRanges( + ranges: NMRRange[], + info: Info +) { + const { nucleus, solvent, name = null } = info + + const frequency = 400 + try { + const { x, y } = rangesToXY(ranges, { + nucleus, + frequency, + nbPoints: 2 ** 17, + }) + + const info = { + isFid: false, + isComplex: false, + dimension: 1, + nucleus, + originFrequency: frequency, + baseFrequency: frequency, + pulseSequence: '', + solvent, + isFt: true, + name, + } + + const spectrum = { + id: crypto.randomUUID(), + data: { x: castToArray(x), im: undefined, re: castToArray(y) }, + info, + ranges: { + values: ranges, + options: { + sum: 100, + isSumConstant: false, + sumAuto: false, + }, + }, + } + + return { data: { spectra: [spectrum] }, version: CURRENT_EXPORT_VERSION } + } catch (error) { + console.log(error) + } +} + +function generateSpectrumFromPublicationString(publicationString: string) { + const { + ranges, + info: { nucleus, solvent = '' }, + parts, + } = resurrect(publicationString) + return generateSpectrumFromRanges(ranges, { + nucleus, + solvent, + name: parts[0], + }) +} + +export { generateSpectrumFromPublicationString } diff --git a/app/scripts/nmr-cli/src/utilities/castToArray.ts b/app/scripts/nmr-cli/src/utilities/castToArray.ts new file mode 100644 index 0000000..bb2482e --- /dev/null +++ b/app/scripts/nmr-cli/src/utilities/castToArray.ts @@ -0,0 +1,3 @@ +export function castToArray(value: Float64Array | number[]): number[] { + return ArrayBuffer.isView(value) ? Array.from(value) : value +} diff --git a/app/scripts/nmr-cli/tsconfig.json b/app/scripts/nmr-cli/tsconfig.json new file mode 100644 index 0000000..45db58d --- /dev/null +++ b/app/scripts/nmr-cli/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "strict": true, + "esModuleInterop": true, + "outDir": "./build", + "skipLibCheck": true + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/docker-compose.yml b/docker-compose.yml index 40ddb3d..30451e3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -28,13 +28,15 @@ services: env_file: - ./.env nmr-load-save: - build: ./app/scripts/nmr-cli + #build: ./app/scripts/nmr-cli + image: nfdi4chem/nmr-cli:dev-latest entrypoint: /bin/sh stdin_open: true tty: true container_name: nmr-converter nmr-respredict: - build: ./app/scripts/nmr-respredict + #build: ./app/scripts/nmr-respredict + image: nfdi4chem/nmr-respredict:dev-latest entrypoint: /bin/sh stdin_open: true tty: true