@trebco/treb 30.16.0 → 31.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api-generator/api-generator.ts +3 -1
- package/api-generator/package.json +2 -1
- package/dist/treb-export-worker.mjs +2 -2
- package/dist/treb-spreadsheet.mjs +13 -13
- package/dist/treb.d.ts +19 -2
- package/package.json +8 -7
- package/treb-base-types/src/font-stack.ts +144 -0
- package/treb-base-types/src/style.ts +121 -11
- package/treb-base-types/src/theme.ts +53 -8
- package/treb-calculator/src/calculator.ts +13 -13
- package/treb-calculator/src/descriptors.ts +12 -4
- package/treb-calculator/src/expression-calculator.ts +17 -4
- package/treb-calculator/src/functions/base-functions.ts +57 -4
- package/treb-calculator/src/functions/statistics-functions.ts +9 -6
- package/treb-calculator/tsconfig.json +11 -0
- package/treb-charts/style/charts.scss +7 -1
- package/treb-data-model/src/annotation.ts +6 -0
- package/treb-data-model/src/data_model.ts +14 -3
- package/treb-data-model/src/sheet.ts +57 -56
- package/treb-embed/markup/toolbar.html +15 -1
- package/treb-embed/src/custom-element/spreadsheet-constructor.ts +38 -0
- package/treb-embed/src/embedded-spreadsheet.ts +119 -29
- package/treb-embed/src/options.ts +3 -0
- package/treb-embed/src/selection-state.ts +1 -0
- package/treb-embed/src/toolbar-message.ts +6 -0
- package/treb-embed/src/types.ts +9 -0
- package/treb-embed/style/defaults.scss +12 -1
- package/treb-embed/style/font-stacks.scss +105 -0
- package/treb-embed/style/layout.scss +1 -0
- package/treb-embed/style/theme-defaults.scss +12 -2
- package/treb-embed/style/toolbar.scss +16 -0
- package/treb-grid/src/editors/overlay_editor.ts +36 -3
- package/treb-grid/src/layout/base_layout.ts +52 -37
- package/treb-grid/src/layout/grid_layout.ts +7 -0
- package/treb-grid/src/render/tile_renderer.ts +154 -148
- package/treb-grid/src/types/grid.ts +188 -54
- package/treb-grid/src/types/grid_events.ts +1 -1
- package/treb-grid/src/types/grid_options.ts +3 -0
- package/treb-grid/src/util/fontmetrics.ts +134 -0
- package/treb-parser/src/parser.ts +12 -3
- package/treb-utils/src/measurement.ts +2 -3
- package/tsproject.json +1 -1
- package/treb-calculator/modern.tsconfig.json +0 -11
- package/treb-grid/src/util/fontmetrics2.ts +0 -182
- package/treb-parser/src/parser.test.ts +0 -298
- /package/treb-embed/{modern.tsconfig.json → tsconfig.json} +0 -0
- /package/treb-export/{modern.tsconfig.json → tsconfig.json} +0 -0
package/tsproject.json
CHANGED
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* This file is part of TREB.
|
|
3
|
-
*
|
|
4
|
-
* TREB is free software: you can redistribute it and/or modify it under the
|
|
5
|
-
* terms of the GNU General Public License as published by the Free Software
|
|
6
|
-
* Foundation, either version 3 of the License, or (at your option) any
|
|
7
|
-
* later version.
|
|
8
|
-
*
|
|
9
|
-
* TREB is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
10
|
-
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
11
|
-
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
12
|
-
* details.
|
|
13
|
-
*
|
|
14
|
-
* You should have received a copy of the GNU General Public License along
|
|
15
|
-
* with TREB. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
-
*
|
|
17
|
-
* Copyright 2022-2024 trebco, llc.
|
|
18
|
-
* info@treb.app
|
|
19
|
-
*
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
export interface FontMetrics2 {
|
|
23
|
-
ascender: number;
|
|
24
|
-
descender: number;
|
|
25
|
-
block: number;
|
|
26
|
-
paren: number;
|
|
27
|
-
hash: number;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export class FontMetricsFactory {
|
|
31
|
-
|
|
32
|
-
private canvas!: HTMLCanvasElement;
|
|
33
|
-
|
|
34
|
-
private cache: Record<string, FontMetrics2> = {};
|
|
35
|
-
|
|
36
|
-
// public base_size_px = 10;
|
|
37
|
-
|
|
38
|
-
constructor() {
|
|
39
|
-
|
|
40
|
-
// you don't have to attach this canvas to the document
|
|
41
|
-
// in order to use it to measure. however, if the font size
|
|
42
|
-
// is relative it needs to be relative to the canvas size;
|
|
43
|
-
// and if the canvas is not attached to the document, size
|
|
44
|
-
// doesn't work.
|
|
45
|
-
|
|
46
|
-
// FIXME: test with a containing node?
|
|
47
|
-
// (NOTE: that doesn't help)
|
|
48
|
-
|
|
49
|
-
if (typeof document !== 'undefined') {
|
|
50
|
-
this.canvas = document.createElement('canvas');
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// FIXME: since this is prelude to drawing, couldn't we use
|
|
54
|
-
// our drawing canvas to render? then we don't need to attach
|
|
55
|
-
// garbage to the DOM
|
|
56
|
-
|
|
57
|
-
// alternatively, we could munge the font description...
|
|
58
|
-
|
|
59
|
-
// this.canvas.style.position = 'absolute';
|
|
60
|
-
// this.canvas.style.top = '-1000px';
|
|
61
|
-
// document.body.appendChild(this.canvas);
|
|
62
|
-
|
|
63
|
-
// what we're doing now is calculating -- we get the base size
|
|
64
|
-
// from theme and if we see em or % we scale manually.
|
|
65
|
-
|
|
66
|
-
// based on the above, we don't need to worry about which
|
|
67
|
-
// document we're using. but we probably should just to be consistent.
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/* *
|
|
72
|
-
* set base font size. the idea here is to have a base in case font sizes
|
|
73
|
-
* are relative (% or em), they need to be relative to something. HOWEVER,
|
|
74
|
-
* canvas doesn't inherit --
|
|
75
|
-
*
|
|
76
|
-
* (moved to base_size_points)
|
|
77
|
-
*
|
|
78
|
-
* /
|
|
79
|
-
public BaseSize(size: string): void {
|
|
80
|
-
this.canvas.style.fontSize = size || '';
|
|
81
|
-
}
|
|
82
|
-
*/
|
|
83
|
-
|
|
84
|
-
public Flush(): void {
|
|
85
|
-
this.cache = {};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
public Get(font: string, base = 10): FontMetrics2 {
|
|
89
|
-
const key = font + ';' + base;
|
|
90
|
-
let metrics = this.cache[key];
|
|
91
|
-
if (metrics) {
|
|
92
|
-
return metrics;
|
|
93
|
-
}
|
|
94
|
-
metrics = this.Measure(font, base);
|
|
95
|
-
this.cache[key] = metrics;
|
|
96
|
-
return metrics;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
public Measure(font: string, base: number): FontMetrics2 {
|
|
100
|
-
|
|
101
|
-
const match = font.match(/([\d.]+)((?:%|em))/);
|
|
102
|
-
|
|
103
|
-
if (match) {
|
|
104
|
-
const target = match[1] + match[2];
|
|
105
|
-
let value = Number(match[1]) * base;
|
|
106
|
-
if (match[2] === '%') { value /= 100; }
|
|
107
|
-
font = font.replace(target, value + 'px');
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// what's up with the double-access on context?
|
|
111
|
-
|
|
112
|
-
let context = this.canvas.getContext('2d', {
|
|
113
|
-
willReadFrequently: true,
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
if (!context) {
|
|
117
|
-
throw new Error('invalid context');
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
context.font = font;
|
|
121
|
-
const metrics = context.measureText('MMM');
|
|
122
|
-
|
|
123
|
-
const size = Math.ceil(metrics.width);
|
|
124
|
-
|
|
125
|
-
this.canvas.setAttribute('width', size.toString());
|
|
126
|
-
this.canvas.setAttribute('height', size.toString());
|
|
127
|
-
|
|
128
|
-
context = this.canvas.getContext('2d', {
|
|
129
|
-
willReadFrequently: true,
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
if (!context) {
|
|
133
|
-
throw new Error('invalid context');
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
context.font = font;
|
|
137
|
-
|
|
138
|
-
context.textAlign = 'center';
|
|
139
|
-
context.textBaseline = 'alphabetic';
|
|
140
|
-
context.fillStyle = '#000';
|
|
141
|
-
|
|
142
|
-
const y = Math.round(size * 2 / 3);
|
|
143
|
-
const x = Math.round(size / 2);
|
|
144
|
-
|
|
145
|
-
context.clearRect(0, 0, size, size);
|
|
146
|
-
for (let i = 0x20; i <= 0x7e; i++) {
|
|
147
|
-
const s = String.fromCharCode(i);
|
|
148
|
-
context.fillText(s, x, y);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const data = context.getImageData(0, 0, this.canvas.width, this.canvas.height).data;
|
|
152
|
-
|
|
153
|
-
const top = Math.floor(this.GetFirstIndex(data)/size);
|
|
154
|
-
const bottom = Math.floor(this.GetLastIndex(data)/size);
|
|
155
|
-
|
|
156
|
-
return {
|
|
157
|
-
ascender: y - top,
|
|
158
|
-
descender: bottom - y,
|
|
159
|
-
block: bottom - top + 1,
|
|
160
|
-
paren: context.measureText('(').width,
|
|
161
|
-
hash: context.measureText('##').width - context.measureText('#').width,
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
private GetFirstIndex(pixels: Uint8ClampedArray) {
|
|
167
|
-
for (let i = 3, n = pixels.length; i < n; i += 4) {
|
|
168
|
-
if (pixels[i] > 0) return (i - 3) / 4;
|
|
169
|
-
}
|
|
170
|
-
return pixels.length;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
private GetLastIndex(pixels: Uint8ClampedArray) {
|
|
174
|
-
for (let i = pixels.length - 1; i >= 3; i -= 4) {
|
|
175
|
-
if (pixels[i] > 0) return i / 4;
|
|
176
|
-
}
|
|
177
|
-
return 0;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
export const FontMetricsCache = new FontMetricsFactory();
|
|
@@ -1,298 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* This file is part of TREB.
|
|
3
|
-
*
|
|
4
|
-
* TREB is free software: you can redistribute it and/or modify it under the
|
|
5
|
-
* terms of the GNU General Public License as published by the Free Software
|
|
6
|
-
* Foundation, either version 3 of the License, or (at your option) any
|
|
7
|
-
* later version.
|
|
8
|
-
*
|
|
9
|
-
* TREB is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
10
|
-
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
11
|
-
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
12
|
-
* details.
|
|
13
|
-
*
|
|
14
|
-
* You should have received a copy of the GNU General Public License along
|
|
15
|
-
* with TREB. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
-
*
|
|
17
|
-
* Copyright 2022-2024 trebco, llc.
|
|
18
|
-
* info@treb.app
|
|
19
|
-
*
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
// import { Parser, UnitLiteral, UnitBinary, UnitUnary, DecimalMarkType, UnitCall, ArgumentSeparatorType } from '../';
|
|
23
|
-
import { Parser } from './parser';
|
|
24
|
-
import { ArgumentSeparatorType,
|
|
25
|
-
UnitLiteral, UnitBinary, UnitUnary, DecimalMarkType, UnitCall } from './parser-types';
|
|
26
|
-
|
|
27
|
-
const parser = new Parser();
|
|
28
|
-
|
|
29
|
-
test('constructor', () => {
|
|
30
|
-
expect(typeof parser).toBe('object');
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
describe('basic parsing', () => {
|
|
34
|
-
|
|
35
|
-
test('3 + 4', () => {
|
|
36
|
-
const result = parser.Parse('3 + 4');
|
|
37
|
-
expect(result).toBeDefined();
|
|
38
|
-
expect(result.valid).toBeTruthy();
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
test('/ 2', () => {
|
|
42
|
-
const result = parser.Parse('/ 2');
|
|
43
|
-
expect(result).toBeDefined();
|
|
44
|
-
expect(result.valid).toBeFalsy();
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
describe('parsing/rendering', () => {
|
|
50
|
-
|
|
51
|
-
const expression = '2.2 + (3 / foo(bar("1"), 8))';
|
|
52
|
-
test(expression, () => {
|
|
53
|
-
const result = parser.Parse(expression);
|
|
54
|
-
expect(result.valid).toBeTruthy();
|
|
55
|
-
expect(result.expression).toBeDefined();
|
|
56
|
-
if (result.expression){
|
|
57
|
-
const rendered = parser.Render(result.expression);
|
|
58
|
-
expect(rendered).toEqual(expression);
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
test('converting separators', () => {
|
|
63
|
-
const result = parser.Parse(expression);
|
|
64
|
-
expect(result.valid).toBeTruthy();
|
|
65
|
-
expect(result.expression).toBeDefined();
|
|
66
|
-
if (result.expression){
|
|
67
|
-
const rendered = parser.Render(result.expression,
|
|
68
|
-
undefined, undefined, DecimalMarkType.Comma, ArgumentSeparatorType.Semicolon);
|
|
69
|
-
expect(rendered).toEqual('2,2 + (3 / foo(bar("1"); 8))');
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
describe('number parsing', () => {
|
|
76
|
-
|
|
77
|
-
const decimals = [1, 1.11, 2.2343, 123819238, -6, -7.77, -0.00012];
|
|
78
|
-
|
|
79
|
-
decimals.forEach((decimal) => {
|
|
80
|
-
const as_string = decimal.toString();
|
|
81
|
-
test(as_string, () => {
|
|
82
|
-
const result = parser.Parse(as_string);
|
|
83
|
-
expect(result).toBeDefined();
|
|
84
|
-
expect(result.expression).toBeDefined();
|
|
85
|
-
if (result.expression) {
|
|
86
|
-
expect(result.expression.type).toBe('literal');
|
|
87
|
-
expect((result.expression as UnitLiteral).value).toBeCloseTo(decimal);
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
test('2.2e-7', () => {
|
|
93
|
-
const result = parser.Parse('2.2e-7');
|
|
94
|
-
expect(result).toBeDefined();
|
|
95
|
-
expect(result.expression).toBeDefined();
|
|
96
|
-
if (result.expression) {
|
|
97
|
-
expect(result.expression.type).toBe('literal');
|
|
98
|
-
expect((result.expression as UnitLiteral).value).toBeCloseTo(2.2e-7);
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
test('-1.123e8', () => {
|
|
103
|
-
const result = parser.Parse('-1.123e8');
|
|
104
|
-
expect(result).toBeDefined();
|
|
105
|
-
expect(result.expression).toBeDefined();
|
|
106
|
-
if (result.expression) {
|
|
107
|
-
expect(result.expression.type).toBe('literal');
|
|
108
|
-
expect((result.expression as UnitLiteral).value).toBeCloseTo(-1.123e8);
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
test('33.33%', () => {
|
|
113
|
-
const result = parser.Parse('33.33%');
|
|
114
|
-
expect(result).toBeDefined();
|
|
115
|
-
expect(result.expression).toBeDefined();
|
|
116
|
-
if (result.expression) {
|
|
117
|
-
expect(result.expression.type).toBe('literal');
|
|
118
|
-
expect((result.expression as UnitLiteral).value).toBeCloseTo(.3333);
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
describe('comma decimal parsing', () => {
|
|
125
|
-
|
|
126
|
-
test('1,23', () => {
|
|
127
|
-
parser.decimal_mark = DecimalMarkType.Comma;
|
|
128
|
-
const result = parser.Parse('1,23');
|
|
129
|
-
parser.decimal_mark = DecimalMarkType.Period;
|
|
130
|
-
expect(result).toBeDefined();
|
|
131
|
-
expect(result.expression).toBeDefined();
|
|
132
|
-
if (result.expression) {
|
|
133
|
-
expect(result.expression.type).toBe('literal');
|
|
134
|
-
expect((result.expression as UnitLiteral).value).toBeCloseTo(1.23);
|
|
135
|
-
}
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
test('-2231,909', () => {
|
|
139
|
-
parser.decimal_mark = DecimalMarkType.Comma;
|
|
140
|
-
const result = parser.Parse('-2231,909');
|
|
141
|
-
parser.decimal_mark = DecimalMarkType.Period;
|
|
142
|
-
expect(result).toBeDefined();
|
|
143
|
-
expect(result.expression).toBeDefined();
|
|
144
|
-
if (result.expression) {
|
|
145
|
-
expect(result.expression.type).toBe('literal');
|
|
146
|
-
expect((result.expression as UnitLiteral).value).toBeCloseTo(-2231.909);
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
describe('unary operators', () => {
|
|
152
|
-
|
|
153
|
-
test('2 + -3', () => {
|
|
154
|
-
const result = parser.Parse('2 + -3');
|
|
155
|
-
expect(result).toBeDefined();
|
|
156
|
-
expect(result.expression).toBeDefined();
|
|
157
|
-
if (result.expression) {
|
|
158
|
-
expect(result.expression.type).toBe('binary');
|
|
159
|
-
const right = (result.expression as UnitBinary).right;
|
|
160
|
-
expect(right).toBeDefined();
|
|
161
|
-
if (right){
|
|
162
|
-
expect(right.type).toBe('unary');
|
|
163
|
-
const unary = (right as UnitUnary);
|
|
164
|
-
expect(unary.operator).toBe('-');
|
|
165
|
-
expect(unary.operand.type).toBe('literal');
|
|
166
|
-
expect((unary.operand as UnitLiteral).value).toBeCloseTo(3);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
test('op() / +3', () => {
|
|
172
|
-
const result = parser.Parse('op() / +3');
|
|
173
|
-
expect(result).toBeDefined();
|
|
174
|
-
expect(result.expression).toBeDefined();
|
|
175
|
-
if (result.expression) {
|
|
176
|
-
expect(result.expression.type).toBe('binary');
|
|
177
|
-
const right = (result.expression as UnitBinary).right;
|
|
178
|
-
expect(right).toBeDefined();
|
|
179
|
-
if (right){
|
|
180
|
-
expect(right.type).toBe('unary');
|
|
181
|
-
const unary = (right as UnitUnary);
|
|
182
|
-
expect(unary.operator).toBe('+');
|
|
183
|
-
expect(unary.operand.type).toBe('literal');
|
|
184
|
-
expect((unary.operand as UnitLiteral).value).toBeCloseTo(3);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
describe('binary operators', () => {
|
|
191
|
-
|
|
192
|
-
test('10 * 8', () => {
|
|
193
|
-
const result = parser.Parse('10 * 8');
|
|
194
|
-
expect(result).toBeDefined();
|
|
195
|
-
expect(result.expression).toBeDefined();
|
|
196
|
-
if (result.expression) {
|
|
197
|
-
expect(result.expression.type).toBe('binary');
|
|
198
|
-
const binary = result.expression as UnitBinary;
|
|
199
|
-
expect(binary.operator).toBe('*');
|
|
200
|
-
expect((binary.left as UnitLiteral).value).toBe(10);
|
|
201
|
-
expect((binary.right as UnitLiteral).value).toBe(8);
|
|
202
|
-
}
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
describe('grouping/ordering', () => {
|
|
208
|
-
test('(2 / (1 + (2 * 3))) * 4', () => {
|
|
209
|
-
const result = parser.Parse('(2 / (1 + (2 * 3))) * 4');
|
|
210
|
-
expect(result).toBeDefined();
|
|
211
|
-
expect(result.expression).toBeDefined();
|
|
212
|
-
if (result.expression){
|
|
213
|
-
expect(result.expression.type).toBe('binary');
|
|
214
|
-
const binary = result.expression as UnitBinary;
|
|
215
|
-
expect(binary.right.type).toBe('literal');
|
|
216
|
-
expect((binary.right as UnitLiteral).value).toBe(4);
|
|
217
|
-
expect(binary.left.type).toBe('group');
|
|
218
|
-
}
|
|
219
|
-
});
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
describe('function calls', () => {
|
|
223
|
-
|
|
224
|
-
test('foo()', () => {
|
|
225
|
-
const result = parser.Parse('foo()');
|
|
226
|
-
expect(result).toBeDefined();
|
|
227
|
-
expect(result.expression).toBeDefined();
|
|
228
|
-
if (result.expression) {
|
|
229
|
-
expect(result.expression.type).toBe('call');
|
|
230
|
-
const call = result.expression as UnitCall;
|
|
231
|
-
expect(call.name).toBe('foo');
|
|
232
|
-
expect(call.args.length).toBe(0);
|
|
233
|
-
}
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
test('oof(1, "bar", 3.3)', () => {
|
|
237
|
-
const result = parser.Parse('oof(1, "bar", 3.3)');
|
|
238
|
-
expect(result).toBeDefined();
|
|
239
|
-
expect(result.expression).toBeDefined();
|
|
240
|
-
if (result.expression) {
|
|
241
|
-
expect(result.expression.type).toBe('call');
|
|
242
|
-
const call = result.expression as UnitCall;
|
|
243
|
-
expect(call.name).toBe('oof');
|
|
244
|
-
expect(call.args.length).toBe(3);
|
|
245
|
-
if (call.args.length === 3){
|
|
246
|
-
expect(call.args[0].type).toBe('literal');
|
|
247
|
-
expect((call.args[0] as UnitLiteral).value).toBe(1);
|
|
248
|
-
expect(call.args[1].type).toBe('literal');
|
|
249
|
-
expect((call.args[1] as UnitLiteral).value).toBe('bar');
|
|
250
|
-
expect(call.args[2].type).toBe('literal');
|
|
251
|
-
expect((call.args[2] as UnitLiteral).value).toBe(3.3);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
describe('addresses', () => {
|
|
259
|
-
test('=A1 + $B2 - C$3 - $ZZ$40', () => {
|
|
260
|
-
const result = parser.Parse('=A1 + $B2 - C$3 - $ZZ$40');
|
|
261
|
-
expect(result).toBeDefined();
|
|
262
|
-
expect(result.expression).toBeDefined();
|
|
263
|
-
if (result.expression) {
|
|
264
|
-
expect(parser.Render(result.expression)).toBe('A1 + $B2 - C$3 - $ZZ$40');
|
|
265
|
-
}
|
|
266
|
-
});
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
describe('semicolon-separated arguments', () => {
|
|
270
|
-
|
|
271
|
-
test('xfoo(1; "xbar"; 3,33)', () => {
|
|
272
|
-
parser.decimal_mark = DecimalMarkType.Comma;
|
|
273
|
-
parser.argument_separator = ArgumentSeparatorType.Semicolon;
|
|
274
|
-
const result = parser.Parse('xfoo(1; "xbar"; 3,33)');
|
|
275
|
-
parser.decimal_mark = DecimalMarkType.Period;
|
|
276
|
-
parser.argument_separator = ArgumentSeparatorType.Comma;
|
|
277
|
-
|
|
278
|
-
expect(result).toBeDefined();
|
|
279
|
-
expect(result.expression).toBeDefined();
|
|
280
|
-
if (result.expression) {
|
|
281
|
-
expect(result.expression.type).toBe('call');
|
|
282
|
-
const call = result.expression as UnitCall;
|
|
283
|
-
expect(call.name).toBe('xfoo');
|
|
284
|
-
expect(call.args.length).toBe(3);
|
|
285
|
-
if (call.args.length === 3){
|
|
286
|
-
expect(call.args[0].type).toBe('literal');
|
|
287
|
-
expect((call.args[0] as UnitLiteral).value).toBe(1);
|
|
288
|
-
expect(call.args[1].type).toBe('literal');
|
|
289
|
-
expect((call.args[1] as UnitLiteral).value).toBe('xbar');
|
|
290
|
-
expect(call.args[2].type).toBe('literal');
|
|
291
|
-
expect((call.args[2] as UnitLiteral).value).toBeCloseTo(3.33);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
});
|
|
297
|
-
|
|
298
|
-
|
|
File without changes
|
|
File without changes
|