@trebco/treb 23.6.2 → 25.0.0-rc1
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/.eslintignore +8 -0
- package/.eslintrc.js +164 -0
- package/README-shadow-DOM.md +88 -0
- package/README.md +37 -130
- package/api-config.json +29 -0
- package/api-generator/api-generator-types.ts +82 -0
- package/api-generator/api-generator.ts +1172 -0
- package/api-generator/package.json +3 -0
- package/build/treb-spreadsheet.mjs +14 -0
- package/{treb.d.ts → build/treb.d.ts} +293 -299
- package/esbuild-custom-element.mjs +336 -0
- package/esbuild.js +305 -0
- package/package.json +43 -14
- package/treb-base-types/package.json +5 -0
- package/treb-base-types/src/api_types.ts +36 -0
- package/treb-base-types/src/area.ts +583 -0
- package/treb-base-types/src/basic_types.ts +45 -0
- package/treb-base-types/src/cell.ts +612 -0
- package/treb-base-types/src/cells.ts +1066 -0
- package/treb-base-types/src/color.ts +124 -0
- package/treb-base-types/src/import.ts +71 -0
- package/treb-base-types/src/index-standalone.ts +29 -0
- package/treb-base-types/src/index.ts +42 -0
- package/treb-base-types/src/layout.ts +47 -0
- package/treb-base-types/src/localization.ts +187 -0
- package/treb-base-types/src/rectangle.ts +145 -0
- package/treb-base-types/src/render_text.ts +72 -0
- package/treb-base-types/src/style.ts +545 -0
- package/treb-base-types/src/table.ts +109 -0
- package/treb-base-types/src/text_part.ts +54 -0
- package/treb-base-types/src/theme.ts +608 -0
- package/treb-base-types/src/union.ts +152 -0
- package/treb-base-types/src/value-type.ts +164 -0
- package/treb-base-types/style/resizable.css +59 -0
- package/treb-calculator/modern.tsconfig.json +11 -0
- package/treb-calculator/package.json +5 -0
- package/treb-calculator/src/calculator.ts +2546 -0
- package/treb-calculator/src/complex-math.ts +558 -0
- package/treb-calculator/src/dag/array-vertex.ts +198 -0
- package/treb-calculator/src/dag/graph.ts +951 -0
- package/treb-calculator/src/dag/leaf_vertex.ts +118 -0
- package/treb-calculator/src/dag/spreadsheet_vertex.ts +327 -0
- package/treb-calculator/src/dag/spreadsheet_vertex_base.ts +44 -0
- package/treb-calculator/src/dag/vertex.ts +352 -0
- package/treb-calculator/src/descriptors.ts +162 -0
- package/treb-calculator/src/expression-calculator.ts +1069 -0
- package/treb-calculator/src/function-error.ts +103 -0
- package/treb-calculator/src/function-library.ts +103 -0
- package/treb-calculator/src/functions/base-functions.ts +1214 -0
- package/treb-calculator/src/functions/checkbox.ts +164 -0
- package/treb-calculator/src/functions/complex-functions.ts +253 -0
- package/treb-calculator/src/functions/finance-functions.ts +399 -0
- package/treb-calculator/src/functions/information-functions.ts +102 -0
- package/treb-calculator/src/functions/matrix-functions.ts +182 -0
- package/treb-calculator/src/functions/sparkline.ts +335 -0
- package/treb-calculator/src/functions/statistics-functions.ts +350 -0
- package/treb-calculator/src/functions/text-functions.ts +298 -0
- package/treb-calculator/src/index.ts +27 -0
- package/treb-calculator/src/notifier-types.ts +59 -0
- package/treb-calculator/src/primitives.ts +428 -0
- package/treb-calculator/src/utilities.ts +305 -0
- package/treb-charts/package.json +5 -0
- package/treb-charts/src/chart-functions.ts +156 -0
- package/treb-charts/src/chart-types.ts +230 -0
- package/treb-charts/src/chart.ts +1288 -0
- package/treb-charts/src/index.ts +24 -0
- package/treb-charts/src/main.ts +37 -0
- package/treb-charts/src/rectangle.ts +52 -0
- package/treb-charts/src/renderer.ts +1841 -0
- package/treb-charts/src/util.ts +122 -0
- package/treb-charts/style/charts.scss +221 -0
- package/treb-charts/style/old-charts.scss +250 -0
- package/treb-embed/markup/layout.html +137 -0
- package/treb-embed/markup/toolbar.html +175 -0
- package/treb-embed/modern.tsconfig.json +25 -0
- package/treb-embed/src/custom-element/content-types.d.ts +18 -0
- package/treb-embed/src/custom-element/global.d.ts +11 -0
- package/treb-embed/src/custom-element/spreadsheet-constructor.ts +1227 -0
- package/treb-embed/src/custom-element/treb-global.ts +44 -0
- package/treb-embed/src/custom-element/treb-spreadsheet-element.ts +52 -0
- package/treb-embed/src/embedded-spreadsheet.ts +5362 -0
- package/treb-embed/src/index.ts +16 -0
- package/treb-embed/src/language-model.ts +41 -0
- package/treb-embed/src/options.ts +320 -0
- package/treb-embed/src/progress-dialog.ts +228 -0
- package/treb-embed/src/selection-state.ts +16 -0
- package/treb-embed/src/spinner.ts +42 -0
- package/treb-embed/src/toolbar-message.ts +96 -0
- package/treb-embed/src/types.ts +167 -0
- package/treb-embed/style/autocomplete.scss +103 -0
- package/treb-embed/style/dark-theme.scss +114 -0
- package/treb-embed/style/defaults.scss +36 -0
- package/treb-embed/style/dialog.scss +181 -0
- package/treb-embed/style/dropdown-select.scss +101 -0
- package/treb-embed/style/formula-bar.scss +193 -0
- package/treb-embed/style/grid.scss +374 -0
- package/treb-embed/style/layout.scss +424 -0
- package/treb-embed/style/mouse-mask.scss +67 -0
- package/treb-embed/style/note.scss +92 -0
- package/treb-embed/style/overlay-editor.scss +102 -0
- package/treb-embed/style/spinner.scss +92 -0
- package/treb-embed/style/tab-bar.scss +228 -0
- package/treb-embed/style/table.scss +80 -0
- package/treb-embed/style/theme-defaults.scss +444 -0
- package/treb-embed/style/toolbar.scss +416 -0
- package/treb-embed/style/tooltip.scss +68 -0
- package/treb-embed/style/treb-icons.scss +130 -0
- package/treb-embed/style/treb-spreadsheet-element.scss +20 -0
- package/treb-embed/style/z-index.scss +43 -0
- package/treb-export/docs/charts.md +68 -0
- package/treb-export/modern.tsconfig.json +19 -0
- package/treb-export/package.json +4 -0
- package/treb-export/src/address-type.ts +77 -0
- package/treb-export/src/base-template.ts +22 -0
- package/treb-export/src/column-width.ts +85 -0
- package/treb-export/src/drawing2/chart-template-components2.ts +389 -0
- package/treb-export/src/drawing2/chart2.ts +282 -0
- package/treb-export/src/drawing2/column-chart-template2.ts +521 -0
- package/treb-export/src/drawing2/donut-chart-template2.ts +296 -0
- package/treb-export/src/drawing2/drawing2.ts +355 -0
- package/treb-export/src/drawing2/embedded-image.ts +71 -0
- package/treb-export/src/drawing2/scatter-chart-template2.ts +555 -0
- package/treb-export/src/export-worker/export-worker.ts +99 -0
- package/treb-export/src/export-worker/index-modern.ts +22 -0
- package/treb-export/src/export2.ts +2204 -0
- package/treb-export/src/import2.ts +882 -0
- package/treb-export/src/relationship.ts +36 -0
- package/treb-export/src/shared-strings2.ts +128 -0
- package/treb-export/src/template-2.ts +22 -0
- package/treb-export/src/unescape_xml.ts +47 -0
- package/treb-export/src/workbook-sheet2.ts +182 -0
- package/treb-export/src/workbook-style2.ts +1285 -0
- package/treb-export/src/workbook-theme2.ts +88 -0
- package/treb-export/src/workbook2.ts +491 -0
- package/treb-export/src/xml-utils.ts +201 -0
- package/treb-export/template/base/[Content_Types].xml +2 -0
- package/treb-export/template/base/_rels/.rels +2 -0
- package/treb-export/template/base/docProps/app.xml +2 -0
- package/treb-export/template/base/docProps/core.xml +12 -0
- package/treb-export/template/base/xl/_rels/workbook.xml.rels +2 -0
- package/treb-export/template/base/xl/sharedStrings.xml +2 -0
- package/treb-export/template/base/xl/styles.xml +2 -0
- package/treb-export/template/base/xl/theme/theme1.xml +2 -0
- package/treb-export/template/base/xl/workbook.xml +2 -0
- package/treb-export/template/base/xl/worksheets/sheet1.xml +2 -0
- package/treb-export/template/base.xlsx +0 -0
- package/treb-format/package.json +8 -0
- package/treb-format/src/format.test.ts +213 -0
- package/treb-format/src/format.ts +942 -0
- package/treb-format/src/format_cache.ts +199 -0
- package/treb-format/src/format_parser.ts +723 -0
- package/treb-format/src/index.ts +25 -0
- package/treb-format/src/number_format_section.ts +100 -0
- package/treb-format/src/value_parser.ts +337 -0
- package/treb-grid/package.json +5 -0
- package/treb-grid/src/editors/autocomplete.ts +394 -0
- package/treb-grid/src/editors/autocomplete_matcher.ts +260 -0
- package/treb-grid/src/editors/formula_bar.ts +473 -0
- package/treb-grid/src/editors/formula_editor_base.ts +910 -0
- package/treb-grid/src/editors/overlay_editor.ts +511 -0
- package/treb-grid/src/index.ts +37 -0
- package/treb-grid/src/layout/base_layout.ts +2618 -0
- package/treb-grid/src/layout/grid_layout.ts +299 -0
- package/treb-grid/src/layout/rectangle_cache.ts +86 -0
- package/treb-grid/src/render/selection-renderer.ts +414 -0
- package/treb-grid/src/render/svg_header_overlay.ts +93 -0
- package/treb-grid/src/render/svg_selection_block.ts +187 -0
- package/treb-grid/src/render/tile_renderer.ts +2122 -0
- package/treb-grid/src/types/annotation.ts +216 -0
- package/treb-grid/src/types/border_constants.ts +34 -0
- package/treb-grid/src/types/clipboard_data.ts +31 -0
- package/treb-grid/src/types/data_model.ts +334 -0
- package/treb-grid/src/types/drag_mask.ts +81 -0
- package/treb-grid/src/types/grid.ts +7743 -0
- package/treb-grid/src/types/grid_base.ts +3644 -0
- package/treb-grid/src/types/grid_command.ts +470 -0
- package/treb-grid/src/types/grid_events.ts +124 -0
- package/treb-grid/src/types/grid_options.ts +97 -0
- package/treb-grid/src/types/grid_selection.ts +60 -0
- package/treb-grid/src/types/named_range.ts +369 -0
- package/treb-grid/src/types/scale-control.ts +202 -0
- package/treb-grid/src/types/serialize_options.ts +72 -0
- package/treb-grid/src/types/set_range_options.ts +52 -0
- package/treb-grid/src/types/sheet.ts +3099 -0
- package/treb-grid/src/types/sheet_types.ts +95 -0
- package/treb-grid/src/types/tab_bar.ts +464 -0
- package/treb-grid/src/types/tile.ts +59 -0
- package/treb-grid/src/types/update_flags.ts +75 -0
- package/treb-grid/src/util/dom_utilities.ts +44 -0
- package/treb-grid/src/util/fontmetrics2.ts +179 -0
- package/treb-grid/src/util/ua.ts +104 -0
- package/treb-logo.svg +18 -0
- package/treb-parser/package.json +5 -0
- package/treb-parser/src/csv-parser.ts +122 -0
- package/treb-parser/src/index.ts +25 -0
- package/treb-parser/src/md-parser.ts +526 -0
- package/treb-parser/src/parser-types.ts +397 -0
- package/treb-parser/src/parser.test.ts +298 -0
- package/treb-parser/src/parser.ts +2673 -0
- package/treb-utils/package.json +5 -0
- package/treb-utils/src/dispatch.ts +57 -0
- package/treb-utils/src/event_source.ts +147 -0
- package/treb-utils/src/ievent_source.ts +33 -0
- package/treb-utils/src/index.ts +31 -0
- package/treb-utils/src/measurement.ts +174 -0
- package/treb-utils/src/resizable.ts +160 -0
- package/treb-utils/src/scale.ts +137 -0
- package/treb-utils/src/serialize_html.ts +124 -0
- package/treb-utils/src/template.ts +70 -0
- package/treb-utils/src/validate_uri.ts +61 -0
- package/tsconfig.json +10 -0
- package/tsproject.json +30 -0
- package/util/license-plugin-esbuild.js +86 -0
- package/util/list-css-vars.sh +46 -0
- package/README-esm.md +0 -37
- package/treb-bundle.css +0 -2
- package/treb-bundle.mjs +0 -15
|
@@ -0,0 +1,118 @@
|
|
|
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-2023 trebco, llc.
|
|
18
|
+
* info@treb.app
|
|
19
|
+
*
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type { GraphCallbacks } from './spreadsheet_vertex_base';
|
|
23
|
+
import { SpreadsheetVertex } from './spreadsheet_vertex';
|
|
24
|
+
import { Vertex, Color } from './vertex';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* second specialization of vertex: this class is for non-cell elements
|
|
28
|
+
* that are dependent on cells: specifically, charts.
|
|
29
|
+
*
|
|
30
|
+
* we want leaf vertices to participate in the normal dirty/calculate
|
|
31
|
+
* cycle, but they don't need to do any calculation other than checking
|
|
32
|
+
* if the underlying data has changed. we should maintain some state so
|
|
33
|
+
* this is a simple check for observers.
|
|
34
|
+
*
|
|
35
|
+
* leaves specifically do not have addresses. we can represent the chart
|
|
36
|
+
* as a calculation, however. (...)
|
|
37
|
+
*
|
|
38
|
+
* FIXME: it might be better to have an intermediate class/interface and
|
|
39
|
+
* have both leaf- and spreadsheet-vertex extend that.
|
|
40
|
+
*
|
|
41
|
+
*/
|
|
42
|
+
export class LeafVertex extends SpreadsheetVertex {
|
|
43
|
+
|
|
44
|
+
public static type = 'leaf-vertex';
|
|
45
|
+
|
|
46
|
+
public state_id = 0;
|
|
47
|
+
public type = LeafVertex.type; // for type guard
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* leaf vertex defaults to black (i.e. tested) because leaf nodes cannot have
|
|
51
|
+
* outbound edges. it is still possible to change this, because it's a property
|
|
52
|
+
* and we can't override the set accessor, but making it an accessor in the
|
|
53
|
+
* superclass just for this purpose is not worthwhile since regular vertices
|
|
54
|
+
* should vastly outnumber leaves.
|
|
55
|
+
*/
|
|
56
|
+
public color = Color.black;
|
|
57
|
+
|
|
58
|
+
protected state_representation = '';
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* construct the state, compare, and increment the state id if
|
|
62
|
+
* it changes. this is expected to be called from Calculate(), but
|
|
63
|
+
* we can also call it on init if we already know the state.
|
|
64
|
+
*
|
|
65
|
+
* FIXME: what's more expensive, generating this state field or
|
|
66
|
+
* re-rendering a chart with the same data? (...?)
|
|
67
|
+
* especially since it's only called on dirty...
|
|
68
|
+
*
|
|
69
|
+
* what is the case where the depenendency is dirty but state
|
|
70
|
+
* does not change? you type in the same value? (...) or maybe
|
|
71
|
+
* there's a volatile function that doesn't change value (e.g. Today())
|
|
72
|
+
*
|
|
73
|
+
* still, it seems like a waste here. let's test without the state.
|
|
74
|
+
* (meaning just update the flag anytime it's dirty)
|
|
75
|
+
*
|
|
76
|
+
* Actually I think the case is manual recalc, when values don't change
|
|
77
|
+
* (especially true for MC charts).
|
|
78
|
+
*
|
|
79
|
+
* TODO: perf
|
|
80
|
+
*/
|
|
81
|
+
public UpdateState(): void {
|
|
82
|
+
|
|
83
|
+
// FIXME: hash!
|
|
84
|
+
//const state = JSON.stringify(this.edges_in.map((edge) => (edge as SpreadsheetVertex).result));
|
|
85
|
+
const state = JSON.stringify(Array.from(this.edges_in).map((edge) => (edge as SpreadsheetVertex).result));
|
|
86
|
+
|
|
87
|
+
if (state !== this.state_representation) {
|
|
88
|
+
this.state_representation = state;
|
|
89
|
+
this.state_id++;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** overrides calculate function */
|
|
95
|
+
public Calculate(graph: GraphCallbacks): void {
|
|
96
|
+
|
|
97
|
+
// if we are not dirty, nothing to do
|
|
98
|
+
if (!this.dirty) return;
|
|
99
|
+
|
|
100
|
+
// check deps
|
|
101
|
+
for (const edge of this.edges_in) {
|
|
102
|
+
if ((edge as SpreadsheetVertex).dirty) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ok, we can evaluate... all we are doing here is checking state consistency
|
|
108
|
+
this.UpdateState();
|
|
109
|
+
this.dirty = false;
|
|
110
|
+
|
|
111
|
+
// we are not allowed to have edges out, so nothing to do
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
public AddDependent(edge: Vertex): void {
|
|
115
|
+
throw(new Error('leaf vertex cannot have dependents'));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
}
|
|
@@ -0,0 +1,327 @@
|
|
|
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-2023 trebco, llc.
|
|
18
|
+
* info@treb.app
|
|
19
|
+
*
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { SpreadsheetVertexBase, GraphCallbacks } from './spreadsheet_vertex_base';
|
|
23
|
+
import { Cell, Box, ICellAddress, ValueType, UnionValue } from 'treb-base-types';
|
|
24
|
+
import type { ExpressionUnit } from 'treb-parser';
|
|
25
|
+
import { Color } from './vertex';
|
|
26
|
+
import { ErrorType } from '../function-error';
|
|
27
|
+
|
|
28
|
+
export enum SpreadsheetError {
|
|
29
|
+
None,
|
|
30
|
+
CalculationError,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* specialization of vertex with attached data and calculation metadata
|
|
35
|
+
*/
|
|
36
|
+
export class SpreadsheetVertex extends SpreadsheetVertexBase {
|
|
37
|
+
|
|
38
|
+
public static type = 'spreadsheet-vertex';
|
|
39
|
+
|
|
40
|
+
// I wonder if we should drop this and look up on demand -- might
|
|
41
|
+
// help in large blocks...
|
|
42
|
+
|
|
43
|
+
public reference?: Cell;
|
|
44
|
+
|
|
45
|
+
public error = SpreadsheetError.None;
|
|
46
|
+
|
|
47
|
+
// why is this (?)? can't we use a default junk address?
|
|
48
|
+
public address?: ICellAddress;
|
|
49
|
+
|
|
50
|
+
//public result: UnionOrArray = UndefinedUnion();
|
|
51
|
+
public result: UnionValue = {type: ValueType.undefined};
|
|
52
|
+
|
|
53
|
+
public expression: ExpressionUnit = { type: 'missing', id: -1 };
|
|
54
|
+
public expression_error = false;
|
|
55
|
+
public short_circuit = false;
|
|
56
|
+
|
|
57
|
+
public type = SpreadsheetVertex.type; // for type guard
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* it seems like this could be cached, if it gets checked a lot
|
|
61
|
+
* also what's with the crazy return signature? [fixed]
|
|
62
|
+
*/
|
|
63
|
+
get array_head(): boolean {
|
|
64
|
+
if (!this.address) return false;
|
|
65
|
+
return (!!this.reference)
|
|
66
|
+
&& (!!this.reference.area)
|
|
67
|
+
&& (this.reference.area.start.column === this.address.column)
|
|
68
|
+
&& (this.reference.area.start.row === this.address.row);
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* to support restoring cached values (from file), we need a way to get
|
|
74
|
+
* the value from the reference (cell). normally this is done during
|
|
75
|
+
* calculation, and in reverse (we set the value).
|
|
76
|
+
*
|
|
77
|
+
* some additional implications of this:
|
|
78
|
+
*
|
|
79
|
+
* - does not set volatile/nonvolatile, which is usually managed as a
|
|
80
|
+
* side-effect of the calculation.
|
|
81
|
+
*
|
|
82
|
+
* - does not remove the entry from the dirty list
|
|
83
|
+
*
|
|
84
|
+
* - does not clear the internal dirty flag. it used to do that, but we
|
|
85
|
+
* took it out because we are now managing multple vertex types, and
|
|
86
|
+
* we don't want to attach that behavior to a type-specific method.
|
|
87
|
+
*
|
|
88
|
+
* so the caller needs to explicitly address the dirty and volatile lists
|
|
89
|
+
* for this vertex.
|
|
90
|
+
*/
|
|
91
|
+
public TakeReferenceValue(): void {
|
|
92
|
+
if (this.reference) {
|
|
93
|
+
this.result = Box(this.reference.GetValue());
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* calculates the function, but only if all dependencies are clean.
|
|
99
|
+
* if one or more dependencies are dirty, just exit. this should work out
|
|
100
|
+
* so that when the last dependency is satisfied, the propagation will
|
|
101
|
+
* succeed. FIXME: optimize order.
|
|
102
|
+
*
|
|
103
|
+
* FIXME: why is this in vertex, instead of graph? [a: dirty check?]
|
|
104
|
+
* A: for overloading. leaf extends this class, and has a separate
|
|
105
|
+
* calculation routine.
|
|
106
|
+
*/
|
|
107
|
+
public Calculate(graph: GraphCallbacks): void {
|
|
108
|
+
|
|
109
|
+
if (!this.dirty) return;
|
|
110
|
+
|
|
111
|
+
// it would be nice if we could get this out of the calculate routine,
|
|
112
|
+
// but that's a problem because we can't calculate in the right order.
|
|
113
|
+
|
|
114
|
+
// one solution might be to have two methods, one which includes it
|
|
115
|
+
// and one which doesn't, and call the checked method only when necessary.
|
|
116
|
+
// OTOH that means maintaining the internal calculation part twice (or
|
|
117
|
+
// adding a method call).
|
|
118
|
+
|
|
119
|
+
if (this.color === Color.white && this.LoopCheck()) {
|
|
120
|
+
|
|
121
|
+
// console.info('LCB', `R${this.address?.row} C${this.address?.column}`, this);
|
|
122
|
+
|
|
123
|
+
// if (this.LoopCheck()) {
|
|
124
|
+
// throw new Error('loop loop 2')
|
|
125
|
+
|
|
126
|
+
this.dirty = false;
|
|
127
|
+
|
|
128
|
+
if (this.edges_in.size) {
|
|
129
|
+
|
|
130
|
+
// console.info('set loop err', `R${this.address?.row} C${this.address?.column}`, this);
|
|
131
|
+
|
|
132
|
+
// this should alwys be true, because it has edges so
|
|
133
|
+
// it must be a formula (right?)
|
|
134
|
+
|
|
135
|
+
// we don't have to do that test because now we only set
|
|
136
|
+
// vertices -> white if they match
|
|
137
|
+
|
|
138
|
+
if (this.reference && (
|
|
139
|
+
this.array_head || this.reference.type === ValueType.formula )) {
|
|
140
|
+
this.reference.SetCalculationError(ErrorType.Loop);
|
|
141
|
+
}
|
|
142
|
+
//this.reference?.SetCalculationError('LOOP');
|
|
143
|
+
|
|
144
|
+
// intuitively this seems like a good idea but I'm not sure
|
|
145
|
+
// that it is actually necessary (TODO: check)
|
|
146
|
+
|
|
147
|
+
for (const edge of this.edges_out){
|
|
148
|
+
(edge as SpreadsheetVertex).Calculate(graph);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return;
|
|
152
|
+
|
|
153
|
+
}
|
|
154
|
+
/*
|
|
155
|
+
else {
|
|
156
|
+
console.info('SKIP loop err', `R${this.address?.row} C${this.address?.column}`, this);
|
|
157
|
+
}
|
|
158
|
+
*/
|
|
159
|
+
|
|
160
|
+
// }
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// this is done before checking if it's a formula for the case of
|
|
164
|
+
// arrays: arrays are not formulae but they are dependent on the
|
|
165
|
+
// array head. if the head is dirty we need to calculate that before
|
|
166
|
+
// any dependents of _this_ cell are calculated.
|
|
167
|
+
|
|
168
|
+
// the head calculation should take care of setting this value, that is,
|
|
169
|
+
// we don't need to do the actual lookup.
|
|
170
|
+
|
|
171
|
+
// this prevents a runaway if there's a loop (and we are not catching it),
|
|
172
|
+
// but there's a side-effect: the dirty flag never gets cleared. if we want
|
|
173
|
+
// to fix this we need to clean the dirty flag on vertices before a full
|
|
174
|
+
// recalc, I guess...
|
|
175
|
+
|
|
176
|
+
// that's also why page reload "fixes" the issue: because there's a global
|
|
177
|
+
// cleaning of dirty flags. or maybe they don't survive serialization, I don't know.
|
|
178
|
+
|
|
179
|
+
for (const edge of this.edges_in) {
|
|
180
|
+
if ((edge as SpreadsheetVertexBase).dirty) {
|
|
181
|
+
// console.info('exiting on dirty deps', `R${this.address?.row} C${this.address?.column}`, this);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// console.info('OK calc', `R${this.address?.row} C${this.address?.column}`, this);
|
|
187
|
+
|
|
188
|
+
// we won't have a reference if the reference is to an empty cell,
|
|
189
|
+
// so check that. [Q: what?]
|
|
190
|
+
|
|
191
|
+
if (this.reference) {
|
|
192
|
+
|
|
193
|
+
if (this.reference.type === ValueType.formula) {
|
|
194
|
+
|
|
195
|
+
this.short_circuit = false;
|
|
196
|
+
const result = graph.CalculationCallback.call(graph, this);
|
|
197
|
+
|
|
198
|
+
// console.info("RX", result);
|
|
199
|
+
|
|
200
|
+
this.result = result.value;
|
|
201
|
+
|
|
202
|
+
// this test is a waste for 99% of calls
|
|
203
|
+
//
|
|
204
|
+
// [FYI it has to do with dynamic dependencies, needs to be documented]
|
|
205
|
+
//
|
|
206
|
+
if (this.short_circuit) { return; } // what about setting dirty flag? (...)
|
|
207
|
+
|
|
208
|
+
// and this one for ~75%?
|
|
209
|
+
if (result.volatile) graph.volatile_list.push(this);
|
|
210
|
+
}
|
|
211
|
+
else this.result = this.reference.GetValue4();
|
|
212
|
+
|
|
213
|
+
// is this going to work properly if it's an error? (...)
|
|
214
|
+
|
|
215
|
+
if (this.array_head) {
|
|
216
|
+
graph.SpreadCallback.call(graph, this, this.result);
|
|
217
|
+
}
|
|
218
|
+
else if (this.reference.type === ValueType.formula) {
|
|
219
|
+
|
|
220
|
+
// data should now be clean when it gets here (famous last words)
|
|
221
|
+
|
|
222
|
+
// we're now sometimes getting 0-length arrays here. that's a
|
|
223
|
+
// function of our new polynomial methods, BUT, we should probably
|
|
224
|
+
// handle it properly regardless.
|
|
225
|
+
|
|
226
|
+
const single = (this.result.type === ValueType.array) ? this.result.value[0][0] : this.result;
|
|
227
|
+
/*
|
|
228
|
+
if (single.type === ValueType.object) {
|
|
229
|
+
this.reference.SetCalculationError('OBJECT');
|
|
230
|
+
}
|
|
231
|
+
else */
|
|
232
|
+
|
|
233
|
+
// we are using object type in the returned value for sparklines...
|
|
234
|
+
// so we can't drop it here. we could change rendering though. or
|
|
235
|
+
// whitelist types. or blacklist types. or something.
|
|
236
|
+
|
|
237
|
+
{
|
|
238
|
+
this.reference.SetCalculatedValue(single.value as any, single.type);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/*
|
|
242
|
+
console.info("T2", t2);
|
|
243
|
+
|
|
244
|
+
// because we let sloppy data filter through, it's possible
|
|
245
|
+
// that we get some random stuff at this point. generally this
|
|
246
|
+
// shoudl not happen but if you use (e.g.) one of the chart
|
|
247
|
+
// functions in a spreadsheet cell, you'll get a 1d array.
|
|
248
|
+
|
|
249
|
+
// so we need to validate that what we have is either a UnionValue
|
|
250
|
+
// or a 2d UnionValue[][] array.
|
|
251
|
+
|
|
252
|
+
// don't know the performance cost of this.
|
|
253
|
+
|
|
254
|
+
// FIXME: don't let sloppy data through.
|
|
255
|
+
|
|
256
|
+
let test: any = this.result;
|
|
257
|
+
|
|
258
|
+
if (Array.isArray(test)) {
|
|
259
|
+
if (test[0] && Array.isArray(test[0])) {
|
|
260
|
+
test = test[0][0];
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
// console.warn('error 1');
|
|
264
|
+
test = undefined;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (!test || typeof (test as any).type === undefined) {
|
|
269
|
+
// console.warn('error 2/3');
|
|
270
|
+
this.reference.SetCalculationError('UNK');
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
this.reference.SetCalculatedValue((test as UnionValue).value, (test as UnionValue).type);
|
|
274
|
+
}
|
|
275
|
+
*/
|
|
276
|
+
|
|
277
|
+
/*
|
|
278
|
+
const single = Array.isArray(this.result) ? this.result[0][0] : this.result;
|
|
279
|
+
|
|
280
|
+
// error is implicit
|
|
281
|
+
this.reference.SetCalculatedValue(single.value, single.type);
|
|
282
|
+
*/
|
|
283
|
+
|
|
284
|
+
/*
|
|
285
|
+
if (typeof this.result === 'object' && this.result.error) {
|
|
286
|
+
this.reference.SetCalculationError(this.result.error);
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
this.reference.SetCalculatedValue(this.result);
|
|
290
|
+
}
|
|
291
|
+
*/
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
console.info('skip dirty constant? [or dangling...]');
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
this.dirty = false;
|
|
300
|
+
|
|
301
|
+
// so this is causing problems in long chains. we need
|
|
302
|
+
// to do this !recursively. there's a slight problem in
|
|
303
|
+
// that we do it in the loop check as well... not sure
|
|
304
|
+
// how this will play out.
|
|
305
|
+
|
|
306
|
+
// some options:
|
|
307
|
+
// (1) push (dirty) edges onto a global list (or list contained in graph)
|
|
308
|
+
// (2) return boolean, with one state indicating our dependencies need calculating
|
|
309
|
+
// (3) return a list of dirty dependencies, caller can push onto their list
|
|
310
|
+
//
|
|
311
|
+
// (4) because dirty vertices are on the list, you could just loop until
|
|
312
|
+
// the list is clean (i.e. restart and exit if there are no dirty
|
|
313
|
+
// vertices left)... that's kind of the same as pushing onto the back of
|
|
314
|
+
// the list but it avoids extending the list (not sure if that that is
|
|
315
|
+
// a useful optimization or not)
|
|
316
|
+
//
|
|
317
|
+
|
|
318
|
+
for (const edge of this.edges_out as Set<SpreadsheetVertexBase>){
|
|
319
|
+
// (edge as SpreadsheetVertex).Calculate(graph);
|
|
320
|
+
if (edge.dirty) {
|
|
321
|
+
graph.calculation_list.push(edge);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
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-2023 trebco, llc.
|
|
18
|
+
* info@treb.app
|
|
19
|
+
*
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { Vertex } from './vertex';
|
|
23
|
+
import type { UnionValue } from 'treb-base-types';
|
|
24
|
+
|
|
25
|
+
export interface CalculationResult {
|
|
26
|
+
// value: any;
|
|
27
|
+
value: UnionValue;
|
|
28
|
+
volatile?: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* this is a subset of Graph so we can avoid the circular dependency.
|
|
33
|
+
*/
|
|
34
|
+
export interface GraphCallbacks {
|
|
35
|
+
CalculationCallback: (vertex: SpreadsheetVertexBase) => CalculationResult;
|
|
36
|
+
SpreadCallback: (vertex: SpreadsheetVertexBase, value: UnionValue) => void;
|
|
37
|
+
volatile_list: SpreadsheetVertexBase[];
|
|
38
|
+
calculation_list: SpreadsheetVertexBase[];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export abstract class SpreadsheetVertexBase extends Vertex {
|
|
42
|
+
public dirty = false;
|
|
43
|
+
public abstract Calculate(graph: GraphCallbacks): void;
|
|
44
|
+
}
|