@@ -2,6 +2,8 @@ import * as glide from "../glide";
22
33import FormulaParser , { FormulaHelpers , Types } from "fast-formula-parser" ;
44
5+ let data : any [ ] [ ] = [ ] ;
6+
57function convertCell ( cell : any ) : any {
68 try {
79 if ( typeof cell === "string" ) {
@@ -16,38 +18,50 @@ function convertCell(cell: any): any {
1618 }
1719}
1820
19- const run : glide . Column = ( formula , ...params ) => {
20- const data : any [ ] [ ] = params . map ( p => [ p . value ] ) ;
21-
22- const parser = new FormulaParser ( {
23- functions : {
24- UPPER : text => {
25- text = FormulaHelpers . accept ( text , Types . STRING ) ;
26- return text . toUpperCase ( ) ;
27- } ,
28- } ,
29- onCell : ( { _, row, col } ) => {
30- return convertCell ( data [ row - 1 ] [ col - 1 ] ) ;
21+ // We keep a single instance of this because it caches parsed formulas. Making
22+ // a new one for each invocation makes running lots of these about 2 order of
23+ // magnitude slower.
24+ const parser = new FormulaParser ( {
25+ functions : {
26+ UPPER : text => {
27+ text = FormulaHelpers . accept ( text , Types . STRING ) ;
28+ return text . toUpperCase ( ) ;
3129 } ,
32- onRange : ( ref : { from : { row : number ; col : number } ; to : { row : number ; col : number } } ) => {
33- const arr : any [ ] [ ] = [ ] ;
34- for ( let row = ref . from . row ; row <= ref . to . row ; row ++ ) {
35- const innerArr : any [ ] = [ ] ;
36- if ( data [ row - 1 ] ) {
37- for ( let col = ref . from . col ; col <= ref . to . col ; col ++ ) {
38- innerArr . push ( convertCell ( data [ row - 1 ] [ col - 1 ] ) ) ;
39- }
30+ } ,
31+ onCell : ( { _, row, col } ) => {
32+ return convertCell ( data [ row - 1 ] [ col - 1 ] ) ;
33+ } ,
34+ onRange : ( ref : { from : { row : number ; col : number } ; to : { row : number ; col : number } } ) => {
35+ const arr : any [ ] [ ] = [ ] ;
36+ for ( let row = ref . from . row ; row <= ref . to . row ; row ++ ) {
37+ const innerArr : any [ ] = [ ] ;
38+ if ( data [ row - 1 ] ) {
39+ for ( let col = ref . from . col ; col <= ref . to . col ; col ++ ) {
40+ innerArr . push ( convertCell ( data [ row - 1 ] [ col - 1 ] ) ) ;
4041 }
41- arr . push ( innerArr ) ;
4242 }
43- return arr ;
44- } ,
45- } ) ;
43+ arr . push ( innerArr ) ;
44+ }
45+ return arr ;
46+ } ,
47+ } ) ;
4648
49+ const run : glide . Column = ( formula , ...params ) => {
4750 if ( formula ?. value === undefined ) return undefined ;
51+
52+ data = params . map ( p => [ p . value ] ) ;
53+
4854 const position = { row : 1 , col : 1 , sheet : 0 } ;
4955 try {
50- return parser . parse ( formula . value , position ) ;
56+ const v = parser . parse ( formula . value , position ) ;
57+ // fast-formula-parser can return non-primitives such as arrays, but
58+ // also error objects, none of which we want to, or are allowed to,
59+ // return.
60+ if ( typeof v === "number" || typeof v === "string" || typeof v === "boolean" ) {
61+ return v ;
62+ } else {
63+ return undefined ;
64+ }
5165 } catch ( err ) { }
5266} ;
5367
@@ -100,5 +114,9 @@ export default glide.column({
100114 { params : { formula : "SUM(A1, A2)" , A1 : 4 , A2 : "4" } , expectedResult : 8 } ,
101115 { params : { formula : "SUM(A1, A2, 5)" , A1 : "5" , A2 : "10" } , expectedResult : 20 } ,
102116 { params : { formula : 'UPPER("hello")' } , expectedResult : "HELLO" } ,
117+ {
118+ params : { formula : 'IF(ISBLANK(A1),"",REPLACE(A1,FIND(" ",A1),1,""))' , A1 : "Unknown" } ,
119+ expectedResult : undefined ,
120+ } ,
103121 ] ,
104122} ) ;
0 commit comments