odf.js 1.13.2 → 2.1.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 (44) hide show
  1. package/README.md +19 -4
  2. package/dist/index.cjs +10 -0
  3. package/dist/index.d.cts +7 -3
  4. package/dist/index.d.ts +7 -3
  5. package/dist/index.js +7 -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/embedded.cjs +42 -0
  11. package/dist/typed/draw/embedded.d.cts +13 -0
  12. package/dist/typed/draw/embedded.d.ts +13 -0
  13. package/dist/typed/draw/embedded.js +41 -0
  14. package/dist/typed/draw/shapes.cjs +86 -30
  15. package/dist/typed/draw/shapes.d.cts +4 -1
  16. package/dist/typed/draw/shapes.d.ts +4 -1
  17. package/dist/typed/draw/shapes.js +86 -30
  18. package/dist/typed/formula/read.cjs +14 -0
  19. package/dist/typed/formula/read.d.cts +3 -2
  20. package/dist/typed/formula/read.d.ts +3 -2
  21. package/dist/typed/formula/read.js +14 -1
  22. package/dist/typed/odb/form.cjs +85 -0
  23. package/dist/typed/odb/form.d.cts +31 -0
  24. package/dist/typed/odb/form.d.ts +31 -0
  25. package/dist/typed/odb/form.js +84 -0
  26. package/dist/typed/odb/read.cjs +60 -23
  27. package/dist/typed/odb/read.d.cts +15 -4
  28. package/dist/typed/odb/read.d.ts +15 -4
  29. package/dist/typed/odb/read.js +60 -24
  30. package/dist/typed/odb/report.cjs +161 -0
  31. package/dist/typed/odb/report.d.cts +48 -0
  32. package/dist/typed/odb/report.d.ts +48 -0
  33. package/dist/typed/odb/report.js +160 -0
  34. package/dist/typed/odb/subdocument.cjs +16 -0
  35. package/dist/typed/odb/subdocument.d.cts +8 -0
  36. package/dist/typed/odb/subdocument.d.ts +8 -0
  37. package/dist/typed/odb/subdocument.js +15 -0
  38. package/dist/typed/ods/read.cjs +98 -4
  39. package/dist/typed/ods/read.js +100 -6
  40. package/dist/typed/shared/table.cjs +94 -7
  41. package/dist/typed/shared/table.d.cts +9 -2
  42. package/dist/typed/shared/table.d.ts +9 -2
  43. package/dist/typed/shared/table.js +94 -8
  44. package/package.json +1 -1
