ofx-data-extractor 1.4.8 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -60
- package/dist/@types/common.d.ts +48 -0
- package/dist/common/analysis.d.ts +4 -0
- package/dist/common/config.d.ts +8 -1
- package/dist/common/constants.d.ts +11 -0
- package/dist/common/date.d.ts +13 -0
- package/dist/common/parse.d.ts +18 -1
- package/dist/common/reader.d.ts +1 -0
- package/dist/esm/index.min.js +8 -8
- package/dist/implementations/extractor.d.ts +17 -1
- package/dist/implementations/reader.d.ts +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/interfaces/extractor.interface.d.ts +4 -1
- package/dist/older-implementation/main.d.ts +5 -1
- package/dist/umd/bundle.min.js +8 -8
- package/package.json +23 -13
package/README.md
CHANGED
|
@@ -1,98 +1,126 @@
|
|
|
1
1
|
# [ofx-data-extractor](https://www.npmjs.com/package/ofx-data-extractor)
|
|
2
2
|
|
|
3
|
-
[](https://badge.fury.io/js/ofx-data-extractor)
|
|
3
|
+
[](https://badge.fury.io/js/ofx-data-extractor)
|
|
4
|
+
[![MIT License][license-image]][license-url]
|
|
4
5
|
[](https://codecov.io/gh/Fabiopf02/ofx-data-extractor)
|
|
5
6
|
[](https://github.com/Fabiopf02/ofx-data-extractor/actions/workflows/release.yml)
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
This is a `Node.js` and `Browser` module written in `TypeScript` that provides a utility for extracting data from an `OFX` file. The module can also format some of the data and retrieve specific parts of the file if requested.
|
|
8
|
+
`ofx-data-extractor` is a TypeScript library for parsing, normalizing and validating OFX files in Node.js and browser environments.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
## Table of Contents
|
|
11
|
+
|
|
12
|
+
- [Installation](#installation)
|
|
13
|
+
- [Quick Start](#quick-start)
|
|
14
|
+
- [Node.js](#nodejs)
|
|
15
|
+
- [Browser (`fromBlob` is async)](#browser-fromblob-is-async)
|
|
16
|
+
- [Main Public API (`Ofx`)](#main-public-api-ofx)
|
|
17
|
+
- [Configuration (Extract)](#configuration-extract)
|
|
18
|
+
- [Developer Documentation](#developer-documentation)
|
|
19
|
+
- [Examples](#examples)
|
|
20
|
+
- [License](#license)
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
12
23
|
|
|
13
|
-
**npm**
|
|
14
24
|
```bash
|
|
15
25
|
npm install ofx-data-extractor
|
|
16
26
|
```
|
|
17
|
-
|
|
27
|
+
|
|
18
28
|
```bash
|
|
19
29
|
yarn add ofx-data-extractor
|
|
20
30
|
```
|
|
21
31
|
|
|
22
|
-
|
|
23
|
-
The `Ofx` class provides the following methods:
|
|
32
|
+
## Quick Start
|
|
24
33
|
|
|
25
|
-
|
|
26
|
-
- `fromBuffer(data: Buffer)`: Used to read files on the node. Returns the methods
|
|
27
|
-
- `fromBlob(data: Blob)`: Used to read files in the browser. Returns the methods below.
|
|
28
|
-
- `config(options: OfxConfig)`: Used for formatting the generated json.`
|
|
29
|
-
- `getHeaders(): OFXMetaData`: Returns the metadata section of the OFX file as an object.
|
|
30
|
-
- `getBankTransferList(): Pick<BankTransferList, 'STRTTRN'>`: Returns a list of bank transfer transactions as an object.
|
|
31
|
-
- `getCreditCardTransferList(): Pick<BankTransferList, 'STRTTRN'>`: Returns a list of credit card transactions as an object.
|
|
32
|
-
- `getTransactionsSummary()`: Object: Returns a summary of transactions for a bank statement as an object.
|
|
33
|
-
- `getContent(): OfxStructure`: Returns the OFX file content as an object.
|
|
34
|
-
- `toJson(): OfxResponse`: Returns the entire OFX file content as a JSON object.
|
|
35
|
-
|
|
36
|
-
### Usage
|
|
37
|
-
The module provides a class called Ofx that can be used to extract and format data from an `OFX` file. Here's an example of how to use it:
|
|
38
|
-
|
|
39
|
-
```typescript
|
|
34
|
+
```ts
|
|
40
35
|
import { Ofx } from 'ofx-data-extractor'
|
|
41
36
|
|
|
42
37
|
const data = 'OFXHEADER:100\nDATA:OFXSGML\nVERSION:102\n...'
|
|
43
|
-
const ofx = new Ofx(data)
|
|
38
|
+
const ofx = new Ofx(data)
|
|
44
39
|
|
|
45
|
-
const
|
|
46
|
-
|
|
40
|
+
const raw = ofx.toJson()
|
|
41
|
+
const summary = ofx.getTransactionsSummary()
|
|
42
|
+
const normalized = ofx.toNormalized()
|
|
43
|
+
const validation = ofx.validate()
|
|
44
|
+
```
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
console.log(transactionsSummary)
|
|
46
|
+
## Node.js
|
|
50
47
|
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
```ts
|
|
49
|
+
import fs from 'fs'
|
|
50
|
+
import { Ofx } from 'ofx-data-extractor'
|
|
53
51
|
|
|
54
|
-
const
|
|
55
|
-
|
|
52
|
+
const file = fs.readFileSync('/path/to/file.ofx')
|
|
53
|
+
const ofx = Ofx.fromBuffer(file)
|
|
54
|
+
console.log(ofx.getTransactionsSummary())
|
|
56
55
|
```
|
|
57
|
-
### Constructor
|
|
58
|
-
The `Ofx` class constructor takes in two arguments:
|
|
59
56
|
|
|
60
|
-
|
|
61
|
-
`config`: Optional configuration options for formatting the OFX data.
|
|
57
|
+
## Browser (`fromBlob` is async)
|
|
62
58
|
|
|
63
|
-
|
|
64
|
-
```typescript
|
|
59
|
+
```ts
|
|
65
60
|
import { Ofx } from 'ofx-data-extractor'
|
|
66
|
-
import fs from 'fs'
|
|
67
61
|
|
|
68
|
-
|
|
69
|
-
const
|
|
62
|
+
async function handleFile(event: Event) {
|
|
63
|
+
const input = event.target as HTMLInputElement
|
|
64
|
+
const file = input.files?.[0]
|
|
65
|
+
if (!file) return
|
|
70
66
|
|
|
71
|
-
const
|
|
72
|
-
console.log(
|
|
67
|
+
const ofx = await Ofx.fromBlob(file)
|
|
68
|
+
console.log(ofx.toJson())
|
|
69
|
+
}
|
|
73
70
|
```
|
|
74
71
|
|
|
75
|
-
|
|
76
|
-
```typescript
|
|
77
|
-
import { Ofx } from 'ofx-data-extractor'
|
|
72
|
+
## Main Public API (`Ofx`)
|
|
78
73
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
74
|
+
- `new Ofx(data: string, config?: ExtractorConfig)`
|
|
75
|
+
- `Ofx.fromBuffer(buffer: Buffer)`
|
|
76
|
+
- `Ofx.fromBlob(blob: Blob)`
|
|
77
|
+
- `config(options)`
|
|
78
|
+
- `getType()`
|
|
79
|
+
- `getHeaders()`
|
|
80
|
+
- `getBankTransferList()`
|
|
81
|
+
- `getCreditCardTransferList()`
|
|
82
|
+
- `getTransactionsSummary()`
|
|
83
|
+
- `getContent()`
|
|
84
|
+
- `toJson()`
|
|
85
|
+
- `toNormalized(options?)`
|
|
86
|
+
- `validate()`
|
|
87
|
+
- `getWarnings()`
|
|
84
88
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
89
|
+
## Configuration (Extract)
|
|
90
|
+
|
|
91
|
+
- `nativeTypes?: boolean`
|
|
92
|
+
- `fitId?: 'normal' | 'separated'`
|
|
93
|
+
- `formatDate?: string`
|
|
94
|
+
- `parserMode?: 'strict' | 'lenient'`
|
|
95
|
+
|
|
96
|
+
Parsing guarantees:
|
|
97
|
+
|
|
98
|
+
- OFX 1.x (SGML) and 2.x (XML) are supported, including bodies without line breaks.
|
|
99
|
+
- Character entities (`&`, `<`, `>`, `"`, `'`, numeric references) are decoded in text values.
|
|
100
|
+
- `toNormalized({ dateMode })` keeps the full `DT*` value (including time) for `raw`, `iso`, `date` and `timestamp`.
|
|
101
|
+
|
|
102
|
+
Parser mode:
|
|
103
|
+
|
|
104
|
+
- `strict` (default): parsing errors throw.
|
|
105
|
+
- `lenient`: parsing errors fallback and are collected via `getWarnings()`.
|
|
106
|
+
|
|
107
|
+
## Developer Documentation
|
|
108
|
+
|
|
109
|
+
- [API Reference](docs/api.md)
|
|
110
|
+
- [Normalization Guide](docs/normalization.md)
|
|
111
|
+
- [Validation Guide](docs/validation.md)
|
|
112
|
+
- [Recipes](docs/recipes.md)
|
|
113
|
+
- [Migration Guide](docs/migration.md)
|
|
114
|
+
|
|
115
|
+
## Examples
|
|
88
116
|
|
|
117
|
+
- [Node basic](examples/node-basic.ts)
|
|
118
|
+
- [Browser basic](examples/browser-basic.ts)
|
|
119
|
+
- [Normalize + validate](examples/normalize-and-validate.ts)
|
|
89
120
|
|
|
90
|
-
|
|
91
|
-
The `Ofx` (`constructor` and `config` method) class can be configured with the following options:
|
|
121
|
+
## License
|
|
92
122
|
|
|
93
|
-
|
|
94
|
-
- `fitId`: A string that determines how the financial institution transaction ID is handled. Possible values are "separated" (the default) or "included".
|
|
95
|
-
- `nativeTypes`: A boolean value that determines whether numeric fields should be represented as numbers or strings in the resulting JSON object.
|
|
123
|
+
MIT
|
|
96
124
|
|
|
97
125
|
[license-image]: https://img.shields.io/badge/license-MIT-blue.svg?style=flat
|
|
98
126
|
[license-url]: LICENSE
|
package/dist/@types/common.d.ts
CHANGED
|
@@ -35,9 +35,13 @@ export type ConfigDate = {
|
|
|
35
35
|
formatDate?: string;
|
|
36
36
|
};
|
|
37
37
|
export type ConfigFitId = 'normal' | 'separated';
|
|
38
|
+
export type ParserMode = 'strict' | 'lenient';
|
|
39
|
+
export type AmountMode = 'string' | 'number' | 'cents';
|
|
40
|
+
export type DateMode = 'raw' | 'formatted' | 'iso' | 'date' | 'timestamp';
|
|
38
41
|
export type ExtractorConfig = ConfigDate & {
|
|
39
42
|
fitId?: ConfigFitId;
|
|
40
43
|
nativeTypes?: boolean;
|
|
44
|
+
parserMode?: ParserMode;
|
|
41
45
|
};
|
|
42
46
|
export type TransactionsSummary = {
|
|
43
47
|
credit: number;
|
|
@@ -51,3 +55,47 @@ export declare enum Types {
|
|
|
51
55
|
'BANK' = "BANK",
|
|
52
56
|
'CREDIT_CARD' = "CREDIT_CARD"
|
|
53
57
|
}
|
|
58
|
+
export type OfxSeverity = 'warning' | 'error';
|
|
59
|
+
export type OfxDiagnostic = {
|
|
60
|
+
code: string;
|
|
61
|
+
message: string;
|
|
62
|
+
severity: OfxSeverity;
|
|
63
|
+
path?: string;
|
|
64
|
+
context?: string;
|
|
65
|
+
};
|
|
66
|
+
export type ValidationStats = {
|
|
67
|
+
totalTransactions: number;
|
|
68
|
+
bankTransactions: number;
|
|
69
|
+
creditCardTransactions: number;
|
|
70
|
+
duplicatedFitIds: number;
|
|
71
|
+
};
|
|
72
|
+
export type ValidationReport = {
|
|
73
|
+
isValid: boolean;
|
|
74
|
+
warnings: OfxDiagnostic[];
|
|
75
|
+
errors: OfxDiagnostic[];
|
|
76
|
+
stats: ValidationStats;
|
|
77
|
+
};
|
|
78
|
+
export type NormalizeOptions = ConfigDate & {
|
|
79
|
+
amountMode?: AmountMode;
|
|
80
|
+
dateMode?: DateMode;
|
|
81
|
+
};
|
|
82
|
+
export type NormalizedDirection = 'credit' | 'debit';
|
|
83
|
+
export type NormalizedTransaction = {
|
|
84
|
+
source: 'bank' | 'credit_card';
|
|
85
|
+
direction: NormalizedDirection;
|
|
86
|
+
amount: number | string | null;
|
|
87
|
+
amountAbs: number | string | null;
|
|
88
|
+
postedAt: string | number | Date | null;
|
|
89
|
+
description: string;
|
|
90
|
+
descriptionNormalized: string;
|
|
91
|
+
fitId: string;
|
|
92
|
+
currency: string | null;
|
|
93
|
+
account: Record<string, any> | null;
|
|
94
|
+
institution: Record<string, any> | null;
|
|
95
|
+
raw: Record<string, any>;
|
|
96
|
+
warnings: OfxDiagnostic[];
|
|
97
|
+
};
|
|
98
|
+
export type NormalizedOfxData = {
|
|
99
|
+
transactions: NormalizedTransaction[];
|
|
100
|
+
warnings: OfxDiagnostic[];
|
|
101
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { NormalizedOfxData, NormalizeOptions, ValidationReport } from '../@types/common';
|
|
2
|
+
import { OfxResponse } from '../@types/ofx/index';
|
|
3
|
+
export declare function normalizeOfxData(data: OfxResponse, options?: NormalizeOptions): NormalizedOfxData;
|
|
4
|
+
export declare function validateOfxData(data: OfxResponse): ValidationReport;
|
package/dist/common/config.d.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import { ExtractorConfig } from '../@types/common';
|
|
2
2
|
export declare class Config {
|
|
3
3
|
private readonly config;
|
|
4
|
+
private readonly rawDates;
|
|
4
5
|
private internConfig;
|
|
5
|
-
|
|
6
|
+
private readonly sanitizeConfig;
|
|
7
|
+
/**
|
|
8
|
+
* @param rawDates internal: keep `DT*` values exactly as they appear in the
|
|
9
|
+
* OFX instead of applying `formatDate` (used by `toNormalized`).
|
|
10
|
+
*/
|
|
11
|
+
constructor(config: ExtractorConfig, rawDates?: boolean);
|
|
6
12
|
getConfig(): ExtractorConfig;
|
|
13
|
+
withRawDates(): Config;
|
|
7
14
|
sanitizeRow(row: string): string;
|
|
8
15
|
getPartialJsonData(data: string): string;
|
|
9
16
|
}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
export declare const ELEMENT_CLOSURE_REGEX: RegExp;
|
|
2
2
|
export declare const ELEMENT_OPENING_REGEX: RegExp;
|
|
3
|
+
/**
|
|
4
|
+
* `<LEAF>value</OTHER>`: an unclosed SGML leaf immediately followed by the
|
|
5
|
+
* closing tag of its parent container (OFX 1.x allows this without line breaks).
|
|
6
|
+
*/
|
|
7
|
+
export declare const SGML_LEAF_FOLLOWED_BY_CLOSURE_REGEX: RegExp;
|
|
3
8
|
export declare const BANK_SERVICE_START = "<BANKMSGSRSV1>";
|
|
4
9
|
export declare const BANK_SERVICE_END = "</BANKMSGSRSV1>";
|
|
5
10
|
export declare const CREDIT_CARD_SERVICE_START = "<CREDITCARDMSGSRSV1>";
|
|
@@ -7,6 +12,12 @@ export declare const CREDIT_CARD_SERVICE_END = "</CREDITCARDMSGSRSV1>";
|
|
|
7
12
|
export declare const START_STATEMENT_TRANSACION = "<STMTTRN>";
|
|
8
13
|
export declare const FINISH_STATEMENT_TRANSACTION = "</STMTTRN>";
|
|
9
14
|
export declare const QUOTE_PATTERN = "_#_";
|
|
15
|
+
/**
|
|
16
|
+
* Text values may contain characters the parser uses as structure (`{ } [ ]`).
|
|
17
|
+
* They are swapped for these tokens while the text is rewritten as JSON and
|
|
18
|
+
* restored once it has been parsed (same idea as `QUOTE_PATTERN`).
|
|
19
|
+
*/
|
|
20
|
+
export declare const STRUCTURAL_CHAR_TOKENS: Readonly<Record<string, string>>;
|
|
10
21
|
export declare const QUOTE_PATTERN_REGEX: RegExp;
|
|
11
22
|
export declare const OPENING_TAGS_INITIALLY_IGNORED: string[];
|
|
12
23
|
export declare const CLOSING_TAGS_INITIALLY_IGNORED: string[];
|
package/dist/common/date.d.ts
CHANGED
|
@@ -1 +1,14 @@
|
|
|
1
1
|
export declare function formatDate(date: string, format: string): string;
|
|
2
|
+
export declare function formatDateFromUtcDate(date: Date, format: string): string;
|
|
3
|
+
type ParsedDateParts = {
|
|
4
|
+
year: number;
|
|
5
|
+
month: number;
|
|
6
|
+
day: number;
|
|
7
|
+
hour: number;
|
|
8
|
+
minutes: number;
|
|
9
|
+
seconds: number;
|
|
10
|
+
};
|
|
11
|
+
export declare function parseDateParts(date: string): ParsedDateParts | null;
|
|
12
|
+
export declare function isValidParsedDate(parts: ParsedDateParts): boolean;
|
|
13
|
+
export declare function parseDateToUtc(date: string): Date | null;
|
|
14
|
+
export {};
|
package/dist/common/parse.d.ts
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import { ExtractorConfig } from '../@types/common';
|
|
2
2
|
import type { StatementTransaction } from '../@types/ofx/common';
|
|
3
3
|
export declare function fixJsonProblems(content: string): string;
|
|
4
|
+
export declare function protectStructuralChars(value: string): string;
|
|
5
|
+
export declare function restoreStructuralChars(value: string): string;
|
|
6
|
+
/** Protects `{ } [ ]` inside text nodes (what follows `>` up to the next `<`). */
|
|
7
|
+
export declare function protectTextNodes(content: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Decodes the XML/SGML character entities OFX allows in text fields.
|
|
10
|
+
* Single pass (`&lt;` -> `<`); unknown or invalid entities are kept as-is.
|
|
11
|
+
*/
|
|
12
|
+
export declare function decodeEntities(value: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Parses the JSON built from the OFX text, decoding entities only in values
|
|
15
|
+
* (after parsing, so decoded text can never be mistaken for tags or JSON).
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseOfxJson(text: string): any;
|
|
4
18
|
export declare const extractFinancialInstitutionTransactionId: (fitid: string) => string;
|
|
5
19
|
export declare const isDateField: (field: string) => boolean;
|
|
6
20
|
export declare const trim: (str: string) => string;
|
|
@@ -14,7 +28,10 @@ type GetDateParams = Pick<ExtractorConfig, 'formatDate'> & {
|
|
|
14
28
|
dateString: string;
|
|
15
29
|
};
|
|
16
30
|
export declare function getConfiguredDate({ dateString, formatDate: format, }: GetDateParams): string;
|
|
17
|
-
export declare function
|
|
31
|
+
export declare function applyConfiguredDates(transaction: unknown, format?: string): void;
|
|
32
|
+
export declare function sanitize(row: string, config: ExtractorConfig & {
|
|
33
|
+
rawDates?: boolean;
|
|
34
|
+
}): string;
|
|
18
35
|
export declare function isValidNumberToConvert(field: string, value: string): boolean;
|
|
19
36
|
export declare function parseTransactions(content: string): {
|
|
20
37
|
oldListText: string;
|
package/dist/common/reader.d.ts
CHANGED
package/dist/esm/index.min.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
"`).replace(/[>]/g,'":{')}function A(e,t=!1){return b.includes(e)&&!t?`
|
|
1
|
+
const U=/<\/[\w.]+>/g,v=/<[\w.]+>/g,nt=/<([\w.]+)>([^<]*)<\/([\w.]+)>/g,T="<BANKMSGSRSV1>",m="</BANKMSGSRSV1>",S="<CREDITCARDMSGSRSV1>",p="</CREDITCARDMSGSRSV1>",b="<STMTTRN>",h="</STMTTRN>";const A={"{":"_#LB#_","}":"_#RB#_","[":"_#LS#_","]":"_#RS#_"},rt=new RegExp("_#_","g"),st=[T,b,S],at=[m,p,h];function it(e){const t=e.slice(0,4),n=e.slice(4,6),r=e.slice(6,8),s=e.slice(8,10),a=e.slice(10,12),i=e.slice(12,14);return{yyyy:t,yy:t.slice(2),y:t,MM:n,M:n,dd:r,d:r,hh:s,h:s,mm:a,m:a,ss:i,s:i}}function P(e,t){const n=["yyyy","yy","y","MM","M","dd","d","hh","h","mm","m","ss","s"];let r=e;for(const s of n)r=r.replace(s,t[s]);return r}function ot(e,t){const n=it(e);return P(t,n)}function ct(e,t){const n=String(e.getUTCFullYear()),r=String(e.getUTCMonth()+1).padStart(2,"0"),s=String(e.getUTCDate()).padStart(2,"0"),a=String(e.getUTCHours()).padStart(2,"0"),i=String(e.getUTCMinutes()).padStart(2,"0"),o=String(e.getUTCSeconds()).padStart(2,"0");return P(t,{yyyy:n,yy:n.slice(2),y:n,MM:r,M:r,dd:s,d:s,hh:a,h:a,mm:i,m:i,ss:o,s:o})}function ut(e){return e%400===0?!0:e%100===0?!1:e%4===0}function ft(e,t){return e===2?ut(t)?29:28:[4,6,9,11].includes(e)?30:31}function lt(e){if(!/^\d{4}-\d{2}-\d{2}$/.test(e))return null;const[t,n,r]=e.split("-").map(Number);return{year:t,month:n,day:r,hour:0,minutes:0,seconds:0}}function dt(e){if(!/^\d{4}-\d{2}-\d{2}T/.test(e))return null;const t=e.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):?(\d{2})(?::?(\d{2}))?(?:\.\d+)?(?:([+-]\d{2}):?(\d{2})|Z)?$/);if(!t)return null;const n=Number(t[1]),r=Number(t[2]),s=Number(t[3]),a=Number(t[4]),i=Number(t[5]),o=Number(t[6]||"0");if(!$({year:n,month:r,day:s,hour:a,minutes:i,seconds:o}))return null;const f=Number(t[7]||"0"),g=Number(t[8]||"0"),d=f<0?f*60-g:f*60+g,u=new Date(Date.UTC(n,r-1,s,a,i,o)-d*6e4);return Number.isNaN(u.getTime())?null:{year:u.getUTCFullYear(),month:u.getUTCMonth()+1,day:u.getUTCDate(),hour:u.getUTCHours(),minutes:u.getUTCMinutes(),seconds:u.getUTCSeconds()}}function gt(e){const n=e.split("[")[0].split(".")[0];return/^\d{8}(\d{6})?$/.test(n)?{year:Number(n.slice(0,4)),month:Number(n.slice(4,6)),day:Number(n.slice(6,8)),hour:Number(n.slice(8,10)||"00"),minutes:Number(n.slice(10,12)||"00"),seconds:Number(n.slice(12,14)||"00")}:null}function Tt(e){const t=e.match(/^(\d{1,4})[/-](\d{1,2})[/-](\d{1,4})$/);if(!t)return null;const n=Number(t[1]),r=Number(t[2]),s=Number(t[3]),a=String(t[1]).length===4,i=String(t[3]).length===4;return!a&&!i?null:{year:a?n:s,month:r,day:a?s:n,hour:0,minutes:0,seconds:0}}function ht(e){return lt(e)||dt(e)||Tt(e)||gt(e)}function $(e){return!(!Number.isFinite(e.year)||!Number.isFinite(e.month)||!Number.isFinite(e.day)||!Number.isFinite(e.hour)||!Number.isFinite(e.minutes)||!Number.isFinite(e.seconds)||e.month<1||e.month>12||e.day<1||e.day>ft(e.month,e.year)||e.hour<0||e.hour>23||e.minutes<0||e.minutes>59||e.seconds<0||e.seconds>59)}function R(e){const t=ht(e);return!t||!$(t)?null:new Date(Date.UTC(t.year,t.month-1,t.day,t.hour,t.minutes,t.seconds))}var C;(function(e){e.BANK="BANK",e.CREDIT_CARD="CREDIT_CARD"})(C||(C={}));const mt=["debit","fee","srvchg","atm","pos","check","payment","directdebit","cash","repeatpmt"],St=e=>e.includes(T)?C.BANK:C.CREDIT_CARD;function G(e){if(String(e.TRNAMT).startsWith("-"))return!0;const t=String(e.TRNTYPE).toLocaleLowerCase();return t==="1"||mt.includes(t)}function E(e){const t=e.replace(/(\\)/g,"\\\\").replace(U,n=>J(n,!0)).replace(v,n=>W(n,!0)).replace(/(},})/g,"}}").replace(/(}")/g,'},"').replace(/(]")/g,'],"').replace(/(},])/g,"}]").replace(/(,})/g,"}").replace(/,\s*}/g,"}").replace(/(,",)/,'",').replace(rt,'\\"').slice(0,-1);return t.endsWith(",")?t.slice(0,-1):t}const pt=Object.keys(A).reduce((e,t)=>({...e,[A[t]]:t}),{});function N(e){return e.replace(/[{}\[\]]/g,t=>A[t])}function K(e){return e.replace(/_#(?:LB|RB|LS|RS)#_/g,t=>pt[t])}function Rt(e){return e.replace(/>([^<]+)/g,(t,n)=>`>${N(n)}`)}const Ct={amp:"&",lt:"<",gt:">",quot:'"',apos:"'"};function Nt(e){return e.indexOf("&")<0?e:e.replace(/&(?:(amp|lt|gt|quot|apos)|#(\d{1,7})|#[xX]([0-9a-fA-F]{1,6}));/g,(t,n,r,s)=>{if(n)return Ct[n];const a=r?Number(r):parseInt(s,16);return a<1||a>1114111||a>=55296&&a<=57343?t:String.fromCodePoint(a)})}function y(e){return JSON.parse(e,(t,n)=>typeof n=="string"?Nt(K(n)):n)}const Dt=e=>JSON.stringify({date:e.slice(0,12),transactionCode:e.slice(12,19),protocol:e.slice(19)}),X=e=>e.startsWith("DT"),z=e=>e.trim();function W(e,t=!1){return st.includes(e)&&!t?e:e.replace(/[<]/g,`
|
|
2
|
+
"`).replace(/[>]/g,'":{')}function J(e,t=!1){return at.includes(e)&&!t?`
|
|
4
3
|
${e}`:`},
|
|
5
|
-
`}function
|
|
6
|
-
`,"").toUpperCase();n[i]=t&&
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
`).
|
|
4
|
+
`}function It({fitId:e,fitValue:t}){if(e==="separated"){const n=JSON.parse(Dt(t));return JSON.stringify(Object.keys(n).reduce((r,s)=>({...r,[s]:N(n[s])}),{}))}return`"${N(t)}",`}function Et(e){return e.search(",")>e.search(".")?e.replace(/[.]/g,"").replace(/[,]/g,"."):e.replace(/[,]/g,"")}function D({dateString:e,formatDate:t="y-M-d"}){return!/^\d{8}(\d{6})?(\.\d+)?(\[[^\]]+\])?$/.test(e)||!R(e)?e:ot(e,t)}function yt(e,t){if(!e||typeof e!="object")return;const n=e;for(const r of Object.keys(n)){const s=n[r];X(r)&&typeof s=="string"&&(n[r]=D({dateString:s,formatDate:t}))}}function bt(e){let t=K(e.value.replace(/[{]/g,"").replace(/(},)/g,"")).replace(/["]/g,"_#_");const n=e.field.replace(/['"]/g,"");return n.endsWith("AMT")&&(t=Et(t)),X(n)&&!e.rawDates&&(t=D({dateString:t,formatDate:e.formatDate})),n==="FITID"?It({fitId:e.fitId,fitValue:t}):e.nativeTypes&&H(n,t)?`${Number(t)},`:`"${N(t)}",`}function At(e,t){let n=e;return e.match(/{(\w|\W)+/)&&(n=n.replace(/({(\w|\W)+)$/,r=>bt({field:n.slice(0,n.indexOf(":")),value:r,...t}))),n}function H(e,t){return e.endsWith("ID")||e.endsWith("NUM")?!1:!isNaN(Number(t))}function V(e){const t=e.indexOf(b),n=e.lastIndexOf(h)+h.length;if(t<0||n<0||t>=n)return{oldListText:e,newListText:e};const r=e.substring(t,n),s=new RegExp(b,"g"),a=new RegExp(h,"g"),i=`"STRTTRN":[${r.replace(s,"{").replace(a,"},")}]`;return{oldListText:e,newListText:e.replace(r,i)}}function L(e){if(!(e.indexOf(T)>0))return{newBankStatementTransactions:null,oldBankStatementTransactions:null};const n=V(e.substring(e.indexOf(T),e.indexOf(m)+m.length));return{newBankStatementTransactions:n.newListText,oldBankStatementTransactions:n.oldListText}}function F(e){if(!(e.indexOf(S)>0))return{newCreditCardStatementTransactions:null,oldCreditCardStatementTransactions:null};const n=e.substring(e.indexOf(S),e.indexOf(p)+p.length),r=V(n);return{newCreditCardStatementTransactions:r.newListText,oldCreditCardStatementTransactions:r.oldListText}}function Ot(e){const t=[];for(const n of e)t.push(...n.replace("<?xml"," ").replace("<?OFX"," ").replace("?>"," ").split(" ").filter(Boolean).map(z).map(r=>r.replace("=",":").replace(/["]/g,"")));return t}function wt(e,t){const n={};e.join("").search("<?")>-1&&(e=Ot(e));for(const r of e){const[s,a]=r.split(":"),i=s.replace(`
|
|
5
|
+
`,"").toUpperCase();n[i]=t&&H(s,a)?Number(a):String(a).replace(/\?>/,"")}return n}function Mt(e){return e.reduce((t,n)=>{const r=Math.abs(+n.TRNAMT);return G(n)?(t.amountOfDebits++,t.debit+=r,t):(t.amountOfCredits++,t.credit+=r,t)},{credit:0,debit:0,amountOfCredits:0,amountOfDebits:0})}class w{config;rawDates;internConfig={};sanitizeConfig;constructor(t,n=!1){this.config=t,this.rawDates=n,this.internConfig=t,this.sanitizeConfig={...t,rawDates:n}}getConfig(){return this.internConfig}withRawDates(){return new w(this.config,!0)}sanitizeRow(t){return At(t,this.sanitizeConfig)}getPartialJsonData(t){const[n,r]=t.split("<OFX>"),s=Rt("<OFX>"+r),{sanitizeRow:a}=this;return s.replace(nt,(i,o,c,f)=>o===f?i:`<${o}>${c}
|
|
6
|
+
</${f}>`).replace(/<(?=[^\/])/g,`
|
|
7
|
+
<`).replace(U,i=>J(i)).replace(v,i=>W(i)).split(`
|
|
8
|
+
`).map(z).filter(Boolean).map(a,this).join("")}}function B(e){return e.toString()}async function k(e){return await new Promise((n,r)=>{if(typeof window<"u"&&window.FileReader){const s=new window.FileReader;s.onload=a=>n(a.target.result),s.onerror=a=>r(a.target.error),s.readAsText(e)}else r(new Error("FileReader is not available in this environment."))})}class l{data;dataRead="";constructor(t){this.data=t,t&&(this.dataRead=t)}getData(){return this.dataRead}fromString(t){return new l(t)}fromBuffer(t){return new l(B(t))}async fromBlob(t){return new l(await k(t))}static fromString(t){return new l(t)}static fromBuffer(t){return new l(B(t))}static async fromBlob(t){return new l(await k(t))}}class xt{configInstance={}}class Y extends xt{setConfig(t){this.configInstance=t}getBankTransferList(t){const{newBankStatementTransactions:n}=L(this.configInstance.getPartialJsonData(t));return n?y(`{${E(n)}}`)?.BANKMSGSRSV1?.STMTTRNRS?.STMTRS?.BANKTRANLIST?.STRTTRN:[]}getCreditCardTransferList(t){const{newCreditCardStatementTransactions:n}=F(this.configInstance.getPartialJsonData(t));return n?y(`{${E(n)}}`)?.CREDITCARDMSGSRSV1?.CCSTMTTRNRS?.CCSTMTRS?.BANKTRANLIST?.STRTTRN:[]}getTransactionsSummary(t){let n=[],r=[];const s=this.configInstance?.getConfig?.().parserMode||"strict";let a=null,i=null;try{n=this.getBankTransferList(t)||[]}catch(I){a=I,n=[]}try{r=this.getCreditCardTransferList(t)||[]}catch(I){i=I,r=[]}const o=t.includes("<STMTTRN>");if(s==="strict"&&a&&i&&o)throw a;const c=n.length?n:r,f=n.length?T:S,g=n.length?m:p,d=t.indexOf(f),u=t.indexOf(g),M=d>=0&&u>d?t.slice(d,u+g.length):"",x=M.match(/<DTSTART>([^\n<]+)/),_=M.match(/<DTEND>([^\n<]+)/),Z=Mt(c||[]),tt=x?.[1]?D({dateString:x[1],formatDate:this.configInstance.getConfig().formatDate}):"",et=_?.[1]?D({dateString:_[1],formatDate:this.configInstance.getConfig().formatDate}):"";return{dateStart:tt,dateEnd:et,...Z}}getContent(t){const n=this.configInstance.getPartialJsonData(t),{newBankStatementTransactions:r,oldBankStatementTransactions:s}=L(n),{newCreditCardStatementTransactions:a,oldCreditCardStatementTransactions:i}=F(n);let o=n;return r&&(o=o.replace(s,r)),a&&(o=o.replace(i,a)),y(`{${E(o)}}`)}}const _t="y-M-d";function j(e){if(e==null)return"";if(typeof e=="string"||typeof e=="number")return String(e);if(typeof e=="object"){const t=e;if(t.date!==void 0&&t.transactionCode!==void 0&&t.protocol!==void 0)return`${t.date}${t.transactionCode}${t.protocol}`;try{return JSON.stringify(e)}catch{return String(e)}}return String(e)}function Q(e){if(e==null)return null;const t=Number(String(e).replace(/,/g,"."));return Number.isNaN(t)?null:t}function Lt(e){return e.normalize("NFD").replace(/[\u0300-\u036f]/g,"").replace(/\s+/g," ").trim().toLowerCase()}function Ft(e,t){const n=t.dateMode||"formatted";if(!e)return{value:null,warning:{code:"MISSING_DATE",message:"Transaction does not include DTPOSTED.",severity:"warning"}};if(n==="raw"||n==="formatted"){const s=R(e);return s?n==="formatted"?{value:ct(s,t.formatDate||_t)}:{value:e}:{value:e,warning:{code:"INVALID_DATE",message:`Unable to parse date '${e}'.`,severity:"warning"}}}const r=R(e);return r?n==="date"?{value:r}:n==="timestamp"?{value:r.getTime()}:{value:r.toISOString()}:{value:null,warning:{code:"INVALID_DATE",message:`Unable to parse date '${e}'.`,severity:"warning"}}}function Bt(e,t){const n=Q(e);return n===null?{amount:null,amountAbs:null,warning:{code:"INVALID_AMOUNT",message:`Unable to parse amount '${String(e)}'.`,severity:"warning"}}:t==="string"?{amount:String(e),amountAbs:String(Math.abs(n))}:t==="cents"?{amount:Math.round(n*100),amountAbs:Math.round(Math.abs(n)*100)}:{amount:n,amountAbs:Math.abs(n)}}function q(e){const t=[],n=e?.OFX?.SIGNONMSGSRSV1?.SONRS?.FI||null,r=e?.OFX?.BANKMSGSRSV1?.STMTTRNRS?.STMTRS;(r?.BANKTRANLIST?.STRTTRN||r?.BANKTRANLIST?.STMTTRN||[]).forEach((o,c)=>{t.push({source:"bank",transaction:o,currency:r?.CURDEF||null,account:r?.BANKACCTFROM||null,institution:n,path:`OFX.BANKMSGSRSV1.STMTTRNRS.STMTRS.BANKTRANLIST.${c}`})});const a=e?.OFX?.CREDITCARDMSGSRSV1?.CCSTMTTRNRS?.CCSTMTRS;return(a?.BANKTRANLIST?.STRTTRN||a?.BANKTRANLIST?.STMTTRN||[]).forEach((o,c)=>{t.push({source:"credit_card",transaction:o,currency:a?.CURDEF||null,account:a?.CCACCTFROM||null,institution:n,path:`OFX.CREDITCARDMSGSRSV1.CCSTMTTRNRS.CCSTMTRS.BANKTRANLIST.${c}`})}),t}function kt(e,t={}){const n=t.amountMode||"number",r=[],s=[];return q(e).forEach(i=>{const o=[],c=String(i.transaction.MEMO||i.transaction.NAME||i.transaction.TRNTYPE||"").trim(),{amount:f,amountAbs:g,warning:d}=Bt(i.transaction.TRNAMT,n);d&&(d.path=i.path,o.push(d),r.push(d));const u=Ft(i.transaction.DTPOSTED,t);u.warning&&(u.warning.path=i.path,o.push(u.warning),r.push(u.warning)),s.push({source:i.source,direction:G(i.transaction)?"debit":"credit",amount:f,amountAbs:g,postedAt:u.value,description:c,descriptionNormalized:Lt(c),fitId:j(i.transaction.FITID),currency:i.currency,account:i.account,institution:i.institution,raw:i.transaction,warnings:o})}),{transactions:s,warnings:r}}function Ut(e){const t=[],n=[],r=q(e);e?.OFX||n.push({code:"MISSING_OFX_BLOCK",message:"Missing OFX root block.",severity:"error",path:"OFX"}),r.length||t.push({code:"NO_TRANSACTIONS_FOUND",message:"No transactions were found in bank or credit card statements.",severity:"warning",path:"OFX"});const s=new Map;r.forEach(c=>{const f=j(c.transaction.FITID);f?s.set(f,(s.get(f)||0)+1):t.push({code:"MISSING_FITID",message:"Transaction does not include FITID.",severity:"warning",path:c.path}),Q(c.transaction.TRNAMT)===null&&n.push({code:"INVALID_AMOUNT",message:`Invalid amount '${String(c.transaction.TRNAMT)}'.`,severity:"error",path:c.path}),R(String(c.transaction.DTPOSTED||""))||t.push({code:"INVALID_DATE",message:`Invalid DTPOSTED '${String(c.transaction.DTPOSTED||"")}'.`,severity:"warning",path:c.path})});const a=Array.from(s.values()).filter(c=>c>1).length;a>0&&t.push({code:"DUPLICATED_FITID",message:`Found ${a} duplicated FITID values.`,severity:"warning",path:"OFX"});const i=r.filter(c=>c.source==="bank").length,o=r.filter(c=>c.source==="credit_card").length;return{isValid:n.length===0,warnings:t,errors:n,stats:{totalTransactions:r.length,bankTransactions:i,creditCardTransactions:o,duplicatedFitIds:a}}}class vt{customExtractor;customExtractorInstance;dataReaderInstance=new l("");diagnostics=[];constructor(t){this.customExtractor=t,this.customExtractorInstance=t||new Y,this.config({})}data(t){return this.dataReaderInstance=t,this}config(t){return this.customExtractorInstance.setConfig(new w(t)),this}getType(){return St(this.dataReaderInstance.getData())}beginOperation(){this.diagnostics=[]}getParserMode(){return this.customExtractorInstance.configInstance.getConfig().parserMode}pushWarning(t){this.diagnostics.push(t)}safelyExecute(t,n,r){try{return r()}catch(s){if(this.getParserMode()!=="lenient")throw s;return this.pushWarning({code:"PARSE_ERROR",message:`Failed to parse OFX while running '${t}'.`,severity:"warning",context:s instanceof Error?s.message:String(s),path:t}),n}}getHeadersInternal(){return this.safelyExecute("getHeaders",{},()=>{const[t]=this.dataReaderInstance.getData().split("<OFX>");return wt(String(t).split(`
|
|
9
|
+
`).filter(n=>!!n.trim().length),!!this.customExtractorInstance.configInstance.getConfig().nativeTypes)})}getContentInternal(){return this.safelyExecute("getContent",{OFX:{}},()=>this.customExtractorInstance.getContent(this.dataReaderInstance.getData()))}getResponseInternal(){const t=this.getHeadersInternal(),n=this.getContentInternal();return{...t,...n}}getHeaders(){return this.beginOperation(),this.getHeadersInternal()}getBankTransferList(){return this.beginOperation(),this.safelyExecute("getBankTransferList",[],()=>this.customExtractorInstance.getBankTransferList(this.dataReaderInstance.getData()))}getCreditCardTransferList(){return this.beginOperation(),this.safelyExecute("getCreditCardTransferList",[],()=>this.customExtractorInstance.getCreditCardTransferList(this.dataReaderInstance.getData()))}getTransactionsSummary(){return this.beginOperation(),this.safelyExecute("getTransactionsSummary",{credit:0,debit:0,amountOfCredits:0,amountOfDebits:0,dateStart:"",dateEnd:""},()=>this.customExtractorInstance.getTransactionsSummary(this.dataReaderInstance.getData()))}getContent(){return this.beginOperation(),this.getContentInternal()}toJson(){return this.beginOperation(),this.getResponseInternal()}getResponseWithRawDates(){const t=this.customExtractorInstance.configInstance;this.customExtractorInstance.setConfig(t.withRawDates());try{return this.getResponseInternal()}finally{this.customExtractorInstance.setConfig(t)}}toNormalized(t={}){this.beginOperation();const n=this.customExtractorInstance.configInstance.getConfig().formatDate,r=kt(this.getResponseWithRawDates(),{...t,formatDate:t.formatDate||n});return r.transactions.forEach(s=>yt(s.raw,n)),r}validate(){return this.beginOperation(),Ut(this.getResponseWithRawDates())}getWarnings(){return[...this.diagnostics]}}class O{extractor;constructor(t,n){this.extractor=new vt(new Y),this.extractor.data(new l(t)),this.extractor.config(n||{})}getType(){return this.extractor.getType()}static fromBuffer(t){return new O(l.fromBuffer(t).getData())}static async fromBlob(t){const n=await l.fromBlob(t);return new O(n.getData())}config(t){return this.extractor.config(t),this}getHeaders(){return this.extractor.getHeaders()}getBankTransferList(){return this.extractor.getBankTransferList()}getCreditCardTransferList(){return this.extractor.getCreditCardTransferList()}getTransactionsSummary(){return this.extractor.getTransactionsSummary()}getContent(){return this.extractor.getContent()}toJson(){return this.extractor.toJson()}toNormalized(t){return this.extractor.toNormalized(t)}validate(){return this.extractor.validate()}getWarnings(){return this.extractor.getWarnings()}}export{vt as Extractor,O as Ofx,Y as OfxExtractor,l as Reader,k as blobToString,B as bufferToString,E as fixJsonProblems,ot as formatDate};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ExtractorConfig, MetaData, TransactionsSummary } from '../@types/common';
|
|
1
|
+
import type { ExtractorConfig, MetaData, NormalizeOptions, NormalizedOfxData, OfxDiagnostic, TransactionsSummary, ValidationReport } from '../@types/common';
|
|
2
2
|
import { IExtractor } from '../interfaces/extractor.interface';
|
|
3
3
|
import { CustomExtractor } from '../interfaces/custom-extractor.interface';
|
|
4
4
|
import { Reader } from './reader';
|
|
@@ -8,14 +8,30 @@ export declare class Extractor<T = any> implements IExtractor<T> {
|
|
|
8
8
|
private readonly customExtractor?;
|
|
9
9
|
private customExtractorInstance;
|
|
10
10
|
private dataReaderInstance;
|
|
11
|
+
private diagnostics;
|
|
11
12
|
constructor(customExtractor?: CustomExtractor | undefined);
|
|
12
13
|
data(readData: Reader): this;
|
|
13
14
|
config(config: ExtractorConfig): this;
|
|
14
15
|
getType(): import("../@types/common").Types;
|
|
16
|
+
private beginOperation;
|
|
17
|
+
private getParserMode;
|
|
18
|
+
private pushWarning;
|
|
19
|
+
private safelyExecute;
|
|
20
|
+
private getHeadersInternal;
|
|
21
|
+
private getContentInternal;
|
|
22
|
+
private getResponseInternal;
|
|
15
23
|
getHeaders(): MetaData;
|
|
16
24
|
getBankTransferList(): StatementTransaction[];
|
|
17
25
|
getCreditCardTransferList(): StatementTransaction[];
|
|
18
26
|
getTransactionsSummary(): TransactionsSummary;
|
|
19
27
|
getContent(): OfxStructure;
|
|
20
28
|
toJson(): OfxResponse;
|
|
29
|
+
/**
|
|
30
|
+
* Runs the extraction with `DT*` fields untouched (no `formatDate`), so
|
|
31
|
+
* date-aware consumers see the full OFX value (including hh:mm:ss).
|
|
32
|
+
*/
|
|
33
|
+
private getResponseWithRawDates;
|
|
34
|
+
toNormalized(options?: NormalizeOptions): NormalizedOfxData;
|
|
35
|
+
validate(): ValidationReport;
|
|
36
|
+
getWarnings(): OfxDiagnostic[];
|
|
21
37
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,4 +9,4 @@ export type { BankTransactionList } from './@types/ofx/banking';
|
|
|
9
9
|
export { Reader } from './implementations/reader';
|
|
10
10
|
export { OfxExtractor } from './implementations/ofx-extractor';
|
|
11
11
|
export { Extractor } from './implementations/extractor';
|
|
12
|
-
export type { MetaData, ExtractorConfig, DateResponse } from './@types/common';
|
|
12
|
+
export type { MetaData, ExtractorConfig, DateResponse, ValidationReport, ValidationStats, OfxDiagnostic, NormalizeOptions, NormalizedTransaction, NormalizedOfxData, ParserMode, AmountMode, DateMode, } from './@types/common';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { OfxResponse, OfxStructure } from '../@types/ofx/index';
|
|
2
|
-
import { ExtractorConfig, MetaData, TransactionsSummary, Types } from '../@types/common';
|
|
2
|
+
import { ExtractorConfig, MetaData, NormalizeOptions, NormalizedOfxData, TransactionsSummary, Types, ValidationReport, OfxDiagnostic } from '../@types/common';
|
|
3
3
|
import type { StatementTransaction } from '../@types/ofx/common';
|
|
4
4
|
export interface IExtractor<T> {
|
|
5
5
|
getType(): Types;
|
|
@@ -10,4 +10,7 @@ export interface IExtractor<T> {
|
|
|
10
10
|
getTransactionsSummary(): TransactionsSummary;
|
|
11
11
|
getContent(): OfxStructure;
|
|
12
12
|
toJson(): OfxResponse;
|
|
13
|
+
toNormalized(options?: NormalizeOptions): NormalizedOfxData;
|
|
14
|
+
validate(): ValidationReport;
|
|
15
|
+
getWarnings(): OfxDiagnostic[];
|
|
13
16
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
import { ExtractorConfig, MetaData, NormalizeOptions, NormalizedOfxData, OfxDiagnostic, ValidationReport } from '../@types/common';
|
|
3
4
|
import { OfxResponse, OfxStructure } from '../@types/ofx/index';
|
|
4
5
|
import { StatementTransaction } from '../@types/ofx/common';
|
|
5
6
|
export declare class Ofx {
|
|
@@ -15,4 +16,7 @@ export declare class Ofx {
|
|
|
15
16
|
getTransactionsSummary(): import("../@types/common").TransactionsSummary;
|
|
16
17
|
getContent(): OfxStructure;
|
|
17
18
|
toJson(): OfxResponse;
|
|
19
|
+
toNormalized(options?: NormalizeOptions): NormalizedOfxData;
|
|
20
|
+
validate(): ValidationReport;
|
|
21
|
+
getWarnings(): OfxDiagnostic[];
|
|
18
22
|
}
|
package/dist/umd/bundle.min.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
"`).replace(/[>]/g,'":{')}function y(e,t=!1){return G.includes(e)&&!t?`
|
|
1
|
+
(function(l,h){typeof exports=="object"&&typeof module<"u"?h(exports):typeof define=="function"&&define.amd?define(["exports"],h):(l=typeof globalThis<"u"?globalThis:l||self,h(l.ofx={}))})(this,(function(l){"use strict";const h=/<\/[\w.]+>/g,B=/<[\w.]+>/g,nt=/<([\w.]+)>([^<]*)<\/([\w.]+)>/g,m="<BANKMSGSRSV1>",S="</BANKMSGSRSV1>",R="<CREDITCARDMSGSRSV1>",p="</CREDITCARDMSGSRSV1>",O="<STMTTRN>",C="</STMTTRN>",A={"{":"_#LB#_","}":"_#RB#_","[":"_#LS#_","]":"_#RS#_"},rt=new RegExp("_#_","g"),st=[m,O,R],at=[S,p,C];function it(e){const t=e.slice(0,4),n=e.slice(4,6),r=e.slice(6,8),s=e.slice(8,10),a=e.slice(10,12),i=e.slice(12,14);return{yyyy:t,yy:t.slice(2),y:t,MM:n,M:n,dd:r,d:r,hh:s,h:s,mm:a,m:a,ss:i,s:i}}function k(e,t){const n=["yyyy","yy","y","MM","M","dd","d","hh","h","mm","m","ss","s"];let r=e;for(const s of n)r=r.replace(s,t[s]);return r}function U(e,t){const n=it(e);return k(t,n)}function ot(e,t){const n=String(e.getUTCFullYear()),r=String(e.getUTCMonth()+1).padStart(2,"0"),s=String(e.getUTCDate()).padStart(2,"0"),a=String(e.getUTCHours()).padStart(2,"0"),i=String(e.getUTCMinutes()).padStart(2,"0"),o=String(e.getUTCSeconds()).padStart(2,"0");return k(t,{yyyy:n,yy:n.slice(2),y:n,MM:r,M:r,dd:s,d:s,hh:a,h:a,mm:i,m:i,ss:o,s:o})}function ct(e){return e%400===0?!0:e%100===0?!1:e%4===0}function ut(e,t){return e===2?ct(t)?29:28:[4,6,9,11].includes(e)?30:31}function ft(e){if(!/^\d{4}-\d{2}-\d{2}$/.test(e))return null;const[t,n,r]=e.split("-").map(Number);return{year:t,month:n,day:r,hour:0,minutes:0,seconds:0}}function lt(e){if(!/^\d{4}-\d{2}-\d{2}T/.test(e))return null;const t=e.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):?(\d{2})(?::?(\d{2}))?(?:\.\d+)?(?:([+-]\d{2}):?(\d{2})|Z)?$/);if(!t)return null;const n=Number(t[1]),r=Number(t[2]),s=Number(t[3]),a=Number(t[4]),i=Number(t[5]),o=Number(t[6]||"0");if(!v({year:n,month:r,day:s,hour:a,minutes:i,seconds:o}))return null;const f=Number(t[7]||"0"),g=Number(t[8]||"0"),T=f<0?f*60-g:f*60+g,u=new Date(Date.UTC(n,r-1,s,a,i,o)-T*6e4);return Number.isNaN(u.getTime())?null:{year:u.getUTCFullYear(),month:u.getUTCMonth()+1,day:u.getUTCDate(),hour:u.getUTCHours(),minutes:u.getUTCMinutes(),seconds:u.getUTCSeconds()}}function dt(e){const n=e.split("[")[0].split(".")[0];return/^\d{8}(\d{6})?$/.test(n)?{year:Number(n.slice(0,4)),month:Number(n.slice(4,6)),day:Number(n.slice(6,8)),hour:Number(n.slice(8,10)||"00"),minutes:Number(n.slice(10,12)||"00"),seconds:Number(n.slice(12,14)||"00")}:null}function Tt(e){const t=e.match(/^(\d{1,4})[/-](\d{1,2})[/-](\d{1,4})$/);if(!t)return null;const n=Number(t[1]),r=Number(t[2]),s=Number(t[3]),a=String(t[1]).length===4,i=String(t[3]).length===4;return!a&&!i?null:{year:a?n:s,month:r,day:a?s:n,hour:0,minutes:0,seconds:0}}function gt(e){return ft(e)||lt(e)||Tt(e)||dt(e)}function v(e){return!(!Number.isFinite(e.year)||!Number.isFinite(e.month)||!Number.isFinite(e.day)||!Number.isFinite(e.hour)||!Number.isFinite(e.minutes)||!Number.isFinite(e.seconds)||e.month<1||e.month>12||e.day<1||e.day>ut(e.month,e.year)||e.hour<0||e.hour>23||e.minutes<0||e.minutes>59||e.seconds<0||e.seconds>59)}function N(e){const t=gt(e);return!t||!v(t)?null:new Date(Date.UTC(t.year,t.month-1,t.day,t.hour,t.minutes,t.seconds))}var D;(function(e){e.BANK="BANK",e.CREDIT_CARD="CREDIT_CARD"})(D||(D={}));const ht=["debit","fee","srvchg","atm","pos","check","payment","directdebit","cash","repeatpmt"],mt=e=>e.includes(m)?D.BANK:D.CREDIT_CARD;function P(e){if(String(e.TRNAMT).startsWith("-"))return!0;const t=String(e.TRNTYPE).toLocaleLowerCase();return t==="1"||ht.includes(t)}function I(e){const t=e.replace(/(\\)/g,"\\\\").replace(h,n=>z(n,!0)).replace(B,n=>X(n,!0)).replace(/(},})/g,"}}").replace(/(}")/g,'},"').replace(/(]")/g,'],"').replace(/(},])/g,"}]").replace(/(,})/g,"}").replace(/,\s*}/g,"}").replace(/(,",)/,'",').replace(rt,'\\"').slice(0,-1);return t.endsWith(",")?t.slice(0,-1):t}const St=Object.keys(A).reduce((e,t)=>({...e,[A[t]]:t}),{});function E(e){return e.replace(/[{}\[\]]/g,t=>A[t])}function $(e){return e.replace(/_#(?:LB|RB|LS|RS)#_/g,t=>St[t])}function Rt(e){return e.replace(/>([^<]+)/g,(t,n)=>`>${E(n)}`)}const pt={amp:"&",lt:"<",gt:">",quot:'"',apos:"'"};function Ct(e){return e.indexOf("&")<0?e:e.replace(/&(?:(amp|lt|gt|quot|apos)|#(\d{1,7})|#[xX]([0-9a-fA-F]{1,6}));/g,(t,n,r,s)=>{if(n)return pt[n];const a=r?Number(r):parseInt(s,16);return a<1||a>1114111||a>=55296&&a<=57343?t:String.fromCodePoint(a)})}function w(e){return JSON.parse(e,(t,n)=>typeof n=="string"?Ct($(n)):n)}const Nt=e=>JSON.stringify({date:e.slice(0,12),transactionCode:e.slice(12,19),protocol:e.slice(19)}),G=e=>e.startsWith("DT"),K=e=>e.trim();function X(e,t=!1){return st.includes(e)&&!t?e:e.replace(/[<]/g,`
|
|
2
|
+
"`).replace(/[>]/g,'":{')}function z(e,t=!1){return at.includes(e)&&!t?`
|
|
4
3
|
${e}`:`},
|
|
5
|
-
`}function
|
|
6
|
-
`,"").toUpperCase();n[i]=t&&
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
`).filter(n
|
|
4
|
+
`}function Dt({fitId:e,fitValue:t}){if(e==="separated"){const n=JSON.parse(Nt(t));return JSON.stringify(Object.keys(n).reduce((r,s)=>({...r,[s]:E(n[s])}),{}))}return`"${E(t)}",`}function It(e){return e.search(",")>e.search(".")?e.replace(/[.]/g,"").replace(/[,]/g,"."):e.replace(/[,]/g,"")}function y({dateString:e,formatDate:t="y-M-d"}){return!/^\d{8}(\d{6})?(\.\d+)?(\[[^\]]+\])?$/.test(e)||!N(e)?e:U(e,t)}function Et(e,t){if(!e||typeof e!="object")return;const n=e;for(const r of Object.keys(n)){const s=n[r];G(r)&&typeof s=="string"&&(n[r]=y({dateString:s,formatDate:t}))}}function yt(e){let t=$(e.value.replace(/[{]/g,"").replace(/(},)/g,"")).replace(/["]/g,"_#_");const n=e.field.replace(/['"]/g,"");return n.endsWith("AMT")&&(t=It(t)),G(n)&&!e.rawDates&&(t=y({dateString:t,formatDate:e.formatDate})),n==="FITID"?Dt({fitId:e.fitId,fitValue:t}):e.nativeTypes&&W(n,t)?`${Number(t)},`:`"${E(t)}",`}function bt(e,t){let n=e;return e.match(/{(\w|\W)+/)&&(n=n.replace(/({(\w|\W)+)$/,r=>yt({field:n.slice(0,n.indexOf(":")),value:r,...t}))),n}function W(e,t){return e.endsWith("ID")||e.endsWith("NUM")?!1:!isNaN(Number(t))}function J(e){const t=e.indexOf(O),n=e.lastIndexOf(C)+C.length;if(t<0||n<0||t>=n)return{oldListText:e,newListText:e};const r=e.substring(t,n),s=new RegExp(O,"g"),a=new RegExp(C,"g"),i=`"STRTTRN":[${r.replace(s,"{").replace(a,"},")}]`;return{oldListText:e,newListText:e.replace(r,i)}}function H(e){if(!(e.indexOf(m)>0))return{newBankStatementTransactions:null,oldBankStatementTransactions:null};const n=J(e.substring(e.indexOf(m),e.indexOf(S)+S.length));return{newBankStatementTransactions:n.newListText,oldBankStatementTransactions:n.oldListText}}function V(e){if(!(e.indexOf(R)>0))return{newCreditCardStatementTransactions:null,oldCreditCardStatementTransactions:null};const n=e.substring(e.indexOf(R),e.indexOf(p)+p.length),r=J(n);return{newCreditCardStatementTransactions:r.newListText,oldCreditCardStatementTransactions:r.oldListText}}function Ot(e){const t=[];for(const n of e)t.push(...n.replace("<?xml"," ").replace("<?OFX"," ").replace("?>"," ").split(" ").filter(Boolean).map(K).map(r=>r.replace("=",":").replace(/["]/g,"")));return t}function At(e,t){const n={};e.join("").search("<?")>-1&&(e=Ot(e));for(const r of e){const[s,a]=r.split(":"),i=s.replace(`
|
|
5
|
+
`,"").toUpperCase();n[i]=t&&W(s,a)?Number(a):String(a).replace(/\?>/,"")}return n}function wt(e){return e.reduce((t,n)=>{const r=Math.abs(+n.TRNAMT);return P(n)?(t.amountOfDebits++,t.debit+=r,t):(t.amountOfCredits++,t.credit+=r,t)},{credit:0,debit:0,amountOfCredits:0,amountOfDebits:0})}class x{config;rawDates;internConfig={};sanitizeConfig;constructor(t,n=!1){this.config=t,this.rawDates=n,this.internConfig=t,this.sanitizeConfig={...t,rawDates:n}}getConfig(){return this.internConfig}withRawDates(){return new x(this.config,!0)}sanitizeRow(t){return bt(t,this.sanitizeConfig)}getPartialJsonData(t){const[n,r]=t.split("<OFX>"),s=Rt("<OFX>"+r),{sanitizeRow:a}=this;return s.replace(nt,(i,o,c,f)=>o===f?i:`<${o}>${c}
|
|
6
|
+
</${f}>`).replace(/<(?=[^\/])/g,`
|
|
7
|
+
<`).replace(h,i=>z(i)).replace(B,i=>X(i)).split(`
|
|
8
|
+
`).map(K).filter(Boolean).map(a,this).join("")}}function M(e){return e.toString()}async function _(e){return await new Promise((n,r)=>{if(typeof window<"u"&&window.FileReader){const s=new window.FileReader;s.onload=a=>n(a.target.result),s.onerror=a=>r(a.target.error),s.readAsText(e)}else r(new Error("FileReader is not available in this environment."))})}class d{data;dataRead="";constructor(t){this.data=t,t&&(this.dataRead=t)}getData(){return this.dataRead}fromString(t){return new d(t)}fromBuffer(t){return new d(M(t))}async fromBlob(t){return new d(await _(t))}static fromString(t){return new d(t)}static fromBuffer(t){return new d(M(t))}static async fromBlob(t){return new d(await _(t))}}class xt{configInstance={}}class L extends xt{setConfig(t){this.configInstance=t}getBankTransferList(t){const{newBankStatementTransactions:n}=H(this.configInstance.getPartialJsonData(t));return n?w(`{${I(n)}}`)?.BANKMSGSRSV1?.STMTTRNRS?.STMTRS?.BANKTRANLIST?.STRTTRN:[]}getCreditCardTransferList(t){const{newCreditCardStatementTransactions:n}=V(this.configInstance.getPartialJsonData(t));return n?w(`{${I(n)}}`)?.CREDITCARDMSGSRSV1?.CCSTMTTRNRS?.CCSTMTRS?.BANKTRANLIST?.STRTTRN:[]}getTransactionsSummary(t){let n=[],r=[];const s=this.configInstance?.getConfig?.().parserMode||"strict";let a=null,i=null;try{n=this.getBankTransferList(t)||[]}catch(F){a=F,n=[]}try{r=this.getCreditCardTransferList(t)||[]}catch(F){i=F,r=[]}const o=t.includes("<STMTTRN>");if(s==="strict"&&a&&i&&o)throw a;const c=n.length?n:r,f=n.length?m:R,g=n.length?S:p,T=t.indexOf(f),u=t.indexOf(g),Z=T>=0&&u>T?t.slice(T,u+g.length):"",tt=Z.match(/<DTSTART>([^\n<]+)/),et=Z.match(/<DTEND>([^\n<]+)/),Ut=wt(c||[]),vt=tt?.[1]?y({dateString:tt[1],formatDate:this.configInstance.getConfig().formatDate}):"",Pt=et?.[1]?y({dateString:et[1],formatDate:this.configInstance.getConfig().formatDate}):"";return{dateStart:vt,dateEnd:Pt,...Ut}}getContent(t){const n=this.configInstance.getPartialJsonData(t),{newBankStatementTransactions:r,oldBankStatementTransactions:s}=H(n),{newCreditCardStatementTransactions:a,oldCreditCardStatementTransactions:i}=V(n);let o=n;return r&&(o=o.replace(s,r)),a&&(o=o.replace(i,a)),w(`{${I(o)}}`)}}const Mt="y-M-d";function j(e){if(e==null)return"";if(typeof e=="string"||typeof e=="number")return String(e);if(typeof e=="object"){const t=e;if(t.date!==void 0&&t.transactionCode!==void 0&&t.protocol!==void 0)return`${t.date}${t.transactionCode}${t.protocol}`;try{return JSON.stringify(e)}catch{return String(e)}}return String(e)}function Y(e){if(e==null)return null;const t=Number(String(e).replace(/,/g,"."));return Number.isNaN(t)?null:t}function _t(e){return e.normalize("NFD").replace(/[\u0300-\u036f]/g,"").replace(/\s+/g," ").trim().toLowerCase()}function Lt(e,t){const n=t.dateMode||"formatted";if(!e)return{value:null,warning:{code:"MISSING_DATE",message:"Transaction does not include DTPOSTED.",severity:"warning"}};if(n==="raw"||n==="formatted"){const s=N(e);return s?n==="formatted"?{value:ot(s,t.formatDate||Mt)}:{value:e}:{value:e,warning:{code:"INVALID_DATE",message:`Unable to parse date '${e}'.`,severity:"warning"}}}const r=N(e);return r?n==="date"?{value:r}:n==="timestamp"?{value:r.getTime()}:{value:r.toISOString()}:{value:null,warning:{code:"INVALID_DATE",message:`Unable to parse date '${e}'.`,severity:"warning"}}}function Ft(e,t){const n=Y(e);return n===null?{amount:null,amountAbs:null,warning:{code:"INVALID_AMOUNT",message:`Unable to parse amount '${String(e)}'.`,severity:"warning"}}:t==="string"?{amount:String(e),amountAbs:String(Math.abs(n))}:t==="cents"?{amount:Math.round(n*100),amountAbs:Math.round(Math.abs(n)*100)}:{amount:n,amountAbs:Math.abs(n)}}function Q(e){const t=[],n=e?.OFX?.SIGNONMSGSRSV1?.SONRS?.FI||null,r=e?.OFX?.BANKMSGSRSV1?.STMTTRNRS?.STMTRS;(r?.BANKTRANLIST?.STRTTRN||r?.BANKTRANLIST?.STMTTRN||[]).forEach((o,c)=>{t.push({source:"bank",transaction:o,currency:r?.CURDEF||null,account:r?.BANKACCTFROM||null,institution:n,path:`OFX.BANKMSGSRSV1.STMTTRNRS.STMTRS.BANKTRANLIST.${c}`})});const a=e?.OFX?.CREDITCARDMSGSRSV1?.CCSTMTTRNRS?.CCSTMTRS;return(a?.BANKTRANLIST?.STRTTRN||a?.BANKTRANLIST?.STMTTRN||[]).forEach((o,c)=>{t.push({source:"credit_card",transaction:o,currency:a?.CURDEF||null,account:a?.CCACCTFROM||null,institution:n,path:`OFX.CREDITCARDMSGSRSV1.CCSTMTTRNRS.CCSTMTRS.BANKTRANLIST.${c}`})}),t}function Bt(e,t={}){const n=t.amountMode||"number",r=[],s=[];return Q(e).forEach(i=>{const o=[],c=String(i.transaction.MEMO||i.transaction.NAME||i.transaction.TRNTYPE||"").trim(),{amount:f,amountAbs:g,warning:T}=Ft(i.transaction.TRNAMT,n);T&&(T.path=i.path,o.push(T),r.push(T));const u=Lt(i.transaction.DTPOSTED,t);u.warning&&(u.warning.path=i.path,o.push(u.warning),r.push(u.warning)),s.push({source:i.source,direction:P(i.transaction)?"debit":"credit",amount:f,amountAbs:g,postedAt:u.value,description:c,descriptionNormalized:_t(c),fitId:j(i.transaction.FITID),currency:i.currency,account:i.account,institution:i.institution,raw:i.transaction,warnings:o})}),{transactions:s,warnings:r}}function kt(e){const t=[],n=[],r=Q(e);e?.OFX||n.push({code:"MISSING_OFX_BLOCK",message:"Missing OFX root block.",severity:"error",path:"OFX"}),r.length||t.push({code:"NO_TRANSACTIONS_FOUND",message:"No transactions were found in bank or credit card statements.",severity:"warning",path:"OFX"});const s=new Map;r.forEach(c=>{const f=j(c.transaction.FITID);f?s.set(f,(s.get(f)||0)+1):t.push({code:"MISSING_FITID",message:"Transaction does not include FITID.",severity:"warning",path:c.path}),Y(c.transaction.TRNAMT)===null&&n.push({code:"INVALID_AMOUNT",message:`Invalid amount '${String(c.transaction.TRNAMT)}'.`,severity:"error",path:c.path}),N(String(c.transaction.DTPOSTED||""))||t.push({code:"INVALID_DATE",message:`Invalid DTPOSTED '${String(c.transaction.DTPOSTED||"")}'.`,severity:"warning",path:c.path})});const a=Array.from(s.values()).filter(c=>c>1).length;a>0&&t.push({code:"DUPLICATED_FITID",message:`Found ${a} duplicated FITID values.`,severity:"warning",path:"OFX"});const i=r.filter(c=>c.source==="bank").length,o=r.filter(c=>c.source==="credit_card").length;return{isValid:n.length===0,warnings:t,errors:n,stats:{totalTransactions:r.length,bankTransactions:i,creditCardTransactions:o,duplicatedFitIds:a}}}class q{customExtractor;customExtractorInstance;dataReaderInstance=new d("");diagnostics=[];constructor(t){this.customExtractor=t,this.customExtractorInstance=t||new L,this.config({})}data(t){return this.dataReaderInstance=t,this}config(t){return this.customExtractorInstance.setConfig(new x(t)),this}getType(){return mt(this.dataReaderInstance.getData())}beginOperation(){this.diagnostics=[]}getParserMode(){return this.customExtractorInstance.configInstance.getConfig().parserMode}pushWarning(t){this.diagnostics.push(t)}safelyExecute(t,n,r){try{return r()}catch(s){if(this.getParserMode()!=="lenient")throw s;return this.pushWarning({code:"PARSE_ERROR",message:`Failed to parse OFX while running '${t}'.`,severity:"warning",context:s instanceof Error?s.message:String(s),path:t}),n}}getHeadersInternal(){return this.safelyExecute("getHeaders",{},()=>{const[t]=this.dataReaderInstance.getData().split("<OFX>");return At(String(t).split(`
|
|
9
|
+
`).filter(n=>!!n.trim().length),!!this.customExtractorInstance.configInstance.getConfig().nativeTypes)})}getContentInternal(){return this.safelyExecute("getContent",{OFX:{}},()=>this.customExtractorInstance.getContent(this.dataReaderInstance.getData()))}getResponseInternal(){const t=this.getHeadersInternal(),n=this.getContentInternal();return{...t,...n}}getHeaders(){return this.beginOperation(),this.getHeadersInternal()}getBankTransferList(){return this.beginOperation(),this.safelyExecute("getBankTransferList",[],()=>this.customExtractorInstance.getBankTransferList(this.dataReaderInstance.getData()))}getCreditCardTransferList(){return this.beginOperation(),this.safelyExecute("getCreditCardTransferList",[],()=>this.customExtractorInstance.getCreditCardTransferList(this.dataReaderInstance.getData()))}getTransactionsSummary(){return this.beginOperation(),this.safelyExecute("getTransactionsSummary",{credit:0,debit:0,amountOfCredits:0,amountOfDebits:0,dateStart:"",dateEnd:""},()=>this.customExtractorInstance.getTransactionsSummary(this.dataReaderInstance.getData()))}getContent(){return this.beginOperation(),this.getContentInternal()}toJson(){return this.beginOperation(),this.getResponseInternal()}getResponseWithRawDates(){const t=this.customExtractorInstance.configInstance;this.customExtractorInstance.setConfig(t.withRawDates());try{return this.getResponseInternal()}finally{this.customExtractorInstance.setConfig(t)}}toNormalized(t={}){this.beginOperation();const n=this.customExtractorInstance.configInstance.getConfig().formatDate,r=Bt(this.getResponseWithRawDates(),{...t,formatDate:t.formatDate||n});return r.transactions.forEach(s=>Et(s.raw,n)),r}validate(){return this.beginOperation(),kt(this.getResponseWithRawDates())}getWarnings(){return[...this.diagnostics]}}class b{extractor;constructor(t,n){this.extractor=new q(new L),this.extractor.data(new d(t)),this.extractor.config(n||{})}getType(){return this.extractor.getType()}static fromBuffer(t){return new b(d.fromBuffer(t).getData())}static async fromBlob(t){const n=await d.fromBlob(t);return new b(n.getData())}config(t){return this.extractor.config(t),this}getHeaders(){return this.extractor.getHeaders()}getBankTransferList(){return this.extractor.getBankTransferList()}getCreditCardTransferList(){return this.extractor.getCreditCardTransferList()}getTransactionsSummary(){return this.extractor.getTransactionsSummary()}getContent(){return this.extractor.getContent()}toJson(){return this.extractor.toJson()}toNormalized(t){return this.extractor.toNormalized(t)}validate(){return this.extractor.validate()}getWarnings(){return this.extractor.getWarnings()}}l.Extractor=q,l.Ofx=b,l.OfxExtractor=L,l.Reader=d,l.blobToString=_,l.bufferToString=M,l.fixJsonProblems=I,l.formatDate=U}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ofx-data-extractor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"ofx",
|
|
6
6
|
"financial",
|
|
@@ -28,16 +28,25 @@
|
|
|
28
28
|
"author": "Fábio Pereira França",
|
|
29
29
|
"repository": {
|
|
30
30
|
"type": "git",
|
|
31
|
-
"url": "https://github.com/Fabiopf02/ofx-
|
|
31
|
+
"url": "https://github.com/Fabiopf02/ofx-data-extractor.git"
|
|
32
32
|
},
|
|
33
33
|
"bugs": {
|
|
34
|
-
"url": "https://github.com/Fabiopf02/ofx-
|
|
34
|
+
"url": "https://github.com/Fabiopf02/ofx-data-extractor/issues"
|
|
35
35
|
},
|
|
36
36
|
"license": "MIT",
|
|
37
|
+
"sideEffects": false,
|
|
37
38
|
"description": "A module written in TypeScript that provides a utility to extract data from an OFX file in Node.js and Browser",
|
|
38
39
|
"main": "dist/umd/bundle.min.js",
|
|
39
40
|
"module": "dist/esm/index.min.js",
|
|
40
41
|
"typings": "dist/index.d.ts",
|
|
42
|
+
"exports": {
|
|
43
|
+
".": {
|
|
44
|
+
"types": "./dist/index.d.ts",
|
|
45
|
+
"import": "./dist/esm/index.min.js",
|
|
46
|
+
"require": "./dist/umd/bundle.min.js",
|
|
47
|
+
"default": "./dist/esm/index.min.js"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
41
50
|
"files": [
|
|
42
51
|
"dist/**/*"
|
|
43
52
|
],
|
|
@@ -45,25 +54,26 @@
|
|
|
45
54
|
"test": "jest tests/*.spec.ts --config jest.config.js",
|
|
46
55
|
"test:coverage": "jest tests/*.spec.ts --coverage --config jest.config.js",
|
|
47
56
|
"build": "rollup --config",
|
|
57
|
+
"build:analyze": "npm run build && node -e \"const fs=require('fs');const z=require('zlib');const files=['dist/esm/index.min.js','dist/umd/bundle.min.js'];for(const f of files){const b=fs.readFileSync(f);const gz=z.gzipSync(b);console.log(f, 'raw='+b.length+'B', 'gzip='+gz.length+'B');}\"",
|
|
48
58
|
"start": "node dist/index.js",
|
|
49
59
|
"format": "prettier --write \"src/**/*.ts\"",
|
|
50
60
|
"prepublish": "npm run build",
|
|
51
61
|
"lint": "tslint -p tsconfig.json"
|
|
52
62
|
},
|
|
53
63
|
"devDependencies": {
|
|
54
|
-
"@rollup/plugin-commonjs": "^25.0.
|
|
55
|
-
"@rollup/plugin-node-resolve": "^15.1
|
|
64
|
+
"@rollup/plugin-commonjs": "^25.0.8",
|
|
65
|
+
"@rollup/plugin-node-resolve": "^15.3.1",
|
|
56
66
|
"@rollup/plugin-typescript": "^10.0.1",
|
|
57
|
-
"@types/jest": "^29.
|
|
58
|
-
"@types/node": "^18.
|
|
59
|
-
"esbuild": "^0.
|
|
60
|
-
"jest": "^29.
|
|
61
|
-
"prettier": "^2.8.
|
|
62
|
-
"rollup": "^3.
|
|
67
|
+
"@types/jest": "^29.5.14",
|
|
68
|
+
"@types/node": "^18.19.130",
|
|
69
|
+
"esbuild": "^0.28.1",
|
|
70
|
+
"jest": "^29.7.0",
|
|
71
|
+
"prettier": "^2.8.8",
|
|
72
|
+
"rollup": "^3.30.0",
|
|
63
73
|
"rollup-plugin-esbuild": "^5.0.0",
|
|
64
|
-
"ts-jest": "^29.
|
|
74
|
+
"ts-jest": "^29.4.6",
|
|
65
75
|
"tslint": "^6.1.3",
|
|
66
76
|
"tslint-config-prettier": "^1.18.0",
|
|
67
|
-
"typescript": "^4.9.
|
|
77
|
+
"typescript": "^4.9.5"
|
|
68
78
|
}
|
|
69
79
|
}
|