odf.js 1.13.2 → 2.0.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.
Files changed (40) hide show
  1. package/README.md +15 -3
  2. package/dist/index.cjs +8 -0
  3. package/dist/index.d.cts +6 -3
  4. package/dist/index.d.ts +6 -3
  5. package/dist/index.js +6 -3
  6. package/dist/ns.cjs +2 -1
  7. package/dist/ns.d.cts +1 -0
  8. package/dist/ns.d.ts +1 -0
  9. package/dist/ns.js +2 -1
  10. package/dist/typed/draw/shapes.cjs +71 -27
  11. package/dist/typed/draw/shapes.d.cts +4 -1
  12. package/dist/typed/draw/shapes.d.ts +4 -1
  13. package/dist/typed/draw/shapes.js +71 -27
  14. package/dist/typed/formula/read.cjs +14 -0
  15. package/dist/typed/formula/read.d.cts +3 -2
  16. package/dist/typed/formula/read.d.ts +3 -2
  17. package/dist/typed/formula/read.js +14 -1
  18. package/dist/typed/odb/form.cjs +85 -0
  19. package/dist/typed/odb/form.d.cts +31 -0
  20. package/dist/typed/odb/form.d.ts +31 -0
  21. package/dist/typed/odb/form.js +84 -0
  22. package/dist/typed/odb/read.cjs +60 -23
  23. package/dist/typed/odb/read.d.cts +15 -4
  24. package/dist/typed/odb/read.d.ts +15 -4
  25. package/dist/typed/odb/read.js +60 -24
  26. package/dist/typed/odb/report.cjs +161 -0
  27. package/dist/typed/odb/report.d.cts +48 -0
  28. package/dist/typed/odb/report.d.ts +48 -0
  29. package/dist/typed/odb/report.js +160 -0
  30. package/dist/typed/odb/subdocument.cjs +16 -0
  31. package/dist/typed/odb/subdocument.d.cts +8 -0
  32. package/dist/typed/odb/subdocument.d.ts +8 -0
  33. package/dist/typed/odb/subdocument.js +15 -0
  34. package/dist/typed/ods/read.cjs +8 -0
  35. package/dist/typed/ods/read.js +9 -1
  36. package/dist/typed/shared/table.cjs +94 -7
  37. package/dist/typed/shared/table.d.cts +9 -2
  38. package/dist/typed/shared/table.d.ts +9 -2
  39. package/dist/typed/shared/table.js +94 -8
  40. package/package.json +1 -1
@@ -5,13 +5,24 @@ interface OdbConnectionInfo {
5
5
  driverClass?: string;
6
6
  url?: string;
7
7
  }
8
+ interface OdbQueryInfo {
9
+ name: string;
10
+ command: string;
11
+ escapeProcessing?: boolean;
12
+ }
13
+ interface OdbComponentInfo {
14
+ name: string;
15
+ href: string;
16
+ asTemplate?: boolean;
17
+ }
8
18
  interface OdbInventory {
9
19
  connection: OdbConnectionInfo | undefined;
10
20
  tables: string[];
11
- queries: string[];
12
- forms: string[];
13
- reports: string[];
21
+ queries: OdbQueryInfo[];
22
+ forms: OdbComponentInfo[];
23
+ reports: OdbComponentInfo[];
14
24
  }
25
+ declare function resolveOdbComponent(pkg: Package, kind: 'form' | 'report', name: string): OdbComponentInfo;
15
26
  declare function readOdbInventory(pkg: Package): OdbInventory;
16
27
  //#endregion
17
- export { OdbConnectionInfo, OdbInventory, readOdbInventory };
28
+ export { OdbComponentInfo, OdbConnectionInfo, OdbInventory, OdbQueryInfo, readOdbInventory, resolveOdbComponent };
@@ -5,13 +5,24 @@ interface OdbConnectionInfo {
5
5
  driverClass?: string;
6
6
  url?: string;
7
7
  }
8
+ interface OdbQueryInfo {
9
+ name: string;
10
+ command: string;
11
+ escapeProcessing?: boolean;
12
+ }
13
+ interface OdbComponentInfo {
14
+ name: string;
15
+ href: string;
16
+ asTemplate?: boolean;
17
+ }
8
18
  interface OdbInventory {
9
19
  connection: OdbConnectionInfo | undefined;
10
20
  tables: string[];
11
- queries: string[];
12
- forms: string[];
13
- reports: string[];
21
+ queries: OdbQueryInfo[];
22
+ forms: OdbComponentInfo[];
23
+ reports: OdbComponentInfo[];
14
24
  }