@@ -0,0 +1,85 @@
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_subdocument = require("./subdocument.cjs");
5
+ const require_typed_odt_read = require("../odt/read.cjs");
6
+ const require_typed_odb_read = require("./read.cjs");
7
+ //#region src/typed/odb/form.ts
8
+ const CONTENT_PART = "content.xml";
9
+ const FORM_ELEMENT_TAG = "form:form";
10
+ const FORM_PROPERTIES_TAG = "form:properties";
11
+ const FORM_TAG_PREFIX = "form:";
12
+ function formAttr(element, name) {
13
+ const raw = require_xml_query.attrValue(element, name);
14
+ return raw === void 0 ? void 0 : require_xml_entities.decodeXmlText(raw);
15
+ }
16
+ function readControl(element) {
17
+ const control = {
18
+ tag: element.tag,
19
+ controls: readControls(element)
20
+ };
21
+ const name = formAttr(element, "form:name");
22
+ if (name !== void 0) control.name = name;
23
+ const controlImplementation = formAttr(element, "form:control-implementation");
24
+ if (controlImplementation !== void 0) control.controlImplementation = controlImplementation;
25
+ const dataField = formAttr(element, "form:data-field");
26
+ if (dataField !== void 0) control.dataField = dataField;
27
+ const id = formAttr(element, "form:id");
28
+ if (id !== void 0) control.id = id;
29
+ const label = formAttr(element, "form:label");
30
+ if (label !== void 0) control.label = label;
31
+ return control;
32
+ }
33
+ function readControls(container) {
34
+ const controls = [];
35
+ for (const child of container.children) {
36
+ if (child.type !== "element" || !child.tag.startsWith(FORM_TAG_PREFIX)) continue;
37
+ if (child.tag === FORM_ELEMENT_TAG || child.tag === FORM_PROPERTIES_TAG) continue;
38
+ controls.push(readControl(child));
39
+ }
40
+ return controls;
41
+ }
42
+ function readFormDefinition(element) {
43
+ const subForms = [];
44
+ for (const child of element.children) if (child.type === "element" && child.tag === FORM_ELEMENT_TAG) subForms.push(readFormDefinition(child));
45
+ const definition = {
46
+ controls: readControls(element),
47
+ subForms
48
+ };
49
+ const name = formAttr(element, "form:name");
50
+ if (name !== void 0) definition.name = name;
51
+ const command = formAttr(element, "form:command");
52
+ if (command !== void 0) definition.command = command;
53
+ const commandType = formAttr(element, "form:command-type");
54
+ if (commandType !== void 0) definition.commandType = commandType;
55
+ const datasource = formAttr(element, "form:datasource");
56
+ if (datasource !== void 0) definition.datasource = datasource;
57
+ const filter = formAttr(element, "form:filter");
58
+ if (filter !== void 0) definition.filter = filter;
59
+ const order = formAttr(element, "form:order");
60
+ if (order !== void 0) definition.order = order;
61
+ return definition;
62
+ }
63
+ function readFormDefinitions(contentRoot) {
64
+ const body = contentRoot === void 0 ? void 0 : require_xml_query.findChildElement(contentRoot.children, "office:body");
65
+ const text = body === void 0 ? void 0 : require_xml_query.findChildElement(body.children, "office:text");
66
+ const forms = text === void 0 ? void 0 : require_xml_query.findChildElement(text.children, "office:forms");
67
+ if (forms === void 0) return [];
68
+ const definitions = [];
69
+ for (const child of forms.children) if (child.type === "element" && child.tag === FORM_ELEMENT_TAG) definitions.push(readFormDefinition(child));
70
+ return definitions;
71
+ }
72
+ function readOdbForm(pkg, formName) {
73
+ const component = require_typed_odb_read.resolveOdbComponent(pkg, "form", formName);
74
+ const subPackage = require_typed_odb_subdocument.subDocumentPackage(pkg, component.href);
75
+ const contentPart = subPackage.parts[CONTENT_PART];
76
+ if (contentPart?.kind !== "xml") throw new Error(`readOdbForm: form "${formName}" sub-document ${component.href}/${CONTENT_PART} is not an XML part`);
77
+ return {
78
+ name: component.name,
79
+ href: component.href,
80
+ document: require_typed_odt_read.readOdt(subPackage),
81
+ forms: readFormDefinitions(require_xml_query.rootElement(contentPart.nodes))
82
+ };
83
+ }
84
+ //#endregion
85
+ exports.readOdbForm = readOdbForm;
@@ -0,0 +1,31 @@
1
+ import { Package } from "../../model/package.cjs";
2
+ import { OdtDocument } from "../odt/read.cjs";
3
+ //#region src/typed/odb/form.d.ts
4
+ interface OdbFormControl {
5
+ tag: string;
6
+ name?: string;
7
+ controlImplementation?: string;
8
+ dataField?: string;
9
+ id?: string;
10
+ label?: string;
11
+ controls: OdbFormControl[];
12
+ }
13
+ interface OdbFormDefinition {
14
+ name?: string;
15
+ command?: string;
16
+ commandType?: string;
17
+ datasource?: string;
18
+ filter?: string;
19
+ order?: string;
20
+ controls: OdbFormControl[];
21
+ subForms: OdbFormDefinition[];
22
+ }
23
+ interface OdbForm {
24
+ name: string;
25
+ href: string;
26
+ document: OdtDocument;
27
+ forms: OdbFormDefinition[];
28
+ }
29
+ declare function readOdbForm(pkg: Package, formName: string): OdbForm;
30
+ //#endregion
31
+ export { OdbForm, OdbFormControl, OdbFormDefinition, readOdbForm };
@@ -0,0 +1,31 @@
1
+ import { Package } from "../../model/package.js";
2
+ import { OdtDocument } from "../odt/read.js";
3
+ //#region src/typed/odb/form.d.ts
4
+ interface OdbFormControl {
5
+ tag: string;
6
+ name?: string;
7
+ controlImplementation?: string;
8
+ dataField?: string;
9
+ id?: string;
10
+ label?: string;
11
+ controls: OdbFormControl[];
12
+ }
13
+ interface OdbFormDefinition {
14
+ name?: string;
15
+ command?: string;
16
+ commandType?: string;
17
+ datasource?: string;
18
+ filter?: string;
19
+ order?: string;
20
+ controls: OdbFormControl[];
21
+ subForms: OdbFormDefinition[];
22
+ }
23
+ interface OdbForm {
24
+ name: string;
25
+ href: string;
26
+ document: OdtDocument;
27
+ forms: OdbFormDefinition[];
28
+ }
29
+ declare function readOdbForm(pkg: Package, formName: string): OdbForm;
30
+ //#endregion
31
+ export { OdbForm, OdbFormControl, OdbFormDefinition, readOdbForm };
@@ -0,0 +1,84 @@
1
+ import { decodeXmlText } from "../../xml/entities.js";
2
+ import { attrValue, findChildElement, rootElement } from "../../xml/query.js";
3
+ import { subDocumentPackage } from "./subdocument.js";
4
+ import { readOdt } from "../odt/read.js";
5
+ import { resolveOdbComponent } from "./read.js";
6
+ //#region src/typed/odb/form.ts
7
+ const CONTENT_PART = "content.xml";
8
+ const FORM_ELEMENT_TAG = "form:form";
9
+ const FORM_PROPERTIES_TAG = "form:properties";
10
+ const FORM_TAG_PREFIX = "form:";
11
+ function formAttr(element, name) {
12
+ const raw = attrValue(element, name);
13
+ return raw === void 0 ? void 0 : decodeXmlText(raw);
14
+ }
15
+ function readControl(element) {
16
+ const control = {
17
+ tag: element.tag,
18
+ controls: readControls(element)
19
+ };
20
+ const name = formAttr(element, "form:name");
21
+ if (name !== void 0) control.name = name;
22
+ const controlImplementation = formAttr(element, "form:control-implementation");
23
+ if (controlImplementation !== void 0) control.controlImplementation = controlImplementation;
24
+ const dataField = formAttr(element, "form:data-field");
25
+ if (dataField !== void 0) control.dataField = dataField;
26
+ const id = formAttr(element, "form:id");
27
+ if (id !== void 0) control.id = id;
28
+ const label = formAttr(element, "form:label");
29
+ if (label !== void 0) control.label = label;
30
+ return control;
31
+ }
32
+ function readControls(container) {
33
+ const controls = [];
34
+ for (const child of container.children) {
35
+ if (child.type !== "element" || !child.tag.startsWith(FORM_TAG_PREFIX)) continue;
36
+ if (child.tag === FORM_ELEMENT_TAG || child.tag === FORM_PROPERTIES_TAG) continue;
37
+ controls.push(readControl(child));
38
+ }
39
+ return controls;
40
+ }
41
+ function readFormDefinition(element) {
42
+ const subForms = [];
43
+ for (const child of element.children) if (child.type === "element" && child.tag === FORM_ELEMENT_TAG) subForms.push(readFormDefinition(child));
44
+ const definition = {
45
+ controls: readControls(element),
46
+ subForms
47
+ };
48
+ const name = formAttr(element, "form:name");
49
+ if (name !== void 0) definition.name = name;
50
+ const command = formAttr(element, "form:command");
51
+ if (command !== void 0) definition.command = command;
52
+ const commandType = formAttr(element, "form:command-type");
53
+ if (commandType !== void 0) definition.commandType = commandType;
54
+ const datasource = formAttr(element, "form:datasource");
55
+ if (datasource !== void 0) definition.datasource = datasource;
56
+ const filter = formAttr(element, "form:filter");
57
+ if (filter !== void 0) definition.filter = filter;
58
+ const order = formAttr(element, "form:order");
59
+ if (order !== void 0) definition.order = order;
60
+ return definition;
61
+ }
62
+ function readFormDefinitions(contentRoot) {
63
+ const body = contentRoot === void 0 ? void 0 : findChildElement(contentRoot.children, "office:body");
64
+ const text = body === void 0 ? void 0 : findChildElement(body.children, "office:text");
65
+ const forms = text === void 0 ? void 0 : findChildElement(text.children, "office:forms");
66
+ if (forms === void 0) return [];
67
+ const definitions = [];
68
+ for (const child of forms.children) if (child.type === "element" && child.tag === FORM_ELEMENT_TAG) definitions.push(readFormDefinition(child));
69
+ return definitions;
70
+ }
71
+ function readOdbForm(pkg, formName) {
72
+ const component = resolveOdbComponent(pkg, "form", formName);
73
+ const subPackage = subDocumentPackage(pkg, component.href);
74
+ const contentPart = subPackage.parts[CONTENT_PART];
75
+ if (contentPart?.kind !== "xml") throw new Error(`readOdbForm: form "${formName}" sub-document ${component.href}/${CONTENT_PART} is not an XML part`);
76
+ return {
77
+ name: component.name,
78
+ href: component.href,
79
+ document: readOdt(subPackage),
80
+ forms: readFormDefinitions(rootElement(contentPart.nodes))
81
+ };
82
+ }
83
+ //#endregion
84
+ export { readOdbForm };
@@ -1,13 +1,9 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_manifest = require("../../manifest.cjs");
2
+ const require_xml_entities = require("../../xml/entities.cjs");
3
3
  const require_xml_query = require("../../xml/query.cjs");
