mf-generator
Advanced tools
Comparing version 0.9.1 to 0.12.0
{ | ||
"name": "mf-generator", | ||
"version": "0.9.1", | ||
"version": "0.12.0", | ||
"description": "", | ||
@@ -21,9 +21,10 @@ "main": "src/index.js", | ||
"dependencies": { | ||
"chemical-elements": "^0.9.1", | ||
"mf-finder": "^0.9.1", | ||
"mf-matcher": "^0.9.1", | ||
"mf-parser": "^0.9.1", | ||
"mf-utilities": "^0.9.1", | ||
"chemical-elements": "^0.12.0", | ||
"mf-finder": "^0.12.0", | ||
"mf-matcher": "^0.12.0", | ||
"mf-parser": "^0.12.0", | ||
"mf-utilities": "^0.12.0", | ||
"sum-object-keys": "^1.0.2" | ||
} | ||
}, | ||
"gitHead": "aa2e6571c5f7121dda616b7d6920b7a653a8f9c7" | ||
} |
@@ -6,4 +6,4 @@ 'use strict'; | ||
test('generateMFs from array of array with comment', function () { | ||
var mfsArray = [['C', 'H$YY'], [], [''], ['Cl', 'Br$XX']]; | ||
var result = generateMFs(mfsArray); | ||
let mfsArray = [['C', 'H$YY'], [], [''], ['Cl', 'Br$XX']]; | ||
let result = generateMFs(mfsArray); | ||
expect(result[0].mf).toBe('HCl'); | ||
@@ -15,4 +15,4 @@ expect(result[0].comment).toBe('YY'); | ||
test('generateMFs from array of string with empty', function () { | ||
var mfsArray = ['C,H,', 'Cl,Br']; | ||
var result = generateMFs(mfsArray).map((entry) => entry.mf); | ||
let mfsArray = ['C,H,', 'Cl,Br']; | ||
let result = generateMFs(mfsArray).map((entry) => entry.mf); | ||
expect(result).toStrictEqual(['Cl', 'HCl', 'CCl', 'Br', 'HBr', 'CBr']); | ||
@@ -22,5 +22,5 @@ }); | ||
test('generateMFs from array of string with comment', function () { | ||
var mfsArray = ['C.H.O', '+,++', ['Cl', 'Br$XX']]; | ||
var result = generateMFs(mfsArray).sort((a, b) => a.em - b.em); | ||
expect(result[0].mf).toBe('HCl(+1)'); | ||
let mfsArray = ['C.H.O', '+,++', ['Cl', 'Br$XX']]; | ||
let result = generateMFs(mfsArray).sort((a, b) => a.ms.em - b.ms.em); | ||
expect(result[0].mf).toBe('HCl(+2)'); | ||
expect(result).toHaveLength(12); | ||
@@ -30,4 +30,4 @@ }); | ||
test('generateMFs from array of string with some range and non range', function () { | ||
var mfsArray = ['CN0-2']; | ||
var result = generateMFs(mfsArray); | ||
let mfsArray = ['CN0-2']; | ||
let result = generateMFs(mfsArray); | ||
expect(result[0].mf).toBe('C'); | ||
@@ -40,4 +40,4 @@ expect(result[1].mf).toBe('CN'); | ||
test('From array of string with some range and non range CN0-2O00-1K', function () { | ||
var mfsArray = ['CN0-2O00-1K']; | ||
var result = generateMFs(mfsArray); | ||
let mfsArray = ['CN0-2O00-1K']; | ||
let result = generateMFs(mfsArray); | ||
expect(result[0].mf).toBe('CK'); | ||
@@ -53,4 +53,4 @@ expect(result[1].mf).toBe('CKN'); | ||
test('From array of string with some range and non range NaK0-2', function () { | ||
var mfsArray = ['NaK0-2']; | ||
var result = generateMFs(mfsArray); | ||
let mfsArray = ['NaK0-2']; | ||
let result = generateMFs(mfsArray); | ||
expect(result[0].mf).toBe('Na'); | ||
@@ -63,4 +63,4 @@ expect(result[1].mf).toBe('KNa'); | ||
test('From array of string with some range and non range C(Me(N2))0-2(CH3)0-1K', function () { | ||
var mfsArray = ['C(Me(N2))0-2(CH3)0-1K']; | ||
var result = generateMFs(mfsArray, { canonizeMF: false, uniqueMFs: false }); | ||
let mfsArray = ['C(Me(N2))0-2(CH3)0-1K']; | ||
let result = generateMFs(mfsArray, { canonizeMF: false, uniqueMFs: false }); | ||
expect(result[0].mf).toBe('CK'); | ||
@@ -76,4 +76,4 @@ expect(result[1].mf).toBe('C(CH3)K'); | ||
test('From array of string with some range', function () { | ||
var mfsArray = ['C1-3N0-2Cl0-0BrO1-1.C2-3H3-4', ['C', 'O']]; | ||
var result = generateMFs(mfsArray, { canonizeMF: true }); | ||
let mfsArray = ['C1-3N0-2Cl0-0BrO1-1.C2-3H3-4', ['C', 'O']]; | ||
let result = generateMFs(mfsArray, { canonizeMF: true }); | ||
expect(result[0].mf).toBe('C3H3'); | ||
@@ -84,5 +84,5 @@ expect(result).toHaveLength(26); | ||
test('From array of string chem em and msem', function () { | ||
var mfsArray = ['C0-2.O', ['+', '(-)', '++', '(--)']]; | ||
let mfsArray = ['C0-2.O', ['+', '(-)', '++', '(--)']]; | ||
var result = generateMFs(mfsArray); | ||
let result = generateMFs(mfsArray); | ||
expect(result[0].mf).toMatch(/^(.*)$/); | ||
@@ -94,4 +94,4 @@ expect(result[0].charge).not.toBe(0); | ||
test('From array of string to large array', function () { | ||
var mfsArray = ['C0-100', 'O0-100']; | ||
var result = generateMFs(mfsArray); | ||
let mfsArray = ['C0-100', 'O0-100']; | ||
let result = generateMFs(mfsArray); | ||
expect(result).toHaveLength(101 * 101); | ||
@@ -101,4 +101,4 @@ }); | ||
test('From array of string to large array and filter', function () { | ||
var mfsArray = ['C0-100', 'O0-100']; | ||
var result = generateMFs(mfsArray, { filter: { minEM: 0.1, maxEM: 13 } }); | ||
let mfsArray = ['C0-100', 'O0-100']; | ||
let result = generateMFs(mfsArray, { filter: { minEM: 0.1, maxEM: 13 } }); | ||
expect(result).toHaveLength(1); | ||
@@ -108,5 +108,5 @@ }); | ||
test('From array of string to large array and filter unsaturation', function () { | ||
var mfsArray = ['C0-100', 'H0-100']; | ||
var result = generateMFs(mfsArray, { | ||
filter: { unsaturation: { min: 0, max: 1 } } | ||
let mfsArray = ['C0-100', 'H0-100']; | ||
let result = generateMFs(mfsArray, { | ||
filter: { unsaturation: { min: 0, max: 1 } }, | ||
}); | ||
@@ -117,5 +117,5 @@ expect(result).toHaveLength(151); | ||
test('From array of string to large array and filter unsaturation min/max and integer unsaturation', function () { | ||
var mfsArray = ['C0-100', 'H0-100']; | ||
var result = generateMFs(mfsArray, { | ||
filter: { unsaturation: { min: 0, max: 1, onlyInteger: true } } | ||
let mfsArray = ['C0-100', 'H0-100']; | ||
let result = generateMFs(mfsArray, { | ||
filter: { unsaturation: { min: 0, max: 1, onlyInteger: true } }, | ||
}); | ||
@@ -126,3 +126,3 @@ expect(result).toHaveLength(101); | ||
test('Combine with ionizations', function () { | ||
var result = generateMFs(['C1-2'], { ionizations: 'H+,Na+,H++' }); | ||
let result = generateMFs(['C1-2'], { ionizations: 'H+,Na+,H++' }); | ||
expect(result.map((a) => a.ms.em).sort((a, b) => a - b)).toStrictEqual([ | ||
@@ -134,3 +134,3 @@ 6.50336393620593, | ||
34.989220702090925, | ||
46.989220702090925 | ||
46.989220702090925, | ||
]); | ||
@@ -140,4 +140,4 @@ }); | ||
test('Strange comments', function () { | ||
var mfsArray = ['C$1>10', 'O$D2>20']; | ||
var result = generateMFs(mfsArray); | ||
let mfsArray = ['C$1>10', 'O$D2>20']; | ||
let result = generateMFs(mfsArray); | ||
expect(result[0].mf).toBe('CO'); | ||
@@ -148,20 +148,12 @@ expect(result[0].comment).toBe('1>10 D2>20'); | ||
test('Check info', function () { | ||
var mfsArray = ['C', '', 'C5(C)2']; | ||
var result = generateMFs(mfsArray, { canonizeMF: true })[0]; | ||
expect(result).toStrictEqual({ | ||
mf: 'C8', | ||
em: 96, | ||
ms: { em: 0, charge: 0, ionization: '' }, | ||
mw: 96.08588717388199, | ||
charge: 0, | ||
ionization: { mf: '', charge: 0, em: 0 }, | ||
parts: ['C', undefined, 'C5(C)2'], | ||
atoms: { C: 8 }, | ||
unsaturation: 9 | ||
}); | ||
let mfsArray = ['C', '', 'C5(C)2']; | ||
let result = generateMFs(mfsArray, { canonizeMF: true })[0]; | ||
expect(JSON.stringify(result)).toBe( | ||
'{"charge":0,"em":96,"mw":96.08588717388199,"ionization":{"mf":"","em":0,"charge":0},"unsaturation":9,"atoms":{"C":8},"ms":{"ionization":"","em":0,"charge":0},"parts":["C",null,"C5(C)2"],"mf":"C8"}', | ||
); | ||
}); | ||
test('generateMFs from array of array with negative ionisation', function () { | ||
var mfsArray = ['H2', ['Cl', 'Br']]; | ||
var result = generateMFs(mfsArray, { ionizations: '(H+)-2' }); | ||
let mfsArray = ['H2', ['Cl', 'Br']]; | ||
let result = generateMFs(mfsArray, { ionizations: '(H+)-2' }); | ||
expect(result[0].ms.em).toBe(17.484974920909067); | ||
@@ -173,4 +165,4 @@ expect(result[1].ms.em).toBe(39.45971737990907); | ||
test('generateMFs from array with charge and range', function () { | ||
var mfsArray = ['(H+)2-3']; | ||
var result = generateMFs(mfsArray, { ionizations: '(H+)-2,Na+' }); | ||
let mfsArray = ['(H+)2-3']; | ||
let result = generateMFs(mfsArray, { ionizations: '(H+)-2,Na+' }); | ||
expect(result.map((a) => a.ms.em).sort((a, b) => a - b)).toStrictEqual([ | ||
@@ -180,4 +172,29 @@ 0, | ||
6.50276251476343, | ||
8.334591202244264 | ||
8.334591202244264, | ||
]); | ||
}); | ||
test('generateMFs from array with target masses', function () { | ||
let mfsArray = ['C1-100']; | ||
let result = generateMFs(mfsArray, { | ||
ionizations: '+,++', | ||
filter: { | ||
targetMasses: [120, 240], | ||
precision: 10, | ||
targetIntensities: [1, 5], | ||
}, | ||
}); | ||
expect(result).toHaveLength(4); | ||
expect(result.sort((a, b) => a.em - b.em)).toMatchSnapshot(); | ||
}); | ||
test('generateMFs from array with charge and negative range', function () { | ||
let mfsArray = ['(H+)-2--4']; | ||
let result = generateMFs(mfsArray); | ||
expect(result.map((a) => a.ms.em).sort((a, b) => a - b)).toStrictEqual([ | ||
-1.0072764523209299, | ||
-1.0072764523209299, | ||
-1.0072764523209299, | ||
]); | ||
}); |
175
src/index.js
@@ -7,3 +7,3 @@ 'use strict'; | ||
const preprocessIonizations = require('mf-utilities/src/preprocessIonizations'); | ||
const processRange = require('mf-utilities/src/processRange'); | ||
/** | ||
@@ -15,20 +15,22 @@ * Generate all the possible combinations of molecular formula and calculate | ||
* @param keys | ||
* @param {object} options | ||
* @param {number} [options.limit=10000000] - Maximum number of results | ||
* @param {boolean} [canonizeMF=true] - Canonize molecular formula | ||
* @param {boolean} [uniqueMFs=true] - Force canonization and make MF unique | ||
* @param {string} [ionizations=''] - Comma separated list of ionizations (to charge the molecule) | ||
* @param {number} [options.filter.minMass=0] - Minimal monoisotopic mass | ||
* @param {number} [options.filter.maxMass=+Infinity] - Maximal monoisotopic mass | ||
* @param {number} [options.filter.minEM=0] - Minimal neutral monoisotopic mass | ||
* @param {number} [options.filter.maxEM=+Infinity] - Maximal neutral monoisotopic mass | ||
* @param {number} [options.filter.targetMass] - Experimental observed mass | ||
* @param {number} [options.filter.precision=1000] - Precision | ||
* @param {number} [options.filter.minCharge=-Infinity] - Minimal charge | ||
* @param {number} [options.filter.maxCharge=+Infinity] - Maximal charge | ||
* @param {number} [options.filter.minUnsaturation=-Infinity] - Minimal unsaturation | ||
* @param {number} [options.filter.maxUnsaturation=+Infinity] - Maximal unsaturation | ||
* @param {number} [options.filter.onlyIntegerUnsaturation=false] - Integer unsaturation | ||
* @param {number} [options.filter.onlyNonIntegerUnsaturation=false] - Non integer unsaturation | ||
* @param {object} [options.filter.atoms] - object of atom:{min, max} | ||
* @param {object} [options={}] | ||
* @param {number} [options.limit=10000000] - Maximum number of results | ||
* @param {boolean} [canonizeMF=true] - Canonize molecular formula | ||
* @param {boolean} [uniqueMFs=true] - Force canonization and make MF unique | ||
* @param {string} [ionizations=''] - Comma separated list of ionizations (to charge the molecule) | ||
* @param {number} [options.filter.minMass=0] - Minimal monoisotopic mass | ||
* @param {number} [options.filter.maxMass=+Infinity] - Maximal monoisotopic mass | ||
* @param {number} [options.filter.minEM=0] - Minimal neutral monoisotopic mass | ||
* @param {number} [options.filter.maxEM=+Infinity] - Maximal neutral monoisotopic mass | ||
* @param {number} [options.filter.precision=1000] - The precision on the experimental mass | ||
* @param {number} [options.filter.targetMass] - Target mass, allows to calculate error and filter results | ||
* @param {Array<number>} [options.filter.targetMasses] - Target masses: SORTED array of numbers | ||
* @param {number} [options.filter.precision=1000] - Precision | ||
* @param {number} [options.filter.minCharge=-Infinity] - Minimal charge | ||
* @param {number} [options.filter.maxCharge=+Infinity] - Maximal charge | ||
* @param {number} [options.filter.minUnsaturation=-Infinity] - Minimal unsaturation | ||
* @param {number} [options.filter.maxUnsaturation=+Infinity] - Maximal unsaturation | ||
* @param {number} [options.filter.onlyIntegerUnsaturation=false] - Integer unsaturation | ||
* @param {number} [options.filter.onlyNonIntegerUnsaturation=false] - Non integer unsaturation | ||
* @param {object} [options.filter.atoms] - object of atom:{min, max} | ||
* @returns {Array} | ||
@@ -48,6 +50,6 @@ */ | ||
// we allow String delimited by ". , or ;" instead of an array | ||
// we allow String delimited by ". or ;" instead of an array | ||
for (let i = 0; i < keys.length; i++) { | ||
if (!Array.isArray(keys[i])) { | ||
keys[i] = keys[i].split(/[.,;]/); | ||
keys[i] = keys[i].split(/[.,]/); | ||
} | ||
@@ -57,3 +59,3 @@ } | ||
// we allow ranges in a string ... | ||
// problem with ranges is that we need to now to what the range applies | ||
// problem with ranges is that we need to know to what the range applies | ||
for (let i = 0; i < keys.length; i++) { | ||
@@ -66,3 +68,4 @@ let parts = keys[i]; | ||
part = part.replace(/\$.*/, '').replace(/\s/g, ''); | ||
if (~part.indexOf('-')) { | ||
if (part.match(/[0-9]-[0-9-]/)) { | ||
// deal with negative numbers | ||
// there are ranges ... we are in trouble ! | ||
@@ -86,3 +89,2 @@ newParts = newParts.concat(processRange(part, comment)); | ||
let evolution = 0; | ||
while (position < currents.length) { | ||
@@ -102,3 +104,3 @@ if (currents[position] < sizes[position]) { | ||
throw new Error( | ||
`You have reached the limit of ${limit}. You could still change this value using the limit option but it is likely to crash.` | ||
`You have reached the limit of ${limit}. You could still change this value using the limit option but it is likely to crash.`, | ||
); | ||
@@ -108,5 +110,4 @@ } | ||
appendResult(results, currents, keys, options); | ||
if (uniqueMFs) { | ||
var uniqueMFsObject = {}; | ||
let uniqueMFsObject = {}; | ||
results.forEach((r) => { | ||
@@ -121,3 +122,3 @@ uniqueMFsObject[r.mf + r.ionization.mf] = r; | ||
var ems = {}; | ||
let ems = {}; | ||
@@ -135,3 +136,3 @@ // internal method used as a cache | ||
unsaturation: (info.unsaturation - 1) * 2, | ||
atoms: info.atoms | ||
atoms: info.atoms, | ||
}; | ||
@@ -143,8 +144,8 @@ } | ||
function getEMFromParts(parts, currents, ionization) { | ||
var charge = 0; | ||
var em = 0; | ||
var mw = 0; | ||
var unsaturation = 0; | ||
var validUnsaturation = true; | ||
var atoms = {}; | ||
let charge = 0; | ||
let em = 0; | ||
let mw = 0; | ||
let unsaturation = 0; | ||
let validUnsaturation = true; | ||
let atoms = {}; | ||
@@ -171,3 +172,3 @@ for (let i = 0; i < parts.length; i++) { | ||
unsaturation: validUnsaturation ? unsaturation / 2 + 1 : undefined, | ||
atoms | ||
atoms, | ||
}; | ||
@@ -178,3 +179,2 @@ } | ||
const { canonizeMF, filter, ionizations } = options; | ||
// this script is designed to combine molecular formula | ||
@@ -188,4 +188,3 @@ // that may contain comments after a "$" sign | ||
let match = matcher(result, filter); | ||
if (!match) return; | ||
if (!match) continue; | ||
result.ms = match.ms; | ||
@@ -208,3 +207,2 @@ result.ionization = match.ionization; | ||
} | ||
if (canonizeMF) { | ||
@@ -219,98 +217,1 @@ result.mf = new MF(result.mf).toMF(); | ||
} | ||
function processRange(string, comment) { | ||
var results = []; | ||
var parts = string.split(/([0-9]+-[0-9]+)/).filter((v) => v); // remove empty parts | ||
let position = -1; | ||
var mfs = []; | ||
for (let i = 0; i < parts.length; i++) { | ||
let part = parts[i]; | ||
if (!~part.search(/[0-9]-[0-9]/)) { | ||
position++; | ||
mfs[position] = { | ||
mf: part, | ||
min: 1, | ||
max: 1 | ||
}; | ||
} else { | ||
mfs[position].min = part.replace(/^(-?[0-9]*)-(-?[0-9]*)/, '$1') >> 0; | ||
mfs[position].max = part.replace(/^(-?[0-9]*)-(-?[0-9]*)/, '$2') >> 0; | ||
} | ||
} | ||
let currents = new Array(mfs.length); | ||
for (let i = 0; i < currents.length; i++) { | ||
currents[i] = mfs[i].min; | ||
} | ||
position = 0; | ||
while (position < currents.length) { | ||
if (currents[position] < mfs[position].max) { | ||
results.push(getMF(mfs, currents, comment)); | ||
currents[position]++; | ||
for (let i = 0; i < position; i++) { | ||
currents[i] = mfs[i].min; | ||
} | ||
position = 0; | ||
} else { | ||
position++; | ||
} | ||
} | ||
results.push(getMF(mfs, currents, comment)); | ||
return results; | ||
} | ||
function getMF(mfs, currents, comment) { | ||
let mf = ''; | ||
for (let i = 0; i < mfs.length; i++) { | ||
if (currents[i] === 0) { | ||
// TODO we need to remove from currents[i] till we reach another part of the MF | ||
mf += removeMFLastPart(mfs[i].mf); | ||
} else { | ||
mf += mfs[i].mf; | ||
if (currents[i] !== 1) { | ||
mf += currents[i]; | ||
} | ||
} | ||
} | ||
if (comment) mf += `$${comment}`; | ||
return mf; | ||
} | ||
/* | ||
Allows to remove the last part of a MF. Useful when you have something with '0' times. | ||
C10H -> C10 | ||
C10((Me)N) -> C10 | ||
C10Ala -> C10 | ||
C10Ala((Me)N) -> C10Ala | ||
*/ | ||
function removeMFLastPart(mf) { | ||
let parenthesis = 0; | ||
let start = true; | ||
for (let i = mf.length - 1; i >= 0; i--) { | ||
let ascii = mf.charCodeAt(i); | ||
if (ascii > 96 && ascii < 123) { | ||
// lowercase | ||
if (!start && !parenthesis) { | ||
return mf.substr(0, i + 1); | ||
} | ||
} else if (ascii > 64 && ascii < 91) { | ||
// uppercase | ||
if (!start && !parenthesis) { | ||
return mf.substr(0, i + 1); | ||
} | ||
start = false; | ||
} else if (ascii === 40) { | ||
// ( | ||
parenthesis--; | ||
if (!parenthesis) return mf.substr(0, i); | ||
} else if (ascii === 41) { | ||
// ) | ||
parenthesis++; | ||
} else { | ||
start = false; | ||
if (!parenthesis) return mf.substr(0, i + 1); | ||
} | ||
} | ||
return ''; | ||
} |
17739
6
344
+ Addedatom-sorter@0.12.0(transitive)
+ Addedchemical-elements@0.12.1(transitive)
+ Addedchemical-groups@0.12.1(transitive)
+ Addedis-any-array@0.0.3(transitive)
+ Addedmf-finder@0.12.1(transitive)
+ Addedmf-matcher@0.12.1(transitive)
+ Addedmf-parser@0.12.0(transitive)
+ Addedmf-utilities@0.12.1(transitive)
+ Addedml-spectra-processing@0.6.1(transitive)
+ Addedpapaparse@5.5.1(transitive)
- Removedatom-sorter@0.9.1(transitive)
- Removedchemical-elements@0.9.1(transitive)
- Removedchemical-groups@0.9.1(transitive)
- Removedmf-finder@0.9.1(transitive)
- Removedmf-matcher@0.9.1(transitive)
- Removedmf-parser@0.9.1(transitive)
- Removedmf-utilities@0.9.1(transitive)
- Removedpapaparse@4.6.3(transitive)
Updatedchemical-elements@^0.12.0
Updatedmf-finder@^0.12.0
Updatedmf-matcher@^0.12.0
Updatedmf-parser@^0.12.0
Updatedmf-utilities@^0.12.0