25
+ declare function resolveOdbComponent(pkg: Package, kind: 'form' | 'report', name: string): OdbComponentInfo;
15
26
  declare function readOdbInventory(pkg: Package): OdbInventory;
16
27
  //#endregion
17
- export { OdbConnectionInfo, OdbInventory, readOdbInventory };
28
+ export { OdbComponentInfo, OdbConnectionInfo, OdbInventory, OdbQueryInfo, readOdbInventory, resolveOdbComponent };
@@ -1,12 +1,8 @@
1
- import { readManifest } from "../../manifest.js";
1
+ import { decodeXmlText } from "../../xml/entities.js";
2
2
  import { attrValue, childrenWithTag, findChildElement, rootElement } from "../../xml/query.js";
3
3
  //#region src/typed/odb/read.ts
4
4
  const CONTENT_PART = "content.xml";
5
5
  const EMBEDDED_URL_PREFIX = "sdbc:embedded:";
6
- const SUBDOCUMENT_CONTENT_SUFFIX = "/content.xml";
7
- function isXmlMediaType(mediaType) {
8
- return mediaType === "text/xml" || mediaType === "application/xml" || mediaType.endsWith("+xml");
9
- }
10
6
  function formatServerDatabaseUrl(serverDatabase) {
11
7
  const dbType = attrValue(serverDatabase, "db:type");
12
8
  if (dbType === void 0) return;
@@ -50,13 +46,24 @@ function readConnectionInfo(databaseElement) {
50
46
  };
51
47
  }
52
48
  }
53
- function collectQueryNames(container, names) {
49
+ function collectQueryDefinitions(container, definitions) {
54
50
  for (const child of container.children) {
55
51
  if (child.type !== "element") continue;
56
52
  if (child.tag === "db:query") {
57
53
  const name = attrValue(child, "db:name");
58
- if (name !== void 0) names.push(name);
59
- } else if (child.tag === "db:query-collection") collectQueryNames(child, names);
54
+ const command = attrValue(child, "db:command");
55
+ if (name === void 0 || command === void 0) continue;
56
+ const decodedCommand = decodeXmlText(command);
57
+ const escapeProcessingRaw = attrValue(child, "db:escape-processing");
58
+ definitions.push(escapeProcessingRaw === void 0 ? {
59
+ name,
60
+ command: decodedCommand
61
+ } : {
62
+ name,
63
+ command: decodedCommand,
64
+ escapeProcessing: escapeProcessingRaw === "true"
65
+ });
66
+ } else if (child.tag === "db:query-collection") collectQueryDefinitions(child, definitions);
60
67
  }
61
68
  }
