@coderoftime/fints 0.0.0-stage → 0.2.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 (249) hide show
  1. package/CHANGELOG.md +152 -0
  2. package/LICENSE +28 -0
  3. package/README.md +246 -2
  4. package/dist/client.d.ts +48 -0
  5. package/dist/client.d.ts.map +1 -0
  6. package/dist/client.js +199 -0
  7. package/dist/client.js.map +1 -0
  8. package/dist/core/account.d.ts +168 -0
  9. package/dist/core/account.d.ts.map +1 -0
  10. package/dist/core/account.js +245 -0
  11. package/dist/core/account.js.map +1 -0
  12. package/dist/core/amount.d.ts +63 -0
  13. package/dist/core/amount.d.ts.map +1 -0
  14. package/dist/core/amount.js +192 -0
  15. package/dist/core/amount.js.map +1 -0
  16. package/dist/core/balance.d.ts +55 -0
  17. package/dist/core/balance.d.ts.map +1 -0
  18. package/dist/core/balance.js +54 -0
  19. package/dist/core/balance.js.map +1 -0
  20. package/dist/core/bank-info.d.ts +49 -0
  21. package/dist/core/bank-info.d.ts.map +1 -0
  22. package/dist/core/bank-info.js +52 -0
  23. package/dist/core/bank-info.js.map +1 -0
  24. package/dist/core/client.d.ts +161 -0
  25. package/dist/core/client.d.ts.map +1 -0
  26. package/dist/core/client.js +2 -0
  27. package/dist/core/client.js.map +1 -0
  28. package/dist/core/config.d.ts +80 -0
  29. package/dist/core/config.d.ts.map +1 -0
  30. package/dist/core/config.js +153 -0
  31. package/dist/core/config.js.map +1 -0
  32. package/dist/core/errors.d.ts +153 -0
  33. package/dist/core/errors.d.ts.map +1 -0
  34. package/dist/core/errors.js +247 -0
  35. package/dist/core/errors.js.map +1 -0
  36. package/dist/core/feedback.d.ts +72 -0
  37. package/dist/core/feedback.d.ts.map +1 -0
  38. package/dist/core/feedback.js +127 -0
  39. package/dist/core/feedback.js.map +1 -0
  40. package/dist/core/transaction.d.ts +103 -0
  41. package/dist/core/transaction.d.ts.map +1 -0
  42. package/dist/core/transaction.js +96 -0
  43. package/dist/core/transaction.js.map +1 -0
  44. package/dist/core/transport.d.ts +64 -0
  45. package/dist/core/transport.d.ts.map +1 -0
  46. package/dist/core/transport.js +149 -0
  47. package/dist/core/transport.js.map +1 -0
  48. package/dist/formats/camt.d.ts +32 -0
  49. package/dist/formats/camt.d.ts.map +1 -0
  50. package/dist/formats/camt.js +242 -0
  51. package/dist/formats/camt.js.map +1 -0
  52. package/dist/formats/mt940.d.ts +54 -0
  53. package/dist/formats/mt940.d.ts.map +1 -0
  54. package/dist/formats/mt940.js +376 -0
  55. package/dist/formats/mt940.js.map +1 -0
  56. package/dist/formats/readers.d.ts +15 -0
  57. package/dist/formats/readers.d.ts.map +1 -0
  58. package/dist/formats/readers.js +42 -0
  59. package/dist/formats/readers.js.map +1 -0
  60. package/dist/formats/record-budget.d.ts +7 -0
  61. package/dist/formats/record-budget.d.ts.map +1 -0
  62. package/dist/formats/record-budget.js +17 -0
  63. package/dist/formats/record-budget.js.map +1 -0
  64. package/dist/formats/sepa-purpose.d.ts +28 -0
  65. package/dist/formats/sepa-purpose.d.ts.map +1 -0
  66. package/dist/formats/sepa-purpose.js +89 -0
  67. package/dist/formats/sepa-purpose.js.map +1 -0
  68. package/dist/index.d.ts +28 -0
  69. package/dist/index.d.ts.map +1 -0
  70. package/dist/index.js +27 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/session/app-approval.d.ts +66 -0
  73. package/dist/session/app-approval.d.ts.map +1 -0
  74. package/dist/session/app-approval.js +226 -0
  75. package/dist/session/app-approval.js.map +1 -0
  76. package/dist/session/dialog-runner.d.ts +31 -0
  77. package/dist/session/dialog-runner.d.ts.map +1 -0
  78. package/dist/session/dialog-runner.js +111 -0
  79. package/dist/session/dialog-runner.js.map +1 -0
  80. package/dist/session/login-guard.d.ts +78 -0
  81. package/dist/session/login-guard.d.ts.map +1 -0
  82. package/dist/session/login-guard.js +181 -0
  83. package/dist/session/login-guard.js.map +1 -0
  84. package/dist/session/sepa-accounts.d.ts +40 -0
  85. package/dist/session/sepa-accounts.d.ts.map +1 -0
  86. package/dist/session/sepa-accounts.js +112 -0
  87. package/dist/session/sepa-accounts.js.map +1 -0
  88. package/dist/session/session-setup.d.ts +80 -0
  89. package/dist/session/session-setup.d.ts.map +1 -0
  90. package/dist/session/session-setup.js +182 -0
  91. package/dist/session/session-setup.js.map +1 -0
  92. package/dist/session/session-state.d.ts +50 -0
  93. package/dist/session/session-state.d.ts.map +1 -0
  94. package/dist/session/session-state.js +182 -0
  95. package/dist/session/session-state.js.map +1 -0
  96. package/dist/session/signed-dialog.d.ts +77 -0
  97. package/dist/session/signed-dialog.d.ts.map +1 -0
  98. package/dist/session/signed-dialog.js +170 -0
  99. package/dist/session/signed-dialog.js.map +1 -0
  100. package/dist/session/tan-selection.d.ts +96 -0
  101. package/dist/session/tan-selection.d.ts.map +1 -0
  102. package/dist/session/tan-selection.js +189 -0
  103. package/dist/session/tan-selection.js.map +1 -0
  104. package/dist/session/user-prompts.d.ts +65 -0
  105. package/dist/session/user-prompts.d.ts.map +1 -0
  106. package/dist/session/user-prompts.js +184 -0
  107. package/dist/session/user-prompts.js.map +1 -0
  108. package/dist/tan/challenge.d.ts +135 -0
  109. package/dist/tan/challenge.d.ts.map +1 -0
  110. package/dist/tan/challenge.js +184 -0
  111. package/dist/tan/challenge.js.map +1 -0
  112. package/dist/tan/flicker.d.ts +42 -0
  113. package/dist/tan/flicker.d.ts.map +1 -0
  114. package/dist/tan/flicker.js +296 -0
  115. package/dist/tan/flicker.js.map +1 -0
  116. package/dist/tan/tan-image.d.ts +22 -0
  117. package/dist/tan/tan-image.d.ts.map +1 -0
  118. package/dist/tan/tan-image.js +43 -0
  119. package/dist/tan/tan-image.js.map +1 -0
  120. package/dist/tan/tan-models.d.ts +149 -0
  121. package/dist/tan/tan-models.d.ts.map +1 -0
  122. package/dist/tan/tan-models.js +153 -0
  123. package/dist/tan/tan-models.js.map +1 -0
  124. package/dist/util/async.d.ts +22 -0
  125. package/dist/util/async.d.ts.map +1 -0
  126. package/dist/util/async.js +45 -0
  127. package/dist/util/async.js.map +1 -0
  128. package/dist/util/bytes.d.ts +22 -0
  129. package/dist/util/bytes.d.ts.map +1 -0
  130. package/dist/util/bytes.js +128 -0
  131. package/dist/util/bytes.js.map +1 -0
  132. package/dist/util/call-context.d.ts +12 -0
  133. package/dist/util/call-context.d.ts.map +1 -0
  134. package/dist/util/call-context.js +30 -0
  135. package/dist/util/call-context.js.map +1 -0
  136. package/dist/util/dates.d.ts +55 -0
  137. package/dist/util/dates.d.ts.map +1 -0
  138. package/dist/util/dates.js +189 -0
  139. package/dist/util/dates.js.map +1 -0
  140. package/dist/util/errors.d.ts +17 -0
  141. package/dist/util/errors.d.ts.map +1 -0
  142. package/dist/util/errors.js +24 -0
  143. package/dist/util/errors.js.map +1 -0
  144. package/dist/util/immutable-map.d.ts +16 -0
  145. package/dist/util/immutable-map.d.ts.map +1 -0
  146. package/dist/util/immutable-map.js +38 -0
  147. package/dist/util/immutable-map.js.map +1 -0
  148. package/dist/util/json.d.ts +17 -0
  149. package/dist/util/json.d.ts.map +1 -0
  150. package/dist/util/json.js +62 -0
  151. package/dist/util/json.js.map +1 -0
  152. package/dist/util/text.d.ts +37 -0
  153. package/dist/util/text.d.ts.map +1 -0
  154. package/dist/util/text.js +107 -0
  155. package/dist/util/text.js.map +1 -0
  156. package/dist/util/xml.d.ts +36 -0
  157. package/dist/util/xml.d.ts.map +1 -0
  158. package/dist/util/xml.js +194 -0
  159. package/dist/util/xml.js.map +1 -0
  160. package/dist/v3/account-extension.d.ts +25 -0
  161. package/dist/v3/account-extension.d.ts.map +1 -0
  162. package/dist/v3/account-extension.js +173 -0
  163. package/dist/v3/account-extension.js.map +1 -0
  164. package/dist/v3/bank-connection.d.ts +34 -0
  165. package/dist/v3/bank-connection.d.ts.map +1 -0
  166. package/dist/v3/bank-connection.js +58 -0
  167. package/dist/v3/bank-connection.js.map +1 -0
  168. package/dist/v3/dialog.d.ts +112 -0
  169. package/dist/v3/dialog.d.ts.map +1 -0
  170. package/dist/v3/dialog.js +241 -0
  171. package/dist/v3/dialog.js.map +1 -0
  172. package/dist/v3/message.d.ts +85 -0
  173. package/dist/v3/message.d.ts.map +1 -0
  174. package/dist/v3/message.js +303 -0
  175. package/dist/v3/message.js.map +1 -0
  176. package/dist/v3/parameter-store.d.ts +75 -0
  177. package/dist/v3/parameter-store.d.ts.map +1 -0
  178. package/dist/v3/parameter-store.js +143 -0
  179. package/dist/v3/parameter-store.js.map +1 -0
  180. package/dist/v3/parameters.d.ts +105 -0
  181. package/dist/v3/parameters.d.ts.map +1 -0
  182. package/dist/v3/parameters.js +450 -0
  183. package/dist/v3/parameters.js.map +1 -0
  184. package/dist/v3/protocol.d.ts +61 -0
  185. package/dist/v3/protocol.d.ts.map +1 -0
  186. package/dist/v3/protocol.js +113 -0
  187. package/dist/v3/protocol.js.map +1 -0
  188. package/dist/v3/queries.d.ts +51 -0
  189. package/dist/v3/queries.d.ts.map +1 -0
  190. package/dist/v3/queries.js +120 -0
  191. package/dist/v3/queries.js.map +1 -0
  192. package/dist/v3/segments.d.ts +106 -0
  193. package/dist/v3/segments.d.ts.map +1 -0
  194. package/dist/v3/segments.js +325 -0
  195. package/dist/v3/segments.js.map +1 -0
  196. package/dist/v3/syntax.d.ts +127 -0
  197. package/dist/v3/syntax.d.ts.map +1 -0
  198. package/dist/v3/syntax.js +367 -0
  199. package/dist/v3/syntax.js.map +1 -0
  200. package/package.json +67 -4
  201. package/src/client.ts +252 -0
  202. package/src/core/account.ts +323 -0
  203. package/src/core/amount.ts +211 -0
  204. package/src/core/balance.ts +85 -0
  205. package/src/core/bank-info.ts +66 -0
  206. package/src/core/client.ts +186 -0
  207. package/src/core/config.ts +182 -0
  208. package/src/core/errors.ts +277 -0
  209. package/src/core/feedback.ts +140 -0
  210. package/src/core/transaction.ts +161 -0
  211. package/src/core/transport.ts +189 -0
  212. package/src/formats/camt.ts +266 -0
  213. package/src/formats/mt940.ts +419 -0
  214. package/src/formats/readers.ts +49 -0
  215. package/src/formats/record-budget.ts +18 -0
  216. package/src/formats/sepa-purpose.ts +94 -0
  217. package/src/index.ts +70 -0
  218. package/src/session/app-approval.ts +278 -0
  219. package/src/session/dialog-runner.ts +122 -0
  220. package/src/session/login-guard.ts +221 -0
  221. package/src/session/sepa-accounts.ts +115 -0
  222. package/src/session/session-setup.ts +184 -0
  223. package/src/session/session-state.ts +204 -0
  224. package/src/session/signed-dialog.ts +192 -0
  225. package/src/session/tan-selection.ts +203 -0
  226. package/src/session/user-prompts.ts +193 -0
  227. package/src/tan/challenge.ts +261 -0
  228. package/src/tan/flicker.ts +308 -0
  229. package/src/tan/tan-image.ts +38 -0
  230. package/src/tan/tan-models.ts +252 -0
  231. package/src/util/async.ts +48 -0
  232. package/src/util/bytes.ts +129 -0
  233. package/src/util/call-context.ts +41 -0
  234. package/src/util/dates.ts +210 -0
  235. package/src/util/errors.ts +27 -0
  236. package/src/util/immutable-map.ts +47 -0
  237. package/src/util/json.ts +67 -0
  238. package/src/util/text.ts +112 -0
  239. package/src/util/xml.ts +183 -0
  240. package/src/v3/account-extension.ts +185 -0
  241. package/src/v3/bank-connection.ts +67 -0
  242. package/src/v3/dialog.ts +283 -0
  243. package/src/v3/message.ts +373 -0
  244. package/src/v3/parameter-store.ts +160 -0
  245. package/src/v3/parameters.ts +524 -0
  246. package/src/v3/protocol.ts +148 -0
  247. package/src/v3/queries.ts +190 -0
  248. package/src/v3/segments.ts +374 -0
  249. package/src/v3/syntax.ts +369 -0
