diff --git a/gulpfile.js b/gulpfile.js index b5f9a21..3e6c5ef 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -3,6 +3,7 @@ var gulp = require('gulp'), rename = require('gulp-rename'), notify = require('gulp-notify'), concat = require('gulp-concat'), + webpack = require('webpack-stream'), del = require('del'), fs = require('fs.extra'), paths = { @@ -33,16 +34,34 @@ gulp.task('update_bs_fonts', function(){ gulp.task('libs', gulp.series('update_jquery', 'update_bs_js', 'update_bs_css', 'update_bs_fonts')); -gulp.task('scripts', function() { +gulp.task('script-concat', function() { return gulp.src(paths.scripts) - .pipe(concat('core.js')) - .pipe(concat('excel-formula.js')) - .pipe(gulp.dest('dist')) - .pipe(rename({suffix: '.min'})) - .pipe(uglify()) - .pipe(gulp.dest('dist')) + .pipe(webpack({ + mode: 'production', + output: { + filename: 'excel-formula.js', + }, + optimization: { + minimize: false + } + })) + .pipe(gulp.dest('dist')) +}); + +gulp.task('script-minify', function() { + return gulp.src(paths.scripts) + .pipe(webpack({ + mode: 'production', + output: { + filename: 'excel-formula.js', + } + })) + .pipe(rename({suffix: '.min'})) + .pipe(gulp.dest('dist')) }); +gulp.task('scripts', gulp.series(['script-concat', 'script-minify'])) + gulp.task('site', function() { return gulp.src(paths.siteScripts) .pipe(concat('page.js')) diff --git a/package.json b/package.json index 3376d5d..6ad5b48 100644 --- a/package.json +++ b/package.json @@ -17,11 +17,7 @@ "repository": { "url": "git://github.com/joshatjben/excelFormulaUtilitiesJS.git" }, - "keyword": [ - "excel", - "formula", - "convert" - ], + "keyword": ["excel", "formula", "convert"], "scripts": { "build": "gulp", "test": "mocha & qunit -t ./test/browser/ExcelFormulaUtilities.test.js -d ./src/core.js -c ./src/ExcelFormulaUtilities.js & qunit -c ./dist/excel-formula.min.js -t ./test/browser/ExcelFormulaUtilities.test.js & qunit -c ./dist/excel-formula.js -t ./test/browser/ExcelFormulaUtilities.test.js" @@ -41,10 +37,13 @@ "gulp-rename": "^1.2.2", "gulp-uglify": "^1.4.1", "mocha": "^9.1.3", - "qunit": "~0.7.7" + "qunit": "~0.7.7", + "webpack": "^5.65.0", + "webpack-stream": "^7.0.0" }, "dependencies": { "bootstrap": "^4.1.3", + "excel-formula-tokenizer": "jlaramie/excel-formula-tokenizer#compatibility_updates", "jquery": "^3.2.1" } } diff --git a/src/ExcelFormulaUtilities.js b/src/ExcelFormulaUtilities.js index a1558fa..ebdb51f 100644 --- a/src/ExcelFormulaUtilities.js +++ b/src/ExcelFormulaUtilities.js @@ -1,3 +1,9 @@ +var Tokenizer = require("excel-formula-tokenizer"); +var getTokens = Tokenizer.tokenize, + types = Tokenizer.TYPES, + F_tokens = Tokenizer.Tokens, + F_tokenStack = Tokenizer.TokenStack; + /* * excelFormulaUtilitiesJS * https://github.com/joshatjben/excelFormulaUtilitiesJS/ @@ -17,33 +23,7 @@ var excelFormulaUtilities = root.excelFormulaUtilities = root.excelFormulaUtilities || {}, core = root.excelFormulaUtilities.core, formatStr = root.excelFormulaUtilities.string.formatStr, - trim = root.excelFormulaUtilities.string.trim, - - types = {}, - TOK_TYPE_NOOP = types.TOK_TYPE_NOOP = "noop", - TOK_TYPE_OPERAND = types.TOK_TYPE_OPERAND = "operand", - TOK_TYPE_FUNCTION = types.TOK_TYPE_FUNCTION = "function", - TOK_TYPE_SUBEXPR = types.TOK_TYPE_SUBEXPR = "subexpression", - TOK_TYPE_ARGUMENT = types.TOK_TYPE_ARGUMENT = "argument", - TOK_TYPE_OP_PRE = types.TOK_TYPE_OP_PRE = "operator-prefix", - TOK_TYPE_OP_IN = types.TOK_TYPE_OP_IN = "operator-infix", - TOK_TYPE_OP_POST = types.TOK_TYPE_OP_POST = "operator-postfix", - TOK_TYPE_WHITE_SPACE = types.TOK_TYPE_WHITE_SPACE = "white-space", - TOK_TYPE_UNKNOWN = types.TOK_TYPE_UNKNOWN = "unknown", - - TOK_SUBTYPE_START = types.TOK_SUBTYPE_START = "start", - TOK_SUBTYPE_STOP = types.TOK_SUBTYPE_STOP = "stop", - - TOK_SUBTYPE_TEXT = types.TOK_SUBTYPE_TEXT = "text", - TOK_SUBTYPE_NUMBER = types.TOK_SUBTYPE_NUMBER = "number", - TOK_SUBTYPE_LOGICAL = types.TOK_SUBTYPE_LOGICAL = "logical", - TOK_SUBTYPE_ERROR = types.TOK_SUBTYPE_ERROR = "error", - TOK_SUBTYPE_RANGE = types.TOK_SUBTYPE_RANGE = "range", - - TOK_SUBTYPE_MATH = types.TOK_SUBTYPE_MATH = "math", - TOK_SUBTYPE_CONCAT = types.TOK_SUBTYPE_CONCAT = "concatenate", - TOK_SUBTYPE_INTERSECT = types.TOK_SUBTYPE_INTERSECT = "intersect", - TOK_SUBTYPE_UNION = types.TOK_SUBTYPE_UNION = "union"; + trim = root.excelFormulaUtilities.string.trim; root.excelFormulaUtilities.isEu = typeof root.excelFormulaUtilities.isEu === 'boolean' ? root.excelFormulaUtilities.isEu : false; @@ -58,529 +38,6 @@ this.subtype = subtype; } - /** - * @class - */ - - function F_tokens() { - - this.items = []; - - this.add = function (value, type, subtype) { - if (!subtype) { - subtype = ""; - } - var token = new F_token(value, type, subtype); - this.addRef(token); - return token; - }; - this.addRef = function (token) { - this.items.push(token); - }; - - this.index = -1; - this.reset = function () { - this.index = -1; - }; - this.BOF = function () { - return (this.index <= 0); - }; - this.EOF = function () { - return (this.index >= (this.items.length - 1)); - }; - this.moveNext = function () { - if (this.EOF()) { - return false; - } - this.index += 1; - return true; - }; - this.current = function () { - if (this.index === -1) { - return null; - } - return (this.items[this.index]); - }; - this.next = function () { - if (this.EOF()) { - return null; - } - return (this.items[this.index + 1]); - }; - this.previous = function () { - if (this.index < 1) { - return null; - } - return (this.items[this.index - 1]); - }; - - } - - function F_tokenStack() { - - this.items = []; - - this.push = function (token) { - this.items.push(token); - }; - this.pop = function (name) { - var token = this.items.pop(); - return (new F_token(name || "", token.type, TOK_SUBTYPE_STOP)); - }; - - this.token = function () { - return ((this.items.length > 0) ? this.items[this.items.length - 1] : null); - }; - this.value = function () { - return ((this.token()) ? this.token().value.toString() : ""); - }; - this.type = function () { - return ((this.token()) ? this.token().type.toString() : ""); - }; - this.subtype = function () { - return ((this.token()) ? this.token().subtype.toString() : ""); - }; - - } - - function getTokens(formula) { - - var tokens = new F_tokens(), - tokenStack = new F_tokenStack(), - - offset = 0, - - currentChar = function () { - return formula.substr(offset, 1); - }, - doubleChar = function () { - return formula.substr(offset, 2); - }, - nextChar = function () { - return formula.substr(offset + 1, 1); - }, - EOF = function () { - return (offset >= formula.length); - }, - - token = "", - - inString = false, - inPath = false, - inRange = false, - inError = false, - regexSN = /^[1-9]{1}(\.[0-9]+)?E{1}$/; - - while (formula.length > 0) { - if (formula.substr(0, 1) === " ") { - formula = formula.substr(1); - } else { - if (formula.substr(0, 1) === "=") { - formula = formula.substr(1); - } - break; - } - } - - - - while (!EOF()) { - // state-dependent character evaluation (order is important) - // double-quoted strings - // embeds are doubled - // end marks token - if (inString) { - if (currentChar() === "\"") { - if (nextChar() === "\"") { - token += "\""; - offset += 1; - } else { - inString = false; - tokens.add(token, TOK_TYPE_OPERAND, TOK_SUBTYPE_TEXT); - token = ""; - } - } else { - token += currentChar(); - } - offset += 1; - continue; - } - - // single-quoted strings (links) - // embeds are double - // end does not mark a token - if (inPath) { - if (currentChar() === "'") { - - if (nextChar() === "'") { - token += "'"; - offset += 1; - } else { - inPath = false; - token += "'"; - } - } else { - token += currentChar(); - } - - offset += 1; - continue; - } - - // bracketed strings (range offset or linked workbook name) - // no embeds (changed to "()" by Excel) - // end does not mark a token - if (inRange) { - if (currentChar() === "]") { - inRange = false; - } - token += currentChar(); - offset += 1; - continue; - } - - // error values - // end marks a token, determined from absolute list of values - if (inError) { - token += currentChar(); - offset += 1; - if ((",#NULL!,#DIV/0!,#VALUE!,#REF!,#NAME?,#NUM!,#N/A,").indexOf("," + token + ",") !== -1) { - inError = false; - tokens.add(token, TOK_TYPE_OPERAND, TOK_SUBTYPE_ERROR); - token = ""; - } - continue; - } - - // scientific notation check - if (("+-").indexOf(currentChar()) !== -1) { - if (token.length > 1) { - if (token.match(regexSN)) { - token += currentChar(); - offset += 1; - continue; - } - } - } - - // independent character evaluation (order not important) - // establish state-dependent character evaluations - if (currentChar() === "\"") { - if (token.length > 0) { - // not expected - tokens.add(token, TOK_TYPE_UNKNOWN); - token = ""; - } - inString = true; - offset += 1; - continue; - } - - if (currentChar() === "'") { - if (token.length > 0) { - // not expected - tokens.add(token, TOK_TYPE_UNKNOWN); - token = ""; - } - token = "'" - inPath = true; - offset += 1; - continue; - } - - if (currentChar() === "[") { - inRange = true; - token += currentChar(); - offset += 1; - continue; - } - - if (currentChar() === "#") { - if (token.length > 0) { - // not expected - tokens.add(token, TOK_TYPE_UNKNOWN); - token = ""; - } - inError = true; - token += currentChar(); - offset += 1; - continue; - } - - // mark start and end of arrays and array rows - if (currentChar() === "{") { - if (token.length > 0) { - // not expected - tokens.add(token, TOK_TYPE_UNKNOWN); - token = ""; - } - tokenStack.push(tokens.add("ARRAY", TOK_TYPE_FUNCTION, TOK_SUBTYPE_START)); - tokenStack.push(tokens.add("ARRAYROW", TOK_TYPE_FUNCTION, TOK_SUBTYPE_START)); - offset += 1; - continue; - } - - if (currentChar() === ";" ) { - if(root.excelFormulaUtilities.isEu){ - // If is EU then handle ; as list separators - if (token.length > 0) { - tokens.add(token, TOK_TYPE_OPERAND); - token = ""; - } - if (tokenStack.type() !== TOK_TYPE_FUNCTION) { - tokens.add(currentChar(), TOK_TYPE_OP_IN, TOK_SUBTYPE_UNION); - } else { - tokens.add(currentChar(), TOK_TYPE_ARGUMENT); - } - offset += 1; - continue; - } else { - // Else if not Eu handle ; as array row separator - if (token.length > 0) { - tokens.add(token, TOK_TYPE_OPERAND); - token = ""; - } - tokens.addRef(tokenStack.pop()); - tokens.add(",", TOK_TYPE_ARGUMENT); - tokenStack.push(tokens.add("ARRAYROW", TOK_TYPE_FUNCTION, TOK_SUBTYPE_START)); - offset += 1; - continue; - } - } - - if (currentChar() === "}") { - if (token.length > 0) { - tokens.add(token, TOK_TYPE_OPERAND); - token = ""; - } - tokens.addRef(tokenStack.pop("ARRAYROWSTOP")); - tokens.addRef(tokenStack.pop("ARRAYSTOP")); - offset += 1; - continue; - } - - // trim white-space - if (currentChar() === " ") { - if (token.length > 0) { - tokens.add(token, TOK_TYPE_OPERAND); - token = ""; - } - tokens.add("", TOK_TYPE_WHITE_SPACE); - offset += 1; - while ((currentChar() === " ") && (!EOF())) { - offset += 1; - } - continue; - } - - // multi-character comparators - if ((",>=,<=,<>,").indexOf("," + doubleChar() + ",") !== -1) { - if (token.length > 0) { - tokens.add(token, TOK_TYPE_OPERAND); - token = ""; - } - tokens.add(doubleChar(), TOK_TYPE_OP_IN, TOK_SUBTYPE_LOGICAL); - offset += 2; - continue; - } - - // standard infix operators - if (("+-*/^&=><").indexOf(currentChar()) !== -1) { - if (token.length > 0) { - tokens.add(token, TOK_TYPE_OPERAND); - token = ""; - } - tokens.add(currentChar(), TOK_TYPE_OP_IN); - offset += 1; - continue; - } - - // standard postfix operators - if (("%").indexOf(currentChar()) !== -1) { - if (token.length > 0) { - tokens.add(token, TOK_TYPE_OPERAND); - token = ""; - } - tokens.add(currentChar(), TOK_TYPE_OP_POST); - offset += 1; - continue; - } - - // start subexpression or function - if (currentChar() === "(") { - if (token.length > 0) { - tokenStack.push(tokens.add(token, TOK_TYPE_FUNCTION, TOK_SUBTYPE_START)); - token = ""; - } else { - tokenStack.push(tokens.add("", TOK_TYPE_SUBEXPR, TOK_SUBTYPE_START)); - } - offset += 1; - continue; - } - - // function, subexpression, array parameters - if (currentChar() === "," && !root.excelFormulaUtilities.isEu) { - if (token.length > 0) { - tokens.add(token, TOK_TYPE_OPERAND); - token = ""; - } - if (tokenStack.type() !== TOK_TYPE_FUNCTION) { - tokens.add(currentChar(), TOK_TYPE_OP_IN, TOK_SUBTYPE_UNION); - } else { - tokens.add(currentChar(), TOK_TYPE_ARGUMENT); - } - offset += 1; - continue; - } - - // stop subexpression - if (currentChar() === ")") { - if (token.length > 0) { - tokens.add(token, TOK_TYPE_OPERAND); - token = ""; - } - tokens.addRef(tokenStack.pop()); - offset += 1; - continue; - } - - // token accumulation - token += currentChar(); - offset += 1; - - } - - // dump remaining accumulation - if (token.length > 0 || inString || inPath || inRange || inError) { - if (inString || inPath || inRange || inError) { - if (inString) { - token = "\"" + token; - } else if (inPath) { - token = "'" + token; - } else if (inRange) { - token = "[" + token; - } else if (inError) { - token = "#" + token; - } - - tokens.add(token, TOK_TYPE_UNKNOWN); - } else { - tokens.add(token, TOK_TYPE_OPERAND); - } - } - - // move all tokens to a new collection, excluding all unnecessary white-space tokens - var tokens2 = new F_tokens(); - - while (tokens.moveNext()) { - - token = tokens.current(); - - if (token.type.toString() === TOK_TYPE_WHITE_SPACE) { - var doAddToken = (tokens.BOF()) || (tokens.EOF()); - //if ((tokens.BOF()) || (tokens.EOF())) {} - doAddToken = doAddToken && (((tokens.previous().type.toString() === TOK_TYPE_FUNCTION) && (tokens.previous().subtype.toString() === TOK_SUBTYPE_STOP)) || ((tokens.previous().type.toString() === TOK_TYPE_SUBEXPR) && (tokens.previous().subtype.toString() === TOK_SUBTYPE_STOP)) || (tokens.previous().type.toString() === TOK_TYPE_OPERAND)); - //else if (!( - // ((tokens.previous().type === TOK_TYPE_FUNCTION) && (tokens.previous().subtype == TOK_SUBTYPE_STOP)) - // || ((tokens.previous().type == TOK_TYPE_SUBEXPR) && (tokens.previous().subtype == TOK_SUBTYPE_STOP)) - // || (tokens.previous().type == TOK_TYPE_OPERAND))) - // {} - doAddToken = doAddToken && (((tokens.next().type.toString() === TOK_TYPE_FUNCTION) && (tokens.next().subtype.toString() === TOK_SUBTYPE_START)) || ((tokens.next().type.toString() === TOK_TYPE_SUBEXPR) && (tokens.next().subtype.toString() === TOK_SUBTYPE_START)) || (tokens.next().type.toString() === TOK_TYPE_OPERAND)); - //else if (!( - // ((tokens.next().type == TOK_TYPE_FUNCTION) && (tokens.next().subtype == TOK_SUBTYPE_START)) - // || ((tokens.next().type == TOK_TYPE_SUBEXPR) && (tokens.next().subtype == TOK_SUBTYPE_START)) - // || (tokens.next().type == TOK_TYPE_OPERAND))) - // {} - //else { tokens2.add(token.value, TOK_TYPE_OP_IN, TOK_SUBTYPE_INTERSECT)}; - if (doAddToken) { - tokens2.add(token.value.toString(), TOK_TYPE_OP_IN, TOK_SUBTYPE_INTERSECT); - } - continue; - } - - tokens2.addRef(token); - - } - - // switch infix "-" operator to prefix when appropriate, switch infix "+" operator to noop when appropriate, identify operand - // and infix-operator subtypes, pull "@" from in front of function names - while (tokens2.moveNext()) { - - token = tokens2.current(); - - if ((token.type.toString() === TOK_TYPE_OP_IN) && (token.value.toString() === "-")) { - if (tokens2.BOF()) { - token.type = TOK_TYPE_OP_PRE.toString(); - } else if (((tokens2.previous().type.toString() === TOK_TYPE_FUNCTION) && (tokens2.previous().subtype.toString() === TOK_SUBTYPE_STOP)) || ((tokens2.previous().type.toString() === TOK_TYPE_SUBEXPR) && (tokens2.previous().subtype.toString() === TOK_SUBTYPE_STOP)) || (tokens2.previous().type.toString() === TOK_TYPE_OP_POST) || (tokens2.previous().type.toString() === TOK_TYPE_OPERAND)) { - token.subtype = TOK_SUBTYPE_MATH.toString(); - } else { - token.type = TOK_TYPE_OP_PRE.toString(); - } - continue; - } - - if ((token.type.toString() === TOK_TYPE_OP_IN) && (token.value.toString() === "+")) { - if (tokens2.BOF()) { - token.type = TOK_TYPE_NOOP.toString(); - } else if (((tokens2.previous().type.toString() === TOK_TYPE_FUNCTION) && (tokens2.previous().subtype.toString() === TOK_SUBTYPE_STOP)) || ((tokens2.previous().type.toString() === TOK_TYPE_SUBEXPR) && (tokens2.previous().subtype.toString() === TOK_SUBTYPE_STOP)) || (tokens2.previous().type.toString() === TOK_TYPE_OP_POST) || (tokens2.previous().type.toString() === TOK_TYPE_OPERAND)) { - token.subtype = TOK_SUBTYPE_MATH.toString(); - } else { - token.type = TOK_TYPE_NOOP.toString(); - } - continue; - } - - if ((token.type.toString() === TOK_TYPE_OP_IN) && (token.subtype.length === 0)) { - if (("<>=").indexOf(token.value.substr(0, 1)) !== -1) { - token.subtype = TOK_SUBTYPE_LOGICAL.toString(); - } else if (token.value.toString() === "&") { - token.subtype = TOK_SUBTYPE_CONCAT.toString(); - } else { - token.subtype = TOK_SUBTYPE_MATH.toString(); - } - continue; - } - - if ((token.type.toString() === TOK_TYPE_OPERAND) && (token.subtype.length === 0)) { - if (isNaN(parseFloat(token.value))) { - if ((token.value.toString() === 'TRUE') || (token.value.toString() === 'FALSE')) { - token.subtype = TOK_SUBTYPE_LOGICAL.toString(); - } else { - token.subtype = TOK_SUBTYPE_RANGE.toString(); - } - } else { - token.subtype = TOK_SUBTYPE_NUMBER.toString(); - } - - continue; - } - - if (token.type.toString() === TOK_TYPE_FUNCTION) { - if (token.value.substr(0, 1) === "@") { - token.value = token.value.substr(1).toString(); - } - continue; - } - - } - - tokens2.reset(); - - // move all tokens to a new collection, excluding all no-ops - tokens = new F_tokens(); - - while (tokens2.moveNext()) { - if (tokens2.current().type.toString() !== TOK_TYPE_NOOP) { - tokens.addRef(tokens2.current()); - } - } - - tokens.reset(); - - return tokens; - } - - var parseFormula = excelFormulaUtilities.parseFormula = function (inputID, outputID) { @@ -598,7 +55,11 @@ var formulaControl = document.getElementById(inputID); var formula = formulaControl.value; - var tokens = getTokens(formula); + var tokens = getTokens(formula, { + asClass: true, + language: root.excelFormulaUtilities.isEu ? "en-EU" : "en-US", + preserveLanguage: true + }); var tokensHtml = ""; @@ -614,7 +75,7 @@ var token = tokens.current(); - if (token.subtype === TOK_SUBTYPE_STOP) { + if (token.subtype === types.TOK_SUBTYPE_STOP) { indentCount -= ((indentCount > 0) ? 1 : 0); } @@ -629,7 +90,7 @@ tokensHtml += ""; - if (token.subtype === TOK_SUBTYPE_START) { + if (token.subtype === types.TOK_SUBTYPE_START) { indentCount += 1; } @@ -777,16 +238,18 @@ //-----------------FUNCTION------------------ switch (token.value) { case "ARRAY": - tokenString = formatStr(replaceTokenTmpl(options.tmplFunctionStartArray), tokenString, indent, lineBreak); + if (token.subtype.toString() === "start") { + tokenString = formatStr(replaceTokenTmpl(options.tmplFunctionStartArray), tokenString, indent, lineBreak); + } else { + tokenString = formatStr(replaceTokenTmpl(options.tmplFunctionStopArray), tokenString, indent, lineBreak); + } break; case "ARRAYROW": - tokenString = formatStr(replaceTokenTmpl(options.tmplFunctionStartArrayRow), tokenString, indent, lineBreak); - break; - case "ARRAYSTOP": - tokenString = formatStr(replaceTokenTmpl(options.tmplFunctionStopArray), tokenString, indent, lineBreak); - break; - case "ARRAYROWSTOP": - tokenString = formatStr(replaceTokenTmpl(options.tmplFunctionStopArrayRow), tokenString, indent, lineBreak); + if (token.subtype.toString() === "start") { + tokenString = formatStr(replaceTokenTmpl(options.tmplFunctionStartArrayRow), tokenString, indent, lineBreak); + } else { + tokenString = formatStr(replaceTokenTmpl(options.tmplFunctionStopArrayRow), tokenString, indent, lineBreak); + } break; default: if (token.subtype.toString() === "start") { @@ -945,7 +408,11 @@ return s; }; - var tokens = getTokens(formula); + var tokens = getTokens(formula, { + asClass: true, + language: root.excelFormulaUtilities.isEu ? "en-EU" : "en-US", + preserveLanguage: true + }); var outputFormula = ""; @@ -971,7 +438,7 @@ var token = tokens.current(); var nextToken = tokens.next(); - if (token.subtype.toString() === TOK_SUBTYPE_STOP) { + if (token.subtype.toString() === types.TOK_SUBTYPE_STOP) { indentCount -= ((indentCount > 0) ? 1 : 0); } @@ -985,7 +452,7 @@ // TODO this strips out spaces which breaks part of issue 28. 'Data Sheet' gets changed to DataSheet outputFormula += applyTokenTemplate(token, options, indent, lineBreak, options.customTokenRender, lastToken); - if (token.subtype.toString() === TOK_SUBTYPE_START) { + if (token.subtype.toString() === types.TOK_SUBTYPE_START) { indentCount += 1; } @@ -1012,8 +479,8 @@ var tokRender = function(tokenStr, token, indent, lineBreak){ var outStr = tokenStr; switch (token.type.toString()) { - case TOK_TYPE_OPERAND: - if(token.subtype === TOK_SUBTYPE_TEXT){ + case types.TOK_TYPE_OPERAND: + if(token.subtype === types.TOK_SUBTYPE_TEXT){ outStr = tokenStr.replace(//gi,">"); } break; @@ -1082,11 +549,11 @@ switch (token.type.toString()) { - case TOK_TYPE_FUNCTION: + case types.TOK_TYPE_FUNCTION: switch (token.subtype) { - case TOK_SUBTYPE_START: + case types.TOK_SUBTYPE_START: functionStack.push({ name: tokenString, @@ -1097,7 +564,7 @@ break; - case TOK_SUBTYPE_STOP: + case types.TOK_SUBTYPE_STOP: useTemplate = true; switch (currentFunctionOnStack.name.toLowerCase()) { @@ -1115,7 +582,7 @@ break; - case TOK_TYPE_ARGUMENT: + case types.TOK_TYPE_ARGUMENT: switch (currentFunctionOnStack.name.toLowerCase()) { case "if": switch (currentFunctionOnStack.argumentNumber) { @@ -1146,11 +613,11 @@ break; - case TOK_TYPE_OPERAND: + case types.TOK_TYPE_OPERAND: switch (token.subtype) { - case TOK_SUBTYPE_RANGE: + case types.TOK_SUBTYPE_RANGE: //Assume '=' sign if(!currentFunctionOnStack){ break; @@ -1296,11 +763,11 @@ switch (token.type.toString()) { - case TOK_TYPE_FUNCTION: + case types.TOK_TYPE_FUNCTION: switch (token.subtype) { - case TOK_SUBTYPE_START: + case types.TOK_SUBTYPE_START: functionStack.push({ name: tokenString, @@ -1311,7 +778,7 @@ break; - case TOK_SUBTYPE_STOP: + case types.TOK_SUBTYPE_STOP: useTemplate = true; switch (currentFunctionOnStack.name.toLowerCase()) { @@ -1332,7 +799,7 @@ break; - case TOK_TYPE_ARGUMENT: + case types.TOK_TYPE_ARGUMENT: switch (currentFunctionOnStack.name.toLowerCase()) { case "if": switch (currentFunctionOnStack.argumentNumber) { @@ -1363,11 +830,11 @@ break; - case TOK_TYPE_OPERAND: + case types.TOK_TYPE_OPERAND: switch (token.subtype) { - case TOK_SUBTYPE_RANGE: + case types.TOK_SUBTYPE_RANGE: //Assume '=' sign if(!currentFunctionOnStack){ break; diff --git a/test/ExcelFormulaUtilities.test.js b/test/ExcelFormulaUtilities.test.js index 2fc0761..22db96f 100644 --- a/test/ExcelFormulaUtilities.test.js +++ b/test/ExcelFormulaUtilities.test.js @@ -60,6 +60,15 @@ describe("ExcelFormulaUtilities", () => { let actual = formula.formatFormulaHTML(inputFormula); assert.equal(actual, expected); }) + }) + + describe("#arrayliterals", () => { + it("Test parsing a formula that contains array literals. From Issue #83", () => { + let inputFormula='=SORT($B$3:$F$20,{2,1},{-1,1})'; + let expected = '={ A1:C2,
        B2:C3}'; + let actual = formula.formatFormulaHTML(inputFormula); + assert.equal(actual, expected); + }) }) })