4
4
  //#region src/typed/odb/read.ts
5
5
  const CONTENT_PART = "content.xml";
6
6
  const EMBEDDED_URL_PREFIX = "sdbc:embedded:";
7
- const SUBDOCUMENT_CONTENT_SUFFIX = "/content.xml";
8
- function isXmlMediaType(mediaType) {
9
- return mediaType === "text/xml" || mediaType === "application/xml" || mediaType.endsWith("+xml");
10
- }
11
7
  function formatServerDatabaseUrl(serverDatabase) {
12
8
  const dbType = require_xml_query.attrValue(serverDatabase, "db:type");
13
9
  if (dbType === void 0) return;
@@ -51,13 +47,24 @@ function readConnectionInfo(databaseElement) {
51
47
  };
52
48
  }
53
49
  }
54
- function collectQueryNames(container, names) {
50
+ function collectQueryDefinitions(container, definitions) {
55
51
  for (const child of container.children) {
56
52
  if (child.type !== "element") continue;
57
53
  if (child.tag === "db:query") {
58
54
  const name = require_xml_query.attrValue(child, "db:name");
59
- if (name !== void 0) names.push(name);
60
- } else if (child.tag === "db:query-collection") collectQueryNames(child, names);
55
+ const command = require_xml_query.attrValue(child, "db:command");
56
+ if (name === void 0 || command === void 0) continue;
57
+ const decodedCommand = require_xml_entities.decodeXmlText(command);
58
+ const escapeProcessingRaw = require_xml_query.attrValue(child, "db:escape-processing");
59
+ definitions.push(escapeProcessingRaw === void 0 ? {
60
+ name,
61
+ command: decodedCommand
62
+ } : {
63
+ name,
64
+ command: decodedCommand,
65
+ escapeProcessing: escapeProcessingRaw === "true"
66
+ });
67
+ } else if (child.tag === "db:query-collection") collectQueryDefinitions(child, definitions);
61
68
  }
62
69
  }
