{"_id":"@alexbosworth/formulas","_rev":"6-69ebd1c3b2b7e9d84f6a8054ab6a6d71","name":"@alexbosworth/formulas","dist-tags":{"latest":"1.5.0"},"versions":{"1.0.0":{"name":"@alexbosworth/formulas","version":"1.0.0","keywords":["spreadsheet","formulas"],"author":{"url":"https://twitter.com/alexbosworth","name":"Alex Bosworth"},"license":"MIT","_id":"@alexbosworth/formulas@1.0.0","maintainers":[{"name":"alexbosworth","email":"alex.bosworth+npm@gmail.com"}],"homepage":"https://github.com/alexbosworth/formulas#readme","bugs":{"url":"https://github.com/alexbosworth/formulas/issues"},"dist":{"shasum":"23d5503f1e6619971925b3b070d5ed776e9efc4a","tarball":"https://registry.npmjs.org/@alexbosworth/formulas/-/formulas-1.0.0.tgz","fileCount":58,"integrity":"sha512-qChI2ScaTIeO1gDtw6PBQNHHJMJdJCIQtlbLgJ4xVcwDk+mwjo92zXfluaEtTPAyJKrISrNbszH1jJYVPmUnqg==","signatures":[{"sig":"MEUCIBE+qdQM7b49wfZDh+m/VEGVV3Sume7THMYeV3U1PhMVAiEAmxtBlJODbTRqcml2BAPvr2PLITQwXLetahg/i62Xy7w=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":96064},"main":"index.js","engines":{"node":">=22"},"gitHead":"61b7292bb1b6e4a53be7d7902b67b341f0e38e58","scripts":{"test":"node --experimental-test-coverage --test"},"_npmUser":{"name":"alexbosworth","email":"alex.bosworth+npm@gmail.com"},"repository":{"url":"git+https://github.com/alexbosworth/formulas.git","type":"git"},"_npmVersion":"8.13.1","description":"spreadsheet-style formulas library","directories":{},"_nodeVersion":"24.15.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/formulas_1.0.0_1784496859952_0.7498212883174629","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@alexbosworth/formulas","version":"1.1.0","keywords":["spreadsheet","formulas"],"author":{"url":"https://twitter.com/alexbosworth","name":"Alex Bosworth"},"license":"MIT","_id":"@alexbosworth/formulas@1.1.0","maintainers":[{"name":"alexbosworth","email":"alex.bosworth+npm@gmail.com"}],"homepage":"https://github.com/alexbosworth/formulas#readme","bugs":{"url":"https://github.com/alexbosworth/formulas/issues"},"dist":{"shasum":"4714d5e09a515fd1d3c15d0ccdeb9cb1ebbddd38","tarball":"https://registry.npmjs.org/@alexbosworth/formulas/-/formulas-1.1.0.tgz","fileCount":62,"integrity":"sha512-vNwJ1anQHkYSDyg/LnsgXsb6lbjLB5z4fvzWmon7CvdYMKxgpGPXPpeVt2zYSqNrbooKAfAx1Y2CyDjramN4Og==","signatures":[{"sig":"MEYCIQCyg9CqeBdZvNtyUGDt8lcvcCWdq7wiVEIFA8AneQTQtwIhALEBPCvu+vN1Z6VM6/F8U73iBRhnMVkAbahogAUd/Nfi","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":107305},"main":"index.js","engines":{"node":">=22"},"gitHead":"dee1d89a11df1cced95247297a0e4b179fe01684","scripts":{"test":"node --experimental-test-coverage --test"},"_npmUser":{"name":"alexbosworth","email":"alex.bosworth+npm@gmail.com"},"repository":{"url":"git+https://github.com/alexbosworth/formulas.git","type":"git"},"_npmVersion":"8.13.1","description":"spreadsheet-style formulas library","directories":{},"_nodeVersion":"24.15.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/formulas_1.1.0_1784562479166_0.3580493849882549","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@alexbosworth/formulas","version":"1.2.0","keywords":["spreadsheet","formulas"],"author":{"url":"https://twitter.com/alexbosworth","name":"Alex Bosworth"},"license":"MIT","_id":"@alexbosworth/formulas@1.2.0","maintainers":[{"name":"alexbosworth","email":"alex.bosworth+npm@gmail.com"}],"homepage":"https://github.com/alexbosworth/formulas#readme","bugs":{"url":"https://github.com/alexbosworth/formulas/issues"},"dist":{"shasum":"3f59701be46f30bb9b54315252804d77cbde22fd","tarball":"https://registry.npmjs.org/@alexbosworth/formulas/-/formulas-1.2.0.tgz","fileCount":64,"integrity":"sha512-38i0A0BGinyYlYaeowS62Usr4UpwoLPM5GoyFkz4jS+/rppZ+QEd5+ZZgY2cjBfoHdnR67FtFWn3Y0eqJ0xZhA==","signatures":[{"sig":"MEUCIEhJY4sVqp2Y8idI3qQA2K7NOwyB3XxqPm97oAHMQq4SAiEAu3U/U36M1NARlJ1cAe8rMCflEAHl1qKpzTj4Y2BNsMw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":110621},"main":"index.js","engines":{"node":">=22"},"gitHead":"db5cb129b2e4f91c18f7da985e4e62e238d2f6b7","scripts":{"test":"node --experimental-test-coverage --test"},"_npmUser":{"name":"alexbosworth","email":"alex.bosworth+npm@gmail.com"},"repository":{"url":"git+https://github.com/alexbosworth/formulas.git","type":"git"},"_npmVersion":"8.13.1","description":"spreadsheet-style formulas library","directories":{},"_nodeVersion":"24.15.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/formulas_1.2.0_1784565585803_0.7283252025716851","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"name":"@alexbosworth/formulas","version":"1.3.0","keywords":["spreadsheet","formulas"],"author":{"url":"https://twitter.com/alexbosworth","name":"Alex Bosworth"},"license":"MIT","_id":"@alexbosworth/formulas@1.3.0","maintainers":[{"name":"alexbosworth","email":"alex.bosworth+npm@gmail.com"}],"homepage":"https://github.com/alexbosworth/formulas#readme","bugs":{"url":"https://github.com/alexbosworth/formulas/issues"},"dist":{"shasum":"3959164a9b4f42783ba786fd3bfd0ec8734f418e","tarball":"https://registry.npmjs.org/@alexbosworth/formulas/-/formulas-1.3.0.tgz","fileCount":64,"integrity":"sha512-Fw+t2QiRc4s8603Ct/U0eB0gwHbKOwGOWXM1EfKqovViRQw0HsmAomoB4IoUu2oIyt8cYO4ihPA6UjE1Xx2xYA==","signatures":[{"sig":"MEUCIQCDkpjzrSFMnyY9W4/gkLOxVJrVS/6gn9XYlMZb2cMFkQIgAcfqnyTwz/mmL7OoEEaB+59T4ok52CkaSdeUL0ufOgo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":113086},"main":"index.js","engines":{"node":">=22"},"gitHead":"131b710177e68eef32b47de8a795427e60300f9c","scripts":{"test":"node --experimental-test-coverage --test"},"_npmUser":{"name":"alexbosworth","email":"alex.bosworth+npm@gmail.com"},"repository":{"url":"git+https://github.com/alexbosworth/formulas.git","type":"git"},"_npmVersion":"8.13.1","description":"spreadsheet-style formulas library","directories":{},"_nodeVersion":"24.18.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/formulas_1.3.0_1784832785668_0.7261563436068643","host":"s3://npm-registry-packages-npm-production"}},"1.4.0":{"name":"@alexbosworth/formulas","version":"1.4.0","keywords":["spreadsheet","formulas"],"author":{"url":"https://twitter.com/alexbosworth","name":"Alex Bosworth"},"license":"MIT","_id":"@alexbosworth/formulas@1.4.0","maintainers":[{"name":"alexbosworth","email":"alex.bosworth+npm@gmail.com"}],"homepage":"https://github.com/alexbosworth/formulas#readme","bugs":{"url":"https://github.com/alexbosworth/formulas/issues"},"dist":{"shasum":"f3d029dd1e405becda84812f011688e64461e316","tarball":"https://registry.npmjs.org/@alexbosworth/formulas/-/formulas-1.4.0.tgz","fileCount":64,"integrity":"sha512-AsPbfBK7fBbq8LUzdxuyDxlm/hXRuQiB0O3txFaR559jQ2e3GznVwsPDznIezKovvNJvvRou0i/wFKC2i88zzA==","signatures":[{"sig":"MEUCIQD+o/x17ejMihO3dsAJA8mZWogn59/0Jrptd3OrYvB2CgIgGyLTKBeFDY9X92uhs37eHIlWWHrI8kKEE5VSHV8VjTs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":116081},"main":"index.js","engines":{"node":">=22"},"gitHead":"2aee7090851a23fa8d30bebea23a79c90c0381e7","scripts":{"test":"node --experimental-test-coverage --test"},"_npmUser":{"name":"alexbosworth","email":"alex.bosworth+npm@gmail.com"},"repository":{"url":"git+https://github.com/alexbosworth/formulas.git","type":"git"},"_npmVersion":"8.13.1","description":"spreadsheet-style formulas library","directories":{},"_nodeVersion":"24.18.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/formulas_1.4.0_1784834834616_0.673473231716891","host":"s3://npm-registry-packages-npm-production"}},"1.5.0":{"_id":"@alexbosworth/formulas@1.5.0","bugs":{"url":"https://github.com/alexbosworth/formulas/issues"},"dist":{"shasum":"ebd122246aafabe7d5cb7df1f229d6b9c85a6362","tarball":"https://registry.npmjs.org/@alexbosworth/formulas/-/formulas-1.5.0.tgz","fileCount":37,"integrity":"sha512-C8HX8TAm6xYHOG84H9mo0kN8RZ2ntbJEISh9H0md94rwVsPRcFRRwM2IStEHUgRRFIwIc7inPNoZfZGIR7inNQ==","signatures":[{"sig":"MEUCIQDVRODFkMmWZSo9cnbCX+1XSMbaUlvaZabsVaR9+IiQjQIgUIzoCwXY+5RJuGHhDgGUSOTuQay0tl0NUj91KUYNDek=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIGuitKf0ZSmtk4zaFbOAreoCK7driCPR+caCD5vO6gJAAiBP60zzKIm+I4NvmFCHiEdsR/ApNxmLYXssNUtSlNQw4A=="}],"unpackedSize":46486},"main":"index.js","name":"@alexbosworth/formulas","author":{"url":"https://x.com/alexbosworth","name":"Alex Bosworth"},"engines":{"node":">=22"},"gitHead":"d7017826ab24780e5c09b37c4c006db237c5b2be","license":"MIT","scripts":{"test":"node --experimental-test-coverage --test"},"version":"1.5.0","_npmUser":{"name":"alexbosworth","email":"alex.bosworth+npm@gmail.com"},"homepage":"https://github.com/alexbosworth/formulas#readme","keywords":["spreadsheet","formulas"],"repository":{"url":"git+https://github.com/alexbosworth/formulas.git","type":"git"},"_npmVersion":"11.19.0","description":"spreadsheet-style formulas library","directories":{},"maintainers":[{"name":"alexbosworth","email":"alex.bosworth+npm@gmail.com"}],"_nodeVersion":"24.18.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/formulas_1.5.0_1790714802136_0.8717878074223167"}}},"time":{"created":"2026-07-19T21:34:19.799Z","modified":"2026-09-29T20:46:42.406Z","1.0.0":"2026-07-19T21:34:20.093Z","1.1.0":"2026-07-20T15:47:59.378Z","1.2.0":"2026-07-20T16:39:45.945Z","1.3.0":"2026-07-23T18:53:05.795Z","1.4.0":"2026-07-23T19:27:14.757Z","1.5.0":"2026-09-29T20:46:42.232Z"},"bugs":{"url":"https://github.com/alexbosworth/formulas/issues"},"author":{"url":"https://x.com/alexbosworth","name":"Alex Bosworth"},"license":"MIT","homepage":"https://github.com/alexbosworth/formulas#readme","keywords":["spreadsheet","formulas"],"repository":{"url":"git+https://github.com/alexbosworth/formulas.git","type":"git"},"description":"spreadsheet-style formulas library","maintainers":[{"name":"alexbosworth","email":"alex.bosworth+npm@gmail.com"}],"readme":"# formulas\n\nEvaluate spreadsheet-style formulas with JavaScript values and functions.\n\n## Requirements\n\n- Node.js 22 or later\n\n## Installation\n\n```sh\nnpm install @alexbosworth/formulas\n```\n\n## Usage\n\nImport the named `evaluateFormula` function and pass it a formula string:\n\n```js\nconst {evaluateFormula} = require('@alexbosworth/formulas');\n\nconst {result} = evaluateFormula({\n  formula: '1 + 2 * 3',\n});\n\nconsole.log(result); // 7\n```\n\nWrite formulas without a leading `=`. For example, use `SUM(1, 2)` rather\nthan `=SUM(1, 2)`.\n\n`evaluateFormula` accepts an object with these properties:\n\n| Property | Required | Description |\n| --- | --- | --- |\n| `formula` | Yes | Formula string to evaluate |\n| `constants` | No | Named values available to the formula |\n| `functions` | No | Custom functions available to the formula |\n\nIt returns an object containing a numeric `result`:\n\n```js\n{result: 7}\n```\n\nA final boolean result is converted to `1` for true or `0` for false.\n\n## Constants\n\nPass constants as finite numbers, booleans, strings, or flat arrays containing\nthose values. Constant names are case-insensitive within formulas.\n\n```js\nconst {evaluateFormula} = require('@alexbosworth/formulas');\n\nconst {result} = evaluateFormula({\n  constants: {\n    subtotal: 25,\n    taxRate: 0.08,\n  },\n  formula: 'ROUND(SUBTOTAL * (1 + TAXRATE), 2)',\n});\n\nconsole.log(result); // 27\n```\n\nArray constants can be passed to aggregate functions:\n\n```js\nconst {evaluateFormula} = require('@alexbosworth/formulas');\n\nconst {result} = evaluateFormula({\n  constants: {values: [4, 4]},\n  formula: 'SUM(VALUES) > 7',\n});\n\nconsole.log(result); // 1\n```\n\n`AVERAGE`, `COUNT`, `MAX`, `MIN`, and `SUM` accept one or more scalar or array\narguments. `COUNT` ignores non-number values. `COUNT`, `MAX`, `MIN`, and `SUM`\nreturn zero for empty arrays. `AVERAGE` requires at least one value, and\n`MEDIAN` requires one non-empty array. `CHOOSE` can select an array value.\nOther built-in functions expect scalar arguments.\n\n## Custom functions\n\nPass custom functions by name through the `functions` object. Function names\nare case-insensitive within formulas, and each argument is evaluated before\nthe JavaScript function is called.\n\n```js\nconst {evaluateFormula} = require('@alexbosworth/formulas');\n\nconst {result} = evaluateFormula({\n  constants: {\n    earned: 17,\n    possible: 20,\n  },\n  formula: 'ROUND(PERCENT(EARNED, POSSIBLE), 1)',\n  functions: {\n    percent: (value, total) => value / total * 100,\n  },\n});\n\nconsole.log(result); // 85\n```\n\nCustom functions must return a finite number, boolean, or string. The final\nformula result must still be a finite number or boolean.\n\n## Formula syntax\n\nFormulas support numbers, `TRUE`, `FALSE`, quoted strings, parentheses, and\nthe following operators:\n\n| Operation | Operators |\n| --- | --- |\n| Unary | `+`, `-` |\n| Exponentiation | `^` |\n| Multiplication and division | `*`, `/` |\n| Addition and subtraction | `+`, `-` |\n| Comparison | `>`, `<`, `>=`, `<=`, `=`, `<>` |\n\nNot-equal comparisons use spreadsheet-style `<>` syntax:\n\n```js\nconst {evaluateFormula} = require('@alexbosworth/formulas');\n\nconst {result} = evaluateFormula({formula: '3 <> 2'});\n\nconsole.log(result); // 1\n```\n\n## Built-in functions\n\n| Function | Description |\n| --- | --- |\n| `ABS(value)` | Return the absolute value |\n| `AND(value, ...)` | Return true when every value is true |\n| `AVERAGE(value, ...)` | Return the average of scalar or array values |\n| `CHOOSE(index, value, ...)` | Return the value at a one-based index |\n| `COUNT(value, ...)` | Count numeric scalar or array values |\n| `EXACT(string1, string2)` | Compare two strings exactly |\n| `IF(condition, ifTrue, ifFalse)` | Return the selected result |\n| `MAX(value, ...)` | Return the largest scalar or array value |\n| `MEDIAN(values)` | Return the median value from an array |\n| `MIN(value, ...)` | Return the smallest scalar or array value |\n| `NOT(value)` | Reverse a boolean value |\n| `OR(value, ...)` | Return true when any value is true |\n| `POWER(number, power)` | Raise a number to a power |\n| `RAND()` | Return a random number from 0 up to but not including 1 |\n| `RANDBETWEEN(low, high)` | Return a random integer within inclusive bounds |\n| `ROUND(value[, places])` | Round a value; places defaults to zero |\n| `SUM(value, ...)` | Add scalar or array values |\n\nFor example:\n\n```js\nconst {evaluateFormula} = require('@alexbosworth/formulas');\n\nconst {result} = evaluateFormula({\n  constants: {\n    disqualified: false,\n    passingScore: 70,\n    score: 82,\n  },\n  formula: 'IF(AND(SCORE >= PASSINGSCORE, NOT(DISQUALIFIED)), 100, 0)',\n});\n\nconsole.log(result); // 100\n```\n\n`IF` and `CHOOSE` only evaluate the selected value, so\n`CHOOSE(1, 5, 1 / 0)` returns `5`.\n\n`EXACT` compares string case and spacing:\n\n```js\nconst {evaluateFormula} = require('@alexbosworth/formulas');\n\nconst {result} = evaluateFormula({\n  formula: 'EXACT(\"Formula\", \"formula\")',\n});\n\nconsole.log(result); // 0\n```\n\n## Errors\n\nInvalid syntax, unknown names, unsupported values, invalid argument counts,\nand non-finite results cause `evaluateFormula` to throw an `Error`.\n\n```js\nconst {evaluateFormula} = require('@alexbosworth/formulas');\n\ntry {\n  evaluateFormula({formula: '1 / 0'});\n} catch (err) {\n  console.error(err.message);\n}\n```\n\n## Testing\n\n```sh\nnpm test\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md"}