Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

mf-parser

Package Overview
Dependencies
Maintainers
6
Versions
73
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mf-parser - npm Package Compare versions

Comparing version 0.6.3 to 0.6.4

9

package.json
{
"name": "mf-parser",
"version": "0.6.3",
"version": "0.6.4",
"description": "",

@@ -21,6 +21,7 @@ "main": "src/index.js",

"dependencies": {
"atom-sorter": "^0.6.3",
"chemical-elements": "^0.6.3",
"mf-utilities": "^0.6.3"
"atom-sorter": "^0.6.4",
"chemical-elements": "^0.6.4",
"chemical-groups": "^0.6.4",
"mf-utilities": "^0.6.4"
}
}

@@ -6,258 +6,279 @@ 'use strict';

test('MF of C', () => {
var mf = new MF('C');
var parts = mf.toParts();
var mf = new MF('C');
var parts = mf.toParts();
expect(parts).toEqual([[{ kind: 'atom', value: 'C', multiplier: 1 }]]);
expect(parts).toEqual([[{ kind: 'atom', value: 'C', multiplier: 1 }]]);
var newMF = mf.toMF();
expect(newMF).toBe('C');
var newMF = mf.toMF();
expect(newMF).toBe('C');
mf.canonize();
let html = mf.toHtml();
mf.canonize();
let html = mf.toHtml();
expect(html).toBe('C');
expect(html).toBe('C');
let info = mf.getInfo();
let info = mf.getInfo();
expect(info).toEqual({
monoisotopicMass: 12,
mass: 12.010735896735248,
charge: 0,
unsaturation: 2,
mf: 'C',
atoms: {
C: 1
}
});
expect(info).toEqual({
monoisotopicMass: 12,
mass: 12.010735896735248,
charge: 0,
unsaturation: 2,
mf: 'C',
atoms: {
C: 1
}
});
});
test('MF of Et3N.HCl', () => {
var mf = new MF('Et3N.HCl');
var parts = mf.toParts();
var mf = new MF('Et3N.HCl');
var parts = mf.toParts();
expect(parts).toEqual([
[
{ kind: 'atom', value: 'C', multiplier: 6 },
{ kind: 'atom', value: 'H', multiplier: 15 },
{ kind: 'atom', value: 'N', multiplier: 1 }
],
[
{ kind: 'atom', value: 'H', multiplier: 1 },
{ kind: 'atom', value: 'Cl', multiplier: 1 }
]
]);
expect(parts).toEqual([
[
{ kind: 'atom', value: 'C', multiplier: 6 },
{ kind: 'atom', value: 'H', multiplier: 15 },
{ kind: 'atom', value: 'N', multiplier: 1 }
],
[
{ kind: 'atom', value: 'H', multiplier: 1 },
{ kind: 'atom', value: 'Cl', multiplier: 1 }
]
]);
var newMF = mf.toMF();
expect(newMF).toBe('C6H15N.HCl');
var newMF = mf.toMF();
expect(newMF).toBe('C6H15N.HCl');
mf.canonize();
let html = mf.toHtml();
mf.canonize();
let html = mf.toHtml();
expect(html).toBe('C<sub>6</sub>H<sub>15</sub>N•HCl');
expect(html).toBe('C<sub>6</sub>H<sub>15</sub>N•HCl');
let info = mf.getInfo();
expect(info).toEqual({
parts: [
{
mass: 101.19022990269394,
monoisotopicMass: 101.12044948788001,
charge: 0,
mf: 'C6H15N',
unsaturation: 0,
atoms: { C: 6, H: 15, N: 1 }
},
{
mass: 36.460878336663775,
monoisotopicMass: 35.97667771423,
charge: 0,
mf: 'HCl',
unsaturation: 0,
atoms: { H: 1, Cl: 1 }
}
],
monoisotopicMass: 137.09712720211002,
mass: 137.6511082393577,
let info = mf.getInfo();
expect(info).toEqual({
parts: [
{
mass: 101.19022990269394,
monoisotopicMass: 101.12044948788001,
charge: 0,
mf: 'C6H15N.HCl'
});
mf: 'C6H15N',
unsaturation: 0,
atoms: { C: 6, H: 15, N: 1 }
},
{
mass: 36.460878336663775,
monoisotopicMass: 35.97667771423,
charge: 0,
mf: 'HCl',
unsaturation: 0,
atoms: { H: 1, Cl: 1 }
}
],
monoisotopicMass: 137.09712720211002,
mass: 137.6511082393577,
charge: 0,
mf: 'C6H15N.HCl'
});
});
test('MF of (Me2CH)3N no expand', () => {
var mf = new MF('(Me2CH)3N');
var parts = mf.toParts({ expand: false });
var mf = new MF('(Me2CH)3N');
var parts = mf.toParts({ expand: false });
expect(parts).toEqual([
[
{ kind: 'atom', value: 'C', multiplier: 3 },
{ kind: 'atom', value: 'H', multiplier: 3 },
{ kind: 'atom', value: 'Me', multiplier: 6 },
{ kind: 'atom', value: 'N', multiplier: 1 }
]
]);
expect(parts).toEqual([
[
{ kind: 'atom', value: 'C', multiplier: 3 },
{ kind: 'atom', value: 'H', multiplier: 3 },
{ kind: 'atom', value: 'Me', multiplier: 6 },
{ kind: 'atom', value: 'N', multiplier: 1 }
]
]);
var newMF = mf.toMF();
expect(newMF).toBe('C3H3Me6N');
var newMF = mf.toMF();
expect(newMF).toBe('C3H3Me6N');
let info = mf.getInfo();
expect(info).toEqual({
mass: 143.27008211723435,
monoisotopicMass: 143.16739968126,
charge: 0,
mf: 'C3H3Me6N',
unsaturation: 0,
atoms: { C: 3, H: 3, Me: 6, N: 1 }
});
let info = mf.getInfo();
expect(info).toEqual({
mass: 143.27008211723435,
monoisotopicMass: 143.16739968126,
charge: 0,
mf: 'C3H3Me6N',
unsaturation: 0,
atoms: { C: 3, H: 3, Me: 6, N: 1 }
});
});
test('MF of (Me2CH)3N with expand', () => {
var mf = new MF('(Me2CH)3N');
var parts = mf.toParts({ expand: true });
var mf = new MF('(Me2CH)3N');
var parts = mf.toParts({ expand: true });
expect(parts).toEqual([
[
{ kind: 'atom', value: 'C', multiplier: 9 },
{ kind: 'atom', value: 'H', multiplier: 21 },
{ kind: 'atom', value: 'N', multiplier: 1 }
]
]);
expect(parts).toEqual([
[
{ kind: 'atom', value: 'C', multiplier: 9 },
{ kind: 'atom', value: 'H', multiplier: 21 },
{ kind: 'atom', value: 'N', multiplier: 1 }
]
]);
var newMF = mf.toMF();
expect(newMF).toBe('C9H21N');
var newMF = mf.toMF();
expect(newMF).toBe('C9H21N');
let info = mf.getInfo();
expect(info).toEqual({
mass: 143.27008211723435,
monoisotopicMass: 143.16739968126,
charge: 0,
mf: 'C9H21N',
unsaturation: 0,
atoms: { C: 9, H: 21, N: 1 }
});
let info = mf.getInfo();
expect(info).toEqual({
mass: 143.27008211723435,
monoisotopicMass: 143.16739968126,
charge: 0,
mf: 'C9H21N',
unsaturation: 0,
atoms: { C: 9, H: 21, N: 1 }
});
});
test('MF of (+)SO4(+)(-2)2', () => {
var mf = new MF('(+)SO4(+)(-2)2');
var parts = mf.toParts();
var mf = new MF('(+)SO4(+)(-2)2');
var parts = mf.toParts();
expect(parts).toEqual([
[
{ kind: 'atom', value: 'O', multiplier: 4 },
{ kind: 'atom', value: 'S', multiplier: 1 },
{ kind: 'charge', value: -2 }
]
]);
expect(parts).toEqual([
[
{ kind: 'atom', value: 'O', multiplier: 4 },
{ kind: 'atom', value: 'S', multiplier: 1 },
{ kind: 'charge', value: -2 }
]
]);
var newMF = mf.toMF();
expect(newMF).toBe('O4S(-2)');
var newMF = mf.toMF();
expect(newMF).toBe('O4S(-2)');
let info = mf.getInfo({
customUnsaturations: {
S: 4
}
});
expect(info).toEqual({
monoisotopicMass: 95.95172965268,
mass: 96.06240710340018,
charge: -2,
observedMonoisotopicMass: 47.97641340624907,
mf: 'O4S(-2)',
unsaturation: 4,
atoms: { O: 4, S: 1 }
});
let info = mf.getInfo({
customUnsaturations: {
S: 4
}
});
expect(info).toEqual({
monoisotopicMass: 95.95172965268,
mass: 96.06240710340018,
charge: -2,
observedMonoisotopicMass: 47.97641340624907,
mf: 'O4S(-2)',
unsaturation: 4,
atoms: { O: 4, S: 1 }
});
});
test('test unsaturation with charges', () => {
expect(new MF('CH4').getInfo().unsaturation).toBe(0);
expect(new MF('C10H22O').getInfo().unsaturation).toBe(0);
expect(new MF('H+').getInfo().unsaturation).toBe(0);
expect(new MF('CO3(--)').getInfo().unsaturation).toBe(3);
expect(new MF('HO(-)').getInfo().unsaturation).toBe(1);
expect(new MF('F(-)').getInfo().unsaturation).toBe(1);
expect(new MF('Na+').getInfo().unsaturation).toBe(0);
expect(new MF('NH4+').getInfo().unsaturation).toBe(-1);
expect(new MF('CH4').getInfo().unsaturation).toBe(0);
expect(new MF('C10H22O').getInfo().unsaturation).toBe(0);
expect(new MF('H+').getInfo().unsaturation).toBe(0);
expect(new MF('CO3(--)').getInfo().unsaturation).toBe(3);
expect(new MF('HO(-)').getInfo().unsaturation).toBe(1);
expect(new MF('F(-)').getInfo().unsaturation).toBe(1);
expect(new MF('Na+').getInfo().unsaturation).toBe(0);
expect(new MF('NH4+').getInfo().unsaturation).toBe(-1);
});
test('MF of NC[13C][15N]2NN2', () => {
var mf = new MF('NC[13C][15N]2NN2');
var parts = mf.toParts();
expect(parts).toEqual([
[
{ kind: 'atom', value: 'C', multiplier: 1 },
{
kind: 'isotope',
value: { atom: 'C', isotope: 13 },
multiplier: 1
},
{ kind: 'atom', value: 'N', multiplier: 4 },
{
kind: 'isotope',
value: { atom: 'N', isotope: 15 },
multiplier: 2
}
]
]);
var mf = new MF('NC[13C][15N]2NN2');
var parts = mf.toParts();
expect(parts).toEqual([
[
{ kind: 'atom', value: 'C', multiplier: 1 },
{
kind: 'isotope',
value: { atom: 'C', isotope: 13 },
multiplier: 1
},
{ kind: 'atom', value: 'N', multiplier: 4 },
{
kind: 'isotope',
value: { atom: 'N', isotope: 15 },
multiplier: 2
}
]
]);
let info = mf.getInfo();
expect(info).toEqual({
monoisotopicMass: 111.01586865055,
mass: 111.04112137534844,
charge: 0,
mf: 'C[13C]N4[15N]2',
unsaturation: 6,
atoms: { C: 2, N: 6 }
});
let info = mf.getInfo();
expect(info).toEqual({
monoisotopicMass: 111.01586865055,
mass: 111.04112137534844,
charge: 0,
mf: 'C[13C]N4[15N]2',
unsaturation: 6,
atoms: { C: 2, N: 6 }
});
var newMF = mf.toMF();
expect(newMF).toBe('C[13C]N4[15N]2');
var newMF = mf.toMF();
expect(newMF).toBe('C[13C]N4[15N]2');
});
test('MF of DNA HODampDtmpDcmpDgmpH ', () => {
var mf = new MF('HODampDtmpDgmpDcmpH');
var info = mf.getInfo();
expect(info).toEqual({ mass: 1253.8043977028433,
monoisotopicMass: 1253.21310019311,
charge: 0,
mf: 'C39H51N15O25P4',
atoms: { C: 39, H: 51, N: 15, O: 25, P: 4 },
unsaturation: 24 });
var mf = new MF('HODampDtmpDgmpDcmpH');
var info = mf.getInfo();
expect(info).toEqual({
mass: 1253.8043977028433,
monoisotopicMass: 1253.21310019311,
charge: 0,
mf: 'C39H51N15O25P4',
atoms: { C: 39, H: 51, N: 15, O: 25, P: 4 },
unsaturation: 24
});
});
test('MF of RNA HOAmpUmpH ', () => {
var mf = new MF('HOAmpUmpH');
var info = mf.getInfo();
expect(info).toEqual({ mass: 653.388021231099,
monoisotopicMass: 653.08838712715,
charge: 0,
mf: 'C19H25N7O15P2',
atoms: { C: 19, H: 25, N: 7, O: 15, P: 2 },
unsaturation: 12 });
var mf = new MF('HOAmpUmpH');
var info = mf.getInfo();
expect(info).toEqual({
mass: 653.388021231099,
monoisotopicMass: 653.08838712715,
charge: 0,
mf: 'C19H25N7O15P2',
atoms: { C: 19, H: 25, N: 7, O: 15, P: 2 },
unsaturation: 12
});
});
test('MF of CC{50,50}H', () => {
var mf = new MF('HC{50,50}C');
var parts = mf.toParts();
expect(parts).toEqual([
[
{ kind: 'atom', value: 'C', multiplier: 1 },
{
kind: 'isotopeRatio',
value: { atom: 'C', ratio: [50, 50] },
multiplier: 1
},
{ kind: 'atom', value: 'H', multiplier: 1 }
]
]);
var mf = new MF('HC{50,50}C');
var parts = mf.toParts();
expect(parts).toEqual([
[
{ kind: 'atom', value: 'C', multiplier: 1 },
{
kind: 'isotopeRatio',
value: { atom: 'C', ratio: [50, 50] },
multiplier: 1
},
{ kind: 'atom', value: 'H', multiplier: 1 }
]
]);
var newMF = mf.toMF();
expect(newMF).toBe('CC{50,50}H');
var newMF = mf.toMF();
expect(newMF).toBe('CC{50,50}H');
let info = mf.getInfo();
expect(info).toEqual({
monoisotopicMass: 25.00782503223,
mass: 25.520354068326025,
charge: 0,
mf: 'CC{50,50}H',
unsaturation: 2.5,
atoms: { C: 2, H: 1 }
});
let info = mf.getInfo();
expect(info).toEqual({
monoisotopicMass: 25.00782503223,
mass: 25.520354068326025,
charge: 0,
mf: 'CC{50,50}H',
unsaturation: 2.5,
atoms: { C: 2, H: 1 }
});
});
test('MF of H(+)(H+)-1H', () => {
var mf = new MF('H(+)(H+)-1H');
var newMF = mf.toMF();
expect(newMF).toBe('H');
let info = mf.getInfo();
expect(info).toEqual({
atoms: { H: 1 },
charge: 0,
mass: 1.0079407540557772,
mf: 'H',
monoisotopicMass: 1.00782503223,
unsaturation: 0.5
});
});

