├── .gitignore ├── API.md ├── Intro101.md ├── README.md ├── build ├── webpack.config.dev.js ├── webpack.config.dist.dev.js └── webpack.config.dist.min.js ├── docs ├── ROADMAP.md └── design │ ├── ErrorHandling.md │ ├── IDE.md │ ├── Misc.md │ └── UnitTest.md ├── gen ├── ReportFormulaLexer.interp ├── ReportFormulaLexer.java └── ReportFormulaLexer.tokens ├── gulpfile.js ├── karma.conf.js ├── package-lock.json ├── package.json ├── src ├── base │ ├── ArrayUtils.js │ ├── StringBuffer.js │ ├── StringUtils.js │ ├── color │ │ └── colorTest.js │ ├── common │ │ ├── assert.js │ │ └── types.js │ └── debounce.js ├── index.js ├── jsconfig.json ├── platform │ ├── contrib │ │ └── errorHandler │ │ │ ├── BaseErrorHandler.js │ │ │ ├── EditorErrorHandler.js │ │ │ └── test │ │ │ └── MockEditorErrorHandler.js │ ├── formula │ │ ├── FormulaEngine.js │ │ ├── FormulaLanguageService.js │ │ ├── autofix │ │ │ └── AutoFixFormulaTool.js │ │ ├── cellAddressParts │ │ │ ├── common │ │ │ │ └── CellAddressParts.js │ │ │ └── test │ │ │ │ ├── CellAddressGrammar.test.js │ │ │ │ └── CellAddressParts.test.js │ │ ├── cellDependency │ │ │ ├── CellDependencyVisitor.js │ │ │ ├── DependencyBuilder.js │ │ │ ├── DependencyFinder.js │ │ │ ├── DependencyGraph.js │ │ │ ├── DependencyTransformer.js │ │ │ ├── FormulaAstVisitor.js │ │ │ ├── common │ │ │ │ ├── ElementaryCircuitsSearch.js │ │ │ │ ├── Graph.js │ │ │ │ └── StrongConnectedComponents.js │ │ │ └── test │ │ │ │ ├── ElementaryCircuitsSearch.test.js │ │ │ │ └── Graph.test.js │ │ ├── cellEvaluation │ │ │ ├── CellValueProviderProxy.js │ │ │ ├── EvaluationErrors.js │ │ │ ├── Evaluator.js │ │ │ └── FormulaEvaluationVisitor.js │ │ ├── core │ │ │ ├── ASTWalker.js │ │ │ ├── EditorTokensVisitor.js │ │ │ ├── SingleFormulaAST.js │ │ │ ├── SingleFormulaContext.js │ │ │ ├── SingleFormulaCore.js │ │ │ └── syntax.js │ │ ├── error │ │ │ ├── BaseErrorListener.js │ │ │ ├── FormulaExceptions.js │ │ │ ├── LexerErrorListener.js │ │ │ └── ParserErrorListener.js │ │ ├── generation │ │ │ └── AutoFillTransformer.js │ │ ├── grammar │ │ │ ├── .antlr │ │ │ │ ├── CellAddress.interp │ │ │ │ ├── CellAddressLexer.interp │ │ │ │ ├── ReportFormulaLexer.interp │ │ │ │ └── ReportFormulaParser.interp │ │ │ ├── CellAddress.g4 │ │ │ ├── ReportFormulaLexer.g4 │ │ │ ├── ReportFormulaParser.g4 │ │ │ └── formulatree.md │ │ ├── intelliSense │ │ │ └── formulaSignatureHelp.js │ │ ├── runtime │ │ │ ├── CellAddress.tokens │ │ │ ├── CellAddressLexer.js │ │ │ ├── CellAddressLexer.tokens │ │ │ ├── CellAddressListener.js │ │ │ ├── CellAddressParser.js │ │ │ ├── CellAddressVisitor.js │ │ │ ├── ReportFormulaLexer.js │ │ │ ├── ReportFormulaLexer.tokens │ │ │ ├── ReportFormulaParser.js │ │ │ ├── ReportFormulaParser.tokens │ │ │ ├── ReportFormulaParserListener.js │ │ │ └── ReportFormulaParserVisitor.js │ │ └── test │ │ │ ├── DependencyBuilder.test.js │ │ │ ├── DependencyTransformer.test.js │ │ │ ├── Evaluator.test.js │ │ │ ├── FormulaParser.test.js │ │ │ ├── SingleFormulaAST.test.js │ │ │ ├── SingleFormulaCore.test.js │ │ │ └── TestUtilsASTNodeBuilder.js │ ├── registry │ │ └── common │ │ │ └── platform.js │ └── theme │ │ └── colorRegistry.js └── workbench │ ├── CellValueProvider.js │ └── monaco-editor │ ├── colorsProvider.js │ ├── languageFeatures.js │ └── monaco.contribution.js └── test ├── .mocharc.js ├── FormulaEngine.test.js ├── event-loop-example.js ├── index.html ├── input └── formula1.txt └── require-alias └── loader.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | .nyc_output/ 4 | node_modules/ 5 | out/ 6 | mochawesome-report/ 7 | dist/ 8 | dist_dev/ 9 | coverage/ 10 | -------------------------------------------------------------------------------- /API.md: -------------------------------------------------------------------------------- 1 | # excel-formula-sdk 2 | 3 | **注意:** 4 | 本项目长期维护,如果您有疑问或功能需求,欢迎在 [issue](https://github.com/yezhang/excel-formula-sdk/issues) 提问。 5 | 6 | ### 基本功能 7 | Excel 公式解析引擎,用于支持公式输入编辑器的智能提示、单元格之间的公式依赖计算、公式的求值、公式语法校验。 8 | 9 | 10 | ### 集成用法 11 | 本 SDK 还可以与各类编辑器(或输入框)、表格组件配合使用。 12 | - [x] 支持公式的语法解析、单元格地址解析、单元格范围解析、单元格公式之间的依赖关系管理等。 13 | - [x] 支持嵌套公式的解析、公式的求值。 14 | - [x] 支持自动补全、函数签名提示、鼠标浮动提示等 IntelliSense 功能所需要的核心信息,包括当前光标所在的函数上下文、当前光标的参数索引。 15 | 16 | 使用场景概述: 17 | - 独立使用。 18 | - 与个人/公司项目中的表格组件、输入框组件配合使用。 19 | - 与 [monaco-editor](https://www.npmjs.com/package/monaco-editor)/[code mirror](https://www.npmjs.com/package/codemirror) 编辑器配合使用,提供智能提示的功能。 20 | - 与 [handsontable](https://www.npmjs.com/package/handsontable) 配合使用,提供公式的联动计算。 21 | 22 | 23 | ### 函数的扩展性 24 | 本 SDK 支持 Excel 内置函数的解析,还支持其他「任何」函数调用语法,可用于扩展支持项目个性化函数。 25 | 例如,项目中需要一个“根据用户ID查询用户名”的函数 getUserNameById('id')。 26 | 并且,输入的公式为 “= getUserNameById('u001')”。该函数及参数是可以解析的。 27 | 28 | ### 变量的扩展性 29 | 本 SDK 支持特殊变量的解析。当变量以 '@' 符号开头时,将解析为特殊变量。 30 | 例如,公式为 '= @lastyear'。 31 | 32 | ### 用于文本格式化(beautify) 33 | 通过生成的解析树、语法树,可以生成美化后的公式文本。 34 | 35 | ## 安装 36 | 37 | CommonJS 规范: 38 | ```js 39 | const formulaSDK = require('excel-formula-sdk'); 40 | const { FormulaEngine, WorkBookContext } = formulaSDK; 41 | ``` 42 | 43 | ` 46 | ``` 47 | 48 | 通过 ` 22 | 23 | 24 | 25 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /test/input/formula1.txt: -------------------------------------------------------------------------------- 1 | Sheet!A1 -------------------------------------------------------------------------------- /test/require-alias/loader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 添加别名功能 3 | */ 4 | 5 | const Module = require('module'); 6 | const path = require('path'); 7 | const mochaMain = require('mocha/lib/cli').main; 8 | 9 | const nodeRequire = Module.prototype.require; 10 | 11 | const resolve = { 12 | alias: { 13 | base: path.resolve(__dirname, '../../src/base/'), 14 | platform: path.resolve(__dirname, '../../src/platform/'), 15 | workbench: path.resolve(__dirname, '../../src/workbench/') 16 | } 17 | } 18 | 19 | function findAlias(id, alias) { 20 | let keys = Object.keys(alias); 21 | return keys.find(function(key) { 22 | return id.startsWith(key); 23 | }); 24 | } 25 | 26 | function resolveId(id, aliasMap) { 27 | let aliasKey = findAlias(id, aliasMap); 28 | if(!aliasKey) { 29 | return id; 30 | } 31 | 32 | return id.replace(aliasKey, aliasMap[aliasKey]); 33 | } 34 | 35 | function requireHooks(id) { 36 | // console.log('hooks ' + id); 37 | let aliasId = resolveId(id, resolve.alias); 38 | return nodeRequire.apply(this, [aliasId]); 39 | } 40 | 41 | 42 | Module.prototype.require = requireHooks; 43 | 44 | mochaMain(); --------------------------------------------------------------------------------