63
70
  function collectTableNames(databaseElement) {
@@ -76,16 +83,47 @@ function collectTableNames(databaseElement) {
76
83
  if (tableDefinitions !== void 0) for (const definition of require_xml_query.childrenWithTag(tableDefinitions, "db:table-definition")) pushName(require_xml_query.attrValue(definition, "db:name"));
77
84
  return names;
78
85
  }
79
- function subdocumentNamesUnderPrefix(entries, prefix) {
80
- const names = [];
81
- for (const entry of entries) {
82
- if (!entry.fullPath.startsWith(prefix) || !entry.fullPath.endsWith(SUBDOCUMENT_CONTENT_SUFFIX) || !isXmlMediaType(entry.mediaType)) continue;
83
- const withoutSuffix = entry.fullPath.slice(0, entry.fullPath.length - 12);
84
- const lastSlash = withoutSuffix.lastIndexOf("/");
85
- const name = lastSlash === -1 ? withoutSuffix.slice(prefix.length) : withoutSuffix.slice(lastSlash + 1);
86
- if (name.length > 0) names.push(name);
86
+ function collectComponents(container, components) {
87
+ for (const child of container.children) {
88
+ if (child.type !== "element") continue;
89
+ if (child.tag === "db:component-collection") {
90
+ collectComponents(child, components);
91
+ continue;
92
+ }
93
+ if (child.tag !== "db:component") continue;
94
+ const name = require_xml_query.attrValue(child, "db:name");
95
+ const rawHref = require_xml_query.attrValue(child, "xlink:href");
96
+ if (name === void 0 || rawHref === void 0) continue;
97
+ const decodedHref = require_xml_entities.decodeXmlText(rawHref);
98
+ const href = decodedHref.endsWith("/") ? decodedHref.slice(0, -1) : decodedHref;
99
+ if (href.length === 0) continue;
100
+ const asTemplateRaw = require_xml_query.attrValue(child, "db:as-template");
101
+ components.push(asTemplateRaw === void 0 ? {
102
+ name: require_xml_entities.decodeXmlText(name),
103
+ href
104
+ } : {
105
+ name: require_xml_entities.decodeXmlText(name),
106
+ href,
107
+ asTemplate: asTemplateRaw === "true"
108
+ });
87
109
  }
88
- return names;
110
+ }
111
+ function readComponents(databaseElement, tag) {
112
+ const container = require_xml_query.findChildElement(databaseElement.children, tag);
113
+ if (container === void 0) return [];
114
+ const components = [];
115
+ collectComponents(container, components);
116
+ return components;
117
+ }
118
+ function resolveOdbComponent(pkg, kind, name) {
119
+ const inventory = readOdbInventory(pkg);
120
+ const components = kind === "form" ? inventory.forms : inventory.reports;
121
+ const match = components.find((component) => component.name === name);
122
+ if (match === void 0) {
123
+ const available = components.map((component) => component.name).join(", ");
124
+ throw new Error(`resolveOdbComponent: no ${kind} named "${name}" -- available: ${available === "" ? "(none)" : available}`);
125
+ }
126
+ return match;
89
127
  }
90
128
  function readOdbInventory(pkg) {
91
129
  const contentPart = pkg.parts[CONTENT_PART];
@@ -97,16 +135,15 @@ function readOdbInventory(pkg) {
97
135
  const connection = readConnectionInfo(databaseElement);
98
136
  const queries = [];
99
137
  const queriesElement = require_xml_query.findChildElement(databaseElement.children, "db:queries");
100
- if (queriesElement !== void 0) collectQueryNames(queriesElement, queries);
101
- const tables = collectTableNames(databaseElement);
102
- const manifest = require_manifest.readManifest(pkg);
138
+ if (queriesElement !== void 0) collectQueryDefinitions(queriesElement, queries);
103
139
  return {
104
140
  connection,
105
- tables,
141
+ tables: collectTableNames(databaseElement),
106
142
  queries,
107
- forms: subdocumentNamesUnderPrefix(manifest.entries, "forms/"),
108
- reports: subdocumentNamesUnderPrefix(manifest.entries, "reports/")
143
+ forms: readComponents(databaseElement, "db:forms"),
144
+ reports: readComponents(databaseElement, "db:reports")
109
145
  };
110
146
  }
111
147
  //#endregion
112
148
  exports.readOdbInventory = readOdbInventory;
149
+ exports.resolveOdbComponent = 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 };
@@ -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 };