@@ -5,3 +5,3 @@ 'use strict';

const elements = require('chemical-elements/src/elementsAndStableIsotopesObject.js');
const groups = require('chemical-elements/src/groupsObject.js');
const groups = require('chemical-groups/src/groupsObject.js');
const unsaturations = require('chemical-elements/src/unsaturationsObject.js');

@@ -20,144 +20,140 @@ const Kind = require('../Kind');

module.exports = function getInfo(parts, options = {}) {
let { customUnsaturations = {} } = options;
if (parts.length === 0) return {};
if (parts.length === 1) {
return getProcessedPart(parts[0], customUnsaturations);
}
let { customUnsaturations = {} } = options;
if (parts.length === 0) return {};
if (parts.length === 1) {
return getProcessedPart(parts[0], customUnsaturations);
}
var result = {
parts: []
};
for (let part of parts) {
result.parts.push(getProcessedPart(part, customUnsaturations));
}
var result = {
parts: []
};
for (let part of parts) {
result.parts.push(getProcessedPart(part, customUnsaturations));
}
result.monoisotopicMass = 0;
result.mass = 0;
result.charge = 0;
result.mf = result.parts.map((a) => a.mf).join('.');
result.parts.forEach((a) => {
result.mass += a.mass;
result.monoisotopicMass += a.monoisotopicMass;
result.charge += a.charge;
});
return result;
result.monoisotopicMass = 0;
result.mass = 0;
result.charge = 0;
result.mf = result.parts.map(a => a.mf).join('.');
result.parts.forEach(a => {
result.mass += a.mass;
result.monoisotopicMass += a.monoisotopicMass;
result.charge += a.charge;
});
return result;
};
function getProcessedPart(part, customUnsaturations) {
let currentPart = {
mass: 0,
monoisotopicMass: 0,
charge: 0,
mf: '',
atoms: partToAtoms(part)
};
let unsaturation = 0;
let validUnsaturation = true;
currentPart.mf = partToMF(part);
for (let line of part) {
let currentElement = '';
switch (line.kind) {
case Kind.ATOM: {
currentElement = line.value;
let element = elements[line.value];
// todo should we have a kind GROUP ?
if (!element) {
element = groups[line.value];
if (!element) throw Error(`Unknown element: ${line.value}`);
if (!customUnsaturations[line.value]) {
customUnsaturations[line.value] = element.unsaturation;
}
}
let currentPart = {
mass: 0,
monoisotopicMass: 0,
charge: 0,
mf: '',
atoms: partToAtoms(part)
};
let unsaturation = 0;
let validUnsaturation = true;
currentPart.mf = partToMF(part);
for (let line of part) {
let currentElement = '';
switch (line.kind) {
case Kind.ATOM: {
currentElement = line.value;
let element = elements[line.value];
// todo should we have a kind GROUP ?
if (!element) {
element = groups[line.value];
if (!element) throw Error(`Unknown element: ${line.value}`);
if (!customUnsaturations[line.value]) {
customUnsaturations[line.value] = element.unsaturation;
}
}
if (!element) throw new Error(`Unknown element: ${line.value}`);
currentPart.monoisotopicMass +=
element.monoisotopicMass * line.multiplier;
currentPart.mass += element.mass * line.multiplier;
break;
}
case Kind.ISOTOPE: {
currentElement = line.value.atom;
let isotope = isotopes[line.value.isotope + line.value.atom];
if (!isotope) {
throw new Error(
`Unknown isotope: ${line.value.isotope}${
line.value.atom
}`
);
}
currentPart.monoisotopicMass += isotope.mass * line.multiplier;
currentPart.mass += isotope.mass * line.multiplier;
break;
}
case Kind.ISOTOPE_RATIO: {
currentElement = line.value.atom;
let isotopeRatioInfo = getIsotopeRatioInfo(line.value);
currentPart.monoisotopicMass +=
isotopeRatioInfo.monoisotopicMass * line.multiplier;
currentPart.mass += isotopeRatioInfo.mass * line.multiplier;
break;
}
case Kind.CHARGE:
currentPart.charge = line.value;
if (validUnsaturation) {
unsaturation -= line.value;
}
break;
default:
throw new Error('Unimplemented Kind in getInfo', line.kind);
if (!element) throw new Error(`Unknown element: ${line.value}`);
currentPart.monoisotopicMass +=
element.monoisotopicMass * line.multiplier;
currentPart.mass += element.mass * line.multiplier;
break;
}
case Kind.ISOTOPE: {
currentElement = line.value.atom;
let isotope = isotopes[line.value.isotope + line.value.atom];
if (!isotope) {
throw new Error(
`Unknown isotope: ${line.value.isotope}${line.value.atom}`
);
}
if (currentElement) {
if (customUnsaturations[currentElement] !== undefined) {
unsaturation +=
customUnsaturations[currentElement] * line.multiplier;
} else if (unsaturations[currentElement] !== undefined) {
unsaturation += unsaturations[currentElement] * line.multiplier;
} else {
validUnsaturation = false;
}
currentPart.monoisotopicMass += isotope.mass * line.multiplier;
currentPart.mass += isotope.mass * line.multiplier;
break;
}
case Kind.ISOTOPE_RATIO: {
currentElement = line.value.atom;
let isotopeRatioInfo = getIsotopeRatioInfo(line.value);
currentPart.monoisotopicMass +=
isotopeRatioInfo.monoisotopicMass * line.multiplier;
currentPart.mass += isotopeRatioInfo.mass * line.multiplier;
break;
}
case Kind.CHARGE:
currentPart.charge = line.value;
if (validUnsaturation) {
unsaturation -= line.value;
}
break;
default:
throw new Error('Unimplemented Kind in getInfo', line.kind);
}
if (currentElement) {
if (customUnsaturations[currentElement] !== undefined) {
unsaturation += customUnsaturations[currentElement] * line.multiplier;
} else if (unsaturations[currentElement] !== undefined) {
unsaturation += unsaturations[currentElement] * line.multiplier;
} else {
validUnsaturation = false;
}
}
}
// need to calculate the observedMonoisotopicMass
if (currentPart.charge) {
currentPart.observedMonoisotopicMass =
(currentPart.monoisotopicMass -
currentPart.charge * ELECTRON_MASS) /
Math.abs(currentPart.charge);
}
if (validUnsaturation) {
currentPart.unsaturation = unsaturation / 2 + 1;
}
return currentPart;
// need to calculate the observedMonoisotopicMass
if (currentPart.charge) {
currentPart.observedMonoisotopicMass =
(currentPart.monoisotopicMass - currentPart.charge * ELECTRON_MASS) /
Math.abs(currentPart.charge);
}
if (validUnsaturation) {
currentPart.unsaturation = unsaturation / 2 + 1;
}
return currentPart;
}
function getIsotopeRatioInfo(value) {
let result = {
mass: 0,
monoisotopicMass: 0
};
let element = elements[value.atom];
if (!element) throw new Error(`Element not found: ${value.atom}`);
let isotopesArray = element.isotopes;
let ratios = normalize(value.ratio);
let max = Math.max(...ratios);
if (ratios.length > isotopesArray.length) {
throw new Error(
`the number of specified ratios is bigger that the number of stable isotopes: ${
value.atom
}`
);
let result = {
mass: 0,
monoisotopicMass: 0
};
let element = elements[value.atom];
if (!element) throw new Error(`Element not found: ${value.atom}`);
let isotopesArray = element.isotopes;
let ratios = normalize(value.ratio);
let max = Math.max(...ratios);
if (ratios.length > isotopesArray.length) {
throw new Error(
`the number of specified ratios is bigger that the number of stable isotopes: ${
value.atom
}`
);
}
for (let i = 0; i < ratios.length; i++) {
result.mass += ratios[i] * isotopesArray[i].mass;
if (max === ratios[i] && result.monoisotopicMass === 0) {
result.monoisotopicMass = isotopesArray[i].mass;
}
for (let i = 0; i < ratios.length; i++) {
result.mass += ratios[i] * isotopesArray[i].mass;
if (max === ratios[i] && result.monoisotopicMass === 0) {
result.monoisotopicMass = isotopesArray[i].mass;
}
}
return result;
}
return result;
}
function normalize(array) {
let sum = array.reduce((prev, current) => prev + current, 0);
return array.map((a) => a / sum);
let sum = array.reduce((prev, current) => prev + current, 0);
return array.map(a => a / sum);
}

@@ -5,23 +5,34 @@ 'use strict';

module.exports = function partToMF(part) {
var mf = [];
for (let line of part) {
switch (line.kind) {
case Kind.ISOTOPE:
mf.push(`[${line.value.isotope}${line.value.atom}]${(line.multiplier !== 1) ? line.multiplier : ''}`);
break;
case Kind.ISOTOPE_RATIO:
mf.push(`${line.value.atom}{${line.value.ratio.join(',')}}${(line.multiplier !== 1) ? line.multiplier : ''}`);
break;
case Kind.ATOM:
mf.push(line.value + ((line.multiplier !== 1) ? line.multiplier : ''));
break;
case Kind.CHARGE:
mf.push(`(${(line.value > 0) ? `+${line.value}` : line.value})`);
break;
default:
}
var mf = [];
for (let line of part) {
switch (line.kind) {
case Kind.ISOTOPE:
if (line.multiplier !== 0)
mf.push(
`[${line.value.isotope}${line.value.atom}]${
line.multiplier !== 1 ? line.multiplier : ''
}`
);
break;
case Kind.ISOTOPE_RATIO:
if (line.multiplier !== 0)
mf.push(
`${line.value.atom}{${line.value.ratio.join(',')}}${
line.multiplier !== 1 ? line.multiplier : ''
}`
);
break;
case Kind.ATOM:
if (line.multiplier !== 0)
mf.push(line.value + (line.multiplier !== 1 ? line.multiplier : ''));
break;
case Kind.CHARGE:
if (line.value === 0) break;
mf.push(`(${line.value > 0 ? `+${line.value}` : line.value})`);
break;
default:
}
return mf.join('');
}
return mf.join('');
};
'use strict';
const Kind = require('../Kind');
const groups = require('chemical-elements/src/groupsObject.js');
const groups = require('chemical-groups/src/groupsObject.js');
const atomSorter = require('atom-sorter');

@@ -15,217 +15,213 @@

module.exports = function toParts(lines, options = {}) {
const { expand: shouldExpandGroups = true } = options;
let parts = [];
const { expand: shouldExpandGroups = true } = options;
let parts = [];
let currentPart = createNewPart();
let previousKind = Kind.BEGIN;
parts.push(currentPart);
for (let line of lines) {
switch (line.kind) {
case Kind.OPENING_PARENTHESIS:
openingParenthesis(currentPart);
break;
case Kind.CLOSING_PARENTHESIS:
closingParenthesis(currentPart);
break;
case Kind.PRE_MULTIPLIER:
preMultiplier(currentPart, line);
break;
case Kind.MULTIPLIER:
postMultiplier(currentPart, line.value, previousKind);
break;
case Kind.SALT:
globalPartMultiplier(currentPart);
currentPart = createNewPart();
parts.push(currentPart);
break;
case Kind.ATOM:
case Kind.ISOTOPE_RATIO:
case Kind.ISOTOPE:
case Kind.CHARGE:
currentPart.lines.push(
Object.assign({}, line, { multiplier: 1 })
);
break;
case Kind.COMMENT: // we ignore comments to create the parts and canonized MF
break;
case Kind.TEXT:
break;
default:
throw new Error(`Can not process mf having: ${line.kind}`);
}
previousKind = line.kind;
let currentPart = createNewPart();
let previousKind = Kind.BEGIN;
parts.push(currentPart);
for (let line of lines) {
switch (line.kind) {
case Kind.OPENING_PARENTHESIS:
openingParenthesis(currentPart);
break;
case Kind.CLOSING_PARENTHESIS:
closingParenthesis(currentPart);
break;
case Kind.PRE_MULTIPLIER:
preMultiplier(currentPart, line);
break;
case Kind.MULTIPLIER:
postMultiplier(currentPart, line.value, previousKind);
break;
case Kind.SALT:
globalPartMultiplier(currentPart);
currentPart = createNewPart();
parts.push(currentPart);
break;
case Kind.ATOM:
case Kind.ISOTOPE_RATIO:
case Kind.ISOTOPE:
case Kind.CHARGE:
currentPart.lines.push(Object.assign({}, line, { multiplier: 1 }));
break;
case Kind.COMMENT: // we ignore comments to create the parts and canonized MF
break;
case Kind.TEXT:
break;
default:
throw new Error(`Can not process mf having: ${line.kind}`);
}
globalPartMultiplier(currentPart);
if (shouldExpandGroups) expandGroups(parts);
return combineAtomsIsotopesCharges(parts);
previousKind = line.kind;
}
globalPartMultiplier(currentPart);
if (shouldExpandGroups) expandGroups(parts);
return combineAtomsIsotopesCharges(parts);
};
function createNewPart() {
let currentMultiplier = { value: 1, fromIndex: 0 };
return {
lines: [],
multipliers: [currentMultiplier],
currentMultiplier
};
let currentMultiplier = { value: 1, fromIndex: 0 };
return {
lines: [],
multipliers: [currentMultiplier],
currentMultiplier
};
}
function openingParenthesis(currentPart) {
currentPart.currentMultiplier = {
value: 1,
fromIndex: currentPart.lines.length
};
currentPart.multipliers.push(currentPart.currentMultiplier);
currentPart.currentMultiplier = {
value: 1,
fromIndex: currentPart.lines.length
};
currentPart.multipliers.push(currentPart.currentMultiplier);
}
function closingParenthesis(currentPart) {
currentPart.currentMultiplier = currentPart.multipliers.pop();
if (currentPart.currentMultiplier !== 1) {
for (
let i = currentPart.currentMultiplier.fromIndex;
i < currentPart.lines.length;
i++
) {
currentPart.lines[i].multiplier *=
currentPart.currentMultiplier.value;
}
currentPart.currentMultiplier = currentPart.multipliers.pop();
if (currentPart.currentMultiplier !== 1) {
for (
let i = currentPart.currentMultiplier.fromIndex;
i < currentPart.lines.length;
i++
) {
currentPart.lines[i].multiplier *= currentPart.currentMultiplier.value;
}
}
}
function preMultiplier(currentPart, line) {
currentPart.currentMultiplier.value *= line.value;
currentPart.currentMultiplier.value *= line.value;
}
function globalPartMultiplier(currentPart) {
for (
let i = currentPart.multipliers[0].fromIndex;
i < currentPart.lines.length;
i++
) {
currentPart.lines[i].multiplier *= currentPart.multipliers[0].value;
}
for (
let i = currentPart.multipliers[0].fromIndex;
i < currentPart.lines.length;
i++
) {
currentPart.lines[i].multiplier *= currentPart.multipliers[0].value;
}
}
function postMultiplier(currentPart, value, previousKind) {
if (previousKind === Kind.CLOSING_PARENTHESIS) {
// need to apply to everything till the previous parenthesis
for (
let i = currentPart.currentMultiplier.fromIndex;
i < currentPart.lines.length;
i++
) {
currentPart.lines[i].multiplier *= value;
}
} else {
// just applies to the previous element
currentPart.lines[currentPart.lines.length - 1].multiplier *= value;
if (previousKind === Kind.CLOSING_PARENTHESIS) {
// need to apply to everything till the previous parenthesis
for (
let i = currentPart.currentMultiplier.fromIndex;
i < currentPart.lines.length;
i++
) {
currentPart.lines[i].multiplier *= value;
}
} else {
// just applies to the previous element
currentPart.lines[currentPart.lines.length - 1].multiplier *= value;
}
}
function expandGroups(parts) {
for (let part of parts) {
let expanded = false;
for (let i = 0; i < part.lines.length; i++) {
let line = part.lines[i];
if (line.kind === Kind.ATOM) {
let group = groups[line.value];
if (group) {
expanded = true;
for (let element of group.elements) {
part.lines.push({
kind: 'atom',
value: element.symbol,
multiplier: line.multiplier * element.number
});
}
part.lines[i] = undefined;
}
}
for (let part of parts) {
let expanded = false;
for (let i = 0; i < part.lines.length; i++) {
let line = part.lines[i];
if (line.kind === Kind.ATOM) {
let group = groups[line.value];
if (group) {
expanded = true;
for (let element of group.elements) {
part.lines.push({
kind: 'atom',
value: element.symbol,
multiplier: line.multiplier * element.number
});
}
part.lines[i] = undefined;
}
if (expanded) part.lines = part.lines.filter((a) => a);
}
}
if (expanded) part.lines = part.lines.filter(a => a);
}
}
function combineAtomsIsotopesCharges(parts) {
let results = [];
for (let part of parts) {
let result = [];
results.push(result);
calculateAndSortKeys(part);
let results = [];
for (let part of parts) {
let result = [];
results.push(result);
calculateAndSortKeys(part);
let currentKey = '';
for (let key of part.keys) {
if (key.key === Kind.CHARGE) {
if (currentKey !== key.key) {
result.push({
kind: Kind.CHARGE,
value: key.value.value * key.value.multiplier
});
} else {
result[result.length - 1].value +=
key.value.value * key.value.multiplier;
}
} else {
if (currentKey !== key.key) {
result.push(key.value);
} else {
result[result.length - 1].multiplier +=
key.value.multiplier;
}
}
currentKey = key.key;
let currentKey = '';
for (let key of part.keys) {
if (key.key === Kind.CHARGE) {
if (currentKey !== key.key) {
result.push({
kind: Kind.CHARGE,
value: key.value.value * key.value.multiplier
});
} else {
result[result.length - 1].value +=
key.value.value * key.value.multiplier;
}
} else {
if (currentKey !== key.key) {
result.push(key.value);
} else {
result[result.length - 1].multiplier += key.value.multiplier;
}
}
currentKey = key.key;
}
result.sort((a, b) => {
if (a.kind === Kind.CHARGE) return 1;
if (b.kind === Kind.CHARGE) return -1;
result.sort((a, b) => {
if (a.kind === Kind.CHARGE) return 1;
if (b.kind === Kind.CHARGE) return -1;
let atomA = a.kind === Kind.ATOM ? a.value : a.value.atom;
let atomB = b.kind === Kind.ATOM ? b.value : b.value.atom;
if (atomA !== atomB) return atomSorter(atomA, atomB);
// same atome but some isotopes ...
if (a.kind === Kind.ATOM) return -1;
if (b.kind === Kind.ATOM) return 1;
if (a.kind === Kind.ISOTOPE) return -1;
if (b.kind === Kind.ISOTOPE) return 1;
if (a.kind === Kind.ISOTOPE_RATIO) return -1;
if (b.kind === Kind.ISOTOPE_RATIO) return 1;
return 0;
});
}
return results;
let atomA = a.kind === Kind.ATOM ? a.value : a.value.atom;
let atomB = b.kind === Kind.ATOM ? b.value : b.value.atom;
if (atomA !== atomB) return atomSorter(atomA, atomB);
// same atome but some isotopes ...
if (a.kind === Kind.ATOM) return -1;
if (b.kind === Kind.ATOM) return 1;
if (a.kind === Kind.ISOTOPE) return -1;
if (b.kind === Kind.ISOTOPE) return 1;
if (a.kind === Kind.ISOTOPE_RATIO) return -1;
if (b.kind === Kind.ISOTOPE_RATIO) return 1;
return 0;
});
}
return results;
}
function calculateAndSortKeys(part) {
part.keys = [];
for (var line of part.lines) {
part.keys.push({
key: getKey(line),
value: line
});
}
part.keys.sort((a, b) => stringComparator(a.key, b.key));
part.keys = [];
for (var line of part.lines) {
part.keys.push({
key: getKey(line),
value: line
});
}
part.keys.sort((a, b) => stringComparator(a.key, b.key));
}
function getKey(line) {
let key = [line.kind];
let key = [line.kind];
switch (line.kind) {
case Kind.CHARGE:
break;
default:
if (typeof line.value === 'string') {
key.push(line.value);
} else {
for (let prop of Object.keys(line.value).sort()) {
key.push(line.value[prop]);
}
}
}
return key.join('-');
switch (line.kind) {
case Kind.CHARGE:
break;
default:
if (typeof line.value === 'string') {
key.push(line.value);
} else {
for (let prop of Object.keys(line.value).sort()) {
key.push(line.value[prop]);
}
}
}
return key.join('-');
}
function stringComparator(a, b) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc