@trebco/treb 29.1.6 → 29.3.1
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/dist/treb-spreadsheet-light.mjs +9 -9
- package/dist/treb-spreadsheet.mjs +15 -15
- package/dist/treb.d.ts +13 -9
- package/package.json +1 -1
- package/treb-base-types/src/area.ts +7 -0
- package/treb-calculator/src/calculator.ts +10 -8
- package/treb-calculator/src/dag/array-vertex.ts +0 -2
- package/treb-calculator/src/dag/graph.ts +88 -2
- package/treb-calculator/src/dag/spreadsheet_vertex.ts +1 -60
- package/treb-calculator/src/expression-calculator.ts +5 -0
- package/treb-calculator/src/functions/base-functions.ts +125 -0
- package/treb-data-model/src/data_model.ts +59 -20
- package/treb-data-model/src/index.ts +1 -1
- package/treb-data-model/src/named.ts +30 -35
- package/treb-data-model/src/sheet.ts +14 -6
- package/treb-export/src/export2.ts +3 -82
- package/treb-export/src/import2.ts +18 -13
- package/treb-export/src/workbook2.ts +2 -2
- package/treb-format/src/format.ts +11 -9
- package/treb-format/src/value_parser.ts +1 -1
- package/treb-grid/src/types/grid.ts +4 -72
- package/treb-parser/src/parser.ts +6 -0
|
@@ -20,15 +20,15 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import { Area } from 'treb-base-types';
|
|
23
|
-
import type {
|
|
23
|
+
import type { IArea } from 'treb-base-types';
|
|
24
24
|
import type { ExpressionUnit } from 'treb-parser';
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
interface NamedExpression {
|
|
27
27
|
type: 'expression';
|
|
28
28
|
expression: ExpressionUnit;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
interface NamedRange {
|
|
32
32
|
type: 'range';
|
|
33
33
|
area: Area;
|
|
34
34
|
}
|
|
@@ -38,44 +38,23 @@ export type Named = (NamedExpression | NamedRange) & {
|
|
|
38
38
|
scope?: number; // scope to sheet by ID
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
-
/**
|
|
42
|
-
* serialized type
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* for the external type we switch on the presence of the area
|
|
47
|
-
* or the expression. area uses a type that includes sheet names
|
|
48
|
-
* (IArea should allow that?). expression here is a string.
|
|
41
|
+
/**
|
|
42
|
+
* serialized type is a composite of expression/range. we determine
|
|
43
|
+
* what it is when parsing the expression. this simplifies passing these
|
|
44
|
+
* things around.
|
|
49
45
|
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
46
|
+
* (named expressions and ranges they have slightly different behavior,
|
|
47
|
+
* which is why we have a distinction at all).
|
|
52
48
|
*
|
|
53
|
-
* when serialized, scope is either the sheet name or nothing
|
|
54
|
-
* (implicit global scope).
|
|
55
49
|
*/
|
|
56
50
|
export interface SerializedNamed {
|
|
57
|
-
name: string;
|
|
58
|
-
area?: SerializedArea;
|
|
59
|
-
expression?: string;
|
|
60
|
-
scope?: string;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* this is a type we're using in imports. it consolidates the
|
|
65
|
-
* two types. we should maybe switch as well, at least for
|
|
66
|
-
* serialized representation? something to think about.
|
|
67
|
-
*/
|
|
68
|
-
export interface CompositeNamed {
|
|
69
51
|
|
|
70
52
|
name: string;
|
|
71
53
|
|
|
72
|
-
/**
|
|
73
|
-
* could be a address/range or a function expression. we'll distinguish
|
|
74
|
-
* when we parse it.
|
|
75
|
-
*/
|
|
54
|
+
/** expression or address/area */
|
|
76
55
|
expression: string;
|
|
77
56
|
|
|
78
|
-
/**
|
|
57
|
+
/** scope is a sheet name (not ID) */
|
|
79
58
|
scope?: string;
|
|
80
59
|
|
|
81
60
|
}
|
|
@@ -136,10 +115,12 @@ export class NamedRangeManager {
|
|
|
136
115
|
|
|
137
116
|
const validated = this.ValidateNamed(name);
|
|
138
117
|
if (!validated) {
|
|
139
|
-
console.warn('invalid name');
|
|
118
|
+
console.warn('invalid name', {name});
|
|
140
119
|
return false;
|
|
141
120
|
}
|
|
142
121
|
|
|
122
|
+
/*
|
|
123
|
+
|
|
143
124
|
if (named.type === 'range') {
|
|
144
125
|
|
|
145
126
|
// why is this considered invalid here? I've seen it done.
|
|
@@ -148,12 +129,14 @@ export class NamedRangeManager {
|
|
|
148
129
|
|
|
149
130
|
if (named.area.entire_column || named.area.entire_row) {
|
|
150
131
|
console.info({named});
|
|
151
|
-
console.warn(
|
|
132
|
+
console.warn('invalid range');
|
|
152
133
|
return false;
|
|
153
134
|
}
|
|
154
135
|
|
|
155
136
|
}
|
|
156
137
|
|
|
138
|
+
*/
|
|
139
|
+
|
|
157
140
|
// this.named.set(name.toLowerCase(), named);
|
|
158
141
|
this.named.set(this.ScopedName(name, named.scope), named);
|
|
159
142
|
|
|
@@ -226,14 +209,26 @@ export class NamedRangeManager {
|
|
|
226
209
|
* - must start with letter or underscore (not a number or dot).
|
|
227
210
|
* - cannot look like a spreadsheet address, which is 1-3 letters followed by numbers.
|
|
228
211
|
*
|
|
212
|
+
* - apparently questuon marks are legal, but not in first position. atm
|
|
213
|
+
* our parser will reject.
|
|
214
|
+
*
|
|
229
215
|
* returns a normalized name (just caps, atm)
|
|
230
216
|
*/
|
|
231
217
|
public ValidateNamed(name: string): string|false {
|
|
232
218
|
name = name.trim();
|
|
219
|
+
|
|
220
|
+
// can't be empty
|
|
233
221
|
if (!name.length) return false;
|
|
222
|
+
|
|
223
|
+
// can't look like a spreadsheet address
|
|
234
224
|
if (/^[A-Za-z]{1,3}\d+$/.test(name)) return false;
|
|
235
|
-
|
|
225
|
+
|
|
226
|
+
// can only contain legal characters
|
|
227
|
+
if (/[^A-Za-z\d_.?]/.test(name)) return false;
|
|
228
|
+
|
|
229
|
+
// must start with ascii letter or underscore
|
|
236
230
|
if (/^[^A-Za-z_]/.test(name)) return false;
|
|
231
|
+
|
|
237
232
|
return name.toUpperCase();
|
|
238
233
|
}
|
|
239
234
|
|
|
@@ -3282,9 +3282,20 @@ export class Sheet {
|
|
|
3282
3282
|
// stop rule. if you go forwards, you need some sort of indicator
|
|
3283
3283
|
// or flag).
|
|
3284
3284
|
|
|
3285
|
+
const area = JSON.parse(JSON.stringify(format.area));
|
|
3286
|
+
|
|
3287
|
+
if (area.start.row === null || area.end.row === null) {
|
|
3288
|
+
area.start.row = 0;
|
|
3289
|
+
area.end.row = this.cells.rows - 1;
|
|
3290
|
+
}
|
|
3291
|
+
if (area.start.column === null || area.end.column === null) {
|
|
3292
|
+
area.start.column = 0;
|
|
3293
|
+
area.end.column = this.cells.columns - 1;
|
|
3294
|
+
}
|
|
3295
|
+
|
|
3296
|
+
const result = format.internal?.vertex?.result;
|
|
3297
|
+
|
|
3285
3298
|
if (format.type === 'gradient') {
|
|
3286
|
-
const area = JSON.parse(JSON.stringify(format.area));
|
|
3287
|
-
const result = format.internal?.vertex?.result;
|
|
3288
3299
|
|
|
3289
3300
|
if (result && format.internal?.gradient) {
|
|
3290
3301
|
const property: 'fill'|'text' = format.property ?? 'fill';
|
|
@@ -3322,16 +3333,13 @@ export class Sheet {
|
|
|
3322
3333
|
|
|
3323
3334
|
// handle types expression, cell-match and duplicate-values
|
|
3324
3335
|
|
|
3325
|
-
const area = JSON.parse(JSON.stringify(format.area));
|
|
3326
|
-
const result = format.internal?.vertex?.result;
|
|
3327
|
-
|
|
3328
3336
|
if (result) {
|
|
3329
3337
|
|
|
3330
3338
|
if (result.type === ValueType.array) {
|
|
3331
3339
|
for (let row = area.start.row; row <= area.end.row; row++) {
|
|
3332
3340
|
for (let column = area.start.column; column <= area.end.column; column++) {
|
|
3333
3341
|
const value = result.value[column - area.start.column][row - area.start.row];
|
|
3334
|
-
if ((value.type === ValueType.boolean || value.type === ValueType.number) && !!value.value) {
|
|
3342
|
+
if (value && (value.type === ValueType.boolean || value.type === ValueType.number) && !!value.value) {
|
|
3335
3343
|
if (!temp[row]) { temp[row] = []; }
|
|
3336
3344
|
if (!temp[row][column] ) { temp[row][column] = []; }
|
|
3337
3345
|
temp[row][column].push(format.style);
|
|
@@ -54,7 +54,7 @@ import { AddRel } from './relationship';
|
|
|
54
54
|
import { type DOMContent, XMLOptions2 } from './xml-utils';
|
|
55
55
|
|
|
56
56
|
import type { UnitAddress, UnitRange, ExpressionUnit} from 'treb-parser';
|
|
57
|
-
import { Parser
|
|
57
|
+
import { Parser } from 'treb-parser';
|
|
58
58
|
|
|
59
59
|
// FIXME: move
|
|
60
60
|
import type { ChartOptions } from './drawing2/chart2';
|
|
@@ -2464,92 +2464,13 @@ export class Exporter {
|
|
|
2464
2464
|
}
|
|
2465
2465
|
}
|
|
2466
2466
|
|
|
2467
|
-
if (entry.area) {
|
|
2468
|
-
let sheet_name = '';
|
|
2469
|
-
const area = new Area(entry.area.start, entry.area.end);
|
|
2470
|
-
area.start.absolute_column = area.start.absolute_row = true;
|
|
2471
|
-
area.end.absolute_column = area.end.absolute_row = true;
|
|
2472
|
-
|
|
2473
|
-
if (entry.area.start.sheet) {
|
|
2474
|
-
sheet_name = entry.area.start.sheet;
|
|
2475
|
-
}
|
|
2476
|
-
else if (entry.area.start.sheet_id) {
|
|
2477
|
-
for (const sheet of source.sheet_data) {
|
|
2478
|
-
if (sheet.id === area.start.sheet_id) {
|
|
2479
|
-
sheet_name = sheet.name || '';
|
|
2480
|
-
break;
|
|
2481
|
-
}
|
|
2482
|
-
}
|
|
2483
|
-
}
|
|
2484
|
-
|
|
2485
|
-
if (sheet_name) {
|
|
2486
|
-
if (QuotedSheetNameRegex.test(sheet_name)) {
|
|
2487
|
-
sheet_name = `'${sheet_name}'`;
|
|
2488
|
-
}
|
|
2489
|
-
sheet_name += '!';
|
|
2490
|
-
}
|
|
2491
|
-
|
|
2492
|
-
// console.info({key, area, lx: area.spreadsheet_label, sheet_name });
|
|
2493
|
-
definedNames.definedName.push({
|
|
2494
|
-
a$: { name: entry.name, localSheetId: scope },
|
|
2495
|
-
t$: sheet_name + area.spreadsheet_label,
|
|
2496
|
-
});
|
|
2497
|
-
|
|
2498
|
-
}
|
|
2499
|
-
else if (entry.expression) {
|
|
2500
|
-
definedNames.definedName.push({
|
|
2501
|
-
a$: { name: entry.name, localSheetId: scope },
|
|
2502
|
-
t$: entry.expression,
|
|
2503
|
-
});
|
|
2504
|
-
}
|
|
2505
|
-
|
|
2506
|
-
}
|
|
2507
|
-
}
|
|
2508
|
-
|
|
2509
|
-
console.info("DB", definedNames);
|
|
2510
|
-
|
|
2511
|
-
/*
|
|
2512
|
-
if (source.named_ranges) {
|
|
2513
|
-
const keys = Object.keys(source.named_ranges);
|
|
2514
|
-
for (const key of keys) {
|
|
2515
|
-
let sheet_name = '';
|
|
2516
|
-
const area = new Area(source.named_ranges[key].start, source.named_ranges[key].end);
|
|
2517
|
-
area.start.absolute_column = area.start.absolute_row = true;
|
|
2518
|
-
area.end.absolute_column = area.end.absolute_row = true;
|
|
2519
|
-
|
|
2520
|
-
if (area.start.sheet_id) {
|
|
2521
|
-
for (const sheet of source.sheet_data) {
|
|
2522
|
-
if (sheet.id === area.start.sheet_id) {
|
|
2523
|
-
sheet_name = sheet.name || '';
|
|
2524
|
-
break;
|
|
2525
|
-
}
|
|
2526
|
-
}
|
|
2527
|
-
}
|
|
2528
|
-
|
|
2529
|
-
if (sheet_name) {
|
|
2530
|
-
if (QuotedSheetNameRegex.test(sheet_name)) {
|
|
2531
|
-
sheet_name = `'${sheet_name}'`;
|
|
2532
|
-
}
|
|
2533
|
-
sheet_name += '!';
|
|
2534
|
-
}
|
|
2535
|
-
|
|
2536
|
-
// console.info({key, area, lx: area.spreadsheet_label, sheet_name });
|
|
2537
2467
|
definedNames.definedName.push({
|
|
2538
|
-
a$: { name:
|
|
2539
|
-
t$: sheet_name + area.spreadsheet_label,
|
|
2540
|
-
});
|
|
2541
|
-
|
|
2542
|
-
}
|
|
2543
|
-
}
|
|
2544
|
-
if (source.named_expressions) {
|
|
2545
|
-
for (const entry of source.named_expressions) {
|
|
2546
|
-
definedNames.definedName.push({
|
|
2547
|
-
a$: { name: entry.name },
|
|
2468
|
+
a$: { name: entry.name, localSheetId: scope },
|
|
2548
2469
|
t$: entry.expression,
|
|
2549
2470
|
});
|
|
2471
|
+
|
|
2550
2472
|
}
|
|
2551
2473
|
}
|
|
2552
|
-
*/
|
|
2553
2474
|
|
|
2554
2475
|
if (!definedNames.definedName.length) {
|
|
2555
2476
|
definedNames = undefined;
|
|
@@ -348,21 +348,23 @@ export class Importer {
|
|
|
348
348
|
case 'duplicateValues':
|
|
349
349
|
case 'uniqueValues':
|
|
350
350
|
|
|
351
|
-
|
|
351
|
+
{
|
|
352
|
+
let style = {};
|
|
352
353
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
354
|
+
if (rule.a$.dxfId) {
|
|
355
|
+
const index = Number(rule.a$.dxfId);
|
|
356
|
+
if (!isNaN(index)) {
|
|
357
|
+
style = this.workbook?.style_cache.dxf_styles[index] || {};
|
|
358
|
+
}
|
|
357
359
|
}
|
|
358
|
-
}
|
|
359
360
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
361
|
+
return {
|
|
362
|
+
type: 'duplicate-values',
|
|
363
|
+
area,
|
|
364
|
+
style,
|
|
365
|
+
unique: (rule.a$.type === 'uniqueValues'),
|
|
366
|
+
};
|
|
367
|
+
}
|
|
366
368
|
|
|
367
369
|
case 'cellIs':
|
|
368
370
|
if (rule.a$.operator && rule.formula) {
|
|
@@ -392,7 +394,10 @@ export class Importer {
|
|
|
392
394
|
}
|
|
393
395
|
break;
|
|
394
396
|
|
|
397
|
+
case 'containsErrors':
|
|
398
|
+
case 'notContainsErrors':
|
|
395
399
|
case 'expression':
|
|
400
|
+
|
|
396
401
|
if (rule.formula) {
|
|
397
402
|
|
|
398
403
|
if (typeof rule.formula !== 'string') {
|
|
@@ -436,7 +441,7 @@ export class Importer {
|
|
|
436
441
|
const stops: GradientStop[] = [];
|
|
437
442
|
for (const [index, entry] of rule.colorScale.cfvo.entries()) {
|
|
438
443
|
let value = 0;
|
|
439
|
-
|
|
444
|
+
const color: Color = {};
|
|
440
445
|
|
|
441
446
|
const color_element = rule.colorScale.color[index];
|
|
442
447
|
if (color_element.a$.rgb) {
|
|
@@ -39,7 +39,7 @@ import { Sheet, VisibleState } from './workbook-sheet2';
|
|
|
39
39
|
import type { RelationshipMap } from './relationship';
|
|
40
40
|
import { ZipWrapper } from './zip-wrapper';
|
|
41
41
|
import type { CellStyle } from 'treb-base-types';
|
|
42
|
-
import type {
|
|
42
|
+
import type { SerializedNamed } from 'treb-data-model';
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
/*
|
|
@@ -155,7 +155,7 @@ export class Workbook {
|
|
|
155
155
|
/* * defined names. these can be ranges or expressions. */
|
|
156
156
|
// public defined_names: Record<string, string> = {};
|
|
157
157
|
|
|
158
|
-
public named: Array<
|
|
158
|
+
public named: Array<SerializedNamed & {local_scope?: number}> = [];
|
|
159
159
|
|
|
160
160
|
/** the workbook "rels" */
|
|
161
161
|
public rels: RelationshipMap = {};
|
|
@@ -70,15 +70,17 @@ export const UnlotusDate = (value: number, local = true): number => {
|
|
|
70
70
|
if (local) {
|
|
71
71
|
|
|
72
72
|
const local_date = new Date(value);
|
|
73
|
-
const utc_date = new Date(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
73
|
+
const utc_date = new Date(
|
|
74
|
+
local_date.getFullYear(),
|
|
75
|
+
local_date.getMonth(),
|
|
76
|
+
local_date.getDate(),
|
|
77
|
+
local_date.getHours(),
|
|
78
|
+
local_date.getMinutes(),
|
|
79
|
+
local_date.getSeconds(),
|
|
80
|
+
local_date.getMilliseconds(),
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
// console.info("Converting local", utc_date.toUTCString());
|
|
82
84
|
|
|
83
85
|
value = utc_date.getTime();
|
|
84
86
|
|
|
@@ -83,7 +83,7 @@ import type { GridEvent } from './grid_events';
|
|
|
83
83
|
import { ErrorCode } from './grid_events';
|
|
84
84
|
|
|
85
85
|
import type {
|
|
86
|
-
|
|
86
|
+
SerializedNamed,
|
|
87
87
|
DataModel,
|
|
88
88
|
GridSelection,
|
|
89
89
|
LegacySerializedSheet,
|
|
@@ -890,7 +890,7 @@ export class Grid extends GridBase {
|
|
|
890
890
|
import_data: {
|
|
891
891
|
sheets: ImportedSheetData[],
|
|
892
892
|
// names?: Record<string, string|number>,
|
|
893
|
-
named?:
|
|
893
|
+
named?: SerializedNamed[],
|
|
894
894
|
active_tab?: number,
|
|
895
895
|
},
|
|
896
896
|
render = false,
|
|
@@ -970,79 +970,11 @@ export class Grid extends GridBase {
|
|
|
970
970
|
this.model.sheets.UpdateIndexes();
|
|
971
971
|
|
|
972
972
|
this.model.named.Reset();
|
|
973
|
-
// this.model.named_ranges.Reset();
|
|
974
|
-
// this.model.named_expressions.clear();
|
|
975
|
-
// console.info({IDX: import_data.named});
|
|
976
973
|
|
|
977
974
|
if (import_data.named) {
|
|
978
|
-
this.model.
|
|
975
|
+
this.model.UnserializeNames(import_data.named, this.active_sheet);
|
|
979
976
|
}
|
|
980
977
|
|
|
981
|
-
/*
|
|
982
|
-
if (import_data.names) {
|
|
983
|
-
|
|
984
|
-
console.info("IDN", { names: import_data.names })
|
|
985
|
-
|
|
986
|
-
for (const name of Object.keys(import_data.names)) {
|
|
987
|
-
|
|
988
|
-
const validated = this.model.named.ValidateNamed(name);
|
|
989
|
-
|
|
990
|
-
if (!validated) {
|
|
991
|
-
console.warn(`invalid name: ${name}`, import_data.names[name]);
|
|
992
|
-
continue;
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
const label = import_data.names[name];
|
|
996
|
-
if (typeof label === 'number') {
|
|
997
|
-
// console.info('dropping (temp)', name, label);
|
|
998
|
-
}
|
|
999
|
-
else {
|
|
1000
|
-
const parse_result = this.parser.Parse(label);
|
|
1001
|
-
|
|
1002
|
-
if (parse_result.expression) {
|
|
1003
|
-
if (parse_result.expression.type === 'range') {
|
|
1004
|
-
const sheet_id = name_map[parse_result.expression.start.sheet || ''];
|
|
1005
|
-
if (sheet_id) {
|
|
1006
|
-
parse_result.expression.start.sheet_id = sheet_id;
|
|
1007
|
-
this.model.named.SetNamedRange(validated, new Area(parse_result.expression.start, parse_result.expression.end));
|
|
1008
|
-
}
|
|
1009
|
-
}
|
|
1010
|
-
else if (parse_result.expression.type === 'address') {
|
|
1011
|
-
const sheet_id = name_map[parse_result.expression.sheet || ''];
|
|
1012
|
-
if (sheet_id) {
|
|
1013
|
-
parse_result.expression.sheet_id = sheet_id;
|
|
1014
|
-
this.model.named.SetNamedRange(validated, new Area(parse_result.expression));
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
else {
|
|
1018
|
-
|
|
1019
|
-
// we need to map sheet names to sheet IDs in named
|
|
1020
|
-
// expressions, if they have any addresses/references.
|
|
1021
|
-
|
|
1022
|
-
const expr = parse_result.expression;
|
|
1023
|
-
this.parser.Walk(expr, unit => {
|
|
1024
|
-
if (unit.type === 'address' || unit.type === 'range') {
|
|
1025
|
-
if (unit.type === 'range') {
|
|
1026
|
-
unit = unit.start;
|
|
1027
|
-
}
|
|
1028
|
-
if (!unit.sheet_id) {
|
|
1029
|
-
unit.sheet_id = name_map[unit.sheet || ''] || 0; // default is bad here -- do we have an active sheet yet?
|
|
1030
|
-
}
|
|
1031
|
-
return false;
|
|
1032
|
-
}
|
|
1033
|
-
return true;
|
|
1034
|
-
});
|
|
1035
|
-
|
|
1036
|
-
this.model.named.SetNamedExpression(validated, expr);
|
|
1037
|
-
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
}
|
|
1041
|
-
}
|
|
1042
|
-
// this.model.named_ranges.RebuildList();
|
|
1043
|
-
}
|
|
1044
|
-
*/
|
|
1045
|
-
|
|
1046
978
|
// FIXME: do we need to rebuild autocomplete here (A: yes)
|
|
1047
979
|
// ...
|
|
1048
980
|
|
|
@@ -1597,7 +1529,7 @@ export class Grid extends GridBase {
|
|
|
1597
1529
|
*/
|
|
1598
1530
|
public SetName(name: string, range?: ICellAddress | Area, expression?: string, scope?: number, overwrite = false): void {
|
|
1599
1531
|
|
|
1600
|
-
// console.info('setname', name, range, expression, scope, overwrite);
|
|
1532
|
+
// console.info('setname', { name, range, expression, scope, overwrite });
|
|
1601
1533
|
|
|
1602
1534
|
// validate/translate name first
|
|
1603
1535
|
|
|
@@ -89,6 +89,7 @@ const CLOSE_BRACE = 0x7d;
|
|
|
89
89
|
const OPEN_SQUARE_BRACKET = 0x5b;
|
|
90
90
|
const CLOSE_SQUARE_BRACKET = 0x5d;
|
|
91
91
|
|
|
92
|
+
const QUESTION_MARK = 0x3f;
|
|
92
93
|
const EXCLAMATION_MARK = 0x21;
|
|
93
94
|
// const COLON = 0x3a; // became an operator
|
|
94
95
|
const SEMICOLON = 0x3b;
|
|
@@ -2100,6 +2101,11 @@ export class Parser {
|
|
|
2100
2101
|
|
|
2101
2102
|
// I think that's all the rules for structured references.
|
|
2102
2103
|
|
|
2104
|
+
// testing question marks, which are legal in defined names
|
|
2105
|
+
// (but I think not in table names or column names)
|
|
2106
|
+
|
|
2107
|
+
|| (char === QUESTION_MARK && square_bracket === 0)
|
|
2108
|
+
|
|
2103
2109
|
/*
|
|
2104
2110
|
|
|
2105
2111
|
|| (this.flags.r1c1 && (
|