├── .gitignore ├── CHANGELOG.md ├── LICENSE.mit ├── README.md ├── index.d.ts ├── index.js ├── package-lock.json ├── package.json └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## [1.1.0] - 2020-01-11 6 | 7 | ### Added 8 | 9 | - TypeScript support (Thanks [@jvatic](https://github.com/jvatic)) 10 | 11 | ## [1.0.3] - 2020-04-29 12 | 13 | ### Changed 14 | 15 | - Dependency bump: `excel-formula-tokenizer` to at least 2.3.1 16 | 17 | ## [1.0.2] - 2017-05-21 18 | 19 | ### Changed 20 | 21 | - Docs updates 22 | 23 | ## [1.0.1] - 2017-05-21 24 | 25 | ### Added 26 | 27 | - More docs 28 | 29 | ## [1.0.0] - 2017-05-20 30 | 31 | ### Added 32 | 33 | - Initial impl 34 | -------------------------------------------------------------------------------- /LICENSE.mit: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Paul Salaets 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # excel-formula-parser 2 | 3 | Parse excel formula into a tree. 4 | 5 | ## Install 6 | 7 | `npm install excel-formula-parser -S` 8 | 9 | or 10 | 11 | `yarn add excel-formula-parser` 12 | 13 | ## Usage 14 | 15 | ```js 16 | const {parse, visit} = require('excel-formula-parser'); 17 | 18 | const tree = parse('SUM(1, 2)'); 19 | 20 | visit(tree, visitor); 21 | ``` 22 | 23 | ## API 24 | 25 | ```js 26 | const {parse, visit} = require('excel-formula-parser'); 27 | ``` 28 | 29 | ### parse(formula) 30 | 31 | Parse a formula into an expression tree. 32 | 33 | - formula: string - Excel formula 34 | 35 | Returns: [ast node](https://github.com/psalaets/excel-formula-ast#node-types) 36 | 37 | ### visit(tree, visitor) 38 | 39 | Visit nodes of the tree. 40 | 41 | - tree: [ast node](https://github.com/psalaets/excel-formula-ast#node-types) 42 | - visitor: object - See [excel-formula-ast visitor](https://github.com/psalaets/excel-formula-ast#visittree-visitor). 43 | 44 | ## License 45 | 46 | MIT 47 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | import { Node, Visitor } from 'excel-formula-ast'; 2 | 3 | export function parse(str: string): Node; 4 | export function visit(tree: Node, visitor: Visitor): void; 5 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const {buildTree, visit} = require('excel-formula-ast'); 2 | const {tokenize} = require('excel-formula-tokenizer'); 3 | 4 | module.exports.parse = parse; 5 | module.exports.visit = visit; 6 | 7 | function parse(formula) { 8 | return buildTree(tokenize(formula)); 9 | } 10 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "excel-formula-parser", 3 | "version": "1.1.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "balanced-match": { 8 | "version": "0.4.2", 9 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", 10 | "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", 11 | "dev": true 12 | }, 13 | "brace-expansion": { 14 | "version": "1.1.7", 15 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz", 16 | "integrity": "sha1-Pv/DxQ4ABTH7cg6v+A8K6O8jz1k=", 17 | "dev": true, 18 | "requires": { 19 | "balanced-match": "^0.4.1", 20 | "concat-map": "0.0.1" 21 | } 22 | }, 23 | "browser-stdout": { 24 | "version": "1.3.0", 25 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", 26 | "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", 27 | "dev": true 28 | }, 29 | "commander": { 30 | "version": "2.9.0", 31 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", 32 | "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", 33 | "dev": true, 34 | "requires": { 35 | "graceful-readlink": ">= 1.0.0" 36 | } 37 | }, 38 | "concat-map": { 39 | "version": "0.0.1", 40 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 41 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 42 | "dev": true 43 | }, 44 | "debug": { 45 | "version": "2.6.0", 46 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.0.tgz", 47 | "integrity": "sha1-vFlryr52F/Edn6FTYe3tVgi4SZs=", 48 | "dev": true, 49 | "requires": { 50 | "ms": "0.7.2" 51 | } 52 | }, 53 | "diff": { 54 | "version": "3.2.0", 55 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", 56 | "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", 57 | "dev": true 58 | }, 59 | "escape-string-regexp": { 60 | "version": "1.0.5", 61 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 62 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 63 | "dev": true 64 | }, 65 | "excel-formula-ast": { 66 | "version": "1.0.0", 67 | "resolved": "https://registry.npmjs.org/excel-formula-ast/-/excel-formula-ast-1.0.0.tgz", 68 | "integrity": "sha1-nKJVbcOoeZEFjh6wbkQFmbBb0mE=" 69 | }, 70 | "excel-formula-tokenizer": { 71 | "version": "2.3.1", 72 | "resolved": "https://registry.npmjs.org/excel-formula-tokenizer/-/excel-formula-tokenizer-2.3.1.tgz", 73 | "integrity": "sha512-CYxE3FwH3G0zrktr1U0+vYWZpvjvkDjQAum5B7tPDxQCMT12kGlMLrzzroPIogeN0y1niZFtW4nGfhYKLLtUDA==" 74 | }, 75 | "fs.realpath": { 76 | "version": "1.0.0", 77 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 78 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 79 | "dev": true 80 | }, 81 | "glob": { 82 | "version": "7.1.1", 83 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", 84 | "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", 85 | "dev": true, 86 | "requires": { 87 | "fs.realpath": "^1.0.0", 88 | "inflight": "^1.0.4", 89 | "inherits": "2", 90 | "minimatch": "^3.0.2", 91 | "once": "^1.3.0", 92 | "path-is-absolute": "^1.0.0" 93 | } 94 | }, 95 | "graceful-readlink": { 96 | "version": "1.0.1", 97 | "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", 98 | "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", 99 | "dev": true 100 | }, 101 | "growl": { 102 | "version": "1.9.2", 103 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", 104 | "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", 105 | "dev": true 106 | }, 107 | "has-flag": { 108 | "version": "1.0.0", 109 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", 110 | "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", 111 | "dev": true 112 | }, 113 | "inflight": { 114 | "version": "1.0.6", 115 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 116 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 117 | "dev": true, 118 | "requires": { 119 | "once": "^1.3.0", 120 | "wrappy": "1" 121 | } 122 | }, 123 | "inherits": { 124 | "version": "2.0.3", 125 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 126 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 127 | "dev": true 128 | }, 129 | "json3": { 130 | "version": "3.3.2", 131 | "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", 132 | "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", 133 | "dev": true 134 | }, 135 | "lodash._baseassign": { 136 | "version": "3.2.0", 137 | "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", 138 | "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", 139 | "dev": true, 140 | "requires": { 141 | "lodash._basecopy": "^3.0.0", 142 | "lodash.keys": "^3.0.0" 143 | } 144 | }, 145 | "lodash._basecopy": { 146 | "version": "3.0.1", 147 | "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", 148 | "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", 149 | "dev": true 150 | }, 151 | "lodash._basecreate": { 152 | "version": "3.0.3", 153 | "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", 154 | "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", 155 | "dev": true 156 | }, 157 | "lodash._getnative": { 158 | "version": "3.9.1", 159 | "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", 160 | "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", 161 | "dev": true 162 | }, 163 | "lodash._isiterateecall": { 164 | "version": "3.0.9", 165 | "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", 166 | "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", 167 | "dev": true 168 | }, 169 | "lodash.create": { 170 | "version": "3.1.1", 171 | "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", 172 | "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", 173 | "dev": true, 174 | "requires": { 175 | "lodash._baseassign": "^3.0.0", 176 | "lodash._basecreate": "^3.0.0", 177 | "lodash._isiterateecall": "^3.0.0" 178 | } 179 | }, 180 | "lodash.isarguments": { 181 | "version": "3.1.0", 182 | "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", 183 | "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", 184 | "dev": true 185 | }, 186 | "lodash.isarray": { 187 | "version": "3.0.4", 188 | "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", 189 | "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", 190 | "dev": true 191 | }, 192 | "lodash.keys": { 193 | "version": "3.1.2", 194 | "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", 195 | "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", 196 | "dev": true, 197 | "requires": { 198 | "lodash._getnative": "^3.0.0", 199 | "lodash.isarguments": "^3.0.0", 200 | "lodash.isarray": "^3.0.0" 201 | } 202 | }, 203 | "minimatch": { 204 | "version": "3.0.4", 205 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 206 | "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", 207 | "dev": true, 208 | "requires": { 209 | "brace-expansion": "^1.1.7" 210 | } 211 | }, 212 | "minimist": { 213 | "version": "0.0.8", 214 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 215 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 216 | "dev": true 217 | }, 218 | "mkdirp": { 219 | "version": "0.5.1", 220 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 221 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 222 | "dev": true, 223 | "requires": { 224 | "minimist": "0.0.8" 225 | } 226 | }, 227 | "mocha": { 228 | "version": "3.4.1", 229 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.4.1.tgz", 230 | "integrity": "sha1-o4ArSqOBk0yss43nDPdxYh2o+a8=", 231 | "dev": true, 232 | "requires": { 233 | "browser-stdout": "1.3.0", 234 | "commander": "2.9.0", 235 | "debug": "2.6.0", 236 | "diff": "3.2.0", 237 | "escape-string-regexp": "1.0.5", 238 | "glob": "7.1.1", 239 | "growl": "1.9.2", 240 | "json3": "3.3.2", 241 | "lodash.create": "3.1.1", 242 | "mkdirp": "0.5.1", 243 | "supports-color": "3.1.2" 244 | } 245 | }, 246 | "ms": { 247 | "version": "0.7.2", 248 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", 249 | "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", 250 | "dev": true 251 | }, 252 | "once": { 253 | "version": "1.4.0", 254 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 255 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 256 | "dev": true, 257 | "requires": { 258 | "wrappy": "1" 259 | } 260 | }, 261 | "path-is-absolute": { 262 | "version": "1.0.1", 263 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 264 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 265 | "dev": true 266 | }, 267 | "supports-color": { 268 | "version": "3.1.2", 269 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", 270 | "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", 271 | "dev": true, 272 | "requires": { 273 | "has-flag": "^1.0.0" 274 | } 275 | }, 276 | "wrappy": { 277 | "version": "1.0.2", 278 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 279 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 280 | "dev": true 281 | } 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "excel-formula-parser", 3 | "version": "1.1.0", 4 | "description": "Parse excel formula into a tree", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha test.js", 8 | "preversion": "npm run test", 9 | "postversion": "git push --tags && npm publish && git push && echo \"Successfully released version $npm_package_version!\"" 10 | }, 11 | "keywords": [ 12 | "excel", 13 | "formula", 14 | "parse", 15 | "parser" 16 | ], 17 | "author": "Paul Salaets ", 18 | "homepage": "https://github.com/psalaets/excel-formula-parser", 19 | "repository": { 20 | "type": "git", 21 | "url": "https://github.com/psalaets/excel-formula-parser.git" 22 | }, 23 | "license": "MIT", 24 | "dependencies": { 25 | "excel-formula-ast": "^1.0.0", 26 | "excel-formula-tokenizer": "^2.3.1" 27 | }, 28 | "devDependencies": { 29 | "mocha": "^3.4.1" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | const {deepStrictEqual} = require('assert'); 2 | const {parse, visit} = require('.'); 3 | 4 | // minimal because most functionality is from deps 5 | describe('tokenizer/tree integration', function () { 6 | it('looks good', function () { 7 | const tree = parse('SUM(1, 2)'); 8 | const v = visitor(); 9 | 10 | visit(tree, v); 11 | 12 | deepStrictEqual(v.calls, [ 13 | 'function: SUM', 14 | 'number: 1', 15 | 'number: 2', 16 | 'end: SUM', 17 | ]); 18 | }); 19 | }); 20 | 21 | function visitor() { 22 | const calls = []; 23 | 24 | return { 25 | calls, 26 | enterFunction(node) { 27 | calls.push(`function: ${node.name}`); 28 | }, 29 | exitFunction(node) { 30 | calls.push(`end: ${node.name}`); 31 | }, 32 | enterNumber(node) { 33 | calls.push(`number: ${node.value}`); 34 | } 35 | }; 36 | } 37 | --------------------------------------------------------------------------------