jcampconverter 9.6.3 → 10.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -3
- package/jcampconverter.cjs +8 -7
- package/jcampconverter.d.ts +156 -196
- package/jcampconverter.mjs +8 -7
- package/package.json +37 -41
package/README.md
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
[![NPM version][npm-image]][npm-url]
|
|
2
2
|
[![build status][ci-image]][ci-url]
|
|
3
|
-
[![Test coverage][codecov-image]][codecov-url]
|
|
4
3
|
[![npm download][download-image]][download-url]
|
|
5
4
|
[](https://doi.org/10.5281/zenodo.5091526)
|
|
6
5
|
|
|
@@ -82,8 +81,6 @@ npm run benchmark
|
|
|
82
81
|
|
|
83
82
|
[npm-image]: https://img.shields.io/npm/v/jcampconverter.svg
|
|
84
83
|
[npm-url]: https://npmjs.org/package/jcampconverter
|
|
85
|
-
[codecov-image]: https://img.shields.io/codecov/c/github/cheminfo/jcampconverter.svg
|
|
86
|
-
[codecov-url]: https://codecov.io/gh/cheminfo/jcampconverter
|
|
87
84
|
[ci-image]: https://github.com/cheminfo/jcampconverter/workflows/Node.js%20CI/badge.svg?branch=main
|
|
88
85
|
[ci-url]: https://github.com/cheminfo/jcampconverter/actions?query=workflow%3A%22Node.js+CI%22
|
|
89
86
|
[download-image]: https://img.shields.io/npm/dm/jcampconverter.svg
|
package/jcampconverter.cjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`),jcamp:`${
|
|
3
|
-
`,children:[]}),
|
|
4
|
-
`;let
|
|
5
|
-
`;let f=u.match(/^##(.*?)=(.+)/);if(f){let m=f[1].replace(/[ _-]/g,"").toUpperCase();m==="DATATYPE"?t.dataType=f[2].trim():m==="DATACLASS"?t.dataClass=f[2].trim():m==="JCAMPDX"?t.jcampDX=M(f[2].trim()):m==="JCAMPCS"&&(t.jcampCS=M(f[2].trim()))}}u.substring(0,5)==="##END"&&o>0&&o--}return s?(n.forEach(c=>{c.children=void 0}),n):r}var me=require("dynamic-typing"),ce=require("ensure-string");var U=["TIC",".RIC","SCANNUMBER"];function oe(e){let i=e.spectra,s=i.length,a={times:new Array(s),series:{ms:{dimension:2,data:new Array(s)}}},n=[];for(let l=0;l<U.length;l++){let r=V(U[l]);i[0][r]&&(n.push(r),a.series[r]={dimension:1,data:new Array(s)})}for(let l=0;l<s;l++){let r=i[l];a.times[l]=r.pageValue;for(let t=0;t<n.length;t++)a.series[n[t]].data[l]=Number(r[n[t]]);r.data&&(a.series.ms.data[l]=[r.data.x,r.data.y])}e.chromatogram=a}function fe(e){return U.indexOf(e)!==-1}function V(e){return e.toLowerCase().replace(/[^a-z0-9]/g,"")}function Y(e){let i=[];for(let s=0;s<e.length;s++)i.push(Number(e[s]));return i}function B(e,i){let s=e.yFactor,a=e.deltaX;e.isXYdata=!0;let n={x:[],y:[]};e.data=n;let l=e.firstX,r=e.firstY,t=!1,o,p=0;for(;p<i.length;p++)if(o=i.charCodeAt(p),o===13||o===10)t=!0;else if(t)break;let c=!0,d=!1,u=!1,f=0,m=!1,h=!1,g=0,A=0,N=!1,y=!1,C=!1,T=0;for(;p<=i.length;p++)if(p===i.length?o=13:o=i.charCodeAt(p),h)(o===13||o===10)&&(c=!0,h=!1);else if(o<=57&&o>=48)y=!0,T>0?g+=(o-48)/10**T++:(g*=10,g+=o-48);else if(o===44||o===46)y=!0,T++;else{if(y){if(c)c=!1,u&&(C=!0);else if(C)C=!1;else{d?(f=N?0-g:g,u=!0,d=!1):m||(A=N?0-g:g);let O=m?g-1:1;for(let v=0;v<O;v++)u?r+=f:r=A,n.x.push(l),n.y.push(r*s),l+=a}N=!1,g=0,T=0,y=!1,m=!1}if(o<74&&o>63)y=!0,u=!1,g=o-64;else if(o>96&&o<106)y=!0,u=!1,g=o-96,N=!0;else if(o===115)y=!0,m=!0,g=9;else if(o>82&&o<91)y=!0,m=!0,g=o-82;else if(o>73&&o<83)y=!0,d=!0,g=o-73;else if(o>105&&o<115)y=!0,d=!0,g=o-105,N=!0;else if(o===36&&i.charCodeAt(p+1)===36)y=!0,h=!0;else if(o===37)y=!0,d=!0,g=0,N=!1;else if(o===45){let O=i.charCodeAt(p+1);(O>=48&&O<=57||O===44||O===46)&&(y=!0,c||(u=!1),N=!0)}else(o===13||o===10)&&(c=!0,h=!1)}}var ue=/[,\t ]+/;function w(e,i,s){if(e.isPeaktable=!0,!e.variables||Object.keys(e.variables)===2?ve(e,i,s):Fe(e,i,s),e.variables)for(let a in e.variables)e.variables[a].data=e.data[a]}function ve(e,i,s){let a={x:[],y:[]};e.data=a;let n=i.split(/,? *,?[;\r\n]+ */);for(let l=1;l<n.length;l++){let r=n[l].trim().replace(D,"").split(ue);if(r.length%2===0)for(let t=0;t<r.length;t=t+2)a.x.push(Number(r[t])*e.xFactor),a.y.push(Number(r[t+1])*e.yFactor);else s.logs.push(`Format error: ${r}`)}}function Fe(e,i,s){let a={},n=Object.keys(e.variables),l=n.length;n.forEach(t=>a[t]=[]),e.data=a;let r=i.split(/,? *,?[;\r\n]+ */);for(let t=1;t<r.length;t++){let o=r[t].trim().replace(D,"").split(ue);if(o.length%l===0)for(let p=0;p<o.length;p++)a[n[p%l]].push(Number(o[p]));else s.logs.push(`Wrong number of columns: ${o}`)}}function k(e,i){e.isXYAdata=!0;let s={};e.data=s;let a=i.split(/\r?\n/),n=a[0].replace(/^.*?([A-Z]+).*$/,"$1").split("").map(l=>l.toLowerCase());for(let l=1;l<a.length;l++){let r=a[l].replace(/^\((.*)\)$/,"$1").split(/ *, */);for(let t=0;t<n.length;t++){let o=r[t];switch(n[t]){case"x":case"y":case"w":o=Number.parseFloat(o);break;case"a":o=o.replace(/^<(.*)>$/,"$1");break;case"m":break;default:continue}s[n[t]]||(s[n[t]]=[]),s[n[t]].push(o)}}}var Q=require("dynamic-typing");var j=require("gyromagnetic-ratio"),Z=Ce(require("ml-array-median"));function pe(e){return Array.isArray(e)?e[0]:e}function J(e){let{spectra:i}=e,s=i[0].data.y[0],a=s,n=i.length,l=i[0].data.x.length,r=new Array(n);for(let f=0;f<n;f++){r[f]=i[f].data.y;for(let m=0;m<l;m++){let h=r[f][m];h<s&&(s=h),h>a&&(a=h)}}let t=i[0].data.x[0],o=i[0].data.x[i[0].data.x.length-1],{firstY:p,lastY:c}=Me(e);if(t>o)for(let f of r)f.reverse();p>c&&r.reverse();let d=[];for(let f=0;f<r.length;f++){let m=Float64Array.from(r[f]);for(let h=0;h<m.length;h++)m[h]<0&&(m[h]=-m[h]);d.push((0,Z.default)(m))}let u=(0,Z.default)(d);return{z:r,minX:Math.min(t,o),maxX:Math.max(t,o),minY:Math.min(p,c),maxY:Math.max(p,c),minZ:s,maxZ:a,noise:u}}function Me(e){let{spectra:i,ntuples:s,info:a}=e;if(s)for(let n=0;n<s.length;n++){let{symbol:l,nucleus:r}=s[n];if(l.match(/[F|T]1/)){let t=pe(a[".OBSERVEFREQUENCY"]),{nucleus:o}=s.find(m=>m.symbol.match(/[F|T]2/));if([t,o,r].some(m=>!m))break;let p=(0,j.getGyromagneticRatio)(o),c=(0,j.getGyromagneticRatio)(r),{first:d,last:u}=s[n],f=t*c/p;return{firstY:d/f,lastY:u/f}}}return{firstY:i[0].pageValue,lastY:i[i.length-1].pageValue}}function G(e,i){let s=e.noise,a=e.z,n,l,r,t,o,p,c,d,u=a.length,f=a[0].length,m,h,g,A,N=e.minX,C=(e.maxX-N)/(f-1),T=e.minY,v=(e.maxY-T)/(u-1),ge=e.minZ,z=e.maxZ,ee=i.nbContourLevels*2,te=new Array(ee),x;for(let R=0;R<ee;R++){let I={};te[R]=I;let be=R%2,le=(z-i.noiseMultiplier*s)*Math.exp((R>>1)-i.nbContourLevels);be===0?x=le+i.noiseMultiplier*s:x=0-le-i.noiseMultiplier*s;let b=[];if(I.zValue=x,I.lines=b,!(x<=ge||x>=z))for(let X=0;X<u-1;X++){let se=a[X],ie=a[X+1];for(let S=0;S<f-1;S++)n=se[S],l=se[S+1],r=ie[S],t=ie[S+1],o=n>x,p=l>x,c=r>x,d=t>x,o!==p&&o!==c&&(m=S+(x-n)/(l-n),h=X,g=S,A=X+(x-n)/(r-n),b.push(m*C+N),b.push(h*v+T),b.push(g*C+N),b.push(A*v+T)),d!==p&&d!==c&&(m=S+1,h=X+1-(x-t)/(l-t),g=S+1-(x-t)/(r-t),A=X+1,b.push(m*C+N),b.push(h*v+T),b.push(g*C+N),b.push(A*v+T)),p!==c&&(m=(S+1-(x-l)/(r-l))*C+N,h=(X+(x-l)/(r-l))*v+T,p!==o&&(g=S+1-(x-l)/(n-l),A=X,b.push(m),b.push(h),b.push(g*C+N),b.push(A*v+T)),c!==o&&(g=S,A=X+1-(x-r)/(n-r),b.push(m),b.push(h),b.push(g*C+N),b.push(A*v+T)),p!==d&&(g=S+1,A=X+(x-l)/(t-l),b.push(m),b.push(h),b.push(g*C+N),b.push(A*v+T)),c!==d&&(g=S+(x-r)/(t-r),A=X+1,b.push(m),b.push(h),b.push(g*C+N),b.push(A*v+T)))}}return{minX:e.minX,maxX:e.maxX,minY:e.minY,maxY:e.maxY,segments:te}}function H(e,i){let s=J(e);i.noContour||(e.contourLines=G(s,i),delete s.z),e.minMax=s}var $=require("gyromagnetic-ratio");function q(e,i){for(let s of e){let a=0,n=0;for(let l of s.spectra){if(s.ntuples&&s.ntuples.symbol?(!a&&l.observeFrequency&&(a=l.observeFrequency),!n&&l.shiftOffsetVal&&(n=l.shiftOffsetVal)):(a=l.observeFrequency,n=l.shiftOffsetVal),a&&l.xUnits&&l.xUnits.toUpperCase().includes("HZ")){l.xUnits="PPM",l.xFactor=l.xFactor/a,l.firstX=l.firstX/a,l.lastX=l.lastX/a,l.deltaX=l.deltaX/a;for(let r=0;r<l.data.x.length;r++)l.data.x[r]/=a}if(n&&l.xUnits.toLowerCase().includes("ppm")){let r=l.firstX-n;l.firstX=l.firstX-r,l.lastX=l.lastX-r;for(let t=0;t<l.data.x.length;t++)l.data.x[t]-=r}if(s.ntuples&&s.ntuples.nucleus&&s.ntuples.symbol)for(let r=0;r<s.ntuples.nucleus.length;r++){let t=s.ntuples.symbol[r],o=s.ntuples.nucleus[r];if(t.match(/^[F|T]/)&&!o){if(t.match(/[F|T]1/))if(s.tmp.$NUC2)s.ntuples.nucleus[r]=s.tmp.$NUC2;else{let p=s.ntuples.symbol.indexOf(t.replace(/^([F|T]).*/,"$12"));p&&s.ntuples.nucleus[p]&&(s.ntuples.nucleus[r]=s.ntuples.nucleus[p])}t.match(/[F|T]2/)&&(s.ntuples.nucleus[r]=s.tmp.$NUC1)}t.match(/[F|T]2/)&&(s.yType=s.ntuples.nucleus[0],(0,$.getGyromagneticRatio)(s.xType)||(s.xType=s.ntuples.nucleus[1]))}if(a&&s.ntuples&&s.ntuples.symbol&&s.ntuples.nucleus){let r="",t=s.ntuples.symbol.indexOf(l.pageSymbol);if(s.ntuples.units&&s.ntuples.units[t]&&(r=s.ntuples.units[t]),!r.toLowerCase().match(/(ppm|seconds)/)){if(t!==0){let u="Not sure about this ntuples format";if(i)i.warn(u);else throw Error(u)}let{nucleus:o}=s.ntuples,p=(0,$.getGyromagneticRatio)(o[0]),c=(0,$.getGyromagneticRatio)(o[1]);if(!p||!c){let u=`Problem with determination of gyromagnetic ratio for ${o.join("-")}`;if(i)i.error(u);else throw Error(u)}let d=p/c*a;l.pageValue/=d}}}}}function L(e,i,s={}){s.logger?.trace(i),e.profiling&&e.profiling.push({action:i,time:Date.now()-s.start})}function K(e){let i=e.spectra[0].data;e.chromatogram={times:i.x.slice(),series:{intensity:{dimension:1,data:i.y.slice()}}}}function W(e,i,s){q(e,s.logger),Le(e,s);for(let a of e){if(Object.keys(a.ntuples).length>0){let n=[],l=Object.keys(a.ntuples);for(let r=0;r<l.length;r++){let t=l[r],o=a.ntuples[t];for(let p=0;p<o.length;p++)n[p]||(n[p]={}),n[p][t]=o[p]}a.ntuples=n}a.twoD&&s.wantXY&&(H(a,s),L(i,"Finished countour plot calculation",s),s.keepSpectra||delete a.spectra),s.chromatogram&&(a.spectra.length>1?oe(a):K(a),L(i,"Finished chromatogram calculation",s)),delete a.tmp}}function Le(e,i){for(let s of e)for(let a in s.meta){let n=s.meta[a];if(typeof n=="string"){if(n[0]==="{"){if(!n.includes(":")&&n[n.length-1]==="}"){let l=n.slice(1,-1).split(/[,; ]+/).filter(r=>r);for(let r=0;r<l.length;r++)s.meta[a+String(r)]=i.dynamicTyping?(0,Q.parseString)(l[r]):l[r]}}else if(n[0]==="("){let l=n.split(/\r?\n/),r=/^\((?<from>\d+)\.\.(?<to>\d+)\).*$/;if(r.test(l[0])){let[t,o]=l[0].match(r).slice(1).map(Number),p=l.slice(1).join(" ").split(/[,; ]+/).filter(c=>c);for(let c=t;c<=o;c++)i.dynamicTyping&&typeof p[c-t]=="string"?s.meta[a+String(c)]=(0,Q.parseString)(p[c-t]):s.meta[a+String(c)]=p[c-t]}}}}}function _(e,i,s){let a=-1,n=-1,l="",r="";if(s.indexOf("++")>0)l=s.replace(/.*\(([a-zA-Z0-9]+)\+\+.*/,"$1"),r=s.replace(/.*\.\.([a-zA-Z0-9]+).*/,"$1");else{s=s.replace(/[^a-zA-Z%]/g,""),l=s.charAt(0),r=s.charAt(1),i.variables={};for(let t of s){let o=t.toLowerCase(),p=e.ntuples.symbol.indexOf(t);if(p===-1)throw Error(`Symbol undefined: ${t}`);i.variables[o]={};for(let c in e.ntuples)e.ntuples[c][p]&&(i.variables[o][c.replace(/^var/,"")]=e.ntuples[c][p])}}a=e.ntuples.symbol.indexOf(l),n=e.ntuples.symbol.indexOf(r),a===-1&&(a=0),n===-1&&(n=0),e.ntuples.first&&(e.ntuples.first.length>a&&(i.firstX=e.ntuples.first[a]),e.ntuples.first.length>n&&(i.firstY=e.ntuples.first[n])),e.ntuples.last&&(e.ntuples.last.length>a&&(i.lastX=e.ntuples.last[a]),e.ntuples.last.length>n&&(i.lastY=e.ntuples.last[n])),e.ntuples.vardim&&e.ntuples.vardim.length>a&&(i.nbPoints=e.ntuples.vardim[a]),e.ntuples.factor&&(e.ntuples.factor.length>a&&(i.xFactor=e.ntuples.factor[a]),e.ntuples.factor.length>n&&(i.yFactor=e.ntuples.factor[n])),e.ntuples.units&&(e.ntuples.units.length>a&&(e.ntuples.varname&&e.ntuples.varname[a]?i.xUnits=`${e.ntuples.varname[a]} [${e.ntuples.units[a]}]`:i.xUnits=e.ntuples.units[a]),e.ntuples.units.length>n&&(e.ntuples.varname&&e.ntuples.varname[n]?i.yUnits=`${e.ntuples.varname[n]} [${e.ntuples.units[n]}]`:i.yUnits=e.ntuples.units[n]))}function E(e){e.xFactor||(e.xFactor=1),e.yFactor||(e.yFactor=1)}var F=/[ \t]*,[ \t]*/,Ye={keepRecordsRegExp:/^$/,canonicDataLabels:!0,canonicMetadataLabels:!1,dynamicTyping:!0,withoutXY:!1,noTrimRegExp:/^$/,chromatogram:!1,keepSpectra:!1,noContour:!1,nbContourLevels:7,noiseMultiplier:5,profiling:!1};function he(e,i={}){e=(0,ce.ensureString)(e),i={...Ye,...i},i.logger?.debug("Starting jcamp conversion"),i.wantXY=!i.withoutXY,i.start=Date.now();let s=[],a={profiling:i.profiling?[]:!1,logs:[],entries:[]},n={children:[]},l=n,r=[],t={};if(typeof e!="string")throw new TypeError("the JCAMP should be a string");L(a,"Before split to LDRS",i);let o=e.replace(/[\r\n]+##/g,`
|
|
1
|
+
"use strict";var he=Object.create;var $=Object.defineProperty;var xe=Object.getOwnPropertyDescriptor;var ye=Object.getOwnPropertyNames;var Ae=Object.getPrototypeOf,Se=Object.prototype.hasOwnProperty;var Ne=(e,f)=>{for(var t in f)$(e,t,{get:f[t],enumerable:!0})},se=(e,f,t,i)=>{if(f&&typeof f=="object"||typeof f=="function")for(let a of ye(f))!Se.call(e,a)&&a!==t&&$(e,a,{get:()=>f[a],enumerable:!(i=xe(f,a))||i.enumerable});return e};var Ce=(e,f,t)=>(t=e!=null?he(Ae(e)):{},se(f||!e||!e.__esModule?$(t,"default",{value:e,enumerable:!0}):t,e)),Te=e=>se($({},"__esModule",{value:!0}),e);var $e={};Ne($e,{convert:()=>de,createTree:()=>oe,parseJcampCS:()=>be});module.exports=Te($e);var ie=require("ensure-string");var P=/\s*\$\$.*/;function O(e){return e.replace(P,"")}function oe(e,f={}){e=(0,ie.ensureString)(e);let{flatten:t=!1}=f,i=e.split(/\r?\n/),a=[],o=[],n=[],m={title:"",jcamp:"",children:[]},r=0,p=e.includes("## ");for(let u=0;u<i.length;u++){let b=i[u],h=p?b.replaceAll(" ",""):b;if(h.startsWith("##NTUPLES")&&r++,h.startsWith("##TITLE")){let s=[h.slice(8).trim()];for(let l=u+1;l<i.length&&!i[l].startsWith("##");l++)s.push(i[l].trim());o.push({title:s.join(`
|
|
2
|
+
`),jcamp:`${b}
|
|
3
|
+
`,children:[]}),m=o.at(-1),a.push(m)}else if(h.startsWith("##END")&&r===0&&m){m.jcamp+=`${b}
|
|
4
|
+
`;let s=o.pop();if(!s)throw new Error("Not finished");o.length>0?(m=o.at(-1),m.children?.push(s)):(m=void 0,n.push(s))}else if(m?.jcamp){m.jcamp+=`${b}
|
|
5
|
+
`;let s=h.match(/^##(.*?)=(.+)/);if(s){let l=s[1].replaceAll(/[ _-]/g,"").toUpperCase();l==="DATATYPE"?m.dataType=s[2].trim():l==="DATACLASS"?m.dataClass=s[2].trim():l==="JCAMPDX"?m.jcampDX=O(s[2].trim()):l==="JCAMPCS"&&(m.jcampCS=O(s[2].trim()))}}h.startsWith("##END")&&r>0&&r--}if(t){for(let u of a)u.children=void 0;return a}else return n}var ce=require("dynamic-typing"),pe=require("ensure-string");var ae=["TIC",".RIC","SCANNUMBER"];function le(e){let f=e.spectra,t=f.length,i={times:new Array(t),series:{ms:{dimension:2,data:new Array(t)}}},a=[];for(let o of ae){let n=B(o);f[0][n]&&(a.push(n),i.series[n]={dimension:1,data:new Array(t)})}for(let o=0;o<t;o++){let n=f[o];i.times[o]=n.pageValue;for(let m of a)i.series[m].data[o]=Number(n[m]);n.data&&(i.series.ms.data[o]=[n.data.x,n.data.y])}e.chromatogram=i}function fe(e){return ae.includes(e)}function B(e){return e.toLowerCase().replaceAll(/[^a-z0-9]/g,"")}function E(e){return e.map(Number)}function j(e,f,t){let{logger:i}=t;i&&(e.xFactor||i.info("The xFactor is not defined, it will be set to 1"),e.yFactor||i.info("The yFactor is not defined, it will be set to 1"));let a=e.yFactor??1,o=e.xFactor??1,n=e.deltaX??1,m=Math.abs(n*.1),r=.01;e.isXYdata=!0;let p={x:[],y:[]};e.data=p;let u=e.firstX||0,b=e.firstY||0,h=!1,s,l=0;for(;l<f.length;l++)if(s=f.codePointAt(l),s===13||s===10)h=!0;else if(h)break;let c=0,d=!0,A=!1,y=!1,k=0,N=!1,C=!1,g=0,X=0,M=!1,S=!1,Y=!1,R=0;for(;l<=f.length;l++)if(l===f.length?s=13:s=f.codePointAt(l),C)(s===13||s===10)&&(d=!0,C=!1,c++);else if(s<=57&&s>=48)S=!0,R>0?g+=(s-48)/10**R++:(g*=10,g+=s-48);else if(s===44||s===46)S=!0,R++;else{if(S){if(M&&(g=g*-1,M=!1),d)g*=o,i&&(y?Math.abs(u-n-g)>m&&(Math.abs(u-g)<m?i.trace(`Data line ${c}: After a DIFFERENCE the next line should repeat the last value and this does not seem to be the case: Current value: ${g} - Expected: ${u}.`):Math.abs(u-n-g)>10*m?i.trace(`Data line ${c}: The difference between the first value ${g} and the expected first x value ${u} based on increment after a DIFFERENCE is too high`):i.trace(`Data line ${c}: The difference between the first value ${g} and the expected first x value ${u} based on increment after a DIFFERENCE is too high`)):Math.abs(u-g)>m&&i.trace(`Data line ${c}: The difference between the first value ${g} and the first x value ${u} is too high`)),d=!1,y&&(Y=!0);else if(Y)Y=!1,i&&Math.abs(b-g)>r&&i.trace(`Data line ${c}: After a duplicate the next line should repeat the same value ${g} !== ${b}`),b=g;else{A?(k=M?0-g:g,y=!0,A=!1):N||(X=M?0-g:g);let x=N?g-1:1;for(let F=0;F<x;F++)y?b+=k:b=X,p.x.push(u),p.y.push(b*a),u+=n}M=!1,g=0,R=0,S=!1,N=!1}if(s<74&&s>63)S=!0,y=!1,g=s-64;else if(s>96&&s<106)S=!0,y=!1,g=s-96,M=!0;else if(s===115)S=!0,N=!0,g=9;else if(s>82&&s<91)S=!0,N=!0,g=s-82;else if(s>73&&s<83)S=!0,A=!0,g=s-73;else if(s>105&&s<115)S=!0,A=!0,g=s-105,M=!0;else if(s===36&&f.codePointAt(l+1)===36)S=!0,C=!0;else if(s===37)S=!0,A=!0,g=0,M=!1;else if(s===45){let x=f.codePointAt(l+1);(x!==void 0&&x>=48&&x<=57||x===44||x===46)&&(S=!0,d||(y=!1),M=!0)}else(s===13||s===10)&&(d=!0,C=!1,c++)}i&&y&&i.warn("The last value is a difference, it should be repeated on the next line")}var me=/[,\t ]+/;function w(e,f,t){if(e.isPeaktable=!0,!e.variables||Object.keys(e.variables).length===2?ve(e,f,t):Xe(e,f,t),e.variables)for(let i in e.variables)e.variables[i].data=e.data?.[i]}function ve(e,f,t){let{logger:i}=t,a={x:[],y:[]};e.data=a;let o=f.split(/,? *,?[;\r\n]+ */);for(let n=1;n<o.length;n++){let m=o[n].trim().replace(P,"").split(me);if(m.length%2===0)for(let r=0;r<m.length;r=r+2)e.xFactor!==void 0&&e.yFactor!==void 0&&(a.x.push(Number(m[r])*e.xFactor),a.y.push(Number(m[r+1])*e.yFactor));else i?.warn(`Format error: ${m.toString()}`)}}function Xe(e,f,t){let{logger:i}=t,a={},o=Object.keys(e.variables),n=o.length;for(let r of o)a[r]=[];e.data=a;let m=f.split(/,? *,?[;\r\n]+ */);for(let r=1;r<m.length;r++){let p=m[r].trim().replace(P,"").split(me);if(p.length%n===0)for(let u=0;u<p.length;u++)a[o[u%n]].push(Number(p[u]));else i?.warn(`Wrong number of columns: ${p.toString()}`)}}function Z(e,f){e.isXYAdata=!0;let t={};e.data=t;let i=f.split(/\r?\n/),a=i[0].replace(/^.*?([A-Z]+).*$/,"$1").split("").map(o=>o.toLowerCase());for(let o=1;o<i.length;o++){let n=i[o].replace(/^\((.*)\)$/,"$1").split(/ *, */);for(let m=0;m<a.length;m++){let r=n[m];switch(a[m]){case"x":case"y":case"w":r=Number.parseFloat(r);break;case"a":r=r.replace(/^<(.*)>$/,"$1");break;case"m":break;default:continue}t[a[m]]||(t[a[m]]=[]),t[a[m]].push(r)}}}var Q=require("dynamic-typing");var G=require("gyromagnetic-ratio"),W=Ce(require("ml-array-median"));function ue(e){return Array.isArray(e)?e[0]:e}function H(e){let{spectra:f}=e,t=f[0].data.y[0],i=t,a=f.length,o=f[0].data.x.length||0,n=new Array(a);for(let s=0;s<a;s++){n[s]=f[s].data.y;for(let l=0;l<o;l++){let c=n[s][l];c<t&&(t=c),c>i&&(i=c)}}let m=f[0].data.x[0],r=f[0].data.x.at(-1),{firstY:p,lastY:u}=Le(e);if(m>r)for(let s of n)s.reverse();p>u&&n.reverse();let b=[];for(let s of n){let l=Float64Array.from(s);for(let c=0;c<l.length;c++)l[c]<0&&(l[c]=-l[c]);b.push((0,W.default)(l))}let h=(0,W.default)(b);return{z:n,minX:Math.min(m,r),maxX:Math.max(m,r),minY:Math.min(p,u),maxY:Math.max(p,u),minZ:t,maxZ:i,noise:h}}function Le(e){let{spectra:f,ntuples:t,info:i}=e;if(t)for(let a of t){let{symbol:o,nucleus:n,units:m}=a;if(o.match(/[F|T]1/)&&m?.toUpperCase().match("HZ")){let r=ue(i[".OBSERVEFREQUENCY"]),{nucleus:p}=t.find(c=>c.symbol.match(/[F|T]2/));if([r,p,n].some(c=>!c))break;let u=(0,G.getGyromagneticRatio)(p),b=(0,G.getGyromagneticRatio)(n),{first:h,last:s}=a,l=b!==null&&u!==null?r*b/u:r;return{firstY:h/l,lastY:s/l}}}return{firstY:f[0].pageValue,lastY:f.at(-1).pageValue}}function J(e,f){let t=e.noise,i=e.z,a,o,n,m,r,p,u,b,h=i.length,s=i[0].length,l,c,d,A,y=e.minX,N=(e.maxX-y)/(s-1),C=e.minY,X=(e.maxY-C)/(h-1),M=e.minZ,S=e.maxZ,Y=f.nbContourLevels*2,R=new Array(Y),x;for(let F=0;F<Y;F++){let V={};R[F]=V;let ge=F%2,te=(S-f.noiseMultiplier*t)*Math.exp((F>>1)-f.nbContourLevels);ge===0?x=te+f.noiseMultiplier*t:x=0-te-f.noiseMultiplier*t;let D=[];if(V.zValue=x,V.lines=D,!(x<=M||x>=S))for(let v=0;v<h-1;v++){let ne=i[v],re=i[v+1];for(let T=0;T<s-1;T++)a=ne[T],o=ne[T+1],n=re[T],m=re[T+1],r=a>x,p=o>x,u=n>x,b=m>x,r!==p&&r!==u&&(l=T+(x-a)/(o-a),c=v,d=T,A=v+(x-a)/(n-a),D.push(l*N+y,c*X+C,d*N+y,A*X+C)),b!==p&&b!==u&&(l=T+1,c=v+1-(x-m)/(o-m),d=T+1-(x-m)/(n-m),A=v+1,D.push(l*N+y,c*X+C,d*N+y,A*X+C)),p!==u&&(l=(T+1-(x-o)/(n-o))*N+y,c=(v+(x-o)/(n-o))*X+C,p!==r&&(d=T+1-(x-o)/(a-o),A=v,D.push(l,c,d*N+y,A*X+C)),u!==r&&(d=T,A=v+1-(x-n)/(a-n),D.push(l,c,d*N+y,A*X+C)),p!==b&&(d=T+1,A=v+(x-o)/(m-o),D.push(l,c,d*N+y,A*X+C)),u!==b&&(d=T+(x-n)/(m-n),A=v+1,D.push(l,c,d*N+y,A*X+C)))}}return{minX:e.minX,maxX:e.maxX,minY:e.minY,maxY:e.maxY,segments:R}}function q(e,f){let t=H(e);f.noContour||(e.contourLines=J(t,f),delete t.z),e.minMax=t}var I=require("gyromagnetic-ratio");function z(e,f){for(let t of e){let i=0,a=0;for(let o of t.spectra){if(t.ntuples?.symbol?(!i&&o.observeFrequency&&(i=o.observeFrequency),!a&&o.shiftOffsetVal&&(a=o.shiftOffsetVal)):(i=o.observeFrequency,a=o.shiftOffsetVal),i&&o.xUnits?.toUpperCase().includes("HZ")&&(o.xUnits="PPM",o.xFactor=o.xFactor!==void 0?o.xFactor/i:void 0,o.firstX=o.firstX!==void 0?o.firstX/i:void 0,o.lastX=o.lastX!==void 0?o.lastX/i:void 0,o.deltaX=o.deltaX!==void 0?o.deltaX/i:void 0,o.data))for(let n=0;n<o.data.x.length;n++)o.data.x[n]/=i;if(a&&o.xUnits.toLowerCase().includes("ppm")&&o.firstX!==void 0&&o.lastX!==void 0){let n=o.firstX-a;if(o.firstX=o.firstX-n,o.lastX=o.lastX-n,o.data)for(let m=0;m<o.data.x.length;m++)o.data.x[m]-=n}if(t.ntuples?.nucleus&&t.ntuples.symbol)for(let n=0;n<t.ntuples.nucleus.length;n++){let m=t.ntuples.symbol[n],r=t.ntuples.nucleus[n];if(m.match(/^[F|T]/)&&!r){if(m.match(/[F|T]1/))if(t.tmp.$NUC2&&typeof t.tmp.$NUC2=="string")t.ntuples.nucleus[n]=t.tmp.$NUC2;else{let p=t.ntuples.symbol.indexOf(m.replace(/^([F|T]).*/,"$12"));p&&t.ntuples.nucleus[p]&&(t.ntuples.nucleus[n]=t.ntuples.nucleus[p])}m.match(/[F|T]2/)&&typeof t.tmp.$NUC1=="string"&&(t.ntuples.nucleus[n]=t.tmp.$NUC1)}m.match(/[F|T]2/)&&(t.yType=t.ntuples.nucleus[0],t.xType&&!(0,I.getGyromagneticRatio)(t.xType)&&(t.xType=t.ntuples.nucleus[1]))}if(i&&t.ntuples?.symbol&&t.ntuples.nucleus){let n="",m=t.ntuples.symbol.indexOf(o.pageSymbol);t.ntuples.units?.[m]&&(n=t.ntuples.units[m]);let{nucleus:r}=t.ntuples;if(!n.toLowerCase().match(/(ppm|seconds)/)&&r.length>1){if(m!==0){let h="Not sure about this ntuples format";if(f){f.warn(h);continue}else throw new Error(h)}let{nucleus:p}=t.ntuples,u=(0,I.getGyromagneticRatio)(p[0]),b=(0,I.getGyromagneticRatio)(p[1]);if(!u||!b){let h=`Problem with determination of gyromagnetic ratio for ${p.join("-")}`;if(f)f.error(h);else throw new Error(h)}else{let h=u/b*i;o.pageValue/=h}}}}}}function K(e){let f=e.spectra[0].data;e.chromatogram={times:f.x.slice(),series:{intensity:{dimension:1,data:f.y.slice()}}}}function _(e,f,t){z(e,t.logger),Me(e,t);for(let i of e){if(Object.keys(i.ntuples).length>0){let a=[],o=Object.keys(i.ntuples);for(let n of o){let m=i.ntuples[n];if(m)for(let r=0;r<m.length;r++)a[r]||(a[r]={}),a[r][n]=m[r]}i.ntuples=a}i.twoD&&t.wantXY&&(q(i,t),t.logger?.trace({profiling:!0},"Finished countour plot calculation"),t.keepSpectra||delete i.spectra),t.chromatogram&&(i.spectra.length>1?le(i):K(i),t.logger?.trace({profiling:!0},"Finished chromatogram calculation")),delete i.tmp}}function Me(e,f){for(let t of e)for(let i in t.meta){let a=t.meta[i];if(typeof a=="string"){if(a.startsWith("{")){if(!a.includes(":")&&a.endsWith("}")){let o=a.slice(1,-1).split(/[,; ]+/).filter(Boolean);for(let n=0;n<o.length;n++)t.meta[i+String(n)]=f.dynamicTyping?(0,Q.parseString)(o[n]):o[n]}}else if(a.startsWith("(")){let o=a.split(/\r?\n/),n=/^\((?<from>\d+)\.\.(?<to>\d+)\).*$/;if(n.test(o[0])){let[m,r]=o[0].match(n)?.slice(1).map(Number)??[],p=o.slice(1).join(" ").split(/[,; ]+/).filter(Boolean);for(let u=m;u<=r;u++)f.dynamicTyping&&typeof p[u-m]=="string"?t.meta[i+String(u)]=(0,Q.parseString)(p[u-m]):t.meta[i+String(u)]=p[u-m]}}}}}function ee(e,f,t){let i=-1,a=-1,o="",n="";if(t.indexOf("++")>0)o=t.replace(/.*\(([a-zA-Z0-9]+)\+\+.*/,"$1"),n=t.replace(/.*\.\.([a-zA-Z0-9]+).*/,"$1");else{t=t.replaceAll(/[^a-zA-Z%]/g,""),o=t.charAt(0),n=t.charAt(1),f.variables={};for(let m of t){let r=m.toLowerCase(),p=e.ntuples.symbol?.indexOf(m)||0;if(p===-1)throw new Error(`Symbol undefined: ${m}`);f.variables[r]={};for(let u in e.ntuples)e.ntuples[u]?.[p]&&(f.variables[r][u.replace(/^var/,"")]=e.ntuples[u]?.[p])}}i=e.ntuples.symbol?.indexOf(o)??-1,a=e.ntuples.symbol?.indexOf(n)??-1,i===-1&&(i=0),a===-1&&(a=0),e.ntuples.first&&(e.ntuples.first.length>i&&(f.firstX=e.ntuples.first[i]),e.ntuples.first.length>a&&(f.firstY=e.ntuples.first[a])),e.ntuples.last&&(e.ntuples.last.length>i&&(f.lastX=e.ntuples.last[i]),e.ntuples.last.length>a&&(f.lastY=e.ntuples.last[a])),e.ntuples.vardim&&e.ntuples.vardim.length>i&&(f.nbPoints=e.ntuples.vardim[i]),e.ntuples.factor&&(e.ntuples.factor.length>i&&(f.xFactor=e.ntuples.factor[i]),e.ntuples.factor.length>a&&(f.yFactor=e.ntuples.factor[a])),e.ntuples.units&&(e.ntuples.units.length>i&&(e.ntuples.varname?.[i]?f.xUnits=`${e.ntuples.varname[i]} [${e.ntuples.units[i]}]`:f.xUnits=e.ntuples.units[i]),e.ntuples.units.length>a&&(e.ntuples.varname?.[a]?f.yUnits=`${e.ntuples.varname[a]} [${e.ntuples.units[a]}]`:f.yUnits=e.ntuples.units[a]))}function U(e){e.xFactor||(e.xFactor=1),e.yFactor||(e.yFactor=1)}var L=/[ \t]*,[ \t]*/,Oe={keepRecordsRegExp:/^$/,canonicDataLabels:!0,canonicMetadataLabels:!1,dynamicTyping:!0,withoutXY:!1,noTrimRegExp:/^$/,chromatogram:!1,keepSpectra:!1,noContour:!1,nbContourLevels:7,noiseMultiplier:5};function de(e,f={}){e=(0,pe.ensureString)(e);let t={...Oe,...f};t.logger?.debug("Starting jcamp conversion"),t.wantXY=!t.withoutXY,t.start=Date.now();let i=[],a={entries:[],flatten:[]},o={children:[],spectra:[],ntuples:{},info:{},meta:{},tmp:{}},n=o,m=[],r={data:{}};t.logger?.trace({profiling:!0},"Before split to LDRS");let p=e.replaceAll(/[\r\n]+##/g,`
|
|
6
6
|
##`).split(`
|
|
7
|
-
##`);
|
|
8
|
-
`);if(
|
|
7
|
+
##`);t.logger?.trace({profiling:!0},"Split to LDRS"),p[0]&&(p[0]=p[0].replace(/^[\r\n ]*##/,""));for(let u of p){let b=u.indexOf("="),h=b>0?u.slice(0,Math.max(0,b)):u,s=b>0?h.match(t.noTrimRegExp)?u.slice(Math.max(0,b+1)):u.slice(Math.max(0,b+1)).trim():"",l=h.replaceAll(/[_ -]/g,"").toUpperCase();if(l==="DATATABLE"){let c=s.indexOf(`
|
|
8
|
+
`);if(c===-1&&(c=s.indexOf("\r")),c>0){let d=s.slice(0,Math.max(0,c)).split(/[ ,;\t]+/);ee(n,r,d[0]),r.datatable=d[0],d[1]?.includes("PEAKS")?l="PEAKTABLE":d[1]&&(d[1].indexOf("XYDATA")||d[0].indexOf("++")>0)&&(l="XYDATA",r.nbPoints&&r.lastX!==void 0&&r.firstX!==void 0&&(r.deltaX=(r.lastX-r.firstX)/(r.nbPoints-1)))}}if(l==="XYDATA"){t.wantXY&&(U(r),s.match(/.*\+\+.*/)?(r.nbPoints&&r.lastX!==void 0&&r.firstX!==void 0&&(r.deltaX=(r.lastX-r.firstX)/(r.nbPoints-1)),j(r,s,t)):w(r,s,t),n?.spectra.push(r),r={data:{}});continue}else if(l==="PEAKTABLE"){t.wantXY&&(U(r),w(r,s,t),n?.spectra.push(r),r={data:{}});continue}if(l==="PEAKASSIGNMENTS"){t.wantXY&&(s.match(/.*[^A-Z]*.*/)&&Z(r,s),n?.spectra.push(r),r={data:{}});continue}if(s=s.split(/\r?\n/).map(c=>c.replace(/ *\$\$.*$/,"")).join(`
|
|
9
|
+
`),l==="TITLE"){let c=n;c.children||(c.children=[]),n={spectra:[],ntuples:{},info:{},meta:{},tmp:{}},c.children.push(n),m.push(c),i.push(n),n.title=s}else l==="DATATYPE"?(n.dataType=s,s.match(/^nd|\snd\s/i)&&(n.twoD=!0)):l==="NTUPLES"?s.match(/^nd|\snd\s/i)&&(n.twoD=!0):l==="DATACLASS"?n.dataClass=s:l==="JCAMPDX"?n.jcampDX=O(s):l==="JCAMPCS"?n.jcampCS=O(s):l==="XUNITS"?r.xUnits=s:l==="YUNITS"?r.yUnits=s:l==="FIRSTX"?r.firstX=Number(s):l==="LASTX"?r.lastX=Number(s):l==="FIRSTY"?r.firstY=Number(s):l==="LASTY"?r.lastY=Number(s):l==="NPOINTS"?r.nbPoints=Number(s):l==="XFACTOR"?r.xFactor=Number(s):l==="YFACTOR"?r.yFactor=Number(s):l==="MAXX"?r.maxX=Number(s):l==="MINX"?r.minX=Number(s):l==="MAXY"?r.maxY=Number(s):l==="MINY"?r.minY=Number(s):l==="DELTAX"?r.deltaX=Number(s):l===".OBSERVEFREQUENCY"||l==="$SFO1"?r.observeFrequency||(r.observeFrequency=Number(s)):l===".OBSERVENUCLEUS"?r.xType||(n.xType=s.replaceAll(/[^a-zA-Z0-9]/g,"")):l==="$OFFSET"?(n.shiftOffsetNum=0,r.shiftOffsetVal||(r.shiftOffsetVal=Number(s))):l==="$REFERENCEPOINT"||(l==="VARNAME"?n.ntuples.varname=s.split(L):l==="SYMBOL"?n.ntuples.symbol=s.split(L):l==="VARTYPE"?n.ntuples.vartype=s.split(L):l==="VARFORM"?n.ntuples.varform=s.split(L):l==="VARDIM"?n.ntuples.vardim=E(s.split(L)):l==="UNITS"?n.ntuples.units=s.split(L):l==="FACTOR"?n.ntuples.factor=E(s.split(L)):l==="FIRST"?n.ntuples.first=E(s.split(L)):l==="LAST"?n.ntuples.last=E(s.split(L)):l==="MIN"?n.ntuples.min=E(s.split(L)):l==="MAX"?n.ntuples.max=E(s.split(L)):l===".NUCLEUS"?n.ntuples&&(n.ntuples.nucleus=s.split(L).map(c=>c.replaceAll(/[^a-zA-Z0-9]/g,""))):l==="PAGE"?(r.page=s.trim(),r.pageValue=Number(s.replace(/^.*=/,"")),r.pageSymbol=r.page.replace(/[=].*/,"")):l==="RETENTIONTIME"?r.pageValue=Number(s):fe(l)?r[B(l)]=s:l==="SAMPLEDESCRIPTION"?r.sampleDescription=s:l.startsWith("$NUC")?!n.tmp[l]&&!s.includes("off")&&(n.tmp[l]=s.replaceAll(/[<>]/g,"")):l==="END"&&(n=m.pop()));if(n?.info&&n.meta&&l.match(t.keepRecordsRegExp)){let c,d;h.startsWith("$")?(d=t.canonicMetadataLabels?l.slice(1):h.slice(1),c=n.meta):(d=t.canonicDataLabels?l:h,c=n.info),t.dynamicTyping&&(s=(0,ce.parseString)(s)),c[d]?(Array.isArray(c[d])||(c[d]=[c[d]]),c[d].push(s)):c[d]=s}}if(t.logger?.trace({profiling:!0},"Finished parsing"),_(i,a,t),t.logger?.trace({profiling:!0},"Total time"),a.entries=o.children||[],a.flatten=i,t.logger){t.logger.debug("Finished jcamp conversion");for(let u of a.flatten)t.logger.debug(`${u.dataType} - ${u.title}`)}return a}function be(e,f){let{logger:t,OCL:i}=f;if(!e.info.ATOMLIST||!e.info.BONDLIST){t?.warn("No ATOMLIST or BONDLIST in the JCAMP-CS entry");return}Ye(e,t);let a=Ee(e.info.ATOMLIST),o=Re(e.info.BONDLIST),n=De(e.info.CHARGE,t),m=Fe(i,a,o,n,t);return{molecule:m,molfile:m.toMolfile()}}function Fe(e,f,t,i,a){let o={S:e.Molecule.cBondTypeSingle,D:e.Molecule.cBondTypeDouble,T:e.Molecule.cBondTypeTriple,Q:e.Molecule.cBondTypeQuadruple},n={},m=new e.Molecule(f.length,t.length);for(let r of f){let p=e.Molecule.getAtomicNoFromLabel(r.element);p||(a?.error(`Atomic number of ${r.element} could not be determined`),p=e.Molecule.getAtomicNoFromLabel("X")),n[r.atomNumber]=m.addAtom(p),m.setAtomMapNo(n[r.atomNumber],r.atomNumber,!1)}for(let r of t){if(n[r.atomNumber1]===void 0){a?.error(`A bond goes to atomNumber ${r.atomNumber1} that does not exists`);continue}if(n[r.atomNumber2]===void 0){a?.error(`A bond goes to atomNumber ${r.atomNumber2} that does not exists`);continue}let p=m.addBond(n[r.atomNumber1],n[r.atomNumber2]);m.setBondType(p,o[r.bondType])}for(let r of i){if(n[r.atomNumber]===void 0){a?.error(`A charge goes to atomNumber ${r.atomNumber} that does not exists`);continue}m.setAtomCharge(n[r.atomNumber],r.value)}return m}function Ee(e){let f=e.split(/\r?\n/).map(i=>O(i)).filter(Boolean),t=[];for(let i of f){let[a,o,n]=i.trim().split(/\s+/);t.push({atomNumber:Number(a),element:o,nbImplicitHydrogens:n?.length>0?Number(n):void 0})}return t}function Re(e){let f=e.split(/\r?\n/).map(i=>O(i)).filter(Boolean),t=[];for(let i of f){let[a,o,n]=i.trim().split(/\s+/);t.push({atomNumber1:Number(a),atomNumber2:Number(o),bondType:n})}return t}function De(e,f){if(!e)return[];let t=e.split(/\r?\n/).map(a=>O(a)).filter(Boolean),i=[];for(let a of t){let[o,n,m]=a.trim().split(/\s+/);m!==void 0&&f?.warn("Charge on multiple atom is not supported"),i.push({atomNumber:Number(n),value:Number(o)})}return i}function Ye(e,f){let t=["STEREOPAIR","STEREOCENTER","RADICAL","STEREOMOLECULE"];for(let i of t)e.info[i]&&f?.warn(`JCAMP-CS parser do not support: ${i}`)}
|
package/jcampconverter.d.ts
CHANGED
|
@@ -1,253 +1,213 @@
|
|
|
1
1
|
import { Logger } from 'cheminfo-types';
|
|
2
|
+
import type { Molecule } from 'openchemlib';
|
|
3
|
+
import { openchemlib } from 'openchemlib';
|
|
4
|
+
|
|
5
|
+
declare interface Add2DOptions extends GenerateContourLinesOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Don't calculate contour in case of 2D.
|
|
8
|
+
*/
|
|
9
|
+
noContour?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
declare interface Chromatogram {
|
|
13
|
+
times: number[];
|
|
14
|
+
series: Record<string, {
|
|
15
|
+
dimension: number;
|
|
16
|
+
data: any[];
|
|
17
|
+
}>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
declare interface ContourLines {
|
|
21
|
+
minX: number;
|
|
22
|
+
maxX: number;
|
|
23
|
+
minY: number;
|
|
24
|
+
maxY: number;
|
|
25
|
+
segments: Array<{
|
|
26
|
+
zValue?: number;
|
|
27
|
+
lines?: number[];
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
2
30
|
|
|
3
31
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* @property {RegExp} [keepRecordsRegExp=/^$/] - By default we don't keep meta information.
|
|
7
|
-
* @property {boolean} [canonicDataLabels=true] - Canonize the Labels (uppercase without symbol).
|
|
8
|
-
* @property {boolean} [canonicMetadataLabels=false] - Canonize the metadata Labels (uppercase without symbol).
|
|
9
|
-
* @property {boolean} [dynamicTyping=false] - Convert numbers to Number.
|
|
10
|
-
* @property {boolean} [withoutXY=false] - Remove the XY data.
|
|
11
|
-
* @property {boolean} [chromatogram=false] - Special post-processing for GC / HPLC / MS.
|
|
12
|
-
* @property {boolean} [keepSpectra=false] - Force to keep the spectra in case of 2D.
|
|
13
|
-
* @property {RegExp} [noTrimRegExp=/^$/] - For which fields we should not trim ?
|
|
14
|
-
* @property {boolean} [noContour=false] - Don't calculate countour in case of 2D.
|
|
15
|
-
* @property {number} [nbContourLevels=7] - Number of positive / negative contour levels to calculate.
|
|
16
|
-
* @property {number} [noiseMultiplier=5] - Define for 2D the level as 5 times the median as default.
|
|
17
|
-
* @property {import('cheminfo-types').Logger} [logger] - A logger like 'pino'
|
|
18
|
-
* @property {boolean} [profiling=false] - Add profiling information.
|
|
19
|
-
*/
|
|
20
|
-
/**
|
|
21
|
-
*
|
|
22
|
-
* @typedef {object} Ntuples@typedef {object} Ntuples
|
|
23
|
-
* @property {string[]} [varname]
|
|
24
|
-
* @property {string[]} [symbol]
|
|
25
|
-
* @property {string[]} [vartype]
|
|
26
|
-
* @property {string[]} [varform]
|
|
27
|
-
* @property {number[]} [vardim]
|
|
28
|
-
* @property {string[]} [units]
|
|
29
|
-
* @property {number[]} [factor]
|
|
30
|
-
* @property {number[]} [first]
|
|
31
|
-
* @property {number[]} [last]
|
|
32
|
-
* @property {number[]} [min]
|
|
33
|
-
* @property {number[]} [max]
|
|
34
|
-
* @property {string[]} [nucleus]
|
|
35
|
-
*/
|
|
36
|
-
/**
|
|
37
|
-
* @typedef { Record<string, any> } Spectrum
|
|
38
|
-
* @property {Record<string, number[]>} [data]
|
|
39
|
-
* @property {number} [firstX] - first X value
|
|
40
|
-
* @property {number} [lastX] - last X value
|
|
41
|
-
* @property {number} [deltaX] - distance between 2 consecutive x axis values
|
|
42
|
-
* @property {number} [yFactor] - y axis scaling factor
|
|
43
|
-
* @property {number} [xFactor] - x axis scaling factor
|
|
44
|
-
* @property {number} [nbPoints] - Number of points
|
|
45
|
-
*/
|
|
46
|
-
/**
|
|
47
|
-
*
|
|
48
|
-
* @typedef {object} MinMax@typedef {object} MinMax
|
|
49
|
-
* @property {number[][]} [z]
|
|
50
|
-
* @property {number} minX
|
|
51
|
-
* @property {number} maxX
|
|
52
|
-
* @property {number} minY
|
|
53
|
-
* @property {number} maxY
|
|
54
|
-
* @property {number} minZ
|
|
55
|
-
* @property {number} maxZ
|
|
56
|
-
* @property {number} median
|
|
57
|
-
*/
|
|
58
|
-
/**
|
|
59
|
-
*
|
|
60
|
-
* @typedef {object} Entry@typedef {object} Entry
|
|
61
|
-
* @property {Spectrum[]} spectra
|
|
62
|
-
* @property {Ntuples} ntuples
|
|
63
|
-
* @property {Record<String, string | string[] | number | number[] | boolean | boolean[] | undefined>} meta
|
|
64
|
-
* @property {Record<String, string | string[] | number | number[] | boolean | boolean[] | undefined>} info
|
|
65
|
-
* @property {Record<String, string | string[] | number | number[] | boolean | boolean[] | undefined>} tmp
|
|
66
|
-
* @property {string} [title]
|
|
67
|
-
* @property {string} [dataType]
|
|
68
|
-
* @property {string} [dataClass]
|
|
69
|
-
* @property {string?} [jcampDX]
|
|
70
|
-
* @property {string?} [jcampCS]
|
|
71
|
-
* @property {boolean} [twoD]
|
|
72
|
-
* @property {MinMax} [minMax]
|
|
73
|
-
*/
|
|
74
|
-
/**
|
|
75
|
-
*
|
|
76
|
-
* @typedef { object } ConvertResult@typedef { object } ConvertResult
|
|
77
|
-
* @property { object[] | boolean } profiling
|
|
78
|
-
* @property { string[] } logs
|
|
79
|
-
* @property { object[] } entries
|
|
80
|
-
* @property { Entry[] } flatten
|
|
81
|
-
*/
|
|
82
|
-
/**
|
|
83
|
-
* Parse a jcamp.
|
|
84
|
-
* The data can be provide as a string or array buffer. In this later case
|
|
32
|
+
* Parse JCAMP-DX data.
|
|
33
|
+
* The data can be provided as a string or array buffer. In this latter case
|
|
85
34
|
* we will convert it first to a string before parsing.
|
|
86
|
-
* @param
|
|
87
|
-
* @param
|
|
88
|
-
* @returns
|
|
35
|
+
* @param jcamp
|
|
36
|
+
* @param optionsParam
|
|
37
|
+
* @returns Converted result.
|
|
89
38
|
*/
|
|
90
|
-
export declare function convert(jcamp: string | ArrayBuffer | Uint8Array,
|
|
39
|
+
export declare function convert(jcamp: string | ArrayBuffer | Uint8Array, optionsParam?: ConvertOptions): ConvertResult;
|
|
91
40
|
|
|
92
41
|
/**
|
|
93
|
-
* Conversion options
|
|
42
|
+
* Conversion options.
|
|
94
43
|
*/
|
|
95
|
-
declare
|
|
44
|
+
declare interface ConvertOptions extends Partial<Add2DOptions> {
|
|
96
45
|
/**
|
|
97
|
-
*
|
|
46
|
+
* By default we don't keep meta information.
|
|
47
|
+
* @default `/^$/`
|
|
98
48
|
*/
|
|
99
|
-
keepRecordsRegExp?: RegExp
|
|
49
|
+
keepRecordsRegExp?: RegExp;
|
|
100
50
|
/**
|
|
101
|
-
*
|
|
51
|
+
* Canonize the Labels (uppercase without symbol).
|
|
102
52
|
*/
|
|
103
|
-
canonicDataLabels?: boolean
|
|
53
|
+
canonicDataLabels?: boolean;
|
|
104
54
|
/**
|
|
105
|
-
*
|
|
55
|
+
* Canonize the metadata Labels (uppercase without symbol).
|
|
106
56
|
*/
|
|
107
|
-
canonicMetadataLabels?: boolean
|
|
57
|
+
canonicMetadataLabels?: boolean;
|
|
108
58
|
/**
|
|
109
|
-
*
|
|
59
|
+
* Convert numbers to Number.
|
|
110
60
|
*/
|
|
111
|
-
dynamicTyping?: boolean
|
|
61
|
+
dynamicTyping?: boolean;
|
|
112
62
|
/**
|
|
113
|
-
*
|
|
63
|
+
* Remove the XY data.
|
|
114
64
|
*/
|
|
115
|
-
withoutXY?: boolean
|
|
65
|
+
withoutXY?: boolean;
|
|
116
66
|
/**
|
|
117
|
-
*
|
|
67
|
+
* Special post-processing for GC / HPLC / MS.
|
|
118
68
|
*/
|
|
119
|
-
chromatogram?: boolean
|
|
69
|
+
chromatogram?: boolean;
|
|
120
70
|
/**
|
|
121
|
-
*
|
|
71
|
+
* Force to keep the spectra in case of 2D.
|
|
122
72
|
*/
|
|
123
|
-
keepSpectra?: boolean
|
|
73
|
+
keepSpectra?: boolean;
|
|
124
74
|
/**
|
|
125
|
-
*
|
|
75
|
+
* For which fields we should not trim ?
|
|
76
|
+
* @default `/^$/`
|
|
126
77
|
*/
|
|
127
|
-
noTrimRegExp?: RegExp
|
|
78
|
+
noTrimRegExp?: RegExp;
|
|
128
79
|
/**
|
|
129
|
-
*
|
|
80
|
+
* A logger like `pino`.
|
|
130
81
|
*/
|
|
131
|
-
|
|
82
|
+
logger?: Logger;
|
|
132
83
|
/**
|
|
133
|
-
*
|
|
84
|
+
* Add profiling information.
|
|
134
85
|
*/
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
noiseMultiplier?: number | undefined;
|
|
140
|
-
/**
|
|
141
|
-
* - A logger like 'pino'
|
|
142
|
-
*/
|
|
143
|
-
logger?: Logger | undefined;
|
|
144
|
-
/**
|
|
145
|
-
* - Add profiling information.
|
|
146
|
-
*/
|
|
147
|
-
profiling?: boolean | undefined;
|
|
148
|
-
};
|
|
86
|
+
wantXY?: boolean;
|
|
87
|
+
start?: number;
|
|
88
|
+
fastParse?: boolean;
|
|
89
|
+
}
|
|
149
90
|
|
|
150
|
-
declare
|
|
151
|
-
|
|
152
|
-
logs: string[];
|
|
153
|
-
entries: object[];
|
|
91
|
+
declare interface ConvertResult {
|
|
92
|
+
entries: Entry[];
|
|
154
93
|
flatten: Entry[];
|
|
155
|
-
}
|
|
94
|
+
}
|
|
156
95
|
|
|
157
96
|
/**
|
|
158
|
-
*
|
|
159
|
-
* @
|
|
160
|
-
* @
|
|
97
|
+
* Parse the JCAMP-DX to extract the structure as a tree.
|
|
98
|
+
* @param jcamp
|
|
99
|
+
* @param options
|
|
100
|
+
* @returns Tree.
|
|
161
101
|
*/
|
|
162
|
-
|
|
163
|
-
*
|
|
164
|
-
* @typedef {object} Tree@typedef {object} Tree
|
|
165
|
-
* @property {string} title
|
|
166
|
-
* @property {string} jcamp
|
|
167
|
-
* @property {Tree[]} [children]
|
|
168
|
-
*/
|
|
169
|
-
/**
|
|
170
|
-
* Parse the jcamp to extract the structure as a tree.
|
|
171
|
-
*
|
|
172
|
-
* @param {string|ArrayBuffer|Uint8Array} jcamp
|
|
173
|
-
* @param {CreateTreeOptions} [options={}]
|
|
174
|
-
* @returns {Tree[]}
|
|
175
|
-
*/
|
|
176
|
-
export declare function createTree(jcamp: string | ArrayBuffer | Uint8Array, options?: CreateTreeOptions | undefined): Tree[];
|
|
102
|
+
export declare function createTree(jcamp: string | ArrayBuffer | Uint8Array, options?: CreateTreeOptions): Stack[];
|
|
177
103
|
|
|
178
|
-
declare
|
|
179
|
-
flatten?: boolean
|
|
180
|
-
}
|
|
104
|
+
declare interface CreateTreeOptions {
|
|
105
|
+
flatten?: boolean;
|
|
106
|
+
}
|
|
181
107
|
|
|
182
|
-
declare
|
|
108
|
+
declare interface Entry {
|
|
183
109
|
spectra: Spectrum[];
|
|
184
110
|
ntuples: Ntuples;
|
|
185
111
|
meta: Record<string, string | string[] | number | number[] | boolean | boolean[] | undefined>;
|
|
186
112
|
info: Record<string, string | string[] | number | number[] | boolean | boolean[] | undefined>;
|
|
187
113
|
tmp: Record<string, string | string[] | number | number[] | boolean | boolean[] | undefined>;
|
|
188
|
-
title?: string
|
|
189
|
-
dataType?: string
|
|
190
|
-
dataClass?: string
|
|
191
|
-
jcampDX?: string
|
|
192
|
-
jcampCS?: string
|
|
193
|
-
twoD?: boolean
|
|
194
|
-
minMax?: MinMax
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
114
|
+
title?: string;
|
|
115
|
+
dataType?: string;
|
|
116
|
+
dataClass?: string;
|
|
117
|
+
jcampDX?: string;
|
|
118
|
+
jcampCS?: string;
|
|
119
|
+
twoD?: boolean;
|
|
120
|
+
minMax?: MinMax;
|
|
121
|
+
children?: Entry[];
|
|
122
|
+
shiftOffsetVal?: number;
|
|
123
|
+
shiftOffsetNum?: number;
|
|
124
|
+
xType?: string;
|
|
125
|
+
yType?: string;
|
|
126
|
+
chromatogram?: Chromatogram;
|
|
127
|
+
contourLines?: ContourLines;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
declare interface GenerateContourLinesOptions {
|
|
131
|
+
/**
|
|
132
|
+
* Number of positive / negative contour levels to calculate.
|
|
133
|
+
* @default `7`
|
|
134
|
+
*/
|
|
135
|
+
nbContourLevels: number;
|
|
136
|
+
/**
|
|
137
|
+
* Define for 2D the level as 5 times the median as default.
|
|
138
|
+
* @default `5`
|
|
139
|
+
*/
|
|
140
|
+
noiseMultiplier: number;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
declare interface MinMax {
|
|
144
|
+
z: number[][];
|
|
199
145
|
minX: number;
|
|
200
146
|
maxX: number;
|
|
201
147
|
minY: number;
|
|
202
148
|
maxY: number;
|
|
203
149
|
minZ: number;
|
|
204
150
|
maxZ: number;
|
|
205
|
-
median
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
151
|
+
median?: number;
|
|
152
|
+
noice?: number;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
declare interface Ntuples {
|
|
156
|
+
varname?: string[];
|
|
157
|
+
symbol?: string[];
|
|
158
|
+
vartype?: string[];
|
|
159
|
+
varform?: string[];
|
|
160
|
+
vardim?: number[];
|
|
161
|
+
units?: string[];
|
|
162
|
+
factor?: number[];
|
|
163
|
+
first?: number[];
|
|
164
|
+
last?: number[];
|
|
165
|
+
min?: number[];
|
|
166
|
+
max?: number[];
|
|
167
|
+
nucleus?: string[];
|
|
168
|
+
[key: string]: any | undefined;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
declare type OCL = openchemlib;
|
|
172
|
+
|
|
173
|
+
declare interface ParsedCS {
|
|
174
|
+
molfile: string;
|
|
175
|
+
molecule: Molecule;
|
|
176
|
+
}
|
|
222
177
|
|
|
223
178
|
/**
|
|
224
179
|
*
|
|
225
|
-
* @
|
|
226
|
-
* @
|
|
227
|
-
* @property {import("openchemlib").OCL} molecule
|
|
228
|
-
*/
|
|
229
|
-
/**
|
|
230
|
-
*
|
|
231
|
-
* @param {import("./convert.js").Entry} entry
|
|
232
|
-
* @param {object} [options={}]
|
|
233
|
-
* @param {import("fifo-logger").Logger} [options.logger]
|
|
234
|
-
* @param {import("openchemlib").OCL} [options.OCL]
|
|
180
|
+
* @param entry
|
|
181
|
+
* @param options
|
|
235
182
|
* @returns ParsedCS
|
|
236
183
|
*/
|
|
237
|
-
export declare function parseJcampCS(entry: Entry, options
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
} | undefined;
|
|
184
|
+
export declare function parseJcampCS(entry: Entry, options: ParseJcampCSOptions): ParsedCS | undefined;
|
|
185
|
+
|
|
186
|
+
declare interface ParseJcampCSOptions {
|
|
187
|
+
OCL: OCL;
|
|
188
|
+
logger?: Logger;
|
|
189
|
+
}
|
|
244
190
|
|
|
245
|
-
declare
|
|
191
|
+
declare interface Spectrum {
|
|
192
|
+
[key: string]: any;
|
|
193
|
+
data: Record<string, number[]>;
|
|
194
|
+
firstX?: number;
|
|
195
|
+
firstY?: number;
|
|
196
|
+
lastX?: number;
|
|
197
|
+
deltaX?: number;
|
|
198
|
+
yFactor?: number;
|
|
199
|
+
xFactor?: number;
|
|
200
|
+
nbPoints?: number;
|
|
201
|
+
}
|
|
246
202
|
|
|
247
|
-
declare
|
|
203
|
+
declare interface Stack {
|
|
248
204
|
title: string;
|
|
249
205
|
jcamp: string;
|
|
250
|
-
children
|
|
251
|
-
|
|
206
|
+
children: Stack[] | undefined;
|
|
207
|
+
jcampDX?: string;
|
|
208
|
+
jcampCS?: string;
|
|
209
|
+
dataType?: string;
|
|
210
|
+
dataClass?: string;
|
|
211
|
+
}
|
|
252
212
|
|
|
253
213
|
export { }
|
package/jcampconverter.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import{ensureString as
|
|
2
|
-
`),jcamp:`${
|
|
3
|
-
`,children:[]}),
|
|
4
|
-
`;let
|
|
5
|
-
`;let f=u.match(/^##(.*?)=(.+)/);if(f){let m=f[1].replace(/[ _-]/g,"").toUpperCase();m==="DATATYPE"?t.dataType=f[2].trim():m==="DATACLASS"?t.dataClass=f[2].trim():m==="JCAMPDX"?t.jcampDX=M(f[2].trim()):m==="JCAMPCS"&&(t.jcampCS=M(f[2].trim()))}}u.substring(0,5)==="##END"&&n>0&&n--}return s?(o.forEach(c=>{c.children=void 0}),o):r}import{parseString as ge}from"dynamic-typing";import{ensureString as be}from"ensure-string";var E=["TIC",".RIC","SCANNUMBER"];function te(e){let a=e.spectra,s=a.length,i={times:new Array(s),series:{ms:{dimension:2,data:new Array(s)}}},o=[];for(let l=0;l<E.length;l++){let r=I(E[l]);a[0][r]&&(o.push(r),i.series[r]={dimension:1,data:new Array(s)})}for(let l=0;l<s;l++){let r=a[l];i.times[l]=r.pageValue;for(let t=0;t<o.length;t++)i.series[o[t]].data[l]=Number(r[o[t]]);r.data&&(i.series.ms.data[l]=[r.data.x,r.data.y])}e.chromatogram=i}function le(e){return E.indexOf(e)!==-1}function I(e){return e.toLowerCase().replace(/[^a-z0-9]/g,"")}function Y(e){let a=[];for(let s=0;s<e.length;s++)a.push(Number(e[s]));return a}function U(e,a){let s=e.yFactor,i=e.deltaX;e.isXYdata=!0;let o={x:[],y:[]};e.data=o;let l=e.firstX,r=e.firstY,t=!1,n,p=0;for(;p<a.length;p++)if(n=a.charCodeAt(p),n===13||n===10)t=!0;else if(t)break;let c=!0,d=!1,u=!1,f=0,m=!1,h=!1,g=0,A=0,N=!1,y=!1,C=!1,T=0;for(;p<=a.length;p++)if(p===a.length?n=13:n=a.charCodeAt(p),h)(n===13||n===10)&&(c=!0,h=!1);else if(n<=57&&n>=48)y=!0,T>0?g+=(n-48)/10**T++:(g*=10,g+=n-48);else if(n===44||n===46)y=!0,T++;else{if(y){if(c)c=!1,u&&(C=!0);else if(C)C=!1;else{d?(f=N?0-g:g,u=!0,d=!1):m||(A=N?0-g:g);let O=m?g-1:1;for(let v=0;v<O;v++)u?r+=f:r=A,o.x.push(l),o.y.push(r*s),l+=i}N=!1,g=0,T=0,y=!1,m=!1}if(n<74&&n>63)y=!0,u=!1,g=n-64;else if(n>96&&n<106)y=!0,u=!1,g=n-96,N=!0;else if(n===115)y=!0,m=!0,g=9;else if(n>82&&n<91)y=!0,m=!0,g=n-82;else if(n>73&&n<83)y=!0,d=!0,g=n-73;else if(n>105&&n<115)y=!0,d=!0,g=n-105,N=!0;else if(n===36&&a.charCodeAt(p+1)===36)y=!0,h=!0;else if(n===37)y=!0,d=!0,g=0,N=!1;else if(n===45){let O=a.charCodeAt(p+1);(O>=48&&O<=57||O===44||O===46)&&(y=!0,c||(u=!1),N=!0)}else(n===13||n===10)&&(c=!0,h=!1)}}var se=/[,\t ]+/;function D(e,a,s){if(e.isPeaktable=!0,!e.variables||Object.keys(e.variables)===2?me(e,a,s):ce(e,a,s),e.variables)for(let i in e.variables)e.variables[i].data=e.data[i]}function me(e,a,s){let i={x:[],y:[]};e.data=i;let o=a.split(/,? *,?[;\r\n]+ */);for(let l=1;l<o.length;l++){let r=o[l].trim().replace(P,"").split(se);if(r.length%2===0)for(let t=0;t<r.length;t=t+2)i.x.push(Number(r[t])*e.xFactor),i.y.push(Number(r[t+1])*e.yFactor);else s.logs.push(`Format error: ${r}`)}}function ce(e,a,s){let i={},o=Object.keys(e.variables),l=o.length;o.forEach(t=>i[t]=[]),e.data=i;let r=a.split(/,? *,?[;\r\n]+ */);for(let t=1;t<r.length;t++){let n=r[t].trim().replace(P,"").split(se);if(n.length%l===0)for(let p=0;p<n.length;p++)i[o[p%l]].push(Number(n[p]));else s.logs.push(`Wrong number of columns: ${n}`)}}function V(e,a){e.isXYAdata=!0;let s={};e.data=s;let i=a.split(/\r?\n/),o=i[0].replace(/^.*?([A-Z]+).*$/,"$1").split("").map(l=>l.toLowerCase());for(let l=1;l<i.length;l++){let r=i[l].replace(/^\((.*)\)$/,"$1").split(/ *, */);for(let t=0;t<o.length;t++){let n=r[t];switch(o[t]){case"x":case"y":case"w":n=Number.parseFloat(n);break;case"a":n=n.replace(/^<(.*)>$/,"$1");break;case"m":break;default:continue}s[o[t]]||(s[o[t]]=[]),s[o[t]].push(n)}}}import{parseString as ne}from"dynamic-typing";import{getGyromagneticRatio as ae}from"gyromagnetic-ratio";import re from"ml-array-median";function ie(e){return Array.isArray(e)?e[0]:e}function B(e){let{spectra:a}=e,s=a[0].data.y[0],i=s,o=a.length,l=a[0].data.x.length,r=new Array(o);for(let f=0;f<o;f++){r[f]=a[f].data.y;for(let m=0;m<l;m++){let h=r[f][m];h<s&&(s=h),h>i&&(i=h)}}let t=a[0].data.x[0],n=a[0].data.x[a[0].data.x.length-1],{firstY:p,lastY:c}=he(e);if(t>n)for(let f of r)f.reverse();p>c&&r.reverse();let d=[];for(let f=0;f<r.length;f++){let m=Float64Array.from(r[f]);for(let h=0;h<m.length;h++)m[h]<0&&(m[h]=-m[h]);d.push(re(m))}let u=re(d);return{z:r,minX:Math.min(t,n),maxX:Math.max(t,n),minY:Math.min(p,c),maxY:Math.max(p,c),minZ:s,maxZ:i,noise:u}}function he(e){let{spectra:a,ntuples:s,info:i}=e;if(s)for(let o=0;o<s.length;o++){let{symbol:l,nucleus:r}=s[o];if(l.match(/[F|T]1/)){let t=ie(i[".OBSERVEFREQUENCY"]),{nucleus:n}=s.find(m=>m.symbol.match(/[F|T]2/));if([t,n,r].some(m=>!m))break;let p=ae(n),c=ae(r),{first:d,last:u}=s[o],f=t*c/p;return{firstY:d/f,lastY:u/f}}}return{firstY:a[0].pageValue,lastY:a[a.length-1].pageValue}}function k(e,a){let s=e.noise,i=e.z,o,l,r,t,n,p,c,d,u=i.length,f=i[0].length,m,h,g,A,N=e.minX,C=(e.maxX-N)/(f-1),T=e.minY,v=(e.maxY-T)/(u-1),oe=e.minZ,K=e.maxZ,Q=a.nbContourLevels*2,W=new Array(Q),x;for(let R=0;R<Q;R++){let $={};W[R]=$;let fe=R%2,_=(K-a.noiseMultiplier*s)*Math.exp((R>>1)-a.nbContourLevels);fe===0?x=_+a.noiseMultiplier*s:x=0-_-a.noiseMultiplier*s;let b=[];if($.zValue=x,$.lines=b,!(x<=oe||x>=K))for(let X=0;X<u-1;X++){let z=i[X],ee=i[X+1];for(let S=0;S<f-1;S++)o=z[S],l=z[S+1],r=ee[S],t=ee[S+1],n=o>x,p=l>x,c=r>x,d=t>x,n!==p&&n!==c&&(m=S+(x-o)/(l-o),h=X,g=S,A=X+(x-o)/(r-o),b.push(m*C+N),b.push(h*v+T),b.push(g*C+N),b.push(A*v+T)),d!==p&&d!==c&&(m=S+1,h=X+1-(x-t)/(l-t),g=S+1-(x-t)/(r-t),A=X+1,b.push(m*C+N),b.push(h*v+T),b.push(g*C+N),b.push(A*v+T)),p!==c&&(m=(S+1-(x-l)/(r-l))*C+N,h=(X+(x-l)/(r-l))*v+T,p!==n&&(g=S+1-(x-l)/(o-l),A=X,b.push(m),b.push(h),b.push(g*C+N),b.push(A*v+T)),c!==n&&(g=S,A=X+1-(x-r)/(o-r),b.push(m),b.push(h),b.push(g*C+N),b.push(A*v+T)),p!==d&&(g=S+1,A=X+(x-l)/(t-l),b.push(m),b.push(h),b.push(g*C+N),b.push(A*v+T)),c!==d&&(g=S+(x-r)/(t-r),A=X+1,b.push(m),b.push(h),b.push(g*C+N),b.push(A*v+T)))}}return{minX:e.minX,maxX:e.maxX,minY:e.minY,maxY:e.maxY,segments:W}}function j(e,a){let s=B(e);a.noContour||(e.contourLines=k(s,a),delete s.z),e.minMax=s}import{getGyromagneticRatio as Z}from"gyromagnetic-ratio";function J(e,a){for(let s of e){let i=0,o=0;for(let l of s.spectra){if(s.ntuples&&s.ntuples.symbol?(!i&&l.observeFrequency&&(i=l.observeFrequency),!o&&l.shiftOffsetVal&&(o=l.shiftOffsetVal)):(i=l.observeFrequency,o=l.shiftOffsetVal),i&&l.xUnits&&l.xUnits.toUpperCase().includes("HZ")){l.xUnits="PPM",l.xFactor=l.xFactor/i,l.firstX=l.firstX/i,l.lastX=l.lastX/i,l.deltaX=l.deltaX/i;for(let r=0;r<l.data.x.length;r++)l.data.x[r]/=i}if(o&&l.xUnits.toLowerCase().includes("ppm")){let r=l.firstX-o;l.firstX=l.firstX-r,l.lastX=l.lastX-r;for(let t=0;t<l.data.x.length;t++)l.data.x[t]-=r}if(s.ntuples&&s.ntuples.nucleus&&s.ntuples.symbol)for(let r=0;r<s.ntuples.nucleus.length;r++){let t=s.ntuples.symbol[r],n=s.ntuples.nucleus[r];if(t.match(/^[F|T]/)&&!n){if(t.match(/[F|T]1/))if(s.tmp.$NUC2)s.ntuples.nucleus[r]=s.tmp.$NUC2;else{let p=s.ntuples.symbol.indexOf(t.replace(/^([F|T]).*/,"$12"));p&&s.ntuples.nucleus[p]&&(s.ntuples.nucleus[r]=s.ntuples.nucleus[p])}t.match(/[F|T]2/)&&(s.ntuples.nucleus[r]=s.tmp.$NUC1)}t.match(/[F|T]2/)&&(s.yType=s.ntuples.nucleus[0],Z(s.xType)||(s.xType=s.ntuples.nucleus[1]))}if(i&&s.ntuples&&s.ntuples.symbol&&s.ntuples.nucleus){let r="",t=s.ntuples.symbol.indexOf(l.pageSymbol);if(s.ntuples.units&&s.ntuples.units[t]&&(r=s.ntuples.units[t]),!r.toLowerCase().match(/(ppm|seconds)/)){if(t!==0){let u="Not sure about this ntuples format";if(a)a.warn(u);else throw Error(u)}let{nucleus:n}=s.ntuples,p=Z(n[0]),c=Z(n[1]);if(!p||!c){let u=`Problem with determination of gyromagnetic ratio for ${n.join("-")}`;if(a)a.error(u);else throw Error(u)}let d=p/c*i;l.pageValue/=d}}}}}function L(e,a,s={}){s.logger?.trace(a),e.profiling&&e.profiling.push({action:a,time:Date.now()-s.start})}function G(e){let a=e.spectra[0].data;e.chromatogram={times:a.x.slice(),series:{intensity:{dimension:1,data:a.y.slice()}}}}function H(e,a,s){J(e,s.logger),de(e,s);for(let i of e){if(Object.keys(i.ntuples).length>0){let o=[],l=Object.keys(i.ntuples);for(let r=0;r<l.length;r++){let t=l[r],n=i.ntuples[t];for(let p=0;p<n.length;p++)o[p]||(o[p]={}),o[p][t]=n[p]}i.ntuples=o}i.twoD&&s.wantXY&&(j(i,s),L(a,"Finished countour plot calculation",s),s.keepSpectra||delete i.spectra),s.chromatogram&&(i.spectra.length>1?te(i):G(i),L(a,"Finished chromatogram calculation",s)),delete i.tmp}}function de(e,a){for(let s of e)for(let i in s.meta){let o=s.meta[i];if(typeof o=="string"){if(o[0]==="{"){if(!o.includes(":")&&o[o.length-1]==="}"){let l=o.slice(1,-1).split(/[,; ]+/).filter(r=>r);for(let r=0;r<l.length;r++)s.meta[i+String(r)]=a.dynamicTyping?ne(l[r]):l[r]}}else if(o[0]==="("){let l=o.split(/\r?\n/),r=/^\((?<from>\d+)\.\.(?<to>\d+)\).*$/;if(r.test(l[0])){let[t,n]=l[0].match(r).slice(1).map(Number),p=l.slice(1).join(" ").split(/[,; ]+/).filter(c=>c);for(let c=t;c<=n;c++)a.dynamicTyping&&typeof p[c-t]=="string"?s.meta[i+String(c)]=ne(p[c-t]):s.meta[i+String(c)]=p[c-t]}}}}}function q(e,a,s){let i=-1,o=-1,l="",r="";if(s.indexOf("++")>0)l=s.replace(/.*\(([a-zA-Z0-9]+)\+\+.*/,"$1"),r=s.replace(/.*\.\.([a-zA-Z0-9]+).*/,"$1");else{s=s.replace(/[^a-zA-Z%]/g,""),l=s.charAt(0),r=s.charAt(1),a.variables={};for(let t of s){let n=t.toLowerCase(),p=e.ntuples.symbol.indexOf(t);if(p===-1)throw Error(`Symbol undefined: ${t}`);a.variables[n]={};for(let c in e.ntuples)e.ntuples[c][p]&&(a.variables[n][c.replace(/^var/,"")]=e.ntuples[c][p])}}i=e.ntuples.symbol.indexOf(l),o=e.ntuples.symbol.indexOf(r),i===-1&&(i=0),o===-1&&(o=0),e.ntuples.first&&(e.ntuples.first.length>i&&(a.firstX=e.ntuples.first[i]),e.ntuples.first.length>o&&(a.firstY=e.ntuples.first[o])),e.ntuples.last&&(e.ntuples.last.length>i&&(a.lastX=e.ntuples.last[i]),e.ntuples.last.length>o&&(a.lastY=e.ntuples.last[o])),e.ntuples.vardim&&e.ntuples.vardim.length>i&&(a.nbPoints=e.ntuples.vardim[i]),e.ntuples.factor&&(e.ntuples.factor.length>i&&(a.xFactor=e.ntuples.factor[i]),e.ntuples.factor.length>o&&(a.yFactor=e.ntuples.factor[o])),e.ntuples.units&&(e.ntuples.units.length>i&&(e.ntuples.varname&&e.ntuples.varname[i]?a.xUnits=`${e.ntuples.varname[i]} [${e.ntuples.units[i]}]`:a.xUnits=e.ntuples.units[i]),e.ntuples.units.length>o&&(e.ntuples.varname&&e.ntuples.varname[o]?a.yUnits=`${e.ntuples.varname[o]} [${e.ntuples.units[o]}]`:a.yUnits=e.ntuples.units[o]))}function w(e){e.xFactor||(e.xFactor=1),e.yFactor||(e.yFactor=1)}var F=/[ \t]*,[ \t]*/,xe={keepRecordsRegExp:/^$/,canonicDataLabels:!0,canonicMetadataLabels:!1,dynamicTyping:!0,withoutXY:!1,noTrimRegExp:/^$/,chromatogram:!1,keepSpectra:!1,noContour:!1,nbContourLevels:7,noiseMultiplier:5,profiling:!1};function Ne(e,a={}){e=be(e),a={...xe,...a},a.logger?.debug("Starting jcamp conversion"),a.wantXY=!a.withoutXY,a.start=Date.now();let s=[],i={profiling:a.profiling?[]:!1,logs:[],entries:[]},o={children:[]},l=o,r=[],t={};if(typeof e!="string")throw new TypeError("the JCAMP should be a string");L(i,"Before split to LDRS",a);let n=e.replace(/[\r\n]+##/g,`
|
|
1
|
+
import{ensureString as fe}from"ensure-string";var $=/\s*\$\$.*/;function O(e){return e.replace($,"")}function me(e,m={}){e=fe(e);let{flatten:n=!1}=m,i=e.split(/\r?\n/),f=[],o=[],t=[],l={title:"",jcamp:"",children:[]},r=0,p=e.includes("## ");for(let u=0;u<i.length;u++){let b=i[u],h=p?b.replaceAll(" ",""):b;if(h.startsWith("##NTUPLES")&&r++,h.startsWith("##TITLE")){let s=[h.slice(8).trim()];for(let a=u+1;a<i.length&&!i[a].startsWith("##");a++)s.push(i[a].trim());o.push({title:s.join(`
|
|
2
|
+
`),jcamp:`${b}
|
|
3
|
+
`,children:[]}),l=o.at(-1),f.push(l)}else if(h.startsWith("##END")&&r===0&&l){l.jcamp+=`${b}
|
|
4
|
+
`;let s=o.pop();if(!s)throw new Error("Not finished");o.length>0?(l=o.at(-1),l.children?.push(s)):(l=void 0,t.push(s))}else if(l?.jcamp){l.jcamp+=`${b}
|
|
5
|
+
`;let s=h.match(/^##(.*?)=(.+)/);if(s){let a=s[1].replaceAll(/[ _-]/g,"").toUpperCase();a==="DATATYPE"?l.dataType=s[2].trim():a==="DATACLASS"?l.dataClass=s[2].trim():a==="JCAMPDX"?l.jcampDX=O(s[2].trim()):a==="JCAMPCS"&&(l.jcampCS=O(s[2].trim()))}}h.startsWith("##END")&&r>0&&r--}if(n){for(let u of f)u.children=void 0;return f}else return t}import{parseString as be}from"dynamic-typing";import{ensureString as ge}from"ensure-string";var ee=["TIC",".RIC","SCANNUMBER"];function te(e){let m=e.spectra,n=m.length,i={times:new Array(n),series:{ms:{dimension:2,data:new Array(n)}}},f=[];for(let o of ee){let t=k(o);m[0][t]&&(f.push(t),i.series[t]={dimension:1,data:new Array(n)})}for(let o=0;o<n;o++){let t=m[o];i.times[o]=t.pageValue;for(let l of f)i.series[l].data[o]=Number(t[l]);t.data&&(i.series.ms.data[o]=[t.data.x,t.data.y])}e.chromatogram=i}function ne(e){return ee.includes(e)}function k(e){return e.toLowerCase().replaceAll(/[^a-z0-9]/g,"")}function E(e){return e.map(Number)}function V(e,m,n){let{logger:i}=n;i&&(e.xFactor||i.info("The xFactor is not defined, it will be set to 1"),e.yFactor||i.info("The yFactor is not defined, it will be set to 1"));let f=e.yFactor??1,o=e.xFactor??1,t=e.deltaX??1,l=Math.abs(t*.1),r=.01;e.isXYdata=!0;let p={x:[],y:[]};e.data=p;let u=e.firstX||0,b=e.firstY||0,h=!1,s,a=0;for(;a<m.length;a++)if(s=m.codePointAt(a),s===13||s===10)h=!0;else if(h)break;let c=0,d=!0,A=!1,y=!1,I=0,N=!1,C=!1,g=0,X=0,M=!1,S=!1,Y=!1,R=0;for(;a<=m.length;a++)if(a===m.length?s=13:s=m.codePointAt(a),C)(s===13||s===10)&&(d=!0,C=!1,c++);else if(s<=57&&s>=48)S=!0,R>0?g+=(s-48)/10**R++:(g*=10,g+=s-48);else if(s===44||s===46)S=!0,R++;else{if(S){if(M&&(g=g*-1,M=!1),d)g*=o,i&&(y?Math.abs(u-t-g)>l&&(Math.abs(u-g)<l?i.trace(`Data line ${c}: After a DIFFERENCE the next line should repeat the last value and this does not seem to be the case: Current value: ${g} - Expected: ${u}.`):Math.abs(u-t-g)>10*l?i.trace(`Data line ${c}: The difference between the first value ${g} and the expected first x value ${u} based on increment after a DIFFERENCE is too high`):i.trace(`Data line ${c}: The difference between the first value ${g} and the expected first x value ${u} based on increment after a DIFFERENCE is too high`)):Math.abs(u-g)>l&&i.trace(`Data line ${c}: The difference between the first value ${g} and the first x value ${u} is too high`)),d=!1,y&&(Y=!0);else if(Y)Y=!1,i&&Math.abs(b-g)>r&&i.trace(`Data line ${c}: After a duplicate the next line should repeat the same value ${g} !== ${b}`),b=g;else{A?(I=M?0-g:g,y=!0,A=!1):N||(X=M?0-g:g);let x=N?g-1:1;for(let F=0;F<x;F++)y?b+=I:b=X,p.x.push(u),p.y.push(b*f),u+=t}M=!1,g=0,R=0,S=!1,N=!1}if(s<74&&s>63)S=!0,y=!1,g=s-64;else if(s>96&&s<106)S=!0,y=!1,g=s-96,M=!0;else if(s===115)S=!0,N=!0,g=9;else if(s>82&&s<91)S=!0,N=!0,g=s-82;else if(s>73&&s<83)S=!0,A=!0,g=s-73;else if(s>105&&s<115)S=!0,A=!0,g=s-105,M=!0;else if(s===36&&m.codePointAt(a+1)===36)S=!0,C=!0;else if(s===37)S=!0,A=!0,g=0,M=!1;else if(s===45){let x=m.codePointAt(a+1);(x!==void 0&&x>=48&&x<=57||x===44||x===46)&&(S=!0,d||(y=!1),M=!0)}else(s===13||s===10)&&(d=!0,C=!1,c++)}i&&y&&i.warn("The last value is a difference, it should be repeated on the next line")}var re=/[,\t ]+/;function P(e,m,n){if(e.isPeaktable=!0,!e.variables||Object.keys(e.variables).length===2?ue(e,m,n):ce(e,m,n),e.variables)for(let i in e.variables)e.variables[i].data=e.data?.[i]}function ue(e,m,n){let{logger:i}=n,f={x:[],y:[]};e.data=f;let o=m.split(/,? *,?[;\r\n]+ */);for(let t=1;t<o.length;t++){let l=o[t].trim().replace($,"").split(re);if(l.length%2===0)for(let r=0;r<l.length;r=r+2)e.xFactor!==void 0&&e.yFactor!==void 0&&(f.x.push(Number(l[r])*e.xFactor),f.y.push(Number(l[r+1])*e.yFactor));else i?.warn(`Format error: ${l.toString()}`)}}function ce(e,m,n){let{logger:i}=n,f={},o=Object.keys(e.variables),t=o.length;for(let r of o)f[r]=[];e.data=f;let l=m.split(/,? *,?[;\r\n]+ */);for(let r=1;r<l.length;r++){let p=l[r].trim().replace($,"").split(re);if(p.length%t===0)for(let u=0;u<p.length;u++)f[o[u%t]].push(Number(p[u]));else i?.warn(`Wrong number of columns: ${p.toString()}`)}}function B(e,m){e.isXYAdata=!0;let n={};e.data=n;let i=m.split(/\r?\n/),f=i[0].replace(/^.*?([A-Z]+).*$/,"$1").split("").map(o=>o.toLowerCase());for(let o=1;o<i.length;o++){let t=i[o].replace(/^\((.*)\)$/,"$1").split(/ *, */);for(let l=0;l<f.length;l++){let r=t[l];switch(f[l]){case"x":case"y":case"w":r=Number.parseFloat(r);break;case"a":r=r.replace(/^<(.*)>$/,"$1");break;case"m":break;default:continue}n[f[l]]||(n[f[l]]=[]),n[f[l]].push(r)}}}import{parseString as ae}from"dynamic-typing";import{getGyromagneticRatio as ie}from"gyromagnetic-ratio";import oe from"ml-array-median";function se(e){return Array.isArray(e)?e[0]:e}function j(e){let{spectra:m}=e,n=m[0].data.y[0],i=n,f=m.length,o=m[0].data.x.length||0,t=new Array(f);for(let s=0;s<f;s++){t[s]=m[s].data.y;for(let a=0;a<o;a++){let c=t[s][a];c<n&&(n=c),c>i&&(i=c)}}let l=m[0].data.x[0],r=m[0].data.x.at(-1),{firstY:p,lastY:u}=pe(e);if(l>r)for(let s of t)s.reverse();p>u&&t.reverse();let b=[];for(let s of t){let a=Float64Array.from(s);for(let c=0;c<a.length;c++)a[c]<0&&(a[c]=-a[c]);b.push(oe(a))}let h=oe(b);return{z:t,minX:Math.min(l,r),maxX:Math.max(l,r),minY:Math.min(p,u),maxY:Math.max(p,u),minZ:n,maxZ:i,noise:h}}function pe(e){let{spectra:m,ntuples:n,info:i}=e;if(n)for(let f of n){let{symbol:o,nucleus:t,units:l}=f;if(o.match(/[F|T]1/)&&l?.toUpperCase().match("HZ")){let r=se(i[".OBSERVEFREQUENCY"]),{nucleus:p}=n.find(c=>c.symbol.match(/[F|T]2/));if([r,p,t].some(c=>!c))break;let u=ie(p),b=ie(t),{first:h,last:s}=f,a=b!==null&&u!==null?r*b/u:r;return{firstY:h/a,lastY:s/a}}}return{firstY:m[0].pageValue,lastY:m.at(-1).pageValue}}function Z(e,m){let n=e.noise,i=e.z,f,o,t,l,r,p,u,b,h=i.length,s=i[0].length,a,c,d,A,y=e.minX,N=(e.maxX-y)/(s-1),C=e.minY,X=(e.maxY-C)/(h-1),M=e.minZ,S=e.maxZ,Y=m.nbContourLevels*2,R=new Array(Y),x;for(let F=0;F<Y;F++){let U={};R[F]=U;let le=F%2,K=(S-m.noiseMultiplier*n)*Math.exp((F>>1)-m.nbContourLevels);le===0?x=K+m.noiseMultiplier*n:x=0-K-m.noiseMultiplier*n;let D=[];if(U.zValue=x,U.lines=D,!(x<=M||x>=S))for(let v=0;v<h-1;v++){let Q=i[v],_=i[v+1];for(let T=0;T<s-1;T++)f=Q[T],o=Q[T+1],t=_[T],l=_[T+1],r=f>x,p=o>x,u=t>x,b=l>x,r!==p&&r!==u&&(a=T+(x-f)/(o-f),c=v,d=T,A=v+(x-f)/(t-f),D.push(a*N+y,c*X+C,d*N+y,A*X+C)),b!==p&&b!==u&&(a=T+1,c=v+1-(x-l)/(o-l),d=T+1-(x-l)/(t-l),A=v+1,D.push(a*N+y,c*X+C,d*N+y,A*X+C)),p!==u&&(a=(T+1-(x-o)/(t-o))*N+y,c=(v+(x-o)/(t-o))*X+C,p!==r&&(d=T+1-(x-o)/(f-o),A=v,D.push(a,c,d*N+y,A*X+C)),u!==r&&(d=T,A=v+1-(x-t)/(f-t),D.push(a,c,d*N+y,A*X+C)),p!==b&&(d=T+1,A=v+(x-o)/(l-o),D.push(a,c,d*N+y,A*X+C)),u!==b&&(d=T+(x-t)/(l-t),A=v+1,D.push(a,c,d*N+y,A*X+C)))}}return{minX:e.minX,maxX:e.maxX,minY:e.minY,maxY:e.maxY,segments:R}}function G(e,m){let n=j(e);m.noContour||(e.contourLines=Z(n,m),delete n.z),e.minMax=n}import{getGyromagneticRatio as W}from"gyromagnetic-ratio";function H(e,m){for(let n of e){let i=0,f=0;for(let o of n.spectra){if(n.ntuples?.symbol?(!i&&o.observeFrequency&&(i=o.observeFrequency),!f&&o.shiftOffsetVal&&(f=o.shiftOffsetVal)):(i=o.observeFrequency,f=o.shiftOffsetVal),i&&o.xUnits?.toUpperCase().includes("HZ")&&(o.xUnits="PPM",o.xFactor=o.xFactor!==void 0?o.xFactor/i:void 0,o.firstX=o.firstX!==void 0?o.firstX/i:void 0,o.lastX=o.lastX!==void 0?o.lastX/i:void 0,o.deltaX=o.deltaX!==void 0?o.deltaX/i:void 0,o.data))for(let t=0;t<o.data.x.length;t++)o.data.x[t]/=i;if(f&&o.xUnits.toLowerCase().includes("ppm")&&o.firstX!==void 0&&o.lastX!==void 0){let t=o.firstX-f;if(o.firstX=o.firstX-t,o.lastX=o.lastX-t,o.data)for(let l=0;l<o.data.x.length;l++)o.data.x[l]-=t}if(n.ntuples?.nucleus&&n.ntuples.symbol)for(let t=0;t<n.ntuples.nucleus.length;t++){let l=n.ntuples.symbol[t],r=n.ntuples.nucleus[t];if(l.match(/^[F|T]/)&&!r){if(l.match(/[F|T]1/))if(n.tmp.$NUC2&&typeof n.tmp.$NUC2=="string")n.ntuples.nucleus[t]=n.tmp.$NUC2;else{let p=n.ntuples.symbol.indexOf(l.replace(/^([F|T]).*/,"$12"));p&&n.ntuples.nucleus[p]&&(n.ntuples.nucleus[t]=n.ntuples.nucleus[p])}l.match(/[F|T]2/)&&typeof n.tmp.$NUC1=="string"&&(n.ntuples.nucleus[t]=n.tmp.$NUC1)}l.match(/[F|T]2/)&&(n.yType=n.ntuples.nucleus[0],n.xType&&!W(n.xType)&&(n.xType=n.ntuples.nucleus[1]))}if(i&&n.ntuples?.symbol&&n.ntuples.nucleus){let t="",l=n.ntuples.symbol.indexOf(o.pageSymbol);n.ntuples.units?.[l]&&(t=n.ntuples.units[l]);let{nucleus:r}=n.ntuples;if(!t.toLowerCase().match(/(ppm|seconds)/)&&r.length>1){if(l!==0){let h="Not sure about this ntuples format";if(m){m.warn(h);continue}else throw new Error(h)}let{nucleus:p}=n.ntuples,u=W(p[0]),b=W(p[1]);if(!u||!b){let h=`Problem with determination of gyromagnetic ratio for ${p.join("-")}`;if(m)m.error(h);else throw new Error(h)}else{let h=u/b*i;o.pageValue/=h}}}}}}function J(e){let m=e.spectra[0].data;e.chromatogram={times:m.x.slice(),series:{intensity:{dimension:1,data:m.y.slice()}}}}function q(e,m,n){H(e,n.logger),de(e,n);for(let i of e){if(Object.keys(i.ntuples).length>0){let f=[],o=Object.keys(i.ntuples);for(let t of o){let l=i.ntuples[t];if(l)for(let r=0;r<l.length;r++)f[r]||(f[r]={}),f[r][t]=l[r]}i.ntuples=f}i.twoD&&n.wantXY&&(G(i,n),n.logger?.trace({profiling:!0},"Finished countour plot calculation"),n.keepSpectra||delete i.spectra),n.chromatogram&&(i.spectra.length>1?te(i):J(i),n.logger?.trace({profiling:!0},"Finished chromatogram calculation")),delete i.tmp}}function de(e,m){for(let n of e)for(let i in n.meta){let f=n.meta[i];if(typeof f=="string"){if(f.startsWith("{")){if(!f.includes(":")&&f.endsWith("}")){let o=f.slice(1,-1).split(/[,; ]+/).filter(Boolean);for(let t=0;t<o.length;t++)n.meta[i+String(t)]=m.dynamicTyping?ae(o[t]):o[t]}}else if(f.startsWith("(")){let o=f.split(/\r?\n/),t=/^\((?<from>\d+)\.\.(?<to>\d+)\).*$/;if(t.test(o[0])){let[l,r]=o[0].match(t)?.slice(1).map(Number)??[],p=o.slice(1).join(" ").split(/[,; ]+/).filter(Boolean);for(let u=l;u<=r;u++)m.dynamicTyping&&typeof p[u-l]=="string"?n.meta[i+String(u)]=ae(p[u-l]):n.meta[i+String(u)]=p[u-l]}}}}}function z(e,m,n){let i=-1,f=-1,o="",t="";if(n.indexOf("++")>0)o=n.replace(/.*\(([a-zA-Z0-9]+)\+\+.*/,"$1"),t=n.replace(/.*\.\.([a-zA-Z0-9]+).*/,"$1");else{n=n.replaceAll(/[^a-zA-Z%]/g,""),o=n.charAt(0),t=n.charAt(1),m.variables={};for(let l of n){let r=l.toLowerCase(),p=e.ntuples.symbol?.indexOf(l)||0;if(p===-1)throw new Error(`Symbol undefined: ${l}`);m.variables[r]={};for(let u in e.ntuples)e.ntuples[u]?.[p]&&(m.variables[r][u.replace(/^var/,"")]=e.ntuples[u]?.[p])}}i=e.ntuples.symbol?.indexOf(o)??-1,f=e.ntuples.symbol?.indexOf(t)??-1,i===-1&&(i=0),f===-1&&(f=0),e.ntuples.first&&(e.ntuples.first.length>i&&(m.firstX=e.ntuples.first[i]),e.ntuples.first.length>f&&(m.firstY=e.ntuples.first[f])),e.ntuples.last&&(e.ntuples.last.length>i&&(m.lastX=e.ntuples.last[i]),e.ntuples.last.length>f&&(m.lastY=e.ntuples.last[f])),e.ntuples.vardim&&e.ntuples.vardim.length>i&&(m.nbPoints=e.ntuples.vardim[i]),e.ntuples.factor&&(e.ntuples.factor.length>i&&(m.xFactor=e.ntuples.factor[i]),e.ntuples.factor.length>f&&(m.yFactor=e.ntuples.factor[f])),e.ntuples.units&&(e.ntuples.units.length>i&&(e.ntuples.varname?.[i]?m.xUnits=`${e.ntuples.varname[i]} [${e.ntuples.units[i]}]`:m.xUnits=e.ntuples.units[i]),e.ntuples.units.length>f&&(e.ntuples.varname?.[f]?m.yUnits=`${e.ntuples.varname[f]} [${e.ntuples.units[f]}]`:m.yUnits=e.ntuples.units[f]))}function w(e){e.xFactor||(e.xFactor=1),e.yFactor||(e.yFactor=1)}var L=/[ \t]*,[ \t]*/,he={keepRecordsRegExp:/^$/,canonicDataLabels:!0,canonicMetadataLabels:!1,dynamicTyping:!0,withoutXY:!1,noTrimRegExp:/^$/,chromatogram:!1,keepSpectra:!1,noContour:!1,nbContourLevels:7,noiseMultiplier:5};function xe(e,m={}){e=ge(e);let n={...he,...m};n.logger?.debug("Starting jcamp conversion"),n.wantXY=!n.withoutXY,n.start=Date.now();let i=[],f={entries:[],flatten:[]},o={children:[],spectra:[],ntuples:{},info:{},meta:{},tmp:{}},t=o,l=[],r={data:{}};n.logger?.trace({profiling:!0},"Before split to LDRS");let p=e.replaceAll(/[\r\n]+##/g,`
|
|
6
6
|
##`).split(`
|
|
7
|
-
##`);
|
|
8
|
-
`);if(
|
|
7
|
+
##`);n.logger?.trace({profiling:!0},"Split to LDRS"),p[0]&&(p[0]=p[0].replace(/^[\r\n ]*##/,""));for(let u of p){let b=u.indexOf("="),h=b>0?u.slice(0,Math.max(0,b)):u,s=b>0?h.match(n.noTrimRegExp)?u.slice(Math.max(0,b+1)):u.slice(Math.max(0,b+1)).trim():"",a=h.replaceAll(/[_ -]/g,"").toUpperCase();if(a==="DATATABLE"){let c=s.indexOf(`
|
|
8
|
+
`);if(c===-1&&(c=s.indexOf("\r")),c>0){let d=s.slice(0,Math.max(0,c)).split(/[ ,;\t]+/);z(t,r,d[0]),r.datatable=d[0],d[1]?.includes("PEAKS")?a="PEAKTABLE":d[1]&&(d[1].indexOf("XYDATA")||d[0].indexOf("++")>0)&&(a="XYDATA",r.nbPoints&&r.lastX!==void 0&&r.firstX!==void 0&&(r.deltaX=(r.lastX-r.firstX)/(r.nbPoints-1)))}}if(a==="XYDATA"){n.wantXY&&(w(r),s.match(/.*\+\+.*/)?(r.nbPoints&&r.lastX!==void 0&&r.firstX!==void 0&&(r.deltaX=(r.lastX-r.firstX)/(r.nbPoints-1)),V(r,s,n)):P(r,s,n),t?.spectra.push(r),r={data:{}});continue}else if(a==="PEAKTABLE"){n.wantXY&&(w(r),P(r,s,n),t?.spectra.push(r),r={data:{}});continue}if(a==="PEAKASSIGNMENTS"){n.wantXY&&(s.match(/.*[^A-Z]*.*/)&&B(r,s),t?.spectra.push(r),r={data:{}});continue}if(s=s.split(/\r?\n/).map(c=>c.replace(/ *\$\$.*$/,"")).join(`
|
|
9
|
+
`),a==="TITLE"){let c=t;c.children||(c.children=[]),t={spectra:[],ntuples:{},info:{},meta:{},tmp:{}},c.children.push(t),l.push(c),i.push(t),t.title=s}else a==="DATATYPE"?(t.dataType=s,s.match(/^nd|\snd\s/i)&&(t.twoD=!0)):a==="NTUPLES"?s.match(/^nd|\snd\s/i)&&(t.twoD=!0):a==="DATACLASS"?t.dataClass=s:a==="JCAMPDX"?t.jcampDX=O(s):a==="JCAMPCS"?t.jcampCS=O(s):a==="XUNITS"?r.xUnits=s:a==="YUNITS"?r.yUnits=s:a==="FIRSTX"?r.firstX=Number(s):a==="LASTX"?r.lastX=Number(s):a==="FIRSTY"?r.firstY=Number(s):a==="LASTY"?r.lastY=Number(s):a==="NPOINTS"?r.nbPoints=Number(s):a==="XFACTOR"?r.xFactor=Number(s):a==="YFACTOR"?r.yFactor=Number(s):a==="MAXX"?r.maxX=Number(s):a==="MINX"?r.minX=Number(s):a==="MAXY"?r.maxY=Number(s):a==="MINY"?r.minY=Number(s):a==="DELTAX"?r.deltaX=Number(s):a===".OBSERVEFREQUENCY"||a==="$SFO1"?r.observeFrequency||(r.observeFrequency=Number(s)):a===".OBSERVENUCLEUS"?r.xType||(t.xType=s.replaceAll(/[^a-zA-Z0-9]/g,"")):a==="$OFFSET"?(t.shiftOffsetNum=0,r.shiftOffsetVal||(r.shiftOffsetVal=Number(s))):a==="$REFERENCEPOINT"||(a==="VARNAME"?t.ntuples.varname=s.split(L):a==="SYMBOL"?t.ntuples.symbol=s.split(L):a==="VARTYPE"?t.ntuples.vartype=s.split(L):a==="VARFORM"?t.ntuples.varform=s.split(L):a==="VARDIM"?t.ntuples.vardim=E(s.split(L)):a==="UNITS"?t.ntuples.units=s.split(L):a==="FACTOR"?t.ntuples.factor=E(s.split(L)):a==="FIRST"?t.ntuples.first=E(s.split(L)):a==="LAST"?t.ntuples.last=E(s.split(L)):a==="MIN"?t.ntuples.min=E(s.split(L)):a==="MAX"?t.ntuples.max=E(s.split(L)):a===".NUCLEUS"?t.ntuples&&(t.ntuples.nucleus=s.split(L).map(c=>c.replaceAll(/[^a-zA-Z0-9]/g,""))):a==="PAGE"?(r.page=s.trim(),r.pageValue=Number(s.replace(/^.*=/,"")),r.pageSymbol=r.page.replace(/[=].*/,"")):a==="RETENTIONTIME"?r.pageValue=Number(s):ne(a)?r[k(a)]=s:a==="SAMPLEDESCRIPTION"?r.sampleDescription=s:a.startsWith("$NUC")?!t.tmp[a]&&!s.includes("off")&&(t.tmp[a]=s.replaceAll(/[<>]/g,"")):a==="END"&&(t=l.pop()));if(t?.info&&t.meta&&a.match(n.keepRecordsRegExp)){let c,d;h.startsWith("$")?(d=n.canonicMetadataLabels?a.slice(1):h.slice(1),c=t.meta):(d=n.canonicDataLabels?a:h,c=t.info),n.dynamicTyping&&(s=be(s)),c[d]?(Array.isArray(c[d])||(c[d]=[c[d]]),c[d].push(s)):c[d]=s}}if(n.logger?.trace({profiling:!0},"Finished parsing"),q(i,f,n),n.logger?.trace({profiling:!0},"Total time"),f.entries=o.children||[],f.flatten=i,n.logger){n.logger.debug("Finished jcamp conversion");for(let u of f.flatten)n.logger.debug(`${u.dataType} - ${u.title}`)}return f}function ye(e,m){let{logger:n,OCL:i}=m;if(!e.info.ATOMLIST||!e.info.BONDLIST){n?.warn("No ATOMLIST or BONDLIST in the JCAMP-CS entry");return}Te(e,n);let f=Se(e.info.ATOMLIST),o=Ne(e.info.BONDLIST),t=Ce(e.info.CHARGE,n),l=Ae(i,f,o,t,n);return{molecule:l,molfile:l.toMolfile()}}function Ae(e,m,n,i,f){let o={S:e.Molecule.cBondTypeSingle,D:e.Molecule.cBondTypeDouble,T:e.Molecule.cBondTypeTriple,Q:e.Molecule.cBondTypeQuadruple},t={},l=new e.Molecule(m.length,n.length);for(let r of m){let p=e.Molecule.getAtomicNoFromLabel(r.element);p||(f?.error(`Atomic number of ${r.element} could not be determined`),p=e.Molecule.getAtomicNoFromLabel("X")),t[r.atomNumber]=l.addAtom(p),l.setAtomMapNo(t[r.atomNumber],r.atomNumber,!1)}for(let r of n){if(t[r.atomNumber1]===void 0){f?.error(`A bond goes to atomNumber ${r.atomNumber1} that does not exists`);continue}if(t[r.atomNumber2]===void 0){f?.error(`A bond goes to atomNumber ${r.atomNumber2} that does not exists`);continue}let p=l.addBond(t[r.atomNumber1],t[r.atomNumber2]);l.setBondType(p,o[r.bondType])}for(let r of i){if(t[r.atomNumber]===void 0){f?.error(`A charge goes to atomNumber ${r.atomNumber} that does not exists`);continue}l.setAtomCharge(t[r.atomNumber],r.value)}return l}function Se(e){let m=e.split(/\r?\n/).map(i=>O(i)).filter(Boolean),n=[];for(let i of m){let[f,o,t]=i.trim().split(/\s+/);n.push({atomNumber:Number(f),element:o,nbImplicitHydrogens:t?.length>0?Number(t):void 0})}return n}function Ne(e){let m=e.split(/\r?\n/).map(i=>O(i)).filter(Boolean),n=[];for(let i of m){let[f,o,t]=i.trim().split(/\s+/);n.push({atomNumber1:Number(f),atomNumber2:Number(o),bondType:t})}return n}function Ce(e,m){if(!e)return[];let n=e.split(/\r?\n/).map(f=>O(f)).filter(Boolean),i=[];for(let f of n){let[o,t,l]=f.trim().split(/\s+/);l!==void 0&&m?.warn("Charge on multiple atom is not supported"),i.push({atomNumber:Number(t),value:Number(o)})}return i}function Te(e,m){let n=["STEREOPAIR","STEREOCENTER","RADICAL","STEREOMOLECULE"];for(let i of n)e.info[i]&&m?.warn(`JCAMP-CS parser do not support: ${i}`)}export{xe as convert,me as createTree,ye as parseJcampCS};
|
package/package.json
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jcampconverter",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "10.0.0",
|
|
4
4
|
"description": "Parse and convert JCAMP data",
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
"keywords": [
|
|
6
|
+
"jcamp",
|
|
7
|
+
"converter"
|
|
8
|
+
],
|
|
9
|
+
"author": "Luc Patiny",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"types": "./jcampconverter.d.ts",
|
|
12
|
+
"require": "./jcampconverter.cjs",
|
|
13
|
+
"module": "./jcampconverter.mjs",
|
|
8
14
|
"exports": {
|
|
9
15
|
".": {
|
|
10
16
|
"types": "./jcampconverter.d.ts",
|
|
@@ -19,63 +25,53 @@
|
|
|
19
25
|
],
|
|
20
26
|
"scripts": {
|
|
21
27
|
"api-extractor": "api-extractor run --local",
|
|
22
|
-
"
|
|
28
|
+
"benchmark": "node benchmark/benchmark.js",
|
|
29
|
+
"build": "tsc --project tsconfig.cheminfo-build.json && cheminfo-build --entry lib/index.js --root JcampConverter --no-source-map && rm dist/jcampconverter.js",
|
|
23
30
|
"bundle": "npm run bundle-cjs && npm run bundle-esm",
|
|
24
|
-
"bundle-common": "esbuild src/index.
|
|
31
|
+
"bundle-common": "esbuild src/index.ts --bundle --packages=external --minify",
|
|
25
32
|
"bundle-cjs": "npm run bundle-common -- --format=cjs --outfile=jcampconverter.cjs",
|
|
26
33
|
"bundle-esm": "npm run bundle-common -- --format=esm --outfile=jcampconverter.mjs",
|
|
27
34
|
"bundle-types": "npm run tsc && npm run api-extractor",
|
|
28
35
|
"check-types": "tsc --noEmit",
|
|
29
|
-
"clean": "rimraf dist types",
|
|
36
|
+
"clean": "rimraf dist lib types",
|
|
37
|
+
"deopt": "node --trace-opt --trace-deopt --code-comments debug/deoptimize.js > deopt.log",
|
|
38
|
+
"hydra": "node --trace-hydrogen --trace-phase=Z --trace-deopt --code-comments --hydrogen-track-positions --redirect-code-traces --redirect-code-traces-to=code.asm debug/deoptimize.js",
|
|
30
39
|
"eslint": "eslint src __tests__",
|
|
31
40
|
"eslint-fix": "npm run eslint -- --fix",
|
|
32
41
|
"jscpd": "jscpd -l 10 -i \"**/__tests__/**\" -t 1 src",
|
|
33
42
|
"prepack": "npm run bundle && npm run bundle-types",
|
|
34
|
-
"prettier": "prettier --check src",
|
|
35
|
-
"prettier-write": "prettier --write src",
|
|
36
|
-
"test": "npm run test-only && npm run
|
|
37
|
-
"test-only": "vitest run --
|
|
38
|
-
"tsc": "tsc --project tsconfig.types.json"
|
|
39
|
-
"benchmark": "node benchmark/benchmark.js",
|
|
40
|
-
"deopt": "node --trace-opt --trace-deopt --code-comments debug/deoptimize.js > deopt.log",
|
|
41
|
-
"hydra": "node --trace-hydrogen --trace-phase=Z --trace-deopt --code-comments --hydrogen-track-positions --redirect-code-traces --redirect-code-traces-to=code.asm debug/deoptimize.js"
|
|
43
|
+
"prettier": "prettier --check src __tests__",
|
|
44
|
+
"prettier-write": "prettier --write src __tests__",
|
|
45
|
+
"test": "npm run test-only && npm run check-types && npm run eslint && npm run prettier",
|
|
46
|
+
"test-only": "vitest run --coverage",
|
|
47
|
+
"tsc": "tsc --project tsconfig.types.json"
|
|
42
48
|
},
|
|
43
|
-
"keywords": [
|
|
44
|
-
"jcamp",
|
|
45
|
-
"converter"
|
|
46
|
-
],
|
|
47
|
-
"author": "Luc Patiny",
|
|
48
|
-
"license": "MIT",
|
|
49
49
|
"bugs": {
|
|
50
50
|
"url": "https://github.com/cheminfo/nmrium/issues/new?title=%5Bjcampconverter%5D"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@microsoft/api-extractor": "^7.
|
|
54
|
-
"@
|
|
55
|
-
"@types/pino": "^7.0.5",
|
|
56
|
-
"@vitest/coverage-v8": "^1.3.1",
|
|
53
|
+
"@microsoft/api-extractor": "^7.47.10",
|
|
54
|
+
"@vitest/coverage-v8": "^2.1.3",
|
|
57
55
|
"benchmark": "^2.1.4",
|
|
58
|
-
"c8": "^9.1.0",
|
|
59
56
|
"cheminfo-build": "^1.2.0",
|
|
60
|
-
"esbuild": "^0.
|
|
61
|
-
"eslint": "^
|
|
62
|
-
"eslint-config-cheminfo-typescript": "^
|
|
63
|
-
"
|
|
64
|
-
"fifo-logger": "^0.6.1",
|
|
57
|
+
"esbuild": "^0.24.0",
|
|
58
|
+
"eslint": "^9.12.0",
|
|
59
|
+
"eslint-config-cheminfo-typescript": "^16.0.0",
|
|
60
|
+
"fifo-logger": "^1.0.0",
|
|
65
61
|
"jest-matcher-deep-close-to": "^3.0.2",
|
|
66
|
-
"jscpd": "^
|
|
67
|
-
"ml-spectra-processing": "^14.
|
|
68
|
-
"openchemlib": "^8.
|
|
69
|
-
"prettier": "^3.
|
|
70
|
-
"rimraf": "^
|
|
71
|
-
"typescript": "^5.
|
|
72
|
-
"vitest": "^1.3
|
|
62
|
+
"jscpd": "^4.0.5",
|
|
63
|
+
"ml-spectra-processing": "^14.6.0",
|
|
64
|
+
"openchemlib": "^8.15.0",
|
|
65
|
+
"prettier": "^3.3.3",
|
|
66
|
+
"rimraf": "^6.0.1",
|
|
67
|
+
"typescript": "^5.6.3",
|
|
68
|
+
"vitest": "^2.1.3"
|
|
73
69
|
},
|
|
74
70
|
"dependencies": {
|
|
75
|
-
"cheminfo-types": "^1.
|
|
76
|
-
"dynamic-typing": "^1.0.
|
|
71
|
+
"cheminfo-types": "^1.8.0",
|
|
72
|
+
"dynamic-typing": "^1.0.1",
|
|
77
73
|
"ensure-string": "^1.2.0",
|
|
78
|
-
"gyromagnetic-ratio": "^1.
|
|
74
|
+
"gyromagnetic-ratio": "^1.2.0",
|
|
79
75
|
"ml-array-median": "^1.1.6"
|
|
80
76
|
}
|
|
81
77
|
}
|