documents.js 1.63.0 → 1.65.0
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/README.md +124 -25
- package/dist/convert/convert.cjs +3 -3
- package/dist/convert/convert.d.cts +5 -2
- package/dist/convert/convert.d.ts +4 -1
- package/dist/convert/convert.js +3 -3
- package/dist/edit/docx/content.d.cts +1 -1
- package/dist/edit/docx/content.d.ts +1 -1
- package/dist/edit/docx/paragraph.d.cts +3 -3
- package/dist/edit/docx/paragraph.d.ts +3 -3
- package/dist/edit/ods/address.cjs +42 -24
- package/dist/edit/ods/address.d.cts +12 -2
- package/dist/edit/ods/address.d.ts +12 -2
- package/dist/edit/ods/address.js +39 -25
- package/dist/edit/ods/column-row.cjs +68 -6
- package/dist/edit/ods/column-row.d.cts +5 -1
- package/dist/edit/ods/column-row.d.ts +5 -1
- package/dist/edit/ods/column-row.js +68 -10
- package/dist/edit/ods/content.cjs +10 -2
- package/dist/edit/ods/content.js +10 -2
- package/dist/edit/ods/floating.cjs +90 -0
- package/dist/edit/ods/floating.d.cts +7 -0
- package/dist/edit/ods/floating.d.ts +7 -0
- package/dist/edit/ods/floating.js +88 -0
- package/dist/edit/ods/print-settings.cjs +158 -2
- package/dist/edit/ods/print-settings.js +159 -3
- package/dist/edit/ods/sheet.cjs +13 -0
- package/dist/edit/ods/sheet.d.cts +5 -1
- package/dist/edit/ods/sheet.d.ts +5 -1
- package/dist/edit/ods/sheet.js +14 -1
- package/dist/edit/odt/content.cjs +8 -4
- package/dist/edit/odt/content.js +8 -4
- package/dist/edit/odt/editor.cjs +7 -0
- package/dist/edit/odt/editor.d.cts +3 -0
- package/dist/edit/odt/editor.d.ts +3 -0
- package/dist/edit/odt/editor.js +7 -0
- package/dist/edit/odt/formula.cjs +19 -0
- package/dist/edit/odt/formula.d.cts +8 -0
- package/dist/edit/odt/formula.d.ts +8 -0
- package/dist/edit/odt/formula.js +17 -0
- package/dist/evaluate-BU5N1Jk1.d.ts +11 -0
- package/dist/evaluate-BhMXY6DM.d.cts +11 -0
- package/dist/firebird/backup.d.cts +1 -1
- package/dist/firebird/backup.d.ts +1 -1
- package/dist/firebird/data.cjs +30 -16
- package/dist/firebird/data.d.cts +3 -2
- package/dist/firebird/data.d.ts +3 -2
- package/dist/firebird/data.js +30 -17
- package/dist/fonts/ooxml.d.cts +1 -1
- package/dist/fonts/registry.d.cts +1 -1
- package/dist/formula-CgydMiTt.d.ts +10 -0
- package/dist/formula-CiwPw8nY.d.cts +10 -0
- package/dist/hsqldb/binary-script.d.cts +1 -1
- package/dist/hsqldb/binary-script.d.ts +1 -1
- package/dist/hsqldb/cache.d.cts +1 -1
- package/dist/hsqldb/cache.d.ts +1 -1
- package/dist/hsqldb/rowformat.cjs +22 -13
- package/dist/hsqldb/rowformat.js +22 -13
- package/dist/hsqldb/script.d.cts +1 -18
- package/dist/hsqldb/script.d.ts +1 -18
- package/dist/index.cjs +56 -0
- package/dist/index.d.cts +24 -10
- package/dist/index.d.ts +23 -9
- package/dist/index.js +15 -2
- package/dist/layout/sheets.cjs +30 -24
- package/dist/layout/sheets.js +31 -25
- package/dist/layout/slides.cjs +6 -4
- package/dist/layout/slides.js +7 -5
- package/dist/lexer-DGPWx_f2.d.cts +42 -0
- package/dist/lexer-DGPWx_f2.d.ts +42 -0
- package/dist/mathml/compose.cjs +8 -0
- package/dist/mathml/compose.js +8 -0
- package/dist/mathml/layout-types.d.cts +14 -2
- package/dist/mathml/layout-types.d.ts +14 -2
- package/dist/mathml/layout.cjs +62 -3
- package/dist/mathml/layout.d.cts +1 -1
- package/dist/mathml/layout.d.ts +1 -1
- package/dist/mathml/layout.js +62 -3
- package/dist/mathml/metrics.d.cts +17 -1
- package/dist/mathml/metrics.d.ts +17 -1
- package/dist/mathml/operators.cjs +1 -1
- package/dist/mathml/operators.js +1 -1
- package/dist/mathml/variant.d.cts +1 -6
- package/dist/mathml/variant.d.ts +1 -6
- package/dist/odb/csv.d.cts +1 -1
- package/dist/odb/csv.d.ts +1 -1
- package/dist/odb/formula/definition.cjs +49 -0
- package/dist/odb/formula/definition.d.cts +8 -0
- package/dist/odb/formula/definition.d.ts +8 -0
- package/dist/odb/formula/definition.js +46 -0
- package/dist/odb/formula/errors.cjs +47 -0
- package/dist/odb/formula/errors.d.cts +21 -0
- package/dist/odb/formula/errors.d.ts +21 -0
- package/dist/odb/formula/errors.js +43 -0
- package/dist/odb/formula/evaluate.cjs +283 -0
- package/dist/odb/formula/evaluate.d.cts +43 -0
- package/dist/odb/formula/evaluate.d.ts +43 -0
- package/dist/odb/formula/evaluate.js +281 -0
- package/dist/odb/formula/parser.cjs +198 -0
- package/dist/odb/formula/parser.d.cts +29 -0
- package/dist/odb/formula/parser.d.ts +29 -0
- package/dist/odb/formula/parser.js +197 -0
- package/dist/odb/read.d.cts +1 -1
- package/dist/odb/read.d.ts +1 -1
- package/dist/odb/report/content.cjs +27 -0
- package/dist/odb/report/content.d.cts +14 -0
- package/dist/odb/report/content.d.ts +14 -0
- package/dist/odb/report/content.js +25 -0
- package/dist/odb/report/render.cjs +106 -0
- package/dist/odb/report/render.d.cts +7 -0
- package/dist/odb/report/render.d.ts +7 -0
- package/dist/odb/report/render.js +106 -0
- package/dist/odb/report/source.cjs +45 -0
- package/dist/odb/report/source.d.cts +14 -0
- package/dist/odb/report/source.d.ts +14 -0
- package/dist/odb/report/source.js +42 -0
- package/dist/odb/spreadsheet.d.cts +1 -1
- package/dist/odb/spreadsheet.d.ts +1 -1
- package/dist/odb/sql/errors.cjs +38 -0
- package/dist/odb/sql/errors.d.cts +17 -0
- package/dist/odb/sql/errors.d.ts +17 -0
- package/dist/odb/sql/errors.js +35 -0
- package/dist/odb/sql/evaluate.cjs +312 -0
- package/dist/odb/sql/evaluate.d.cts +2 -0
- package/dist/odb/sql/evaluate.d.ts +2 -0
- package/dist/odb/sql/evaluate.js +311 -0
- package/dist/odb/sql/lexer.cjs +282 -0
- package/dist/odb/sql/lexer.d.cts +2 -0
- package/dist/odb/sql/lexer.d.ts +2 -0
- package/dist/odb/sql/lexer.js +281 -0
- package/dist/odb/sql/parser.cjs +479 -0
- package/dist/odb/sql/parser.d.cts +2 -0
- package/dist/odb/sql/parser.d.ts +2 -0
- package/dist/odb/sql/parser.js +478 -0
- package/dist/odb/values.cjs +75 -0
- package/dist/odb/values.d.cts +2 -0
- package/dist/odb/values.d.ts +2 -0
- package/dist/odb/values.js +69 -0
- package/dist/odf/odt/read.cjs +43 -21
- package/dist/odf/odt/read.js +43 -21
- package/dist/odf-package/formula.cjs +59 -0
- package/dist/odf-package/formula.d.cts +11 -0
- package/dist/odf-package/formula.d.ts +11 -0
- package/dist/odf-package/formula.js +58 -0
- package/dist/odf-package/manifest.cjs +29 -0
- package/dist/odf-package/manifest.d.cts +5 -2
- package/dist/odf-package/manifest.d.ts +5 -2
- package/dist/odf-package/manifest.js +30 -2
- package/dist/odf-package/media.cjs +2 -1
- package/dist/odf-package/media.js +2 -2
- package/dist/omml/read.cjs +265 -0
- package/dist/omml/read.d.cts +12 -0
- package/dist/omml/read.d.ts +12 -0
- package/dist/omml/read.js +263 -0
- package/dist/omml/shared.cjs +67 -0
- package/dist/omml/shared.d.cts +2 -0
- package/dist/omml/shared.d.ts +2 -0
- package/dist/omml/shared.js +64 -0
- package/dist/omml/write.cjs +3 -51
- package/dist/omml/write.d.cts +2 -2
- package/dist/omml/write.d.ts +2 -2
- package/dist/omml/write.js +1 -49
- package/dist/ooxml/docx/extras.cjs +15 -0
- package/dist/ooxml/docx/extras.d.cts +12 -0
- package/dist/ooxml/docx/extras.d.ts +12 -0
- package/dist/ooxml/docx/extras.js +14 -0
- package/dist/ooxml/docx/formula.cjs +109 -0
- package/dist/ooxml/docx/formula.d.cts +2 -0
- package/dist/ooxml/docx/formula.d.ts +2 -0
- package/dist/ooxml/docx/formula.js +108 -0
- package/dist/ooxml/docx/read.cjs +10 -2
- package/dist/ooxml/docx/read.d.cts +6 -2
- package/dist/ooxml/docx/read.d.ts +6 -2
- package/dist/ooxml/docx/read.js +11 -3
- package/dist/parser-B9vC1T6T.d.cts +101 -0
- package/dist/parser-DQSgYJzQ.d.ts +101 -0
- package/dist/{registry-CtPhMD0f.d.cts → registry-lqJej0Jr.d.cts} +1 -1
- package/dist/script-DsGGIzGU.d.cts +19 -0
- package/dist/script-DsGGIzGU.d.ts +19 -0
- package/dist/shared-DLZ3IQUl.d.cts +15 -0
- package/dist/shared-DUOzjwcL.d.ts +15 -0
- package/dist/values-BetetbaH.d.cts +23 -0
- package/dist/values-BetetbaH.d.ts +23 -0
- package/dist/variant-BMrebjMw.d.cts +7 -0
- package/dist/variant-BMrebjMw.d.ts +7 -0
- package/dist/{write-DuyfnbL_.d.cts → write-BQ6SK8r8.d.cts} +2 -6
- package/dist/{write-Zqwx6pka.d.ts → write-THs7ipBq.d.ts} +2 -6
- package/package.json +2 -2
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_odb_values = require("../values.cjs");
|
|
3
|
+
const require_odb_formula_errors = require("./errors.cjs");
|
|
4
|
+
const require_odb_formula_parser = require("./parser.cjs");
|
|
5
|
+
//#region src/odb/formula/evaluate.ts
|
|
6
|
+
function fail(message, formula) {
|
|
7
|
+
throw new require_odb_formula_errors.RptFormulaEvaluationError(message, formula);
|
|
8
|
+
}
|
|
9
|
+
function matchNamed(candidates, nameOf, name) {
|
|
10
|
+
const exact = candidates.filter((candidate) => nameOf(candidate) === name);
|
|
11
|
+
return exact.length > 0 ? exact : candidates.filter((candidate) => nameOf(candidate).toUpperCase() === name.toUpperCase());
|
|
12
|
+
}
|
|
13
|
+
function identity(name) {
|
|
14
|
+
return name;
|
|
15
|
+
}
|
|
16
|
+
function prepareBandFormulas(band) {
|
|
17
|
+
return band.formulas.map((formula) => formula === void 0 ? void 0 : require_odb_formula_parser.parseRptFormula(formula));
|
|
18
|
+
}
|
|
19
|
+
function prepareBand(band) {
|
|
20
|
+
return band === void 0 ? void 0 : prepareBandFormulas(band);
|
|
21
|
+
}
|
|
22
|
+
var PreparedReport = class {
|
|
23
|
+
resultSet;
|
|
24
|
+
namedFunctions;
|
|
25
|
+
groupExpressions;
|
|
26
|
+
bands;
|
|
27
|
+
columnNames;
|
|
28
|
+
resolutions = /* @__PURE__ */ new Map();
|
|
29
|
+
constructor(definition, resultSet) {
|
|
30
|
+
this.resultSet = resultSet;
|
|
31
|
+
this.columnNames = resultSet.columns;
|
|
32
|
+
const named = /* @__PURE__ */ new Map();
|
|
33
|
+
const declare = (functions, scope) => {
|
|
34
|
+
for (const declaration of functions) {
|
|
35
|
+
if (named.has(declaration.name)) fail(`rpt:function "${declaration.name}" is declared more than once in this report`, declaration.formula);
|
|
36
|
+
named.set(declaration.name, {
|
|
37
|
+
name: declaration.name,
|
|
38
|
+
formula: require_odb_formula_parser.parseRptFormula(declaration.formula),
|
|
39
|
+
scope
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
declare(definition.functions, { kind: "report" });
|
|
44
|
+
for (const [level, group] of definition.groups.entries()) declare(group.functions, {
|
|
45
|
+
kind: "group",
|
|
46
|
+
level
|
|
47
|
+
});
|
|
48
|
+
this.namedFunctions = named;
|
|
49
|
+
this.groupExpressions = definition.groups.map((group) => require_odb_formula_parser.parseRptFormula(group.groupExpression));
|
|
50
|
+
this.bands = {
|
|
51
|
+
reportHeader: prepareBand(definition.reportHeader),
|
|
52
|
+
detail: prepareBand(definition.detail),
|
|
53
|
+
reportFooter: prepareBand(definition.reportFooter),
|
|
54
|
+
groups: definition.groups.map((group) => ({
|
|
55
|
+
header: prepareBand(group.header),
|
|
56
|
+
footer: prepareBand(group.footer)
|
|
57
|
+
}))
|
|
58
|
+
};
|
|
59
|
+
for (const expression of this.groupExpressions) this.rejectAggregateDependency(expression, expression, /* @__PURE__ */ new Set());
|
|
60
|
+
}
|
|
61
|
+
rejectAggregateDependency(formula, expression, visiting) {
|
|
62
|
+
if (formula.kind === "aggregate") fail(`a group expression cannot depend on the aggregate rpt:${formula.aggregate}(${formula.reference.name}) -- an aggregate's own rows are defined by the very group boundaries this expression decides`, expression.text);
|
|
63
|
+
const resolved = matchNamed([...this.namedFunctions.values()], (candidate) => candidate.name, formula.reference.name)[0];
|
|
64
|
+
if (resolved === void 0) return;
|
|
65
|
+
if (visiting.has(resolved.name)) fail(`rpt:function "${resolved.name}" refers to itself, directly or through another function`, expression.text);
|
|
66
|
+
this.rejectAggregateDependency(resolved.formula, expression, /* @__PURE__ */ new Set([...visiting, resolved.name]));
|
|
67
|
+
}
|
|
68
|
+
resolveReference(reference, formula) {
|
|
69
|
+
const cached = this.resolutions.get(reference);
|
|
70
|
+
if (cached !== void 0) return cached;
|
|
71
|
+
const functionMatches = matchNamed([...this.namedFunctions.values()], (candidate) => candidate.name, reference.name);
|
|
72
|
+
const columnMatches = matchNamed(this.columnNames, identity, reference.name);
|
|
73
|
+
if (functionMatches.length + columnMatches.length > 1) fail(`reference "${reference.name}" is ambiguous -- it matches ${[...functionMatches.map((match) => `rpt:function ${match.name}`), ...columnMatches.map((match) => `column ${match}`)].join(", ")}`, formula);
|
|
74
|
+
const resolved = this.resolveSingleMatch(reference, functionMatches[0], columnMatches[0], formula);
|
|
75
|
+
this.resolutions.set(reference, resolved);
|
|
76
|
+
return resolved;
|
|
77
|
+
}
|
|
78
|
+
resolveSingleMatch(reference, named, columnName, formula) {
|
|
79
|
+
if (named !== void 0) return {
|
|
80
|
+
kind: "function",
|
|
81
|
+
resolved: named
|
|
82
|
+
};
|
|
83
|
+
if (columnName === void 0) fail(`reference "${reference.name}" names neither a declared rpt:function nor a column of the report's own data -- functions: ${this.namedFunctions.size === 0 ? "(none)" : [...this.namedFunctions.keys()].join(", ")}; columns: ${this.columnNames.length === 0 ? "(none)" : this.columnNames.join(", ")}`, formula);
|
|
84
|
+
return {
|
|
85
|
+
kind: "column",
|
|
86
|
+
index: this.columnNames.indexOf(columnName)
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
valueAt(columnIndex, rowIndex, formula) {
|
|
90
|
+
const value = this.resultSet.rows[rowIndex]?.[columnIndex];
|
|
91
|
+
if (value === void 0) fail(`the report's own data has no value at row ${String(rowIndex)}, column ${String(columnIndex)}`, formula);
|
|
92
|
+
return value;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
var RunState = class {
|
|
96
|
+
rowCount;
|
|
97
|
+
openInstances;
|
|
98
|
+
constructor(levels, rowCount) {
|
|
99
|
+
this.rowCount = rowCount;
|
|
100
|
+
this.openInstances = Array.from({ length: levels }, () => void 0);
|
|
101
|
+
}
|
|
102
|
+
open(level, range) {
|
|
103
|
+
this.openInstances[level] = range;
|
|
104
|
+
}
|
|
105
|
+
openAt(level) {
|
|
106
|
+
return this.openInstances[level];
|
|
107
|
+
}
|
|
108
|
+
close(level) {
|
|
109
|
+
this.openInstances[level] = void 0;
|
|
110
|
+
}
|
|
111
|
+
rangeFor(scope, formula) {
|
|
112
|
+
if (scope.kind === "report") return {
|
|
113
|
+
startRow: 0,
|
|
114
|
+
endRowExclusive: this.rowCount
|
|
115
|
+
};
|
|
116
|
+
const open = this.openInstances[scope.level];
|
|
117
|
+
if (open === void 0) fail(`an aggregate scoped to group level ${String(scope.level)} was evaluated while no instance of that group was open`, formula);
|
|
118
|
+
return open;
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
function textOf(value, formula, what) {
|
|
122
|
+
if (value.kind === "empty") return;
|
|
123
|
+
const key = require_odb_values.cellComparisonKey(value);
|
|
124
|
+
if (key?.valueClass !== "text") fail(`${what} requires a text value, but found a ${value.kind} value -- this engine does not format a number or a boolean into text, since a report's own number format lives in its band styles rather than in the formula`, formula);
|
|
125
|
+
return key.text;
|
|
126
|
+
}
|
|
127
|
+
var FormulaEvaluator = class {
|
|
128
|
+
prepared;
|
|
129
|
+
state;
|
|
130
|
+
constructor(prepared, state) {
|
|
131
|
+
this.prepared = prepared;
|
|
132
|
+
this.state = state;
|
|
133
|
+
}
|
|
134
|
+
evaluate(formula, rowIndex, scope, visiting = /* @__PURE__ */ new Set()) {
|
|
135
|
+
switch (formula.kind) {
|
|
136
|
+
case "field": return this.referenceValue(formula.reference, this.requireRow(rowIndex, formula.text, "a field: reference"), formula.text, visiting);
|
|
137
|
+
case "hasChanged": {
|
|
138
|
+
const rowOfChange = this.requireRow(rowIndex, formula.text, "rpt:HASCHANGED");
|
|
139
|
+
const current = this.referenceValue(formula.reference, rowOfChange, formula.text, visiting);
|
|
140
|
+
if (rowOfChange === 0) return {
|
|
141
|
+
kind: "boolean",
|
|
142
|
+
value: true
|
|
143
|
+
};
|
|
144
|
+
const previous = this.referenceValue(formula.reference, rowOfChange - 1, formula.text, visiting);
|
|
145
|
+
return {
|
|
146
|
+
kind: "boolean",
|
|
147
|
+
value: !require_odb_values.cellValuesEqual(current, previous)
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
case "left": {
|
|
151
|
+
const text = textOf(this.referenceValue(formula.reference, this.requireRow(rowIndex, formula.text, "rpt:LEFT"), formula.text, visiting), formula.text, "rpt:LEFT");
|
|
152
|
+
return text === void 0 ? require_odb_values.CELL_NULL : {
|
|
153
|
+
kind: "string",
|
|
154
|
+
value: [...text].slice(0, formula.length).join("")
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
case "aggregate": {
|
|
158
|
+
const range = this.state.rangeFor(scope, formula.text);
|
|
159
|
+
const values = [];
|
|
160
|
+
for (let row = range.startRow; row < range.endRowExclusive; row += 1) values.push(this.referenceValue(formula.reference, row, formula.text, visiting));
|
|
161
|
+
return require_odb_values.aggregateCellValues(formula.aggregate, values, (message) => new require_odb_formula_errors.RptFormulaEvaluationError(message, formula.text));
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
requireRow(rowIndex, formula, what) {
|
|
166
|
+
if (rowIndex === void 0) fail(`${what} needs a data row, but the band it appears in belongs to no row (the report header and footer print outside the data)`, formula);
|
|
167
|
+
return rowIndex;
|
|
168
|
+
}
|
|
169
|
+
referenceValue(reference, rowIndex, formula, visiting) {
|
|
170
|
+
const resolved = this.prepared.resolveReference(reference, formula);
|
|
171
|
+
if (resolved.kind === "column") return this.prepared.valueAt(resolved.index, rowIndex, formula);
|
|
172
|
+
if (visiting.has(resolved.resolved.name)) fail(`rpt:function "${resolved.resolved.name}" refers to itself, directly or through another function`, formula);
|
|
173
|
+
return this.evaluate(resolved.resolved.formula, rowIndex, resolved.resolved.scope, /* @__PURE__ */ new Set([...visiting, resolved.resolved.name]));
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
function resolveOwnBreak(value, formula) {
|
|
177
|
+
if (value.kind !== "boolean") fail(`a group expression must evaluate to a boolean break test (rpt:HASCHANGED(...)), but this one produced a ${value.kind} value`, formula);
|
|
178
|
+
return value.value;
|
|
179
|
+
}
|
|
180
|
+
var GroupBreaks = class {
|
|
181
|
+
rowCount;
|
|
182
|
+
rows;
|
|
183
|
+
constructor(prepared, evaluator, rowCount) {
|
|
184
|
+
this.rowCount = rowCount;
|
|
185
|
+
const rows = [];
|
|
186
|
+
for (let rowIndex = 0; rowIndex < rowCount; rowIndex += 1) {
|
|
187
|
+
const flags = [];
|
|
188
|
+
let enclosingBroke = false;
|
|
189
|
+
for (const [level, expression] of prepared.groupExpressions.entries()) {
|
|
190
|
+
const ownBreak = resolveOwnBreak(evaluator.evaluate(expression, rowIndex, {
|
|
191
|
+
kind: "group",
|
|
192
|
+
level
|
|
193
|
+
}), expression.text);
|
|
194
|
+
const broke = enclosingBroke || rowIndex === 0 || ownBreak;
|
|
195
|
+
flags.push(broke);
|
|
196
|
+
enclosingBroke = broke;
|
|
197
|
+
}
|
|
198
|
+
rows.push(flags);
|
|
199
|
+
}
|
|
200
|
+
this.rows = rows;
|
|
201
|
+
}
|
|
202
|
+
flagsAt(rowIndex) {
|
|
203
|
+
const flags = this.rows[rowIndex];
|
|
204
|
+
if (flags === void 0) throw new Error(`rpt report run: row ${String(rowIndex)} is outside the ${String(this.rowCount)} rows its group breaks were computed for`);
|
|
205
|
+
return flags;
|
|
206
|
+
}
|
|
207
|
+
outermostBreakAt(rowIndex) {
|
|
208
|
+
return this.flagsAt(rowIndex).indexOf(true);
|
|
209
|
+
}
|
|
210
|
+
breaksAt(rowIndex, level) {
|
|
211
|
+
return this.flagsAt(rowIndex)[level] === true;
|
|
212
|
+
}
|
|
213
|
+
instanceContaining(level, rowIndex) {
|
|
214
|
+
let startRow = rowIndex;
|
|
215
|
+
while (startRow > 0 && !this.breaksAt(startRow, level)) startRow -= 1;
|
|
216
|
+
let endRowExclusive = rowIndex + 1;
|
|
217
|
+
while (endRowExclusive < this.rowCount && !this.breaksAt(endRowExclusive, level)) endRowExclusive += 1;
|
|
218
|
+
return {
|
|
219
|
+
startRow,
|
|
220
|
+
endRowExclusive
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
function detailScope(groupCount) {
|
|
225
|
+
return groupCount === 0 ? { kind: "report" } : {
|
|
226
|
+
kind: "group",
|
|
227
|
+
level: groupCount - 1
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function runRptReport(definition, resultSet) {
|
|
231
|
+
const rowCount = resultSet.rows.length;
|
|
232
|
+
const levels = definition.groups.length;
|
|
233
|
+
const prepared = new PreparedReport(definition, resultSet);
|
|
234
|
+
const state = new RunState(levels, rowCount);
|
|
235
|
+
const evaluator = new FormulaEvaluator(prepared, state);
|
|
236
|
+
const bands = [];
|
|
237
|
+
const emit = (band, kind, groupLevel, rowIndex, scope) => {
|
|
238
|
+
if (band === void 0) return;
|
|
239
|
+
bands.push({
|
|
240
|
+
kind,
|
|
241
|
+
groupLevel,
|
|
242
|
+
rowIndex,
|
|
243
|
+
values: band.map((formula) => formula === void 0 ? void 0 : evaluator.evaluate(formula, rowIndex, scope))
|
|
244
|
+
});
|
|
245
|
+
};
|
|
246
|
+
emit(prepared.bands.reportHeader, "report-header", void 0, void 0, { kind: "report" });
|
|
247
|
+
const breaks = new GroupBreaks(prepared, evaluator, rowCount);
|
|
248
|
+
const closeFrom = (level) => {
|
|
249
|
+
for (let openLevel = levels - 1; openLevel >= level; openLevel -= 1) {
|
|
250
|
+
const open = state.openAt(openLevel);
|
|
251
|
+
if (open === void 0) continue;
|
|
252
|
+
emit(prepared.bands.groups[openLevel]?.footer, "group-footer", openLevel, open.endRowExclusive - 1, {
|
|
253
|
+
kind: "group",
|
|
254
|
+
level: openLevel
|
|
255
|
+
});
|
|
256
|
+
state.close(openLevel);
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
for (let rowIndex = 0; rowIndex < rowCount; rowIndex += 1) {
|
|
260
|
+
const outermostBroken = breaks.outermostBreakAt(rowIndex);
|
|
261
|
+
if (outermostBroken >= 0) {
|
|
262
|
+
closeFrom(outermostBroken);
|
|
263
|
+
for (let level = outermostBroken; level < levels; level += 1) {
|
|
264
|
+
state.open(level, breaks.instanceContaining(level, rowIndex));
|
|
265
|
+
emit(prepared.bands.groups[level]?.header, "group-header", level, rowIndex, {
|
|
266
|
+
kind: "group",
|
|
267
|
+
level
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
emit(prepared.bands.detail, "detail", void 0, rowIndex, detailScope(levels));
|
|
272
|
+
}
|
|
273
|
+
closeFrom(0);
|
|
274
|
+
emit(prepared.bands.reportFooter, "report-footer", void 0, void 0, { kind: "report" });
|
|
275
|
+
return { bands };
|
|
276
|
+
}
|
|
277
|
+
function evaluateRptBandOutsideData(definition, band, resultSet) {
|
|
278
|
+
const evaluator = new FormulaEvaluator(new PreparedReport(definition, resultSet), new RunState(definition.groups.length, resultSet.rows.length));
|
|
279
|
+
return prepareBandFormulas(band).map((formula) => formula === void 0 ? void 0 : evaluator.evaluate(formula, void 0, { kind: "report" }));
|
|
280
|
+
}
|
|
281
|
+
//#endregion
|
|
282
|
+
exports.evaluateRptBandOutsideData = evaluateRptBandOutsideData;
|
|
283
|
+
exports.runRptReport = runRptReport;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { t as SqlResultSet } from "../../evaluate-BhMXY6DM.cjs";
|
|
2
|
+
import { ContentCellValue } from "document-schema.js";
|
|
3
|
+
//#region src/odb/formula/evaluate.d.ts
|
|
4
|
+
type RptBandKind = 'report-header' | 'group-header' | 'detail' | 'group-footer' | 'report-footer';
|
|
5
|
+
type RptScope = {
|
|
6
|
+
readonly kind: 'report';
|
|
7
|
+
} | {
|
|
8
|
+
readonly kind: 'group';
|
|
9
|
+
readonly level: number;
|
|
10
|
+
};
|
|
11
|
+
interface RptNamedFunctionDefinition {
|
|
12
|
+
readonly name: string;
|
|
13
|
+
readonly formula: string;
|
|
14
|
+
}
|
|
15
|
+
interface RptBandDefinition {
|
|
16
|
+
readonly formulas: readonly (string | undefined)[];
|
|
17
|
+
}
|
|
18
|
+
interface RptGroupDefinition {
|
|
19
|
+
readonly groupExpression: string;
|
|
20
|
+
readonly functions: readonly RptNamedFunctionDefinition[];
|
|
21
|
+
readonly header: RptBandDefinition | undefined;
|
|
22
|
+
readonly footer: RptBandDefinition | undefined;
|
|
23
|
+
}
|
|
24
|
+
interface RptReportDefinition {
|
|
25
|
+
readonly functions: readonly RptNamedFunctionDefinition[];
|
|
26
|
+
readonly reportHeader: RptBandDefinition | undefined;
|
|
27
|
+
readonly groups: readonly RptGroupDefinition[];
|
|
28
|
+
readonly detail: RptBandDefinition | undefined;
|
|
29
|
+
readonly reportFooter: RptBandDefinition | undefined;
|
|
30
|
+
}
|
|
31
|
+
interface RptBandInstance {
|
|
32
|
+
readonly kind: RptBandKind;
|
|
33
|
+
readonly groupLevel: number | undefined;
|
|
34
|
+
readonly rowIndex: number | undefined;
|
|
35
|
+
readonly values: readonly (ContentCellValue | undefined)[];
|
|
36
|
+
}
|
|
37
|
+
interface RptReportRun {
|
|
38
|
+
readonly bands: readonly RptBandInstance[];
|
|
39
|
+
}
|
|
40
|
+
declare function runRptReport(definition: RptReportDefinition, resultSet: SqlResultSet): RptReportRun;
|
|
41
|
+
declare function evaluateRptBandOutsideData(definition: RptReportDefinition, band: RptBandDefinition, resultSet: SqlResultSet): readonly (ContentCellValue | undefined)[];
|
|
42
|
+
//#endregion
|
|
43
|
+
export { RptBandDefinition, RptBandInstance, RptBandKind, RptGroupDefinition, RptNamedFunctionDefinition, RptReportDefinition, RptReportRun, RptScope, evaluateRptBandOutsideData, runRptReport };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { t as SqlResultSet } from "../../evaluate-BU5N1Jk1.js";
|
|
2
|
+
import { ContentCellValue } from "document-schema.js";
|
|
3
|
+
//#region src/odb/formula/evaluate.d.ts
|
|
4
|
+
type RptBandKind = 'report-header' | 'group-header' | 'detail' | 'group-footer' | 'report-footer';
|
|
5
|
+
type RptScope = {
|
|
6
|
+
readonly kind: 'report';
|
|
7
|
+
} | {
|
|
8
|
+
readonly kind: 'group';
|
|
9
|
+
readonly level: number;
|
|
10
|
+
};
|
|
11
|
+
interface RptNamedFunctionDefinition {
|
|
12
|
+
readonly name: string;
|
|
13
|
+
readonly formula: string;
|
|
14
|
+
}
|
|
15
|
+
interface RptBandDefinition {
|
|
16
|
+
readonly formulas: readonly (string | undefined)[];
|
|
17
|
+
}
|
|
18
|
+
interface RptGroupDefinition {
|
|
19
|
+
readonly groupExpression: string;
|
|
20
|
+
readonly functions: readonly RptNamedFunctionDefinition[];
|
|
21
|
+
readonly header: RptBandDefinition | undefined;
|
|
22
|
+
readonly footer: RptBandDefinition | undefined;
|
|
23
|
+
}
|
|
24
|
+
interface RptReportDefinition {
|
|
25
|
+
readonly functions: readonly RptNamedFunctionDefinition[];
|
|
26
|
+
readonly reportHeader: RptBandDefinition | undefined;
|
|
27
|
+
readonly groups: readonly RptGroupDefinition[];
|
|
28
|
+
readonly detail: RptBandDefinition | undefined;
|
|
29
|
+
readonly reportFooter: RptBandDefinition | undefined;
|
|
30
|
+
}
|
|
31
|
+
interface RptBandInstance {
|
|
32
|
+
readonly kind: RptBandKind;
|
|
33
|
+
readonly groupLevel: number | undefined;
|
|
34
|
+
readonly rowIndex: number | undefined;
|
|
35
|
+
readonly values: readonly (ContentCellValue | undefined)[];
|
|
36
|
+
}
|
|
37
|
+
interface RptReportRun {
|
|
38
|
+
readonly bands: readonly RptBandInstance[];
|
|
39
|
+
}
|
|
40
|
+
declare function runRptReport(definition: RptReportDefinition, resultSet: SqlResultSet): RptReportRun;
|
|
41
|
+
declare function evaluateRptBandOutsideData(definition: RptReportDefinition, band: RptBandDefinition, resultSet: SqlResultSet): readonly (ContentCellValue | undefined)[];
|
|
42
|
+
//#endregion
|
|
43
|
+
export { RptBandDefinition, RptBandInstance, RptBandKind, RptGroupDefinition, RptNamedFunctionDefinition, RptReportDefinition, RptReportRun, RptScope, evaluateRptBandOutsideData, runRptReport };
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { CELL_NULL, aggregateCellValues, cellComparisonKey, cellValuesEqual } from "../values.js";
|
|
2
|
+
import { RptFormulaEvaluationError } from "./errors.js";
|
|
3
|
+
import { parseRptFormula } from "./parser.js";
|
|
4
|
+
//#region src/odb/formula/evaluate.ts
|
|
5
|
+
function fail(message, formula) {
|
|
6
|
+
throw new RptFormulaEvaluationError(message, formula);
|
|
7
|
+
}
|
|
8
|
+
function matchNamed(candidates, nameOf, name) {
|
|
9
|
+
const exact = candidates.filter((candidate) => nameOf(candidate) === name);
|
|
10
|
+
return exact.length > 0 ? exact : candidates.filter((candidate) => nameOf(candidate).toUpperCase() === name.toUpperCase());
|
|
11
|
+
}
|
|
12
|
+
function identity(name) {
|
|
13
|
+
return name;
|
|
14
|
+
}
|
|
15
|
+
function prepareBandFormulas(band) {
|
|
16
|
+
return band.formulas.map((formula) => formula === void 0 ? void 0 : parseRptFormula(formula));
|
|
17
|
+
}
|
|
18
|
+
function prepareBand(band) {
|
|
19
|
+
return band === void 0 ? void 0 : prepareBandFormulas(band);
|
|
20
|
+
}
|
|
21
|
+
var PreparedReport = class {
|
|
22
|
+
resultSet;
|
|
23
|
+
namedFunctions;
|
|
24
|
+
groupExpressions;
|
|
25
|
+
bands;
|
|
26
|
+
columnNames;
|
|
27
|
+
resolutions = /* @__PURE__ */ new Map();
|
|
28
|
+
constructor(definition, resultSet) {
|
|
29
|
+
this.resultSet = resultSet;
|
|
30
|
+
this.columnNames = resultSet.columns;
|
|
31
|
+
const named = /* @__PURE__ */ new Map();
|
|
32
|
+
const declare = (functions, scope) => {
|
|
33
|
+
for (const declaration of functions) {
|
|
34
|
+
if (named.has(declaration.name)) fail(`rpt:function "${declaration.name}" is declared more than once in this report`, declaration.formula);
|
|
35
|
+
named.set(declaration.name, {
|
|
36
|
+
name: declaration.name,
|
|
37
|
+
formula: parseRptFormula(declaration.formula),
|
|
38
|
+
scope
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
declare(definition.functions, { kind: "report" });
|
|
43
|
+
for (const [level, group] of definition.groups.entries()) declare(group.functions, {
|
|
44
|
+
kind: "group",
|
|
45
|
+
level
|
|
46
|
+
});
|
|
47
|
+
this.namedFunctions = named;
|
|
48
|
+
this.groupExpressions = definition.groups.map((group) => parseRptFormula(group.groupExpression));
|
|
49
|
+
this.bands = {
|
|
50
|
+
reportHeader: prepareBand(definition.reportHeader),
|
|
51
|
+
detail: prepareBand(definition.detail),
|
|
52
|
+
reportFooter: prepareBand(definition.reportFooter),
|
|
53
|
+
groups: definition.groups.map((group) => ({
|
|
54
|
+
header: prepareBand(group.header),
|
|
55
|
+
footer: prepareBand(group.footer)
|
|
56
|
+
}))
|
|
57
|
+
};
|
|
58
|
+
for (const expression of this.groupExpressions) this.rejectAggregateDependency(expression, expression, /* @__PURE__ */ new Set());
|
|
59
|
+
}
|
|
60
|
+
rejectAggregateDependency(formula, expression, visiting) {
|
|
61
|
+
if (formula.kind === "aggregate") fail(`a group expression cannot depend on the aggregate rpt:${formula.aggregate}(${formula.reference.name}) -- an aggregate's own rows are defined by the very group boundaries this expression decides`, expression.text);
|
|
62
|
+
const resolved = matchNamed([...this.namedFunctions.values()], (candidate) => candidate.name, formula.reference.name)[0];
|
|
63
|
+
if (resolved === void 0) return;
|
|
64
|
+
if (visiting.has(resolved.name)) fail(`rpt:function "${resolved.name}" refers to itself, directly or through another function`, expression.text);
|
|
65
|
+
this.rejectAggregateDependency(resolved.formula, expression, /* @__PURE__ */ new Set([...visiting, resolved.name]));
|
|
66
|
+
}
|
|
67
|
+
resolveReference(reference, formula) {
|
|
68
|
+
const cached = this.resolutions.get(reference);
|
|
69
|
+
if (cached !== void 0) return cached;
|
|
70
|
+
const functionMatches = matchNamed([...this.namedFunctions.values()], (candidate) => candidate.name, reference.name);
|
|
71
|
+
const columnMatches = matchNamed(this.columnNames, identity, reference.name);
|
|
72
|
+
if (functionMatches.length + columnMatches.length > 1) fail(`reference "${reference.name}" is ambiguous -- it matches ${[...functionMatches.map((match) => `rpt:function ${match.name}`), ...columnMatches.map((match) => `column ${match}`)].join(", ")}`, formula);
|
|
73
|
+
const resolved = this.resolveSingleMatch(reference, functionMatches[0], columnMatches[0], formula);
|
|
74
|
+
this.resolutions.set(reference, resolved);
|
|
75
|
+
return resolved;
|
|
76
|
+
}
|
|
77
|
+
resolveSingleMatch(reference, named, columnName, formula) {
|
|
78
|
+
if (named !== void 0) return {
|
|
79
|
+
kind: "function",
|
|
80
|
+
resolved: named
|
|
81
|
+
};
|
|
82
|
+
if (columnName === void 0) fail(`reference "${reference.name}" names neither a declared rpt:function nor a column of the report's own data -- functions: ${this.namedFunctions.size === 0 ? "(none)" : [...this.namedFunctions.keys()].join(", ")}; columns: ${this.columnNames.length === 0 ? "(none)" : this.columnNames.join(", ")}`, formula);
|
|
83
|
+
return {
|
|
84
|
+
kind: "column",
|
|
85
|
+
index: this.columnNames.indexOf(columnName)
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
valueAt(columnIndex, rowIndex, formula) {
|
|
89
|
+
const value = this.resultSet.rows[rowIndex]?.[columnIndex];
|
|
90
|
+
if (value === void 0) fail(`the report's own data has no value at row ${String(rowIndex)}, column ${String(columnIndex)}`, formula);
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
var RunState = class {
|
|
95
|
+
rowCount;
|
|
96
|
+
openInstances;
|
|
97
|
+
constructor(levels, rowCount) {
|
|
98
|
+
this.rowCount = rowCount;
|
|
99
|
+
this.openInstances = Array.from({ length: levels }, () => void 0);
|
|
100
|
+
}
|
|
101
|
+
open(level, range) {
|
|
102
|
+
this.openInstances[level] = range;
|
|
103
|
+
}
|
|
104
|
+
openAt(level) {
|
|
105
|
+
return this.openInstances[level];
|
|
106
|
+
}
|
|
107
|
+
close(level) {
|
|
108
|
+
this.openInstances[level] = void 0;
|
|
109
|
+
}
|
|
110
|
+
rangeFor(scope, formula) {
|
|
111
|
+
if (scope.kind === "report") return {
|
|
112
|
+
startRow: 0,
|
|
113
|
+
endRowExclusive: this.rowCount
|
|
114
|
+
};
|
|
115
|
+
const open = this.openInstances[scope.level];
|
|
116
|
+
if (open === void 0) fail(`an aggregate scoped to group level ${String(scope.level)} was evaluated while no instance of that group was open`, formula);
|
|
117
|
+
return open;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
function textOf(value, formula, what) {
|
|
121
|
+
if (value.kind === "empty") return;
|
|
122
|
+
const key = cellComparisonKey(value);
|
|
123
|
+
if (key?.valueClass !== "text") fail(`${what} requires a text value, but found a ${value.kind} value -- this engine does not format a number or a boolean into text, since a report's own number format lives in its band styles rather than in the formula`, formula);
|
|
124
|
+
return key.text;
|
|
125
|
+
}
|
|
126
|
+
var FormulaEvaluator = class {
|
|
127
|
+
prepared;
|
|
128
|
+
state;
|
|
129
|
+
constructor(prepared, state) {
|
|
130
|
+
this.prepared = prepared;
|
|
131
|
+
this.state = state;
|
|
132
|
+
}
|
|
133
|
+
evaluate(formula, rowIndex, scope, visiting = /* @__PURE__ */ new Set()) {
|
|
134
|
+
switch (formula.kind) {
|
|
135
|
+
case "field": return this.referenceValue(formula.reference, this.requireRow(rowIndex, formula.text, "a field: reference"), formula.text, visiting);
|
|
136
|
+
case "hasChanged": {
|
|
137
|
+
const rowOfChange = this.requireRow(rowIndex, formula.text, "rpt:HASCHANGED");
|
|
138
|
+
const current = this.referenceValue(formula.reference, rowOfChange, formula.text, visiting);
|
|
139
|
+
if (rowOfChange === 0) return {
|
|
140
|
+
kind: "boolean",
|
|
141
|
+
value: true
|
|
142
|
+
};
|
|
143
|
+
const previous = this.referenceValue(formula.reference, rowOfChange - 1, formula.text, visiting);
|
|
144
|
+
return {
|
|
145
|
+
kind: "boolean",
|
|
146
|
+
value: !cellValuesEqual(current, previous)
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
case "left": {
|
|
150
|
+
const text = textOf(this.referenceValue(formula.reference, this.requireRow(rowIndex, formula.text, "rpt:LEFT"), formula.text, visiting), formula.text, "rpt:LEFT");
|
|
151
|
+
return text === void 0 ? CELL_NULL : {
|
|
152
|
+
kind: "string",
|
|
153
|
+
value: [...text].slice(0, formula.length).join("")
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
case "aggregate": {
|
|
157
|
+
const range = this.state.rangeFor(scope, formula.text);
|
|
158
|
+
const values = [];
|
|
159
|
+
for (let row = range.startRow; row < range.endRowExclusive; row += 1) values.push(this.referenceValue(formula.reference, row, formula.text, visiting));
|
|
160
|
+
return aggregateCellValues(formula.aggregate, values, (message) => new RptFormulaEvaluationError(message, formula.text));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
requireRow(rowIndex, formula, what) {
|
|
165
|
+
if (rowIndex === void 0) fail(`${what} needs a data row, but the band it appears in belongs to no row (the report header and footer print outside the data)`, formula);
|
|
166
|
+
return rowIndex;
|
|
167
|
+
}
|
|
168
|
+
referenceValue(reference, rowIndex, formula, visiting) {
|
|
169
|
+
const resolved = this.prepared.resolveReference(reference, formula);
|
|
170
|
+
if (resolved.kind === "column") return this.prepared.valueAt(resolved.index, rowIndex, formula);
|
|
171
|
+
if (visiting.has(resolved.resolved.name)) fail(`rpt:function "${resolved.resolved.name}" refers to itself, directly or through another function`, formula);
|
|
172
|
+
return this.evaluate(resolved.resolved.formula, rowIndex, resolved.resolved.scope, /* @__PURE__ */ new Set([...visiting, resolved.resolved.name]));
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
function resolveOwnBreak(value, formula) {
|
|
176
|
+
if (value.kind !== "boolean") fail(`a group expression must evaluate to a boolean break test (rpt:HASCHANGED(...)), but this one produced a ${value.kind} value`, formula);
|
|
177
|
+
return value.value;
|
|
178
|
+
}
|
|
179
|
+
var GroupBreaks = class {
|
|
180
|
+
rowCount;
|
|
181
|
+
rows;
|
|
182
|
+
constructor(prepared, evaluator, rowCount) {
|
|
183
|
+
this.rowCount = rowCount;
|
|
184
|
+
const rows = [];
|
|
185
|
+
for (let rowIndex = 0; rowIndex < rowCount; rowIndex += 1) {
|
|
186
|
+
const flags = [];
|
|
187
|
+
let enclosingBroke = false;
|
|
188
|
+
for (const [level, expression] of prepared.groupExpressions.entries()) {
|
|
189
|
+
const ownBreak = resolveOwnBreak(evaluator.evaluate(expression, rowIndex, {
|
|
190
|
+
kind: "group",
|
|
191
|
+
level
|
|
192
|
+
}), expression.text);
|
|
193
|
+
const broke = enclosingBroke || rowIndex === 0 || ownBreak;
|
|
194
|
+
flags.push(broke);
|
|
195
|
+
enclosingBroke = broke;
|
|
196
|
+
}
|
|
197
|
+
rows.push(flags);
|
|
198
|
+
}
|
|
199
|
+
this.rows = rows;
|
|
200
|
+
}
|
|
201
|
+
flagsAt(rowIndex) {
|
|
202
|
+
const flags = this.rows[rowIndex];
|
|
203
|
+
if (flags === void 0) throw new Error(`rpt report run: row ${String(rowIndex)} is outside the ${String(this.rowCount)} rows its group breaks were computed for`);
|
|
204
|
+
return flags;
|
|
205
|
+
}
|
|
206
|
+
outermostBreakAt(rowIndex) {
|
|
207
|
+
return this.flagsAt(rowIndex).indexOf(true);
|
|
208
|
+
}
|
|
209
|
+
breaksAt(rowIndex, level) {
|
|
210
|
+
return this.flagsAt(rowIndex)[level] === true;
|
|
211
|
+
}
|
|
212
|
+
instanceContaining(level, rowIndex) {
|
|
213
|
+
let startRow = rowIndex;
|
|
214
|
+
while (startRow > 0 && !this.breaksAt(startRow, level)) startRow -= 1;
|
|
215
|
+
let endRowExclusive = rowIndex + 1;
|
|
216
|
+
while (endRowExclusive < this.rowCount && !this.breaksAt(endRowExclusive, level)) endRowExclusive += 1;
|
|
217
|
+
return {
|
|
218
|
+
startRow,
|
|
219
|
+
endRowExclusive
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
function detailScope(groupCount) {
|
|
224
|
+
return groupCount === 0 ? { kind: "report" } : {
|
|
225
|
+
kind: "group",
|
|
226
|
+
level: groupCount - 1
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
function runRptReport(definition, resultSet) {
|
|
230
|
+
const rowCount = resultSet.rows.length;
|
|
231
|
+
const levels = definition.groups.length;
|
|
232
|
+
const prepared = new PreparedReport(definition, resultSet);
|
|
233
|
+
const state = new RunState(levels, rowCount);
|
|
234
|
+
const evaluator = new FormulaEvaluator(prepared, state);
|
|
235
|
+
const bands = [];
|
|
236
|
+
const emit = (band, kind, groupLevel, rowIndex, scope) => {
|
|
237
|
+
if (band === void 0) return;
|
|
238
|
+
bands.push({
|
|
239
|
+
kind,
|
|
240
|
+
groupLevel,
|
|
241
|
+
rowIndex,
|
|
242
|
+
values: band.map((formula) => formula === void 0 ? void 0 : evaluator.evaluate(formula, rowIndex, scope))
|
|
243
|
+
});
|
|
244
|
+
};
|
|
245
|
+
emit(prepared.bands.reportHeader, "report-header", void 0, void 0, { kind: "report" });
|
|
246
|
+
const breaks = new GroupBreaks(prepared, evaluator, rowCount);
|
|
247
|
+
const closeFrom = (level) => {
|
|
248
|
+
for (let openLevel = levels - 1; openLevel >= level; openLevel -= 1) {
|
|
249
|
+
const open = state.openAt(openLevel);
|
|
250
|
+
if (open === void 0) continue;
|
|
251
|
+
emit(prepared.bands.groups[openLevel]?.footer, "group-footer", openLevel, open.endRowExclusive - 1, {
|
|
252
|
+
kind: "group",
|
|
253
|
+
level: openLevel
|
|
254
|
+
});
|
|
255
|
+
state.close(openLevel);
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
for (let rowIndex = 0; rowIndex < rowCount; rowIndex += 1) {
|
|
259
|
+
const outermostBroken = breaks.outermostBreakAt(rowIndex);
|
|
260
|
+
if (outermostBroken >= 0) {
|
|
261
|
+
closeFrom(outermostBroken);
|
|
262
|
+
for (let level = outermostBroken; level < levels; level += 1) {
|
|
263
|
+
state.open(level, breaks.instanceContaining(level, rowIndex));
|
|
264
|
+
emit(prepared.bands.groups[level]?.header, "group-header", level, rowIndex, {
|
|
265
|
+
kind: "group",
|
|
266
|
+
level
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
emit(prepared.bands.detail, "detail", void 0, rowIndex, detailScope(levels));
|
|
271
|
+
}
|
|
272
|
+
closeFrom(0);
|
|
273
|
+
emit(prepared.bands.reportFooter, "report-footer", void 0, void 0, { kind: "report" });
|
|
274
|
+
return { bands };
|
|
275
|
+
}
|
|
276
|
+
function evaluateRptBandOutsideData(definition, band, resultSet) {
|
|
277
|
+
const evaluator = new FormulaEvaluator(new PreparedReport(definition, resultSet), new RunState(definition.groups.length, resultSet.rows.length));
|
|
278
|
+
return prepareBandFormulas(band).map((formula) => formula === void 0 ? void 0 : evaluator.evaluate(formula, void 0, { kind: "report" }));
|
|
279
|
+
}
|
|
280
|
+
//#endregion
|
|
281
|
+
export { evaluateRptBandOutsideData, runRptReport };
|