@@ -0,0 +1,54 @@
1
+ import { Amount } from '../core/amount.js';
2
+ import { Transaction, type TransactionStatus } from '../core/transaction.js';
3
+ import { RecordBudget } from './record-budget.js';
4
+ /** One statement from an MT940 or MT942 file, with its balances and transactions. */
5
+ export interface Mt940Statement {
6
+ /** The sender's reference of the statement (field 20). */
7
+ readonly reference: string | undefined;
8
+ /** The account the statement is for (field 25). */
9
+ readonly accountId: string | undefined;
10
+ /** Statement and sequence number (field 28C). */
11
+ readonly statementNumber: string | undefined;
12
+ /** Currency of the statement; `undefined` for a statement without balances and transactions. */
13
+ readonly currency: string | undefined;
14
+ /** The balance at the start of the statement (field 60), negative for a debit. */
15
+ readonly openingBalance: Amount | undefined;
16
+ /** The date of `openingBalance`. */
17
+ readonly openingDate: Date | undefined;
18
+ /** The balance at the end of the statement (field 62), negative for a debit. */
19
+ readonly closingBalance: Amount | undefined;
20
+ /** The date of `closingBalance`. */
21
+ readonly closingDate: Date | undefined;
22
+ /**
23
+ * The transactions of the statement, in the order the bank lists them; they lead from `openingBalance` to
24
+ * `closingBalance` where the statement states these.
25
+ */
26
+ readonly transactions: readonly Transaction[];
27
+ }
28
+ /** What the MT940 parser takes besides the text. */
29
+ export interface Mt940Options {
30
+ /** The status of the transactions: `booked` (MT940, the default) or `pending` (MT942). */
31
+ status?: TransactionStatus;
32
+ /** The currency of statements that state none in their balances. */
33
+ currency?: string | undefined;
34
+ }
35
+ /** Parser for SWIFT MT940/MT942 statements, including German structured `:86:` fields. */
36
+ export declare const Mt940: Readonly<{
37
+ /** Parses all transactions; see `parse`. */
38
+ parseTransactions(text: string, options?: Mt940Options): Transaction[];
39
+ /**
40
+ * Parses all statements. Their lines are separated by line breaks, and by `@@` as well where the first line holds it,
41
+ * as some banks separate them.
42
+ *
43
+ * Throws `FormatError` for text without any field, and if a transaction line (`:61:`) or a balance cannot be read or
44
+ * the currency of a transaction is unknown. It does as well for a statement that states only one of its opening and
45
+ * closing balances, one of them, its account or its number twice, or transactions that do not lead from the one
46
+ * balance to the other: a line of a purpose that starts like a field, such as `:61:` or `:25:`, would pass for a
47
+ * transaction, the account or a statement of its own otherwise. Text of more than 200,000 statements and
48
+ * transactions is a `FormatError` as well.
49
+ */
50
+ parse(text: string, options?: Mt940Options): Mt940Statement[];
51
+ }>;
52
+ /** `Mt940.parse`, which takes each statement and transaction from `budget`, before it builds it. */
53
+ export declare function parseMt940(text: string, options: Mt940Options, budget: RecordBudget): Mt940Statement[];
54
+ //# sourceMappingURL=mt940.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mt940.d.ts","sourceRoot":"","sources":["../../src/formats/mt940.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,KAAK,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAI7E,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,qFAAqF;AACrF,MAAM,WAAW,cAAc;IAC7B,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,mDAAmD;IACnD,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,iDAAiD;IACjD,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,gGAAgG;IAChG,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,kFAAkF;IAClF,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,oCAAoC;IACpC,QAAQ,CAAC,WAAW,EAAE,IAAI,GAAG,SAAS,CAAC;IACvC,gFAAgF;IAChF,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,oCAAoC;IACpC,QAAQ,CAAC,WAAW,EAAE,IAAI,GAAG,SAAS,CAAC;IACvC;;;OAGG;IACH,QAAQ,CAAC,YAAY,EAAE,SAAS,WAAW,EAAE,CAAC;CAC/C;AAED,oDAAoD;AACpD,MAAM,WAAW,YAAY;IAC3B,0FAA0F;IAC1F,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAID,0FAA0F;AAC1F,eAAO,MAAM,KAAK;IAChB,4CAA4C;4BACpB,MAAM,YAAW,YAAY,GAAQ,WAAW,EAAE;IAI1E;;;;;;;;;;OAUG;gBACS,MAAM,YAAW,YAAY,GAAQ,cAAc,EAAE;EAGjE,CAAC;AAEH,oGAAoG;AACpG,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,GAAG,cAAc,EAAE,CAiBtG"}
@@ -0,0 +1,376 @@
1
+ import { Amount } from '../core/amount.js';
2
+ import { Transaction } from '../core/transaction.js';
3
+ import { clampedDate, parseSwiftDate } from '../util/dates.js';
4
+ import { FormatError } from '../util/errors.js';
5
+ import { nonBlank } from '../util/text.js';
6
+ import { RecordBudget } from './record-budget.js';
7
+ import { providedReference, SepaPurpose } from './sepa-purpose.js';
8
+ const tagPattern = /^:(\d{2}[A-Z]?):/gm;
9
+ /** Parser for SWIFT MT940/MT942 statements, including German structured `:86:` fields. */
10
+ export const Mt940 = Object.freeze({
11
+ /** Parses all transactions; see `parse`. */
12
+ parseTransactions(text, options = {}) {
13
+ return Mt940.parse(text, options).flatMap((s) => [...s.transactions]);
14
+ },
15
+ /**
16
+ * Parses all statements. Their lines are separated by line breaks, and by `@@` as well where the first line holds it,
17
+ * as some banks separate them.
18
+ *
19
+ * Throws `FormatError` for text without any field, and if a transaction line (`:61:`) or a balance cannot be read or
20
+ * the currency of a transaction is unknown. It does as well for a statement that states only one of its opening and
21
+ * closing balances, one of them, its account or its number twice, or transactions that do not lead from the one
22
+ * balance to the other: a line of a purpose that starts like a field, such as `:61:` or `:25:`, would pass for a
23
+ * transaction, the account or a statement of its own otherwise. Text of more than 200,000 statements and
24
+ * transactions is a `FormatError` as well.
25
+ */
26
+ parse(text, options = {}) {
27
+ return parseMt940(text, options, new RecordBudget());
28
+ },
29
+ });
30
+ /** `Mt940.parse`, which takes each statement and transaction from `budget`, before it builds it. */
31
+ export function parseMt940(text, options, budget) {
32
+ const status = options.status ?? 'booked';
33
+ const normalized = withLineFeeds(text);
34
+ const statements = [];
35
+ let current;
36
+ for (const [tag, value] of taggedParts(normalized, tagPattern)) {
37
+ if (tag === '20' || current === undefined) {
38
+ if (current !== undefined)
39
+ statements.push(current.build());
40
+ budget.take();
41
+ current = new StatementBuilder(status, options.currency);
42
+ }
43
+ if (tag === '61')
44
+ budget.take();
45
+ current.add(tag, fieldValue(value));
46
+ }
47
+ if (current !== undefined)
48
+ statements.push(current.build());
49
+ else if (normalized.trim() !== '')
50
+ throw new FormatError('MT940 data without fields');
51
+ return statements;
52
+ }
53
+ /**
54
+ * The parts of `text` that the matches of `tag` start, each the first group of its match and the text up to the next
55
+ * match: the fields of a statement, or the subfields of a `:86:`. One by one: text of a few megabytes holds millions of
56
+ * them. A pattern that matched the text up to the next tag as well would run out of backtracking stack on a part of a
57
+ * few million characters.
58
+ */
59
+ function* taggedParts(text, tag) {
60
+ let current;
61
+ let start = 0;
62
+ for (const match of text.matchAll(tag)) {
63
+ if (current !== undefined)
64
+ yield [current, text.substring(start, match.index)];
65
+ current = match[1];
66
+ start = match.index + match[0].length;
67
+ }
68
+ if (current !== undefined)
69
+ yield [current, text.substring(start)];
70
+ }
71
+ /**
72
+ * `text` with line feeds between its lines. Some banks separate them with `@@`, and may still break the line between
73
+ * statements or at the ends. So `@@` separates lines where the first line holds it, which the bank writes; in other
74
+ * text, `@@` may be part of a purpose, which the payer writes.
75
+ */
76
+ function withLineFeeds(text) {
77
+ const lines = text.replace(/\r\n?/g, '\n');
78
+ return lines.trimStart().split('\n', 1)[0].includes('@@') ? lines.replace(/@@/g, '\n') : lines;
79
+ }
80
+ /**
81
+ * The value of a field in `text`, which runs from its tag to the next one: without the blanks and the statement end
82
+ * (`-`) at its end.
83
+ *
84
+ * Trimmed without a pattern such as `/\n+$/`, which takes quadratic time on a long run of line breaks.
85
+ */
86
+ function fieldValue(text) {
87
+ const value = text.trimEnd();
88
+ return value.endsWith('\n-') ? value.substring(0, value.length - 2).trimEnd() : value;
89
+ }
90
+ const balancePattern = /^([CD])(\d{6})([A-Z]{3})(\d+,\d*)/;
91
+ const currencyPrefix = /^([A-Z]{3})/;
92
+ class StatementBuilder {
93
+ status;
94
+ fallbackCurrency;
95
+ reference;
96
+ accountId;
97
+ statementNumber;
98
+ currency;
99
+ opening;
100
+ openingDate;
101
+ closing;
102
+ closingDate;
103
+ transactions = [];
104
+ /**
105
+ * The tag added last: a `:86:` right after a `:61:` details the transaction, anywhere else it informs the account
106
+ * owner about the statement.
107
+ */
108
+ previousTag;
109
+ constructor(status,
110
+ /** Currency to use when the statement states none. */
111
+ fallbackCurrency) {
112
+ this.status = status;
113
+ this.fallbackCurrency = fallbackCurrency;
114
+ }
115
+ add(tag, value) {
116
+ switch (tag) {
117
+ case '20':
118
+ this.reference = value.trim();
119
+ break;
120
+ case '25':
121
+ if (this.accountId !== undefined)
122
+ throw new FormatError('MT940 statement with two accounts', this.reference);
123
+ this.accountId = value.trim();
124
+ break;
125
+ case '28C':
126
+ case '28':
127
+ if (this.statementNumber !== undefined) {
128
+ throw new FormatError('MT940 statement with two statement numbers', this.reference);
129
+ }
130
+ this.statementNumber = value.trim();
131
+ break;
132
+ case '60F':
133
+ case '60M': {
134
+ if (this.opening !== undefined) {
135
+ throw new FormatError('MT940 statement with two opening balances', this.reference);
136
+ }
137
+ const [balance, date] = parseBalance(value);
138
+ this.opening = balance;
139
+ this.openingDate = date;
140
+ this.currency ??= balance.currency;
141
+ break;
142
+ }
143
+ case '62F':
144
+ case '62M': {
145
+ if (this.closing !== undefined) {
146
+ throw new FormatError('MT940 statement with two closing balances', this.reference);
147
+ }
148
+ const [balance, date] = parseBalance(value);
149
+ this.closing = balance;
150
+ this.closingDate = date;
151
+ this.currency ??= balance.currency;
152
+ break;
153
+ }
154
+ case '34F':
155
+ this.currency ??= currencyPrefix.exec(value.trim())?.[1];
156
+ break;
157
+ case '61':
158
+ this.transactions.push(new TransactionLines(value));
159
+ break;
160
+ case '86':
161
+ if (this.previousTag === '61')
162
+ this.transactions.at(-1).details = value;
163
+ break;
164
+ }
165
+ this.previousTag = tag;
166
+ }
167
+ build() {
168
+ const statementCurrency = this.currency ?? this.fallbackCurrency;
169
+ if (statementCurrency === undefined && this.transactions.length > 0) {
170
+ throw new FormatError('MT940 statement without currency', this.reference);
171
+ }
172
+ const { openingDate, closingDate } = this;
173
+ const period = openingDate && closingDate ? [openingDate, closingDate] : undefined;
174
+ const transactions = this.transactions.map((t) => t.toTransaction(statementCurrency, this.status, period));
175
+ this.checkBalances(transactions);
176
+ return Object.freeze({
177
+ reference: this.reference,
178
+ accountId: this.accountId,
179
+ statementNumber: this.statementNumber,
180
+ currency: statementCurrency,
181
+ openingBalance: this.opening,
182
+ openingDate: this.openingDate,
183
+ closingBalance: this.closing,
184
+ closingDate: this.closingDate,
185
+ transactions: Object.freeze(transactions),
186
+ });
187
+ }
188
+ /** Checks that the statement states both balances or neither, and that its `transactions` lead from one to the other. */
189
+ checkBalances(transactions) {
190
+ const { opening, closing } = this;
191
+ if (opening === undefined && closing === undefined)
192
+ return;
193
+ if (opening === undefined || closing === undefined) {
194
+ throw new FormatError('MT940 statement with only one of its balances', this.reference);
195
+ }
196
+ if (opening.currency !== this.currency || closing.currency !== this.currency) {
197
+ throw new FormatError('MT940 balances in another currency than the statement', this.reference);
198
+ }
199
+ if (!balanceAfter(opening, transactions).equals(closing)) {
200
+ throw new FormatError('MT940 transactions do not add up to the closing balance', this.reference);
201
+ }
202
+ }
203
+ }
204
+ /** `opening` plus the amounts of `transactions`; throws `FormatError` for a sum beyond what an `Amount` holds. */
205
+ function balanceAfter(opening, transactions) {
206
+ try {
207
+ return transactions.reduce((balance, t) => balance.add(t.amount), opening);
208
+ }
209
+ catch (error) {
210
+ if (error instanceof RangeError)
211
+ throw new FormatError('MT940 amounts too large to add up');
212
+ throw error;
213
+ }
214
+ }
215
+ function parseBalance(value) {
216
+ const m = balancePattern.exec(value.trim());
217
+ if (!m)
218
+ throw new FormatError('Unreadable MT940 balance', value);
219
+ const amount = Amount.parseDecimal(m[4], m[3]);
220
+ const date = parseSwiftDate(m[2]);
221
+ if (date === undefined)
222
+ throw new FormatError('Invalid balance date', value);
223
+ return [m[1] === 'D' ? amount.negate() : amount, date];
224
+ }
225
+ /**
226
+ * Value date, optional booking date (MMDD), debit/credit mark, funds code, amount, transaction type, customer
227
+ * reference, optional bank reference and supplementary details.
228
+ */
229
+ const line61 = /^(\d{6})(\d{4})?(RC|RD|C|D)([A-Z])?(\d+,\d*)([NFS][A-Z0-9]{3})([^\n]*?)(?:\/\/([^\n]*))?(?:\n([\s\S]*))?$/;
230
+ /** The `:61:` line of a transaction and its `:86:` details. */
231
+ class TransactionLines {
232
+ line;
233
+ details;
234
+ constructor(line) {
235
+ this.line = line;
236
+ }
237
+ toTransaction(currency, status, period) {
238
+ const m = line61.exec(this.line.trim());
239
+ const valueDate = m ? parseSwiftDate(m[1]) : undefined;
240
+ if (!m || valueDate === undefined)
241
+ throw new FormatError('Unreadable MT940 transaction line (:61:)', this.line);
242
+ const mark = m[3];
243
+ const amount = Amount.parseDecimal(m[5], currency);
244
+ const debit = mark === 'D' || mark === 'RC';
245
+ const customerReference = nonBlank(m[7]);
246
+ const d = Details.parse(this.details);
247
+ return new Transaction({
248
+ status,
249
+ bookingDate: this.bookingDate(m[2], valueDate, period),
250
+ valueDate,
251
+ amount: debit ? amount.negate() : amount,
252
+ isReversal: mark.startsWith('R'),
253
+ transactionTypeId: m[6],
254
+ customerReference: customerReference === 'NONREF' ? undefined : customerReference,
255
+ bankReference: nonBlank(m[8]),
256
+ transactionCode: d.transactionCode,
257
+ bookingText: d.bookingText,
258
+ primaNota: d.primaNota,
259
+ purpose: d.purpose,
260
+ counterpartyName: d.name,
261
+ counterpartyIban: d.iban,
262
+ counterpartyBic: d.bic,
263
+ counterpartyAccountNumber: d.accountNumber,
264
+ counterpartyBankCode: d.bankCode,
265
+ endToEndId: providedReference(d.sepa.get('EREF')),
266
+ mandateId: d.sepa.get('MREF'),
267
+ creditorId: d.sepa.get('CRED'),
268
+ ultimateCreditor: d.sepa.get('ABWE'),
269
+ ultimateDebtor: d.sepa.get('ABWA'),
270
+ purposeCodes: d.sepa,
271
+ });
272
+ }
273
+ /**
274
+ * The booking date `MMDD`, in the year that places it within `period`, or else closest to it; of several such years,
275
+ * the one closest to `valueDate`; without a period, the year closest to `valueDate`. The value date alone misleads:
276
+ * banks book refunds and corrections with the value date of the original booking, up to 13 months before.
277
+ */
278
+ bookingDate(mmdd, valueDate, period) {
279
+ if (mmdd === undefined)
280
+ return undefined;
281
+ const month = Number(mmdd.substring(0, 2));
282
+ const day = Number(mmdd.substring(2, 4));
283
+ const [first, last] = period ?? [valueDate, valueDate];
284
+ const outside = (date) => Math.max(first.getTime() - date.getTime(), date.getTime() - last.getTime(), 0);
285
+ const fromValueDate = (date) => Math.abs(date.getTime() - valueDate.getTime());
286
+ // The best year lies next to one of these, however long the period.
287
+ const years = new Set([first, valueDate, last].flatMap((d) => [d.getFullYear() - 1, d.getFullYear(), d.getFullYear() + 1]));
288
+ let best;
289
+ for (const year of years) {
290
+ const date = clampedDate(year, month, day);
291
+ if (date === undefined)
292
+ throw new FormatError('Invalid booking date', this.line);
293
+ if (best === undefined || (outside(date) - outside(best) || fromValueDate(date) - fromValueDate(best)) < 0) {
294
+ best = date;
295
+ }
296
+ }
297
+ return best;
298
+ }
299
+ }
300
+ /**
301
+ * Three-digit business transaction code (GVC), then the first subfield: `?` and its two-digit number. Text that merely
302
+ * starts with three digits, such as `100 Euro` or `100,00 EUR`, is free text.
303
+ */
304
+ const structuredPattern = /^\d{3}\?\d{2}/;
305
+ const subfieldTag = /\?(\d{2})/g;
306
+ const ibanPattern = /^[A-Z]{2}\d{2}[A-Z0-9]+$/;
307
+ const bicPattern = /^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$/;
308
+ /** The German structured `:86:` field: a business transaction code and `?nn` subfields. */
309
+ class Details {
310
+ transactionCode;
311
+ bookingText;
312
+ primaNota;
313
+ purpose;
314
+ name;
315
+ iban;
316
+ bic;
317
+ accountNumber;
318
+ bankCode;
319
+ sepa = new Map();
320
+ static parse(raw) {
321
+ const d = new Details();
322
+ if (raw === undefined)
323
+ return d;
324
+ const text = raw.replace(/\n/g, '');
325
+ if (!structuredPattern.test(text)) {
326
+ // Free text, whose lines are separate phrases; the purpose and its keywords are read from the same text.
327
+ const free = raw.replace(/\n/g, ' ').trim();
328
+ d.sepa = SepaPurpose.parse(free);
329
+ d.purpose = d.sepa.get('SVWZ') ?? nonBlank(free);
330
+ return d;
331
+ }
332
+ d.transactionCode = text.substring(0, 3);
333
+ const subfields = Details.subfields(text.substring(3));
334
+ const subfield = (key) => nonBlank(subfields.get(key));
335
+ // Subfields continue each other: they are joined keeping the spaces at their boundaries.
336
+ const parts = (keys) => keys.map((k) => subfields.get(k)).filter((v) => v !== undefined);
337
+ d.bookingText = subfield(0);
338
+ d.primaNota = subfield(10);
339
+ const purposeParts = parts([20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 60, 61, 62, 63]);
340
+ d.sepa = SepaPurpose.parseParts(purposeParts);
341
+ d.purpose = d.sepa.get('SVWZ') ?? nonBlank(purposeParts.join(''));
342
+ d.name = nonBlank(parts([32, 33]).join(''));
343
+ d.readCounterpartyAccount(subfield(30), subfield(31));
344
+ d.iban ??= d.sepa.get('IBAN');
345
+ d.bic ??= d.sepa.get('BIC');
346
+ return d;
347
+ }
348
+ /** The text of each subfield (`?nn` and what follows), by its number; a subfield that appears twice is joined. */
349
+ static subfields(text) {
350
+ const subfields = new Map();
351
+ for (const [tag, value] of taggedParts(text, subfieldTag)) {
352
+ const key = Number(tag);
353
+ subfields.set(key, (subfields.get(key) ?? '') + value);
354
+ }
355
+ return subfields;
356
+ }
357
+ /**
358
+ * Takes the counterparty's account from subfields 30 (bank) and 31 (account): IBAN and BIC, or account number and
359
+ * bank code.
360
+ */
361
+ readCounterpartyAccount(bank, account) {
362
+ if (account !== undefined && ibanPattern.test(account)) {
363
+ this.iban = account;
364
+ this.bic = bank;
365
+ return;
366
+ }
367
+ this.accountNumber = account;
368
+ if (bank !== undefined && bicPattern.test(bank)) {
369
+ this.bic = bank;
370
+ }
371
+ else {
372
+ this.bankCode = bank;
373
+ }
374
+ }
375
+ }
376
+ //# sourceMappingURL=mt940.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mt940.js","sourceRoot":"","sources":["../../src/formats/mt940.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { Transaction } from '../core/transaction.js';
2
+ /**
3
+ * The transactions in MT940 data: the `booked` parts joined, since a statement may continue on the next page, then the
4
+ * `pending` ones (MT942).
5
+ *
6
+ * `currency` applies to statements that do not state one; throws `FormatError` if both are missing, and for more than
7
+ * 200,000 statements and transactions in all.
8
+ */
9
+ export declare function mt940Transactions(booked: readonly Uint8Array[], pending: readonly Uint8Array[], currency: string | undefined): Transaction[];
10
+ /**
11
+ * The transactions in camt documents; each document stands on its own. Throws `FormatError` for more than 200,000
12
+ * statements and transactions in all.
13
+ */
14
+ export declare function camtTransactions(booked: readonly Uint8Array[], pending: readonly Uint8Array[]): Transaction[];
15
+ //# sourceMappingURL=readers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readers.d.ts","sourceRoot":"","sources":["../../src/formats/readers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAM1D;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,UAAU,EAAE,EAC7B,OAAO,EAAE,SAAS,UAAU,EAAE,EAC9B,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,WAAW,EAAE,CAMf;AAeD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,EAAE,OAAO,EAAE,SAAS,UAAU,EAAE,GAAG,WAAW,EAAE,CAM7G"}
@@ -0,0 +1,42 @@
1
+ import { decodeBankText, decodeXmlText } from '../util/text.js';
2
+ import { parseCamt } from './camt.js';
3
+ import { parseMt940 } from './mt940.js';
4
+ import { RecordBudget } from './record-budget.js';
5
+ /**
6
+ * The transactions in MT940 data: the `booked` parts joined, since a statement may continue on the next page, then the
7
+ * `pending` ones (MT942).
8
+ *
9
+ * `currency` applies to statements that do not state one; throws `FormatError` if both are missing, and for more than
10
+ * 200,000 statements and transactions in all.
11
+ */
12
+ export function mt940Transactions(booked, pending, currency) {
13
+ const budget = new RecordBudget();
14
+ return [
15
+ ...parseMt940(joinedMt940(booked), { currency }, budget),
16
+ ...parseMt940(joinedMt940(pending), { currency, status: 'pending' }, budget),
17
+ ].flatMap((statement) => statement.transactions);
18
+ }
19
+ /**
20
+ * The MT940 `parts` as one text, whose line separator the parser takes from its first line: a later page may start
21
+ * with a purpose, which the payer writes.
22
+ *
23
+ * Each part is decoded on its own, since a bank may start each page with a byte order mark. Each part ends a line
24
+ * before the next one follows, since the parser finds fields at the start of a line and a bank need not end its pages
25
+ * with a line break.
26
+ */
27
+ function joinedMt940(parts) {
28
+ const pages = parts.filter((part) => part.length > 0).map((part) => decodeBankText(part));
29
+ return pages.map((page, i) => (i + 1 < pages.length && !page.endsWith('\n') ? `${page}\n` : page)).join('');
30
+ }
31
+ /**
32
+ * The transactions in camt documents; each document stands on its own. Throws `FormatError` for more than 200,000
33
+ * statements and transactions in all.
34
+ */
35
+ export function camtTransactions(booked, pending) {
36
+ const budget = new RecordBudget();
37
+ return [
38
+ ...booked.flatMap((document) => parseCamt(decodeXmlText(document), undefined, budget)),
39
+ ...pending.flatMap((document) => parseCamt(decodeXmlText(document), 'pending', budget)),
40
+ ].flatMap((statement) => statement.transactions);
41
+ }
42
+ //# sourceMappingURL=readers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readers.js","sourceRoot":"","sources":["../../src/formats/readers.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAA6B,EAC7B,OAA8B,EAC9B,QAA4B;IAE5B,MAAM,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;IAClC,OAAO;QACL,GAAG,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,MAAM,CAAC;QACxD,GAAG,UAAU,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC;KAC7E,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;AACnD,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,WAAW,CAAC,KAA4B;IAC/C,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1F,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC9G,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAA6B,EAAE,OAA8B;IAC5F,MAAM,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;IAClC,OAAO;QACL,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,SAAS,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QACtF,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,SAAS,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;KACxF,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;AACnD,CAAC"}
@@ -0,0 +1,7 @@
1
+ /** The statements and transactions the parsers may still build; the parses of one query share one budget. */
2
+ export declare class RecordBudget {
3
+ private left;
4
+ /** Counts a statement or transaction about to be built; throws `FormatError` for one beyond the budget. */
5
+ take(): void;
6
+ }
7
+ //# sourceMappingURL=record-budget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record-budget.d.ts","sourceRoot":"","sources":["../../src/formats/record-budget.ts"],"names":[],"mappings":"AASA,6GAA6G;AAC7G,qBAAa,YAAY;IACvB,OAAO,CAAC,IAAI,CAAc;IAE1B,2GAA2G;IAC3G,IAAI,IAAI,IAAI;CAGb"}
@@ -0,0 +1,17 @@
1
+ import { FormatError } from '../util/errors.js';
2
+ /**
3
+ * Most statements and transactions the parsers build for one query: several times what a year of a busy business
4
+ * account holds, and few enough that a hostile answer cannot exhaust the memory, at about 600 bytes each. The size of
5
+ * the answer does not bound them: a transaction takes up to 25 times the bytes of its MT940 line.
6
+ */
7
+ const maxRecords = 200_000;
8
+ /** The statements and transactions the parsers may still build; the parses of one query share one budget. */
9
+ export class RecordBudget {
10
+ left = maxRecords;
11
+ /** Counts a statement or transaction about to be built; throws `FormatError` for one beyond the budget. */
12
+ take() {
13
+ if (--this.left < 0)
14
+ throw new FormatError(`More than ${maxRecords} statements and transactions`);
15
+ }
16
+ }
17
+ //# sourceMappingURL=record-budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record-budget.js","sourceRoot":"","sources":["../../src/formats/record-budget.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD;;;;GAIG;AACH,MAAM,UAAU,GAAG,OAAO,CAAC;AAE3B,6GAA6G;AAC7G,MAAM,OAAO,YAAY;IACf,IAAI,GAAG,UAAU,CAAC;IAE1B,2GAA2G;IAC3G,IAAI;QACF,IAAI,EAAE,IAAI,CAAC,IAAI,GAAG,CAAC;YAAE,MAAM,IAAI,WAAW,CAAC,aAAa,UAAU,8BAA8B,CAAC,CAAC;IACpG,CAAC;CACF"}
@@ -0,0 +1,28 @@
1
+ /** `reference`, or `undefined` if it is missing or the filler for a reference the payer did not give. */
2
+ export declare function providedReference(reference: string | undefined): string | undefined;
3
+ /** Parser for the SEPA keywords in a purpose text. */
4
+ export declare const SepaPurpose: Readonly<{
5
+ /**
6
+ * Splits `purpose` into its SEPA keywords (EREF, KREF, MREF, CRED, SVWZ, …) and their values.
7
+ *
8
+ * A keyword counts unless a capital letter comes right before it, so `XEREF+` does not open an EREF value. After a
9
+ * digit or a small letter it does: a purpose line cut at 35 characters is joined to the next one without a space, so
10
+ * `…4711EREF+` may be where one line ends and the next begins.
11
+ *
12
+ * The remittance information (`SVWZ+`) and the ultimate debtor and creditor (`ABWA+`, `ABWE+`) are text the payer or
13
+ * the payee writes, which banks put after every other keyword. So from the first of them on only `ABWA+` and `ABWE+`
14
+ * start a value: a keyword in that text, such as `IBAN+`, is part of it. A keyword that occurs twice has no value:
15
+ * which of the two the bank wrote cannot be told, since a reference the payee chose, such as `EREF+`, comes before
16
+ * the bank's `CRED+` and may hold `CRED+…` and `SVWZ+`, which turns the bank's value into remittance information.
17
+ */
18
+ parse(purpose: string): Map<string, string>;
19
+ /**
20
+ * Like `parse` for a purpose the bank sends in `parts`, such as the MT940 subfields `?20` to `?29`, which continue
21
+ * each other without a separator.
22
+ *
23
+ * A keyword also counts at the start of a part, where the previous value may end in a capital letter, as in
24
+ * `EREF+NOTPROVIDED` followed by a part `MREF+…`.
25
+ */
26
+ parseParts(parts: Iterable<string>): Map<string, string>;
27
+ }>;
28
+ //# sourceMappingURL=sepa-purpose.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sepa-purpose.d.ts","sourceRoot":"","sources":["../../src/formats/sepa-purpose.ts"],"names":[],"mappings":"AAqBA,yGAAyG;AACzG,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAEnF;AAOD,sDAAsD;AACtD,eAAO,MAAM,WAAW;IACtB;;;;;;;;;;;;OAYG;mBACY,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAI3C;;;;;;OAMG;sBACe,QAAQ,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;EASxD,CAAC"}