@fin.cx/opendata 4.6.0 → 4.8.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/.smartconfig.json +6 -2
- package/dist_ts/00_commitinfo_data.js +3 -3
- package/dist_ts/financialstatements/amounts.d.ts +58 -0
- package/dist_ts/financialstatements/amounts.js +130 -0
- package/dist_ts/financialstatements/classes.financialstatementerror.d.ts +24 -0
- package/dist_ts/financialstatements/classes.financialstatementerror.js +10 -0
- package/dist_ts/financialstatements/constants.d.ts +16 -0
- package/dist_ts/financialstatements/constants.js +20 -0
- package/dist_ts/financialstatements/dates.d.ts +16 -0
- package/dist_ts/financialstatements/dates.js +72 -0
- package/dist_ts/financialstatements/html.d.ts +21 -0
- package/dist_ts/financialstatements/html.js +92 -0
- package/dist_ts/financialstatements/index.d.ts +6 -0
- package/dist_ts/financialstatements/index.js +11 -0
- package/dist_ts/financialstatements/interfaces.d.ts +258 -0
- package/dist_ts/financialstatements/interfaces.js +2 -0
- package/dist_ts/financialstatements/layout.d.ts +20 -0
- package/dist_ts/financialstatements/layout.html.d.ts +8 -0
- package/dist_ts/financialstatements/layout.html.js +125 -0
- package/dist_ts/financialstatements/layout.js +2 -0
- package/dist_ts/financialstatements/layout.pdf.d.ts +6 -0
- package/dist_ts/financialstatements/layout.pdf.js +229 -0
- package/dist_ts/financialstatements/mediatypes.d.ts +3 -0
- package/dist_ts/financialstatements/mediatypes.js +11 -0
- package/dist_ts/financialstatements/outline.d.ts +22 -0
- package/dist_ts/financialstatements/outline.js +26 -0
- package/dist_ts/financialstatements/parse.esef.d.ts +13 -0
- package/dist_ts/financialstatements/parse.esef.js +349 -0
- package/dist_ts/financialstatements/parse.hgb.d.ts +9 -0
- package/dist_ts/financialstatements/parse.hgb.js +1014 -0
- package/dist_ts/financialstatements/parse.statement.d.ts +8 -0
- package/dist_ts/financialstatements/parse.statement.js +25 -0
- package/dist_ts/financialstatements/plugins.d.ts +10 -0
- package/dist_ts/financialstatements/plugins.js +15 -0
- package/dist_ts/financialstatements/read.d.ts +10 -0
- package/dist_ts/financialstatements/read.js +113 -0
- package/dist_ts/handelsregister/classes.handelsregisterclient.d.ts +8 -2
- package/dist_ts/handelsregister/classes.handelsregisterclient.js +14 -5
- package/dist_ts/handelsregister/classes.handelsregistererror.d.ts +3 -1
- package/dist_ts/handelsregister/classes.handelsregistererror.js +1 -1
- package/dist_ts/handelsregister/classes.portalsession.d.ts +19 -3
- package/dist_ts/handelsregister/classes.portalsession.js +67 -9
- package/dist_ts/handelsregister/interfaces.d.ts +9 -2
- package/package.json +16 -6
- package/readme.md +86 -5
- package/ts/00_commitinfo_data.ts +2 -2
- package/ts/financialstatements/amounts.ts +181 -0
- package/ts/financialstatements/classes.financialstatementerror.ts +35 -0
- package/ts/financialstatements/constants.ts +24 -0
- package/ts/financialstatements/dates.ts +89 -0
- package/ts/financialstatements/html.ts +107 -0
- package/ts/financialstatements/index.ts +17 -0
- package/ts/financialstatements/interfaces.ts +268 -0
- package/ts/financialstatements/layout.html.ts +130 -0
- package/ts/financialstatements/layout.pdf.ts +268 -0
- package/ts/financialstatements/layout.ts +16 -0
- package/ts/financialstatements/mediatypes.ts +14 -0
- package/ts/financialstatements/outline.ts +44 -0
- package/ts/financialstatements/parse.esef.ts +394 -0
- package/ts/financialstatements/parse.hgb.ts +1235 -0
- package/ts/financialstatements/parse.statement.ts +26 -0
- package/ts/financialstatements/plugins.ts +29 -0
- package/ts/financialstatements/read.ts +135 -0
- package/ts/handelsregister/classes.handelsregisterclient.ts +18 -4
- package/ts/handelsregister/classes.handelsregistererror.ts +3 -0
- package/ts/handelsregister/classes.portalsession.ts +78 -9
- package/ts/handelsregister/interfaces.ts +9 -2
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/** An ISO date, `2024-12-31`. */
|
|
2
|
+
export type TIsoDate = string;
|
|
3
|
+
/**
|
|
4
|
+
* Where a statement was published:
|
|
5
|
+
* - `unternehmensregister`: the Unternehmensregister, for financial years beginning after 31.12.2021,
|
|
6
|
+
* and for the balance sheets micro companies deposit there (§ 326 Abs. 2 HGB);
|
|
7
|
+
* - `bundesanzeiger`: the Bundesanzeiger, for earlier financial years;
|
|
8
|
+
* - `issuer`: the company's own publication, as listed issuers publish their ESEF reports;
|
|
9
|
+
* - `unknown`: a document whose origin the caller does not know.
|
|
10
|
+
*/
|
|
11
|
+
export type TFilingSource = 'unternehmensregister' | 'bundesanzeiger' | 'issuer' | 'unknown';
|
|
12
|
+
/**
|
|
13
|
+
* What a filing is:
|
|
14
|
+
* - `annual_accounts`: the Jahresabschluss of one company (§§ 242, 264 HGB);
|
|
15
|
+
* - `consolidated_accounts`: a group's Konzernabschluss (§ 290 HGB);
|
|
16
|
+
* - `deposited_balance_sheet`: the balance sheet a micro company deposits instead of publishing
|
|
17
|
+
* (§ 326 Abs. 2 HGB);
|
|
18
|
+
* - `annual_financial_report`: a listed issuer's Jahresfinanzbericht (§ 114 WpHG), as an ESEF report.
|
|
19
|
+
*/
|
|
20
|
+
export type TFilingKind = 'annual_accounts' | 'consolidated_accounts' | 'deposited_balance_sheet' | 'annual_financial_report';
|
|
21
|
+
/** The size classes of § 267 and § 267a HGB, as a filing states them. */
|
|
22
|
+
export type TSizeClass = 'micro' | 'small' | 'medium' | 'large';
|
|
23
|
+
/**
|
|
24
|
+
* One published statement as its publisher lists it. Every field the caller does not know is null;
|
|
25
|
+
* none is derived from the document.
|
|
26
|
+
*/
|
|
27
|
+
export interface IFiling {
|
|
28
|
+
source: TFilingSource;
|
|
29
|
+
kind: TFilingKind;
|
|
30
|
+
/** the company's name as the publisher writes it */
|
|
31
|
+
companyName: string | null;
|
|
32
|
+
/** the register sheet, as the caller writes it: `Amtsgericht Bremen HRB 35230 HB` */
|
|
33
|
+
registerReference: string | null;
|
|
34
|
+
/** the company's Legal Entity Identifier */
|
|
35
|
+
lei: string | null;
|
|
36
|
+
fiscalYearStart: TIsoDate | null;
|
|
37
|
+
fiscalYearEnd: TIsoDate | null;
|
|
38
|
+
/**
|
|
39
|
+
* the day the publisher posted the document; for a deposited balance sheet, the day it was
|
|
40
|
+
* deposited. The Unternehmensregister's origin note names this day.
|
|
41
|
+
*/
|
|
42
|
+
publishedOn: TIsoDate | null;
|
|
43
|
+
/** the publisher's own title of the document */
|
|
44
|
+
title: string | null;
|
|
45
|
+
sizeClass: TSizeClass | null;
|
|
46
|
+
/** the publisher's identifier of the document */
|
|
47
|
+
documentId: string | null;
|
|
48
|
+
/** where the publisher shows the document */
|
|
49
|
+
sourceUrl: string | null;
|
|
50
|
+
}
|
|
51
|
+
/** What a caller states about a filing: `source` and `kind`, and whatever else it knows. */
|
|
52
|
+
export interface IFilingInput extends Pick<IFiling, 'source' | 'kind'>, Partial<Omit<IFiling, 'source' | 'kind'>> {
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The media types this entry point reads:
|
|
56
|
+
* - `text/html`: a statement as the Unternehmensregister or the Bundesanzeiger shows it;
|
|
57
|
+
* - `application/pdf`: the same as a PDF with a text layer;
|
|
58
|
+
* - `application/xhtml+xml`: an ESEF report (inline XBRL) on its own;
|
|
59
|
+
* - `application/zip`: an ESEF report package (`.zip` or `.xbri`).
|
|
60
|
+
*/
|
|
61
|
+
export type TStatementMediaType = 'text/html' | 'application/pdf' | 'application/xhtml+xml' | 'application/zip';
|
|
62
|
+
/** The document as it was obtained, byte for byte. */
|
|
63
|
+
export interface IRawStatementDocument {
|
|
64
|
+
bytes: Uint8Array;
|
|
65
|
+
mediaType: TStatementMediaType;
|
|
66
|
+
/** the SHA-256 of `bytes`, lowercase hex */
|
|
67
|
+
sha256: string;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The unit a statement prints its amounts in. Amounts in this entry point are always in the
|
|
71
|
+
* currency itself, the unit's factor applied: `1.234` printed in TEUR is `'1234000'`.
|
|
72
|
+
*/
|
|
73
|
+
export interface IStatementUnit {
|
|
74
|
+
/** as this entry point names it */
|
|
75
|
+
label: 'EUR' | 'TEUR' | 'Mio. EUR';
|
|
76
|
+
/** the number of euros one printed unit stands for */
|
|
77
|
+
factor: '1' | '1000' | '1000000';
|
|
78
|
+
}
|
|
79
|
+
/** One of the two years a statement shows. */
|
|
80
|
+
export interface IStatementPeriod {
|
|
81
|
+
/** the column heading as printed, `Geschäftsjahr Euro` or `31.12.2024`; null where none is printed */
|
|
82
|
+
heading: string | null;
|
|
83
|
+
/** the first day, where the statement states it */
|
|
84
|
+
start: TIsoDate | null;
|
|
85
|
+
/** the balance sheet date, the last day of the period, where the statement states it */
|
|
86
|
+
end: TIsoDate | null;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The figures most readers look for first, as decimal strings in the currency. Each is null where
|
|
90
|
+
* the statement does not print it:
|
|
91
|
+
* - `totalAssets`: the balance sheet total;
|
|
92
|
+
* - `equity`: the equity section of the balance sheet, its printed total or, where the statement
|
|
93
|
+
* prints only its parts, their sum;
|
|
94
|
+
* - `netIncome`: the net income or loss (Jahresüberschuss or Jahresfehlbetrag), from the income
|
|
95
|
+
* statement or, where none is published, from the balance sheet's equity section;
|
|
96
|
+
* - `revenue`: the revenue (Umsatzerlöse); small companies may print only a gross result
|
|
97
|
+
* (Rohergebnis, § 276 HGB), and then it is null.
|
|
98
|
+
*/
|
|
99
|
+
export interface IKeyFigures {
|
|
100
|
+
totalAssets: string | null;
|
|
101
|
+
equity: string | null;
|
|
102
|
+
netIncome: string | null;
|
|
103
|
+
revenue: string | null;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The kind of a printed line:
|
|
107
|
+
* - `position`: a position of the outline of § 266 or § 275 HGB, or a line the statement adds to it;
|
|
108
|
+
* - `subtotal`: a printed sum of the lines above it, such as Summe Anlagevermögen, or an
|
|
109
|
+
* intermediate result of the income statement, such as Rohergebnis or Ergebnis nach Steuern;
|
|
110
|
+
* no total adds it again;
|
|
111
|
+
* - `total`: the total of a side of the balance sheet, or the income statement's net income;
|
|
112
|
+
* - `memo`: a "davon" line, part of the line above it and never added.
|
|
113
|
+
*/
|
|
114
|
+
export type TStatementLineKind = 'position' | 'subtotal' | 'total' | 'memo';
|
|
115
|
+
/** One printed line of a balance sheet or an income statement. */
|
|
116
|
+
export interface IStatementPosition {
|
|
117
|
+
/** the outline path of the line, its printed codes joined: `A.I.1`; null for a line without a code */
|
|
118
|
+
code: string | null;
|
|
119
|
+
/** the code as printed: `1.` or `a)` */
|
|
120
|
+
printedCode: string | null;
|
|
121
|
+
/** the line's text as printed, without its code */
|
|
122
|
+
label: string;
|
|
123
|
+
/** the depth in the outline, 0 for the top level */
|
|
124
|
+
level: number;
|
|
125
|
+
kind: TStatementLineKind;
|
|
126
|
+
/** the amount for the current year as a decimal string in the currency, null where none is printed */
|
|
127
|
+
current: string | null;
|
|
128
|
+
/** the same for the prior year */
|
|
129
|
+
prior: string | null;
|
|
130
|
+
}
|
|
131
|
+
export interface IBalanceSheet {
|
|
132
|
+
unit: IStatementUnit;
|
|
133
|
+
/** Aktiva, in printed order, with the total last */
|
|
134
|
+
assets: IStatementPosition[];
|
|
135
|
+
/** Passiva, in printed order, with the total last */
|
|
136
|
+
equityAndLiabilities: IStatementPosition[];
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* The method of an income statement: `total_cost` (Gesamtkostenverfahren, § 275 Abs. 2 HGB) or
|
|
140
|
+
* `cost_of_sales` (Umsatzkostenverfahren, § 275 Abs. 3 HGB); null where its lines do not tell.
|
|
141
|
+
*/
|
|
142
|
+
export type TIncomeStatementMethod = 'total_cost' | 'cost_of_sales';
|
|
143
|
+
export interface IIncomeStatement {
|
|
144
|
+
unit: IStatementUnit;
|
|
145
|
+
method: TIncomeStatementMethod | null;
|
|
146
|
+
/**
|
|
147
|
+
* how the statement prints its expenses: `negative`, with a minus, so that its lines add up as
|
|
148
|
+
* printed, or `positive`, as amounts to subtract. The positions keep the amounts as printed.
|
|
149
|
+
*/
|
|
150
|
+
expenses: 'negative' | 'positive';
|
|
151
|
+
positions: IStatementPosition[];
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* A statement under the HGB read from the HTML or the PDF a register shows. Everything in it was
|
|
155
|
+
* printed and adds up: each position with parts equals their sum, each side of the balance sheet its
|
|
156
|
+
* total, both totals each other, and the income statement's lines its net income. A prior year whose
|
|
157
|
+
* figures do not add up, and an income statement that does not, are left out with a note.
|
|
158
|
+
*/
|
|
159
|
+
export interface IHgbStatement {
|
|
160
|
+
standard: 'hgb';
|
|
161
|
+
currency: 'EUR';
|
|
162
|
+
periods: {
|
|
163
|
+
current: IStatementPeriod;
|
|
164
|
+
prior: IStatementPeriod | null;
|
|
165
|
+
};
|
|
166
|
+
keyFigures: {
|
|
167
|
+
current: IKeyFigures;
|
|
168
|
+
prior: IKeyFigures | null;
|
|
169
|
+
};
|
|
170
|
+
balanceSheet: IBalanceSheet;
|
|
171
|
+
/** null where the document publishes none, as small companies may (§ 326 Abs. 1 HGB) */
|
|
172
|
+
incomeStatement: IIncomeStatement | null;
|
|
173
|
+
/** what was left out and why, in English */
|
|
174
|
+
notes: string[];
|
|
175
|
+
}
|
|
176
|
+
/** The period of an ESEF fact: an instant (`start` null) or a duration. */
|
|
177
|
+
export interface IEsefPeriod {
|
|
178
|
+
start: TIsoDate | null;
|
|
179
|
+
end: TIsoDate;
|
|
180
|
+
}
|
|
181
|
+
/** One numeric fact of an ESEF report (`ix:nonFraction`). */
|
|
182
|
+
export interface IEsefFact {
|
|
183
|
+
/** the concept with the prefix the report declares for it: `ifrs-full:Revenue` */
|
|
184
|
+
concept: string;
|
|
185
|
+
/** the namespace of the concept */
|
|
186
|
+
namespace: string;
|
|
187
|
+
contextId: string;
|
|
188
|
+
period: IEsefPeriod;
|
|
189
|
+
/** the explicit dimension members of the context, dimension to member, both as written */
|
|
190
|
+
dimensions: Record<string, string>;
|
|
191
|
+
/** the unit: an ISO 4217 code such as `EUR`, `shares`, `pure`, or a ratio such as `EUR/shares` */
|
|
192
|
+
unit: string | null;
|
|
193
|
+
/** the value as a decimal string, scale and sign applied; null for a nil fact */
|
|
194
|
+
value: string | null;
|
|
195
|
+
/** the `decimals` attribute as written: `0`, `-3`, `INF` */
|
|
196
|
+
decimals: string | null;
|
|
197
|
+
/** the fact's `id`, where it has one */
|
|
198
|
+
id: string | null;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* A listed issuer's annual financial report in the European Single Electronic Format: the numeric
|
|
202
|
+
* facts its inline XBRL tags, and the key figures of its consolidated statements (IFRS).
|
|
203
|
+
*/
|
|
204
|
+
export interface IEsefStatement {
|
|
205
|
+
standard: 'esef';
|
|
206
|
+
/** the LEI the report's contexts identify the issuer with */
|
|
207
|
+
lei: string | null;
|
|
208
|
+
/** the path of the report in its package; null for a report read on its own */
|
|
209
|
+
reportPath: string | null;
|
|
210
|
+
/** the language the report declares */
|
|
211
|
+
language: string | null;
|
|
212
|
+
/** the currency of the key figures, ISO 4217 */
|
|
213
|
+
currency: string | null;
|
|
214
|
+
periods: {
|
|
215
|
+
current: IStatementPeriod;
|
|
216
|
+
prior: IStatementPeriod | null;
|
|
217
|
+
};
|
|
218
|
+
keyFigures: {
|
|
219
|
+
current: IKeyFigures;
|
|
220
|
+
prior: IKeyFigures | null;
|
|
221
|
+
};
|
|
222
|
+
facts: IEsefFact[];
|
|
223
|
+
/** what could not be read and why, in English */
|
|
224
|
+
notes: string[];
|
|
225
|
+
}
|
|
226
|
+
export type TParsedStatement = IHgbStatement | IEsefStatement;
|
|
227
|
+
/** Why a document was kept without a parsed statement. */
|
|
228
|
+
export interface IStatementParseFailure {
|
|
229
|
+
code: 'invalid_package' | 'unreadable' | 'no_text' | 'unparseable' | 'too_large';
|
|
230
|
+
message: string;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* A statement as a caller keeps it: the filing, the document byte for byte, and what could be read
|
|
234
|
+
* from it. `parsed` is null rather than guessed: a document this entry point cannot read with
|
|
235
|
+
* certainty keeps its raw bytes, and `parseFailure` says why.
|
|
236
|
+
*/
|
|
237
|
+
export interface IFinancialStatement {
|
|
238
|
+
filing: IFiling;
|
|
239
|
+
raw: IRawStatementDocument;
|
|
240
|
+
parsed: TParsedStatement | null;
|
|
241
|
+
parseFailure: IStatementParseFailure | null;
|
|
242
|
+
/** when the document was obtained, milliseconds since the epoch */
|
|
243
|
+
obtainedAt: number;
|
|
244
|
+
/**
|
|
245
|
+
* the origin note the publisher marks the document with, for a copy to keep it: for the
|
|
246
|
+
* Unternehmensregister "Auszug aus dem Unternehmensregister" and the day the document was posted
|
|
247
|
+
* or deposited (Nutzungsbedingungen § 3 Abs. 5); null for other publishers
|
|
248
|
+
*/
|
|
249
|
+
notice: string | null;
|
|
250
|
+
}
|
|
251
|
+
export interface IReadFinancialStatementOptions {
|
|
252
|
+
filing: IFilingInput;
|
|
253
|
+
bytes: Uint8Array;
|
|
254
|
+
/** the media type of `bytes`; parameters such as `; charset=utf-8` are ignored */
|
|
255
|
+
mediaType: string;
|
|
256
|
+
/** clock for `obtainedAt`; default `Date.now` */
|
|
257
|
+
now?: () => number;
|
|
258
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A statement as this entry point reads it, whatever it came as: text in printed order, and tables
|
|
3
|
+
* of cells. An HTML table keeps its own columns; a PDF page becomes one table whose column 0 holds
|
|
4
|
+
* the labels and whose other columns are the columns its amounts are aligned in.
|
|
5
|
+
*/
|
|
6
|
+
export interface ILayoutCell {
|
|
7
|
+
text: string;
|
|
8
|
+
/** the first column the cell covers */
|
|
9
|
+
first: number;
|
|
10
|
+
/** the last column the cell covers */
|
|
11
|
+
last: number;
|
|
12
|
+
}
|
|
13
|
+
export type TLayoutBlock = {
|
|
14
|
+
kind: 'text';
|
|
15
|
+
text: string;
|
|
16
|
+
heading: boolean;
|
|
17
|
+
} | {
|
|
18
|
+
kind: 'table';
|
|
19
|
+
rows: ILayoutCell[][];
|
|
20
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { TLayoutBlock } from './layout.js';
|
|
2
|
+
/**
|
|
3
|
+
* The blocks of an HTML statement in document order: headings, lines of text and tables. Reads the
|
|
4
|
+
* publication itself (`div.publication_container`, as the Unternehmensregister and the Bundesanzeiger
|
|
5
|
+
* show it) where the page has one, else the whole body. A table that only lays out other tables is
|
|
6
|
+
* read through to them.
|
|
7
|
+
*/
|
|
8
|
+
export declare const htmlLayout: (htmlArg: string) => TLayoutBlock[];
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import { descendants, elementChildren, getAttribute, hasClass, isElement, parseHtml, textOf } from './html.js';
|
|
3
|
+
import { normalizeSpaces } from './amounts.js';
|
|
4
|
+
const headingTags = new Set(['h1', 'h2', 'h3', 'h4', 'h5', 'h6']);
|
|
5
|
+
const skippedTags = new Set(['head', 'script', 'style', 'template', 'noscript', 'svg', 'math', 'img', 'button', 'select', 'input']);
|
|
6
|
+
/** elements that end a line of text before and after them */
|
|
7
|
+
const blockTags = new Set([
|
|
8
|
+
'address', 'article', 'aside', 'blockquote', 'body', 'caption', 'center', 'dd', 'details', 'dialog', 'div',
|
|
9
|
+
'dl', 'dt', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'header', 'hgroup', 'hr', 'li', 'main',
|
|
10
|
+
'nav', 'ol', 'p', 'pre', 'section', 'summary', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'ul',
|
|
11
|
+
]);
|
|
12
|
+
/** colspan and rowspan as a statement may write them, kept to 1 to 50 */
|
|
13
|
+
const spanOf = (valueArg) => {
|
|
14
|
+
const value = Number.parseInt(valueArg ?? '1', 10);
|
|
15
|
+
return Number.isFinite(value) ? Math.min(Math.max(value, 1), 50) : 1;
|
|
16
|
+
};
|
|
17
|
+
/** the rows of a table without nested tables, every cell placed in the columns it covers */
|
|
18
|
+
const tableRows = (tableArg) => {
|
|
19
|
+
const rowElements = descendants(tableArg).filter((elementArg) => elementArg.tagName === 'tr');
|
|
20
|
+
const occupied = rowElements.map(() => new Set());
|
|
21
|
+
const rows = [];
|
|
22
|
+
rowElements.forEach((rowElement, rowIndex) => {
|
|
23
|
+
const cells = [];
|
|
24
|
+
let column = 0;
|
|
25
|
+
for (const cellElement of elementChildren(rowElement)) {
|
|
26
|
+
if (cellElement.tagName !== 'td' && cellElement.tagName !== 'th') {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
while (occupied[rowIndex].has(column)) {
|
|
30
|
+
column++;
|
|
31
|
+
}
|
|
32
|
+
const colspan = spanOf(getAttribute(cellElement, 'colspan'));
|
|
33
|
+
const rowspan = spanOf(getAttribute(cellElement, 'rowspan'));
|
|
34
|
+
for (let spannedRow = rowIndex; spannedRow < Math.min(rowIndex + rowspan, rowElements.length); spannedRow++) {
|
|
35
|
+
for (let spannedColumn = column; spannedColumn < column + colspan; spannedColumn++) {
|
|
36
|
+
occupied[spannedRow].add(spannedColumn);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const text = normalizeSpaces(textOf(cellElement));
|
|
40
|
+
if (text !== '') {
|
|
41
|
+
cells.push({ text, first: column, last: column + colspan - 1 });
|
|
42
|
+
}
|
|
43
|
+
column += colspan;
|
|
44
|
+
}
|
|
45
|
+
if (cells.length > 0) {
|
|
46
|
+
rows.push(cells);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
return rows;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* The blocks of an HTML statement in document order: headings, lines of text and tables. Reads the
|
|
53
|
+
* publication itself (`div.publication_container`, as the Unternehmensregister and the Bundesanzeiger
|
|
54
|
+
* show it) where the page has one, else the whole body. A table that only lays out other tables is
|
|
55
|
+
* read through to them.
|
|
56
|
+
*/
|
|
57
|
+
export const htmlLayout = (htmlArg) => {
|
|
58
|
+
const document = parseHtml(htmlArg);
|
|
59
|
+
const elements = descendants(document);
|
|
60
|
+
const root = elements.find((elementArg) => elementArg.tagName === 'div' && hasClass(elementArg, 'publication_container')) ??
|
|
61
|
+
elements.find((elementArg) => elementArg.tagName === 'body');
|
|
62
|
+
if (!root) {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
const blocks = [];
|
|
66
|
+
let run = [];
|
|
67
|
+
const flush = () => {
|
|
68
|
+
const text = normalizeSpaces(run.join(' '));
|
|
69
|
+
run = [];
|
|
70
|
+
if (text !== '') {
|
|
71
|
+
blocks.push({ kind: 'text', text, heading: false });
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const stack = [
|
|
75
|
+
{ children: root.childNodes, index: 0, block: true },
|
|
76
|
+
];
|
|
77
|
+
while (stack.length > 0) {
|
|
78
|
+
const frame = stack[stack.length - 1];
|
|
79
|
+
if (frame.index >= frame.children.length) {
|
|
80
|
+
stack.pop();
|
|
81
|
+
if (frame.block) {
|
|
82
|
+
flush();
|
|
83
|
+
}
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const child = frame.children[frame.index++];
|
|
87
|
+
if (!isElement(child)) {
|
|
88
|
+
if ('value' in child && child.nodeName === '#text') {
|
|
89
|
+
run.push(child.value);
|
|
90
|
+
}
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const tag = child.tagName;
|
|
94
|
+
if (skippedTags.has(tag)) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (tag === 'br') {
|
|
98
|
+
flush();
|
|
99
|
+
}
|
|
100
|
+
else if (headingTags.has(tag)) {
|
|
101
|
+
flush();
|
|
102
|
+
const text = normalizeSpaces(textOf(child));
|
|
103
|
+
if (text !== '') {
|
|
104
|
+
blocks.push({ kind: 'text', text, heading: true });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else if (tag === 'table' && !descendants(child).some((elementArg) => elementArg.tagName === 'table')) {
|
|
108
|
+
flush();
|
|
109
|
+
const rows = tableRows(child);
|
|
110
|
+
if (rows.length > 0) {
|
|
111
|
+
blocks.push({ kind: 'table', rows });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
const block = tag === 'table' || blockTags.has(tag);
|
|
116
|
+
if (block) {
|
|
117
|
+
flush();
|
|
118
|
+
}
|
|
119
|
+
stack.push({ children: child.childNodes, index: 0, block });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
flush();
|
|
123
|
+
return blocks;
|
|
124
|
+
};
|
|
125
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGF5b3V0Lmh0bWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9maW5hbmNpYWxzdGF0ZW1lbnRzL2xheW91dC5odG1sLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxXQUFXLEVBQUUsZUFBZSxFQUFFLFlBQVksRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQXFCLE1BQU0sV0FBVyxDQUFDO0FBQ2xJLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFLL0MsTUFBTSxXQUFXLEdBQUcsSUFBSSxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUM7QUFDbEUsTUFBTSxXQUFXLEdBQUcsSUFBSSxHQUFHLENBQUMsQ0FBQyxNQUFNLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztBQUVwSSw2REFBNkQ7QUFDN0QsTUFBTSxTQUFTLEdBQUcsSUFBSSxHQUFHLENBQUM7SUFDeEIsU0FBUyxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsUUFBUSxFQUFFLEtBQUs7SUFDMUcsSUFBSSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsWUFBWSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxNQUFNO0lBQ3hHLEtBQUssRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFF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
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { TLayoutBlock } from './layout.js';
|
|
2
|
+
/**
|
|
3
|
+
* The blocks of a PDF statement: each page one table. Reads the text layer only; a PDF without one,
|
|
4
|
+
* such as a scan, is `no_text`.
|
|
5
|
+
*/
|
|
6
|
+
export declare const pdfLayout: (bytesArg: Uint8Array) => Promise<TLayoutBlock[]>;
|