62
69
  function collectTableNames(databaseElement) {
@@ -75,16 +82,47 @@ function collectTableNames(databaseElement) {
75
82
  if (tableDefinitions !== void 0) for (const definition of childrenWithTag(tableDefinitions, "db:table-definition")) pushName(attrValue(definition, "db:name"));
76
83
  return names;
77
84
  }
78
- function subdocumentNamesUnderPrefix(entries, prefix) {
79
- const names = [];
80
- for (const entry of entries) {
81
- if (!entry.fullPath.startsWith(prefix) || !entry.fullPath.endsWith(SUBDOCUMENT_CONTENT_SUFFIX) || !isXmlMediaType(entry.mediaType)) continue;
82
- const withoutSuffix = entry.fullPath.slice(0, entry.fullPath.length - 12);
83
- const lastSlash = withoutSuffix.lastIndexOf("/");
84
- const name = lastSlash === -1 ? withoutSuffix.slice(prefix.length) : withoutSuffix.slice(lastSlash + 1);
85
- if (name.length > 0) names.push(name);
85
+ function collectComponents(container, components) {
86
+ for (const child of container.children) {
87
+ if (child.type !== "element") continue;
88
+ if (child.tag === "db:component-collection") {
89
+ collectComponents(child, components);
90
+ continue;
91
+ }
92
+ if (child.tag !== "db:component") continue;
93
+ const name = attrValue(child, "db:name");
94
+ const rawHref = attrValue(child, "xlink:href");
95
+ if (name === void 0 || rawHref === void 0) continue;
96
+ const decodedHref = decodeXmlText(rawHref);
97
+ const href = decodedHref.endsWith("/") ? decodedHref.slice(0, -1) : decodedHref;
98
+ if (href.length === 0) continue;
99
+ const asTemplateRaw = attrValue(child, "db:as-template");
100
+ components.push(asTemplateRaw === void 0 ? {
101
+ name: decodeXmlText(name),
102
+ href
103
+ } : {
104
+ name: decodeXmlText(name),
105
+ href,
106
+ asTemplate: asTemplateRaw === "true"
107
+ });
86
108
  }
87
- return names;
109
+ }
110
+ function readComponents(databaseElement, tag) {
111
+ const container = findChildElement(databaseElement.children, tag);
112
+ if (container === void 0) return [];
113
+ const components = [];
114
+ collectComponents(container, components);
115
+ return components;
116
+ }
117
+ function resolveOdbComponent(pkg, kind, name) {
118
+ const inventory = readOdbInventory(pkg);
119
+ const components = kind === "form" ? inventory.forms : inventory.reports;
120
+ const match = components.find((component) => component.name === name);
121
+ if (match === void 0) {
122
+ const available = components.map((component) => component.name).join(", ");
123
+ throw new Error(`resolveOdbComponent: no ${kind} named "${name}" -- available: ${available === "" ? "(none)" : available}`);
124
+ }
125
+ return match;
88
126
  }
89
127
  function readOdbInventory(pkg) {
90
128
  const contentPart = pkg.parts[CONTENT_PART];
@@ -96,16 +134,14 @@ function readOdbInventory(pkg) {
96
134
  const connection = readConnectionInfo(databaseElement);
97
135
  const queries = [];
98
136
  const queriesElement = findChildElement(databaseElement.children, "db:queries");
99
- if (queriesElement !== void 0) collectQueryNames(queriesElement, queries);
100
- const tables = collectTableNames(databaseElement);
101
- const manifest = readManifest(pkg);
137
+ if (queriesElement !== void 0) collectQueryDefinitions(queriesElement, queries);
102
138
  return {
103
139
  connection,
104
- tables,
140
+ tables: collectTableNames(databaseElement),
105
141
  queries,
106
- forms: subdocumentNamesUnderPrefix(manifest.entries, "forms/"),
107
- reports: subdocumentNamesUnderPrefix(manifest.entries, "reports/")
142
+ forms: readComponents(databaseElement, "db:forms"),
143
+ reports: readComponents(databaseElement, "db:reports")
108
144
  };
109
145
  }
110
146
  //#endregion
111
- export { readOdbInventory };
147
+ export { readOdbInventory, resolveOdbComponent };
@@ -0,0 +1,161 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_xml_entities = require("../../xml/entities.cjs");
3
+ const require_xml_query = require("../../xml/query.cjs");
4
+ const require_typed_odb_read = require("./read.cjs");
5
+ const require_typed_odb_subdocument = require("./subdocument.cjs");
6
+ //#region src/typed/odb/report.ts
7
+ const CONTENT_PART = "content.xml";
8
+ const GROUP_TAG = "rpt:group";
9
+ const FUNCTION_TAG = "rpt:function";
10
+ const REPORT_ELEMENT_TAG = "rpt:report-element";
11
+ const REPORT_COMPONENT_TAG = "rpt:report-component";
12
+ const RPT_TAG_PREFIX = "rpt:";
13
+ const FIELD_FORMULA_PREFIX = "field:[";
14
+ const FIELD_FORMULA_SUFFIX = "]";
15
+ function reportAttr(element, name) {
16
+ const raw = require_xml_query.attrValue(element, name);
17
+ return raw === void 0 ? void 0 : require_xml_entities.decodeXmlText(raw);
18
+ }
19
+ function parseOptionalBoolean(raw) {
20
+ return raw === void 0 ? void 0 : raw === "true";
21
+ }
22
+ function boundFieldName(formula) {
23
+ if (formula === void 0 || !formula.startsWith(FIELD_FORMULA_PREFIX) || !formula.endsWith(FIELD_FORMULA_SUFFIX)) return;
24
+ const inner = formula.slice(7, formula.length - 1);
25
+ return inner.length === 0 ? void 0 : inner;
26
+ }
27
+ function elementText(element) {
28
+ let text = "";
29
+ for (const child of element.children) if (child.type === "text") text += require_xml_entities.decodeXmlText(child.value);
30
+ else if (child.type === "element") text += elementText(child);
31
+ return text;
32
+ }
33
+ function reportElementChild(element) {
34
+ return require_xml_query.findChildElement(element.children, REPORT_ELEMENT_TAG);
35
+ }
36
+ function readReportElement(element, reportElement) {
37
+ const control = { tag: element.tag };
38
+ const component = require_xml_query.findChildElement(reportElement.children, REPORT_COMPONENT_TAG);
39
+ const name = component === void 0 ? void 0 : reportAttr(component, "draw:name");
40
+ if (name !== void 0) control.name = name;
41
+ const formula = reportAttr(element, "rpt:formula");
42
+ if (formula !== void 0) control.formula = formula;
43
+ let text = "";
44
+ for (const child of element.children) if (child.type === "text") text += require_xml_entities.decodeXmlText(child.value);
45
+ else if (child.type === "element" && !child.tag.startsWith(RPT_TAG_PREFIX)) text += elementText(child);
46
+ if (text.length > 0) control.text = text;
47
+ const dataField = boundFieldName(formula);
48
+ if (dataField !== void 0) control.dataField = dataField;
49
+ return control;
50
+ }
51
+ function collectControls(nodes, controls) {
52
+ for (const node of nodes) {
53
+ if (node.type !== "element") continue;
54
+ if (node.tag.startsWith(RPT_TAG_PREFIX)) {
55
+ const reportElement = reportElementChild(node);
56
+ if (reportElement !== void 0) {
57
+ controls.push(readReportElement(node, reportElement));
58
+ continue;
59
+ }
60
+ }
61
+ collectControls(node.children, controls);
62
+ }
63
+ }
64
+ function readBand(element, kind) {
65
+ const elements = [];
66
+ collectControls(element.children, elements);
67
+ const band = {
68
+ kind,
69
+ elements
70
+ };
71
+ const table = require_xml_query.findChildElement(element.children, "table:table");
72
+ const name = table === void 0 ? void 0 : reportAttr(table, "table:name");
73
+ if (name !== void 0) band.name = name;
74
+ return band;
75
+ }
76
+ function readBandIfPresent(container, tag, kind) {
77
+ const element = require_xml_query.findChildElement(container.children, tag);
78
+ return element === void 0 ? void 0 : readBand(element, kind);
79
+ }
80
+ function readFunctions(container) {
81
+ const functions = [];
82
+ for (const child of container.children) {
83
+ if (child.type !== "element" || child.tag !== FUNCTION_TAG) continue;
84
+ const name = reportAttr(child, "rpt:name");
85
+ const formula = reportAttr(child, "rpt:formula");
86
+ if (name === void 0 || formula === void 0) continue;
87
+ functions.push({
88
+ name,
89
+ formula
90
+ });
91
+ }
92
+ return functions;
93
+ }
94
+ function readGroup(element) {
95
+ const group = {
96
+ functions: readFunctions(element),
97
+ groups: []
98
+ };
99
+ const groupExpression = reportAttr(element, "rpt:group-expression");
100
+ if (groupExpression !== void 0) group.groupExpression = groupExpression;
101
+ const sortExpression = reportAttr(element, "rpt:sort-expression");
102
+ if (sortExpression !== void 0) group.sortExpression = sortExpression;
103
+ const sortAscending = parseOptionalBoolean(require_xml_query.attrValue(element, "rpt:sort-ascending"));
104
+ if (sortAscending !== void 0) group.sortAscending = sortAscending;
105
+ const startNewColumn = parseOptionalBoolean(require_xml_query.attrValue(element, "rpt:start-new-column"));
106
+ if (startNewColumn !== void 0) group.startNewColumn = startNewColumn;
107
+ const resetPageNumber = parseOptionalBoolean(require_xml_query.attrValue(element, "rpt:reset-page-number"));
108
+ if (resetPageNumber !== void 0) group.resetPageNumber = resetPageNumber;
109
+ const keepTogether = reportAttr(element, "rpt:keep-together");
110
+ if (keepTogether !== void 0) group.keepTogether = keepTogether;
111
+ const header = readBandIfPresent(element, "rpt:group-header", "group-header");
112
+ if (header !== void 0) group.header = header;
113
+ const footer = readBandIfPresent(element, "rpt:group-footer", "group-footer");
114
+ if (footer !== void 0) group.footer = footer;
115
+ for (const child of element.children) if (child.type === "element" && child.tag === GROUP_TAG) group.groups.push(readGroup(child));
116
+ return group;
117
+ }
118
+ function findDetail(container) {
119
+ const detail = require_xml_query.findChildElement(container.children, "rpt:detail");
120
+ if (detail !== void 0) return readBand(detail, "detail");
121
+ const group = require_xml_query.findChildElement(container.children, GROUP_TAG);
122
+ return group === void 0 ? void 0 : findDetail(group);
123
+ }
124
+ function readOdbReport(pkg, reportName) {
125
+ const component = require_typed_odb_read.resolveOdbComponent(pkg, "report", reportName);
126
+ const contentPart = require_typed_odb_subdocument.subDocumentPackage(pkg, component.href).parts[CONTENT_PART];
127
+ if (contentPart?.kind !== "xml") throw new Error(`readOdbReport: report "${reportName}" sub-document ${component.href}/${CONTENT_PART} is not an XML part`);
128
+ const contentRoot = require_xml_query.rootElement(contentPart.nodes);
129
+ const body = contentRoot === void 0 ? void 0 : require_xml_query.findChildElement(contentRoot.children, "office:body");
130
+ const reportElement = body === void 0 ? void 0 : require_xml_query.findChildElement(body.children, "office:report");
131
+ if (reportElement === void 0) throw new Error(`readOdbReport: report "${reportName}" sub-document ${component.href}/${CONTENT_PART} has no office:body/office:report element`);
132
+ const groups = [];
133
+ for (const child of reportElement.children) if (child.type === "element" && child.tag === GROUP_TAG) groups.push(readGroup(child));
134
+ const report = {
135
+ name: component.name,
136
+ href: component.href,
137
+ groups,
138
+ functions: readFunctions(reportElement)
139
+ };
140
+ const command = reportAttr(reportElement, "rpt:command");
141
+ if (command !== void 0) report.command = command;
142
+ const commandType = reportAttr(reportElement, "rpt:command-type");
143
+ if (commandType !== void 0) report.commandType = commandType;
144
+ const caption = reportAttr(reportElement, "office:caption");
145
+ if (caption !== void 0) report.caption = caption;
146
+ const mimeType = reportAttr(reportElement, "office:mimetype");
147
+ if (mimeType !== void 0) report.mimeType = mimeType;
148
+ const reportHeader = readBandIfPresent(reportElement, "rpt:report-header", "report-header");
149
+ if (reportHeader !== void 0) report.reportHeader = reportHeader;
150
+ const pageHeader = readBandIfPresent(reportElement, "rpt:page-header", "page-header");
151
+ if (pageHeader !== void 0) report.pageHeader = pageHeader;
152
+ const detail = findDetail(reportElement);
153
+ if (detail !== void 0) report.detail = detail;
154
+ const pageFooter = readBandIfPresent(reportElement, "rpt:page-footer", "page-footer");
155
+ if (pageFooter !== void 0) report.pageFooter = pageFooter;
156
+ const reportFooter = readBandIfPresent(reportElement, "rpt:report-footer", "report-footer");
157
+ if (reportFooter !== void 0) report.reportFooter = reportFooter;
158
+ return report;
159
+ }
160
+ //#endregion
161
+ exports.readOdbReport = readOdbReport;
@@ -0,0 +1,48 @@
1
+ import { Package } from "../../model/package.cjs";
2
+ //#region src/typed/odb/report.d.ts
3
+ interface OdbReportElement {
4
+ tag: string;
5
+ name?: string;
6
+ text?: string;
7
+ formula?: string;
8
+ dataField?: string;
9
+ }
10
+ interface OdbReportBand {
11
+ kind: 'report-header' | 'page-header' | 'group-header' | 'detail' | 'group-footer' | 'page-footer' | 'report-footer';
12
+ name?: string;
13
+ elements: OdbReportElement[];
14
+ }
15
+ interface OdbReportFunction {
16
+ name: string;
17
+ formula: string;
18
+ }
19
+ interface OdbReportGroup {
20
+ groupExpression?: string;
21
+ sortExpression?: string;
22
+ sortAscending?: boolean;
23
+ startNewColumn?: boolean;
24
+ resetPageNumber?: boolean;
25
+ keepTogether?: string;
26
+ header?: OdbReportBand;
27
+ footer?: OdbReportBand;
28
+ functions: OdbReportFunction[];
29
+ groups: OdbReportGroup[];
30
+ }
31
+ interface OdbReport {
32
+ name: string;
33
+ href: string;
34
+ command?: string;
35
+ commandType?: string;
36
+ caption?: string;
37
+ mimeType?: string;
38
+ reportHeader?: OdbReportBand;
39
+ pageHeader?: OdbReportBand;
40
+ groups: OdbReportGroup[];
41
+ detail?: OdbReportBand;
42
+ pageFooter?: OdbReportBand;
43
+ reportFooter?: OdbReportBand;
44
+ functions: OdbReportFunction[];
45
+ }
46
+ declare function readOdbReport(pkg: Package, reportName: string): OdbReport;
47
+ //#endregion
48
+ export { OdbReport, OdbReportBand, OdbReportElement, OdbReportFunction, OdbReportGroup, readOdbReport };
@@ -0,0 +1,48 @@
1
+ import { Package } from "../../model/package.js";
2
+ //#region src/typed/odb/report.d.ts
3
+ interface OdbReportElement {
4
+ tag: string;
5
+ name?: string;
6
+ text?: string;
7
+ formula?: string;
8
+ dataField?: string;
9
+ }
10
+ interface OdbReportBand {
11
+ kind: 'report-header' | 'page-header' | 'group-header' | 'detail' | 'group-footer' | 'page-footer' | 'report-footer';
12
+ name?: string;
13
+ elements: OdbReportElement[];
14
+ }
15
+ interface OdbReportFunction {
16
+ name: string;
17
+ formula: string;
18
+ }
19
+ interface OdbReportGroup {
20
+ groupExpression?: string;
21
+ sortExpression?: string;
22
+ sortAscending?: boolean;
23
+ startNewColumn?: boolean;
24
+ resetPageNumber?: boolean;
25
+ keepTogether?: string;
26
+ header?: OdbReportBand;
27
+ footer?: OdbReportBand;
28
+ functions: OdbReportFunction[];
29
+ groups: OdbReportGroup[];
30
+ }
31
+ interface OdbReport {
32
+ name: string;
33
+ href: string;
34
+ command?: string;
35
+ commandType?: string;
36
+ caption?: string;
37
+ mimeType?: string;
38
+ reportHeader?: OdbReportBand;
39
+ pageHeader?: OdbReportBand;
40
+ groups: OdbReportGroup[];
41
+ detail?: OdbReportBand;
42
+ pageFooter?: OdbReportBand;
43
+ reportFooter?: OdbReportBand;
44
+ functions: OdbReportFunction[];
45
+ }
46
+ declare function readOdbReport(pkg: Package, reportName: string): OdbReport;
47
+ //#endregion
48
+ export { OdbReport, OdbReportBand, OdbReportElement, OdbReportFunction, OdbReportGroup, readOdbReport };
@@ -0,0 +1,160 @@
1
+ import { decodeXmlText } from "../../xml/entities.js";
2
+ import { attrValue, findChildElement, rootElement } from "../../xml/query.js";
3
+ import { resolveOdbComponent } from "./read.js";
4
+ import { subDocumentPackage } from "./subdocument.js";
5
+ //#region src/typed/odb/report.ts
6
+ const CONTENT_PART = "content.xml";
7
+ const GROUP_TAG = "rpt:group";
8
+ const FUNCTION_TAG = "rpt:function";
9
+ const REPORT_ELEMENT_TAG = "rpt:report-element";
10
+ const REPORT_COMPONENT_TAG = "rpt:report-component";
11
+ const RPT_TAG_PREFIX = "rpt:";
12
+ const FIELD_FORMULA_PREFIX = "field:[";
13
+ const FIELD_FORMULA_SUFFIX = "]";
14
+ function reportAttr(element, name) {
15
+ const raw = attrValue(element, name);
16
+ return raw === void 0 ? void 0 : decodeXmlText(raw);
17
+ }
18
+ function parseOptionalBoolean(raw) {
19
+ return raw === void 0 ? void 0 : raw === "true";
20
+ }
21
+ function boundFieldName(formula) {
22
+ if (formula === void 0 || !formula.startsWith(FIELD_FORMULA_PREFIX) || !formula.endsWith(FIELD_FORMULA_SUFFIX)) return;
23
+ const inner = formula.slice(7, formula.length - 1);
24
+ return inner.length === 0 ? void 0 : inner;
25
+ }
26
+ function elementText(element) {
27
+ let text = "";
28
+ for (const child of element.children) if (child.type === "text") text += decodeXmlText(child.value);
29
+ else if (child.type === "element") text += elementText(child);
30
+ return text;
31
+ }
32
+ function reportElementChild(element) {
33
+ return findChildElement(element.children, REPORT_ELEMENT_TAG);
34
+ }
35
+ function readReportElement(element, reportElement) {
36
+ const control = { tag: element.tag };
37
+ const component = findChildElement(reportElement.children, REPORT_COMPONENT_TAG);
38
+ const name = component === void 0 ? void 0 : reportAttr(component, "draw:name");
39
+ if (name !== void 0) control.name = name;
40
+ const formula = reportAttr(element, "rpt:formula");
41
+ if (formula !== void 0) control.formula = formula;
42
+ let text = "";
43
+ for (const child of element.children) if (child.type === "text") text += decodeXmlText(child.value);
44
+ else if (child.type === "element" && !child.tag.startsWith(RPT_TAG_PREFIX)) text += elementText(child);
45
+ if (text.length > 0) control.text = text;
46
+ const dataField = boundFieldName(formula);
47
+ if (dataField !== void 0) control.dataField = dataField;
48
+ return control;
49
+ }
50
+ function collectControls(nodes, controls) {
51
+ for (const node of nodes) {
52
+ if (node.type !== "element") continue;
53
+ if (node.tag.startsWith(RPT_TAG_PREFIX)) {
54
+ const reportElement = reportElementChild(node);
55
+ if (reportElement !== void 0) {
56
+ controls.push(readReportElement(node, reportElement));
57
+ continue;
58
+ }
59
+ }
60
+ collectControls(node.children, controls);
61
+ }
62
+ }
63
+ function readBand(element, kind) {
64
+ const elements = [];
65
+ collectControls(element.children, elements);
66
+ const band = {
67
+ kind,
68
+ elements
69
+ };
70
+ const table = findChildElement(element.children, "table:table");
71
+ const name = table === void 0 ? void 0 : reportAttr(table, "table:name");
72
+ if (name !== void 0) band.name = name;
73
+ return band;
74
+ }
75
+ function readBandIfPresent(container, tag, kind) {
76
+ const element = findChildElement(container.children, tag);
77
+ return element === void 0 ? void 0 : readBand(element, kind);
78
+ }
79
+ function readFunctions(container) {
80
+ const functions = [];
81
+ for (const child of container.children) {
82
+ if (child.type !== "element" || child.tag !== FUNCTION_TAG) continue;
83
+ const name = reportAttr(child, "rpt:name");
84
+ const formula = reportAttr(child, "rpt:formula");
85
+ if (name === void 0 || formula === void 0) continue;
86
+ functions.push({
87
+ name,
88
+ formula
89
+ });
90
+ }
91
+ return functions;
92
+ }
93
+ function readGroup(element) {
94
+ const group = {
95
+ functions: readFunctions(element),
96
+ groups: []
97
+ };
98
+ const groupExpression = reportAttr(element, "rpt:group-expression");
99
+ if (groupExpression !== void 0) group.groupExpression = groupExpression;
100
+ const sortExpression = reportAttr(element, "rpt:sort-expression");
101
+ if (sortExpression !== void 0) group.sortExpression = sortExpression;
102
+ const sortAscending = parseOptionalBoolean(attrValue(element, "rpt:sort-ascending"));
103
+ if (sortAscending !== void 0) group.sortAscending = sortAscending;
104
+ const startNewColumn = parseOptionalBoolean(attrValue(element, "rpt:start-new-column"));
105
+ if (startNewColumn !== void 0) group.startNewColumn = startNewColumn;
106
+ const resetPageNumber = parseOptionalBoolean(attrValue(element, "rpt:reset-page-number"));
107
+ if (resetPageNumber !== void 0) group.resetPageNumber = resetPageNumber;
108
+ const keepTogether = reportAttr(element, "rpt:keep-together");
109
+ if (keepTogether !== void 0) group.keepTogether = keepTogether;
110
+ const header = readBandIfPresent(element, "rpt:group-header", "group-header");
111
+ if (header !== void 0) group.header = header;
112
+ const footer = readBandIfPresent(element, "rpt:group-footer", "group-footer");
113
+ if (footer !== void 0) group.footer = footer;
114
+ for (const child of element.children) if (child.type === "element" && child.tag === GROUP_TAG) group.groups.push(readGroup(child));
115
+ return group;
116
+ }
117
+ function findDetail(container) {
118
+ const detail = findChildElement(container.children, "rpt:detail");
119
+ if (detail !== void 0) return readBand(detail, "detail");
120
+ const group = findChildElement(container.children, GROUP_TAG);
121
+ return group === void 0 ? void 0 : findDetail(group);
122
+ }
123
+ function readOdbReport(pkg, reportName) {
124
+ const component = resolveOdbComponent(pkg, "report", reportName);
125
+ const contentPart = subDocumentPackage(pkg, component.href).parts[CONTENT_PART];
126
+ if (contentPart?.kind !== "xml") throw new Error(`readOdbReport: report "${reportName}" sub-document ${component.href}/${CONTENT_PART} is not an XML part`);
127
+ const contentRoot = rootElement(contentPart.nodes);
128
+ const body = contentRoot === void 0 ? void 0 : findChildElement(contentRoot.children, "office:body");
129
+ const reportElement = body === void 0 ? void 0 : findChildElement(body.children, "office:report");
130
+ if (reportElement === void 0) throw new Error(`readOdbReport: report "${reportName}" sub-document ${component.href}/${CONTENT_PART} has no office:body/office:report element`);
131
+ const groups = [];
132
+ for (const child of reportElement.children) if (child.type === "element" && child.tag === GROUP_TAG) groups.push(readGroup(child));
133
+ const report = {
134
+ name: component.name,
135
+ href: component.href,
136
+ groups,
137
+ functions: readFunctions(reportElement)
138
+ };
139
+ const command = reportAttr(reportElement, "rpt:command");
140
+ if (command !== void 0) report.command = command;
141
+ const commandType = reportAttr(reportElement, "rpt:command-type");
142
+ if (commandType !== void 0) report.commandType = commandType;
143
+ const caption = reportAttr(reportElement, "office:caption");
144
+ if (caption !== void 0) report.caption = caption;
145
+ const mimeType = reportAttr(reportElement, "office:mimetype");
146
+ if (mimeType !== void 0) report.mimeType = mimeType;
147
+ const reportHeader = readBandIfPresent(reportElement, "rpt:report-header", "report-header");
148
+ if (reportHeader !== void 0) report.reportHeader = reportHeader;
149
+ const pageHeader = readBandIfPresent(reportElement, "rpt:page-header", "page-header");
150
+ if (pageHeader !== void 0) report.pageHeader = pageHeader;
151
+ const detail = findDetail(reportElement);
152
+ if (detail !== void 0) report.detail = detail;
153
+ const pageFooter = readBandIfPresent(reportElement, "rpt:page-footer", "page-footer");
154
+ if (pageFooter !== void 0) report.pageFooter = pageFooter;
155
+ const reportFooter = readBandIfPresent(reportElement, "rpt:report-footer", "report-footer");
156
+ if (reportFooter !== void 0) report.reportFooter = reportFooter;
157
+ return report;
158
+ }
159
+ //#endregion
160
+ export { readOdbReport };
@@ -0,0 +1,16 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/typed/odb/subdocument.ts
3
+ const CONTENT_PART = "content.xml";
4
+ function subDocumentPackage(pkg, prefix, options = {}) {
5
+ const normalised = prefix.endsWith("/") ? prefix : `${prefix}/`;
6
+ const parts = {};
7
+ for (const [path, part] of Object.entries(pkg.parts)) {
8
+ if (!path.startsWith(normalised)) continue;
9
+ const relative = path.slice(normalised.length);
10
+ if (relative.length > 0) parts[relative] = part;
11
+ }
12
+ if (options.allowMissingContent !== true && parts[CONTENT_PART] === void 0) throw new Error(`subDocumentPackage: package has no ${normalised}${CONTENT_PART} part`);
13
+ return { parts };
14
+ }
15
+ //#endregion
16
+ exports.subDocumentPackage = subDocumentPackage;
@@ -0,0 +1,8 @@
1
+ import { Package } from "../../model/package.cjs";
2
+ //#region src/typed/odb/subdocument.d.ts
3
+ interface SubDocumentPackageOptions {
4
+ allowMissingContent?: boolean;
5
+ }
6
+ declare function subDocumentPackage(pkg: Package, prefix: string, options?: SubDocumentPackageOptions): Package;
7
+ //#endregion
8
+ export { SubDocumentPackageOptions, subDocumentPackage };
@@ -0,0 +1,8 @@
1
+ import { Package } from "../../model/package.js";
2
+ //#region src/typed/odb/subdocument.d.ts
3
+ interface SubDocumentPackageOptions {
4
+ allowMissingContent?: boolean;
5
+ }
6
+ declare function subDocumentPackage(pkg: Package, prefix: string, options?: SubDocumentPackageOptions): Package;
7
+ //#endregion
8
+ export { SubDocumentPackageOptions, subDocumentPackage };
@@ -0,0 +1,15 @@
1
+ //#region src/typed/odb/subdocument.ts
2
+ const CONTENT_PART = "content.xml";
3
+ function subDocumentPackage(pkg, prefix, options = {}) {
4
+ const normalised = prefix.endsWith("/") ? prefix : `${prefix}/`;
5
+ const parts = {};
6
+ for (const [path, part] of Object.entries(pkg.parts)) {
7
+ if (!path.startsWith(normalised)) continue;
8
+ const relative = path.slice(normalised.length);
9
+ if (relative.length > 0) parts[relative] = part;
10
+ }
11
+ if (options.allowMissingContent !== true && parts[CONTENT_PART] === void 0) throw new Error(`subDocumentPackage: package has no ${normalised}${CONTENT_PART} part`);
12
+ return { parts };
13
+ }
14
+ //#endregion
15
+ export { subDocumentPackage };