xfina 0.4.0__tar.gz
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.
- xfina-0.4.0/.cargo/config.toml +2 -0
- xfina-0.4.0/.github/workflows/deploy-unreleased.yml +43 -0
- xfina-0.4.0/.github/workflows/publish.yml +235 -0
- xfina-0.4.0/.github/workflows/test.yml +69 -0
- xfina-0.4.0/.gitignore +47 -0
- xfina-0.4.0/AGENTS.md +39 -0
- xfina-0.4.0/CHANGELOG.md +162 -0
- xfina-0.4.0/CONTRIBUTING.md +75 -0
- xfina-0.4.0/Cargo.lock +1792 -0
- xfina-0.4.0/Cargo.toml +85 -0
- xfina-0.4.0/LICENSE +201 -0
- xfina-0.4.0/PKG-INFO +137 -0
- xfina-0.4.0/README.md +254 -0
- xfina-0.4.0/pyproject.toml +28 -0
- xfina-0.4.0/python/Cargo.toml +20 -0
- xfina-0.4.0/python/README.md +119 -0
- xfina-0.4.0/python/src/lib.rs +88 -0
- xfina-0.4.0/src/bank_accounts/axis.rs +404 -0
- xfina-0.4.0/src/bank_accounts/bob.rs +453 -0
- xfina-0.4.0/src/bank_accounts/hdfc.rs +476 -0
- xfina-0.4.0/src/bank_accounts/icici.rs +301 -0
- xfina-0.4.0/src/bank_accounts/layout.rs +80 -0
- xfina-0.4.0/src/bank_accounts/pdf_parser.rs +98 -0
- xfina-0.4.0/src/bank_accounts/sbi.rs +632 -0
- xfina-0.4.0/src/credit_cards/axis.rs +403 -0
- xfina-0.4.0/src/credit_cards/hdfc.rs +514 -0
- xfina-0.4.0/src/credit_cards/icici.rs +495 -0
- xfina-0.4.0/src/error.rs +34 -0
- xfina-0.4.0/src/intl_stocks/ibkr.rs +523 -0
- xfina-0.4.0/src/lib.rs +79 -0
- xfina-0.4.0/src/main.rs +307 -0
- xfina-0.4.0/src/models/credit_card.rs +263 -0
- xfina-0.4.0/src/models/date_utils.rs +35 -0
- xfina-0.4.0/src/models/deposit.rs +330 -0
- xfina-0.4.0/src/models/equity.rs +318 -0
- xfina-0.4.0/src/models/mod.rs +135 -0
- xfina-0.4.0/src/models/mutual_funds.rs +403 -0
- xfina-0.4.0/src/models/request.rs +33 -0
- xfina-0.4.0/src/models/serializer.rs +61 -0
- xfina-0.4.0/src/models/validation.rs +342 -0
- xfina-0.4.0/src/mutual_funds/cams.rs +135 -0
- xfina-0.4.0/src/mutual_funds/cas.rs +1248 -0
- xfina-0.4.0/src/mutual_funds/layout.rs +83 -0
- xfina-0.4.0/tests/bank_accounts_axis_integration.rs +68 -0
- xfina-0.4.0/tests/bank_accounts_bob_integration.rs +70 -0
- xfina-0.4.0/tests/bank_accounts_hdfc_integration.rs +88 -0
- xfina-0.4.0/tests/bank_accounts_icici_integration.rs +90 -0
- xfina-0.4.0/tests/bank_accounts_sbi_integration.rs +86 -0
- xfina-0.4.0/tests/credit_cards_axis_integration.rs +91 -0
- xfina-0.4.0/tests/credit_cards_hdfc_integration.rs +107 -0
- xfina-0.4.0/tests/credit_cards_icici_integration.rs +99 -0
- xfina-0.4.0/tests/intl_stocks_ibkr_integration.rs +65 -0
- xfina-0.4.0/tests/mutual_funds_cams_integration.rs +132 -0
- xfina-0.4.0/web/.gitignore +28 -0
- xfina-0.4.0/web/.vscode/extensions.json +3 -0
- xfina-0.4.0/web/README.md +5 -0
- xfina-0.4.0/web/components.json +15 -0
- xfina-0.4.0/web/index.html +13 -0
- xfina-0.4.0/web/jsconfig.json +8 -0
- xfina-0.4.0/web/package-lock.json +4011 -0
- xfina-0.4.0/web/package.json +30 -0
- xfina-0.4.0/web/postcss.config.js +6 -0
- xfina-0.4.0/web/public/CNAME +1 -0
- xfina-0.4.0/web/public/favicon.svg +59 -0
- xfina-0.4.0/web/public/icons.svg +24 -0
- xfina-0.4.0/web/src/App.vue +1647 -0
- xfina-0.4.0/web/src/assets/hero.png +0 -0
- xfina-0.4.0/web/src/assets/vite.svg +1 -0
- xfina-0.4.0/web/src/assets/vue.svg +1 -0
- xfina-0.4.0/web/src/components/EquityStatementUI.txt +126 -0
- xfina-0.4.0/web/src/components/HelloWorld.vue +95 -0
- xfina-0.4.0/web/src/components/StatementHeader.vue +107 -0
- xfina-0.4.0/web/src/components/ui/accordion/Accordion.vue +25 -0
- xfina-0.4.0/web/src/components/ui/accordion/AccordionContent.vue +29 -0
- xfina-0.4.0/web/src/components/ui/accordion/AccordionItem.vue +28 -0
- xfina-0.4.0/web/src/components/ui/accordion/AccordionTrigger.vue +39 -0
- xfina-0.4.0/web/src/components/ui/accordion/index.js +4 -0
- xfina-0.4.0/web/src/components/ui/button/Button.vue +27 -0
- xfina-0.4.0/web/src/components/ui/button/index.js +34 -0
- xfina-0.4.0/web/src/components/ui/card/Card.vue +24 -0
- xfina-0.4.0/web/src/components/ui/card/CardContent.vue +17 -0
- xfina-0.4.0/web/src/components/ui/card/CardDescription.vue +17 -0
- xfina-0.4.0/web/src/components/ui/card/CardFooter.vue +17 -0
- xfina-0.4.0/web/src/components/ui/card/CardHeader.vue +17 -0
- xfina-0.4.0/web/src/components/ui/card/CardTitle.vue +21 -0
- xfina-0.4.0/web/src/components/ui/card/index.js +6 -0
- xfina-0.4.0/web/src/components/ui/dialog/Dialog.vue +19 -0
- xfina-0.4.0/web/src/components/ui/dialog/DialogClose.vue +14 -0
- xfina-0.4.0/web/src/components/ui/dialog/DialogContent.vue +62 -0
- xfina-0.4.0/web/src/components/ui/dialog/DialogDescription.vue +28 -0
- xfina-0.4.0/web/src/components/ui/dialog/DialogFooter.vue +24 -0
- xfina-0.4.0/web/src/components/ui/dialog/DialogHeader.vue +19 -0
- xfina-0.4.0/web/src/components/ui/dialog/DialogScrollContent.vue +75 -0
- xfina-0.4.0/web/src/components/ui/dialog/DialogTitle.vue +30 -0
- xfina-0.4.0/web/src/components/ui/dialog/DialogTrigger.vue +14 -0
- xfina-0.4.0/web/src/components/ui/dialog/index.js +9 -0
- xfina-0.4.0/web/src/components/ui/input/Input.vue +33 -0
- xfina-0.4.0/web/src/components/ui/input/index.js +1 -0
- xfina-0.4.0/web/src/components/ui/label/Label.vue +32 -0
- xfina-0.4.0/web/src/components/ui/label/index.js +1 -0
- xfina-0.4.0/web/src/components/ui/select/Select.vue +27 -0
- xfina-0.4.0/web/src/components/ui/select/SelectContent.vue +88 -0
- xfina-0.4.0/web/src/components/ui/select/SelectGroup.vue +23 -0
- xfina-0.4.0/web/src/components/ui/select/SelectItem.vue +50 -0
- xfina-0.4.0/web/src/components/ui/select/SelectItemText.vue +14 -0
- xfina-0.4.0/web/src/components/ui/select/SelectLabel.vue +23 -0
- xfina-0.4.0/web/src/components/ui/select/SelectScrollDownButton.vue +33 -0
- xfina-0.4.0/web/src/components/ui/select/SelectScrollUpButton.vue +33 -0
- xfina-0.4.0/web/src/components/ui/select/SelectSeparator.vue +24 -0
- xfina-0.4.0/web/src/components/ui/select/SelectTrigger.vue +39 -0
- xfina-0.4.0/web/src/components/ui/select/SelectValue.vue +15 -0
- xfina-0.4.0/web/src/components/ui/select/index.js +11 -0
- xfina-0.4.0/web/src/components/ui/table/Table.vue +19 -0
- xfina-0.4.0/web/src/components/ui/table/TableBody.vue +17 -0
- xfina-0.4.0/web/src/components/ui/table/TableCaption.vue +17 -0
- xfina-0.4.0/web/src/components/ui/table/TableCell.vue +19 -0
- xfina-0.4.0/web/src/components/ui/table/TableEmpty.vue +35 -0
- xfina-0.4.0/web/src/components/ui/table/TableFooter.vue +21 -0
- xfina-0.4.0/web/src/components/ui/table/TableHead.vue +24 -0
- xfina-0.4.0/web/src/components/ui/table/TableHeader.vue +17 -0
- xfina-0.4.0/web/src/components/ui/table/TableRow.vue +24 -0
- xfina-0.4.0/web/src/components/ui/table/index.js +9 -0
- xfina-0.4.0/web/src/components/ui/tooltip/Tooltip.vue +22 -0
- xfina-0.4.0/web/src/components/ui/tooltip/TooltipContent.vue +55 -0
- xfina-0.4.0/web/src/components/ui/tooltip/TooltipProvider.vue +19 -0
- xfina-0.4.0/web/src/components/ui/tooltip/TooltipTrigger.vue +15 -0
- xfina-0.4.0/web/src/components/ui/tooltip/index.js +4 -0
- xfina-0.4.0/web/src/lib/analytics.js +58 -0
- xfina-0.4.0/web/src/lib/utils.js +6 -0
- xfina-0.4.0/web/src/main.js +6 -0
- xfina-0.4.0/web/src/style.css +59 -0
- xfina-0.4.0/web/tailwind.config.js +75 -0
- xfina-0.4.0/web/vite.config.js +39 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: Deploy Unreleased Docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: write
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
deploy_docs_unreleased:
|
|
17
|
+
name: Deploy Unreleased Docs
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v7
|
|
21
|
+
with:
|
|
22
|
+
fetch-depth: 0
|
|
23
|
+
- name: Configure Git User
|
|
24
|
+
run: |
|
|
25
|
+
git config --global user.name "github-actions[bot]"
|
|
26
|
+
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
|
27
|
+
- name: Setup Node
|
|
28
|
+
uses: actions/setup-node@v7
|
|
29
|
+
with:
|
|
30
|
+
node-version: 22
|
|
31
|
+
- name: Setup Rust
|
|
32
|
+
uses: dtolnay/rust-toolchain@stable
|
|
33
|
+
with:
|
|
34
|
+
target: wasm32-unknown-unknown
|
|
35
|
+
- name: Cache Cargo dependencies
|
|
36
|
+
uses: Swatinem/rust-cache@v2
|
|
37
|
+
- name: Install wasm-pack
|
|
38
|
+
run: |
|
|
39
|
+
if ! command -v wasm-pack &> /dev/null; then
|
|
40
|
+
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
|
41
|
+
fi
|
|
42
|
+
- name: Deploy Site via xtask
|
|
43
|
+
run: cargo run -p xtask -- deploy-site --unreleased
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
name: Multi-Ecosystem Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*.*.*'
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
publish_crates:
|
|
10
|
+
description: 'Publish to crates.io'
|
|
11
|
+
type: boolean
|
|
12
|
+
default: true
|
|
13
|
+
publish_npm:
|
|
14
|
+
description: 'Publish to NPM'
|
|
15
|
+
type: boolean
|
|
16
|
+
default: true
|
|
17
|
+
publish_pypi:
|
|
18
|
+
description: 'Publish to PyPI'
|
|
19
|
+
type: boolean
|
|
20
|
+
default: true
|
|
21
|
+
deploy_docs:
|
|
22
|
+
description: 'Deploy Docs'
|
|
23
|
+
type: boolean
|
|
24
|
+
default: true
|
|
25
|
+
|
|
26
|
+
concurrency:
|
|
27
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
28
|
+
cancel-in-progress: true
|
|
29
|
+
|
|
30
|
+
permissions:
|
|
31
|
+
contents: write
|
|
32
|
+
id-token: write
|
|
33
|
+
|
|
34
|
+
jobs:
|
|
35
|
+
check_branch:
|
|
36
|
+
name: Verify Tag is on Main
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@v7
|
|
40
|
+
with:
|
|
41
|
+
fetch-depth: 0
|
|
42
|
+
- name: Check if tag is on main
|
|
43
|
+
run: |
|
|
44
|
+
git fetch origin main
|
|
45
|
+
if ! git branch -r --contains ${{ github.sha }} | grep -E -q '(^|\s)origin/main$'; then
|
|
46
|
+
echo "Error: Tag ${{ github.ref_name }} is not on the main branch."
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
crates_io:
|
|
51
|
+
name: Publish to crates.io
|
|
52
|
+
if: github.event_name == 'push' || inputs.publish_crates != false
|
|
53
|
+
needs: check_branch
|
|
54
|
+
runs-on: ubuntu-latest
|
|
55
|
+
steps:
|
|
56
|
+
- uses: actions/checkout@v7
|
|
57
|
+
- name: Install Rust
|
|
58
|
+
uses: dtolnay/rust-toolchain@stable
|
|
59
|
+
- name: Cache Cargo dependencies
|
|
60
|
+
uses: Swatinem/rust-cache@v2
|
|
61
|
+
- name: Authenticate with crates.io
|
|
62
|
+
uses: rust-lang/crates-io-auth-action@v1
|
|
63
|
+
id: auth
|
|
64
|
+
- name: Publish xfina crate
|
|
65
|
+
env:
|
|
66
|
+
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
|
|
67
|
+
run: cargo publish --package xfina --allow-dirty
|
|
68
|
+
|
|
69
|
+
npm:
|
|
70
|
+
name: Publish to NPM
|
|
71
|
+
if: github.event_name == 'push' || inputs.publish_npm != false
|
|
72
|
+
runs-on: ubuntu-latest
|
|
73
|
+
needs: check_branch
|
|
74
|
+
steps:
|
|
75
|
+
- uses: actions/checkout@v7
|
|
76
|
+
- name: Setup Node
|
|
77
|
+
uses: actions/setup-node@v7
|
|
78
|
+
with:
|
|
79
|
+
node-version: 22
|
|
80
|
+
- name: Setup Rust
|
|
81
|
+
uses: dtolnay/rust-toolchain@stable
|
|
82
|
+
with:
|
|
83
|
+
target: wasm32-unknown-unknown
|
|
84
|
+
- name: Cache Cargo dependencies
|
|
85
|
+
uses: Swatinem/rust-cache@v2
|
|
86
|
+
- name: Install wasm-pack
|
|
87
|
+
run: |
|
|
88
|
+
if ! command -v wasm-pack &> /dev/null; then
|
|
89
|
+
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
|
90
|
+
fi
|
|
91
|
+
- name: Build WASM (Web Target)
|
|
92
|
+
working-directory: wasm
|
|
93
|
+
run: wasm-pack build --target web
|
|
94
|
+
- name: Publish to NPM
|
|
95
|
+
working-directory: wasm/pkg
|
|
96
|
+
run: |
|
|
97
|
+
npm install -g npm@latest
|
|
98
|
+
unset NODE_AUTH_TOKEN
|
|
99
|
+
npm publish --access public --provenance
|
|
100
|
+
|
|
101
|
+
wheels_linux:
|
|
102
|
+
name: Wheels (linux ${{ matrix.target }})
|
|
103
|
+
if: github.event_name == 'push' || inputs.publish_pypi != false
|
|
104
|
+
needs: check_branch
|
|
105
|
+
runs-on: ubuntu-latest
|
|
106
|
+
strategy:
|
|
107
|
+
fail-fast: false
|
|
108
|
+
matrix:
|
|
109
|
+
target: [x86_64, aarch64]
|
|
110
|
+
steps:
|
|
111
|
+
- uses: actions/checkout@v7
|
|
112
|
+
- name: Build wheel
|
|
113
|
+
uses: PyO3/maturin-action@v1
|
|
114
|
+
with:
|
|
115
|
+
target: ${{ matrix.target }}
|
|
116
|
+
args: --release --out dist
|
|
117
|
+
manylinux: auto
|
|
118
|
+
sccache: 'true'
|
|
119
|
+
working-directory: python
|
|
120
|
+
- uses: actions/upload-artifact@v7
|
|
121
|
+
with:
|
|
122
|
+
name: wheels-linux-${{ matrix.target }}
|
|
123
|
+
path: python/dist
|
|
124
|
+
|
|
125
|
+
wheels_macos:
|
|
126
|
+
name: Wheels (macos ${{ matrix.target }})
|
|
127
|
+
if: github.event_name == 'push' || inputs.publish_pypi != false
|
|
128
|
+
needs: check_branch
|
|
129
|
+
# Both targets build on Apple Silicon: GitHub retired the macos-13 Intel
|
|
130
|
+
# runner, so x86_64 is cross-compiled. Xcode ships both SDKs, so this needs
|
|
131
|
+
# nothing beyond the extra rustup target that maturin-action installs.
|
|
132
|
+
runs-on: macos-latest
|
|
133
|
+
strategy:
|
|
134
|
+
fail-fast: false
|
|
135
|
+
matrix:
|
|
136
|
+
target: [x86_64-apple-darwin, aarch64-apple-darwin]
|
|
137
|
+
steps:
|
|
138
|
+
- uses: actions/checkout@v7
|
|
139
|
+
- name: Build wheel
|
|
140
|
+
uses: PyO3/maturin-action@v1
|
|
141
|
+
with:
|
|
142
|
+
target: ${{ matrix.target }}
|
|
143
|
+
args: --release --out dist
|
|
144
|
+
sccache: 'true'
|
|
145
|
+
working-directory: python
|
|
146
|
+
- uses: actions/upload-artifact@v7
|
|
147
|
+
with:
|
|
148
|
+
name: wheels-macos-${{ matrix.target }}
|
|
149
|
+
path: python/dist
|
|
150
|
+
|
|
151
|
+
wheels_windows:
|
|
152
|
+
name: Wheels (windows x64)
|
|
153
|
+
if: github.event_name == 'push' || inputs.publish_pypi != false
|
|
154
|
+
needs: check_branch
|
|
155
|
+
runs-on: windows-latest
|
|
156
|
+
steps:
|
|
157
|
+
- uses: actions/checkout@v7
|
|
158
|
+
- name: Build wheel
|
|
159
|
+
uses: PyO3/maturin-action@v1
|
|
160
|
+
with:
|
|
161
|
+
target: x64
|
|
162
|
+
args: --release --out dist
|
|
163
|
+
sccache: 'true'
|
|
164
|
+
working-directory: python
|
|
165
|
+
- uses: actions/upload-artifact@v7
|
|
166
|
+
with:
|
|
167
|
+
name: wheels-windows-x64
|
|
168
|
+
path: python/dist
|
|
169
|
+
|
|
170
|
+
sdist:
|
|
171
|
+
name: Source distribution
|
|
172
|
+
if: github.event_name == 'push' || inputs.publish_pypi != false
|
|
173
|
+
needs: check_branch
|
|
174
|
+
runs-on: ubuntu-latest
|
|
175
|
+
steps:
|
|
176
|
+
- uses: actions/checkout@v7
|
|
177
|
+
- name: Build sdist
|
|
178
|
+
uses: PyO3/maturin-action@v1
|
|
179
|
+
with:
|
|
180
|
+
command: sdist
|
|
181
|
+
args: --out dist
|
|
182
|
+
working-directory: python
|
|
183
|
+
- uses: actions/upload-artifact@v7
|
|
184
|
+
with:
|
|
185
|
+
name: wheels-sdist
|
|
186
|
+
path: python/dist
|
|
187
|
+
|
|
188
|
+
pypi_publish:
|
|
189
|
+
name: Upload to PyPI
|
|
190
|
+
if: github.event_name == 'push' || inputs.publish_pypi != false
|
|
191
|
+
needs: [wheels_linux, wheels_macos, wheels_windows, sdist]
|
|
192
|
+
runs-on: ubuntu-latest
|
|
193
|
+
permissions:
|
|
194
|
+
id-token: write
|
|
195
|
+
steps:
|
|
196
|
+
- name: Download wheels
|
|
197
|
+
uses: actions/download-artifact@v8
|
|
198
|
+
with:
|
|
199
|
+
pattern: wheels-*
|
|
200
|
+
merge-multiple: true
|
|
201
|
+
path: dist
|
|
202
|
+
- name: List artifacts
|
|
203
|
+
run: ls -l dist
|
|
204
|
+
- name: Publish to PyPI
|
|
205
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
206
|
+
with:
|
|
207
|
+
packages-dir: dist/
|
|
208
|
+
skip-existing: true
|
|
209
|
+
|
|
210
|
+
deploy_docs_tag:
|
|
211
|
+
name: Deploy Tagged Docs
|
|
212
|
+
if: github.event_name == 'push' || inputs.deploy_docs != false
|
|
213
|
+
runs-on: ubuntu-latest
|
|
214
|
+
needs: [check_branch, npm]
|
|
215
|
+
steps:
|
|
216
|
+
- uses: actions/checkout@v7
|
|
217
|
+
with:
|
|
218
|
+
fetch-depth: 0
|
|
219
|
+
- name: Configure Git User
|
|
220
|
+
run: |
|
|
221
|
+
git config --global user.name "github-actions[bot]"
|
|
222
|
+
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
|
223
|
+
- name: Extract Tag Name
|
|
224
|
+
id: extract_tag
|
|
225
|
+
run: echo "TAG_NAME=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
|
226
|
+
- name: Setup Node
|
|
227
|
+
uses: actions/setup-node@v7
|
|
228
|
+
with:
|
|
229
|
+
node-version: 22
|
|
230
|
+
- name: Setup Rust
|
|
231
|
+
uses: dtolnay/rust-toolchain@stable
|
|
232
|
+
- name: Cache Cargo dependencies
|
|
233
|
+
uses: Swatinem/rust-cache@v2
|
|
234
|
+
- name: Deploy Site via xtask
|
|
235
|
+
run: cargo run -p xtask -- deploy-site --tag ${{ env.TAG_NAME }}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
name: PR Checks
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches: [ "main" ]
|
|
6
|
+
|
|
7
|
+
env:
|
|
8
|
+
CARGO_TERM_COLOR: always
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
test:
|
|
12
|
+
name: Approve PR
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v7
|
|
16
|
+
with:
|
|
17
|
+
fetch-depth: 0
|
|
18
|
+
|
|
19
|
+
- name: Check Changes and Changelog
|
|
20
|
+
id: check_changes
|
|
21
|
+
if: github.event_name == 'pull_request'
|
|
22
|
+
run: |
|
|
23
|
+
git fetch origin ${{ github.base_ref }}
|
|
24
|
+
|
|
25
|
+
# Define the core paths that require a changelog update (excluding markdown files like README.md)
|
|
26
|
+
CORE_CHANGED=$(git diff --name-only origin/${{ github.base_ref }}...HEAD -- src/ python/ wasm/ tests/ Cargo.toml | grep -v -i '\.md$' || true)
|
|
27
|
+
|
|
28
|
+
if [ -n "$CORE_CHANGED" ]; then
|
|
29
|
+
echo "The following core files were modified:"
|
|
30
|
+
echo "$CORE_CHANGED"
|
|
31
|
+
echo "----------------------------------------"
|
|
32
|
+
|
|
33
|
+
# Check if CHANGELOG.md is in the diff
|
|
34
|
+
if ! git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -q "^CHANGELOG.md$"; then
|
|
35
|
+
echo "::error::Core files were modified but CHANGELOG.md was not updated. Please document your changes."
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
echo "Success: CHANGELOG.md was updated!"
|
|
39
|
+
echo "run_tests=true" >> "$GITHUB_OUTPUT"
|
|
40
|
+
else
|
|
41
|
+
echo "No core files modified. Changelog update not strictly required."
|
|
42
|
+
echo "run_tests=false" >> "$GITHUB_OUTPUT"
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
- name: Install Rust
|
|
46
|
+
if: steps.check_changes.outputs.run_tests == 'true'
|
|
47
|
+
uses: dtolnay/rust-toolchain@stable
|
|
48
|
+
with:
|
|
49
|
+
targets: wasm32-unknown-unknown
|
|
50
|
+
|
|
51
|
+
- name: Cache cargo registry and build
|
|
52
|
+
if: steps.check_changes.outputs.run_tests == 'true'
|
|
53
|
+
uses: Swatinem/rust-cache@v2
|
|
54
|
+
|
|
55
|
+
- name: Check formatting
|
|
56
|
+
if: steps.check_changes.outputs.run_tests == 'true'
|
|
57
|
+
run: cargo fmt --check
|
|
58
|
+
|
|
59
|
+
- name: Check for warnings
|
|
60
|
+
if: steps.check_changes.outputs.run_tests == 'true'
|
|
61
|
+
run: cargo clippy --workspace --all-targets --all-features -- -D warnings
|
|
62
|
+
|
|
63
|
+
- name: Run tests
|
|
64
|
+
if: steps.check_changes.outputs.run_tests == 'true'
|
|
65
|
+
run: cargo test --workspace --all-features
|
|
66
|
+
|
|
67
|
+
- name: Build WASM
|
|
68
|
+
if: steps.check_changes.outputs.run_tests == 'true'
|
|
69
|
+
run: cargo build --target wasm32-unknown-unknown -p xfina-wasm
|
xfina-0.4.0/.gitignore
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Generated by Cargo
|
|
2
|
+
# will have compiled files and executables
|
|
3
|
+
debug
|
|
4
|
+
target
|
|
5
|
+
|
|
6
|
+
# These are backup files generated by rustfmt
|
|
7
|
+
**/*.rs.bk
|
|
8
|
+
|
|
9
|
+
# MSVC Windows builds of rustc generate these, which store debugging information
|
|
10
|
+
*.pdb
|
|
11
|
+
|
|
12
|
+
# Generated by cargo mutants
|
|
13
|
+
# Contains mutation testing data
|
|
14
|
+
**/mutants.out*/
|
|
15
|
+
|
|
16
|
+
# RustRover
|
|
17
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
18
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
19
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
20
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
21
|
+
#.idea/
|
|
22
|
+
|
|
23
|
+
# Build outputs
|
|
24
|
+
docs/
|
|
25
|
+
|
|
26
|
+
# Local test data and statements
|
|
27
|
+
test_data/
|
|
28
|
+
*.xls
|
|
29
|
+
*.xlsx
|
|
30
|
+
*.pdf
|
|
31
|
+
*.csv
|
|
32
|
+
|
|
33
|
+
# Scratch/debug test files
|
|
34
|
+
parse_test
|
|
35
|
+
parse_test[0-9]*
|
|
36
|
+
*.rs.scratch
|
|
37
|
+
test_out.txt
|
|
38
|
+
parse_test*.rs
|
|
39
|
+
*.py
|
|
40
|
+
gh-pages-worktree/
|
|
41
|
+
/web/public/versions.json
|
|
42
|
+
.venv/
|
|
43
|
+
|
|
44
|
+
# Scratch and debug files
|
|
45
|
+
scratch/
|
|
46
|
+
test_output.json
|
|
47
|
+
*.txt
|
xfina-0.4.0/AGENTS.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Xfina - Agent Context & Guidelines
|
|
2
|
+
|
|
3
|
+
This document serves as a cheat sheet for AI agents working on the Xfina project to quickly understand the architecture, build processes, and specific domain rules.
|
|
4
|
+
|
|
5
|
+
## Architecture Overview
|
|
6
|
+
- **Backend (Rust + WASM):** Financial statements (PDFs, XLS, etc.) are parsed securely entirely within the browser using Rust compiled to WebAssembly. Parsers are split into domain-specific packages (`bank-accounts/`, `credit-cards/`, `mutual-funds/`, `intl-stocks/`).
|
|
7
|
+
- **Frontend (Vue 3 + Vite):** The user interface is built with Vue 3, Tailwind CSS, and `shadcn-vue` style components. It takes the JSON output from the WASM parsers and renders standardized views.
|
|
8
|
+
- **Models (`xfina-models`):** Shared Rust data structures used to serialize data. They adhere closely to the Sahamati Account Aggregator (AA) schema standards, with our own project-specific extensions nested inside `xfina` objects (e.g. `XfinaCreditCardAccount`).
|
|
9
|
+
|
|
10
|
+
## Build & Run Instructions
|
|
11
|
+
- **WASM Rebuild (CRITICAL):** Anytime a Rust parser or model is modified, the WASM package MUST be rebuilt and copied to the web directory for the frontend to see the changes.
|
|
12
|
+
```bash
|
|
13
|
+
cd wasm
|
|
14
|
+
wasm-pack build --target web && cp -r pkg/* ../web/src/wasm/
|
|
15
|
+
```
|
|
16
|
+
*(Note: Vite aggressively caches WASM files. If UI doesn't update after rebuild, wipe `web/node_modules/.vite` and hard-refresh the browser).*
|
|
17
|
+
- **Frontend Dev Server:**
|
|
18
|
+
```bash
|
|
19
|
+
cd web
|
|
20
|
+
npm run dev
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Testing Workflow
|
|
24
|
+
- **Integration Tests:** Each parser has an `integration.rs` which reads sample raw statements and asserts them against expected JSON snapshots.
|
|
25
|
+
- **Test Data Repo:** Test data lives OUTSIDE this repository in a sibling folder at `../xfina-test-data/`.
|
|
26
|
+
- **Updating Snapshots:** If a parser modification intentionally changes the JSON output shape, run tests with the `UPDATE_EXPECTED=1` environment variable to overwrite the expected snapshots.
|
|
27
|
+
|
|
28
|
+
## Technical Rules & Conventions
|
|
29
|
+
1. **Timezones & Dates:**
|
|
30
|
+
- Use `NaiveDate` (from `chrono`) for fields that are strictly dates (e.g. statement start/end dates).
|
|
31
|
+
- Use `DateTime<Utc>` for timestamps (e.g. transaction exact times). When parsing local Indian dates from statements, parse them using `Asia/Kolkata` (IST `+05:30`) timezone offset before converting to `Utc`.
|
|
32
|
+
2. **Standardized Naming:**
|
|
33
|
+
- Always use full institution names across parsers and UI: `"HDFC Bank"`, `"ICICI Bank"`, `"State Bank of India"`, `"Bank of Baroda"`.
|
|
34
|
+
3. **Transaction Sorting:** Parsed transactions should generally be emitted in chronological (ascending) order.
|
|
35
|
+
4. **Data Fallbacks & Safety:** Parsers should fail gracefully. Try to derive information when missing (e.g. deriving missing transaction years from the statement date).
|
|
36
|
+
|
|
37
|
+
## UI/UX Rules
|
|
38
|
+
- **Color & Styling:** Maintain consistency in financial coloring (green for deposits/payments, default colors for neutral balances). Use the predefined Tailwind semantic colors (e.g. `text-muted-foreground`, `text-primary`).
|
|
39
|
+
- Ensure UI bindings exactly match the serialized JSON paths (e.g., watch out for `camelCase` conversions like `institution_name` becoming `institutionName` in JS).
|
xfina-0.4.0/CHANGELOG.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.4.0] - 2026-09-02
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **Parsers (Axis CC):** The card variant printed in the statement title (e.g. `Neo`) is now extracted into `summary.xfina.cardProduct`.
|
|
14
|
+
- **Web App:** Credit card statement details now show the card variant as `Product`, mirroring the bank account view.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- **Python wheels:** the PyPI job built a single wheel on `ubuntu-latest` with
|
|
18
|
+
CPython 3.11, so only that exact combination could `pip install xfina`
|
|
19
|
+
without a Rust toolchain — 0.2.4 shipped nothing but a
|
|
20
|
+
`manylinux_2_34_x86_64` CPython 3.11 wheel. Fixed on three fronts, mirroring
|
|
21
|
+
[sakthipriyan/xfingine](https://github.com/sakthipriyan/xfingine):
|
|
22
|
+
- The extension now builds against the **stable ABI** (`pyo3/abi3-py38`), so
|
|
23
|
+
one wheel per OS/arch covers CPython 3.8+ instead of needing one per
|
|
24
|
+
version — turning a ~25-build matrix into 5.
|
|
25
|
+
- Wheels are built for **linux x86_64 / aarch64, macOS x86_64 / arm64, and
|
|
26
|
+
windows x64** via `PyO3/maturin-action`, which cross-compiles properly. A
|
|
27
|
+
plain `maturin build` only ever targets the runner's own platform, which
|
|
28
|
+
was the root cause. Both macOS wheels build on `macos-latest` (Apple
|
|
29
|
+
Silicon), since GitHub has retired the `macos-13` Intel runner.
|
|
30
|
+
- An **sdist** is built and uploaded as its own job, giving pip a source
|
|
31
|
+
fallback on any platform without a prebuilt wheel.
|
|
32
|
+
- **Python metadata:** `pyproject.toml` advertised PyPy support that an abi3
|
|
33
|
+
CPython extension cannot provide. Replaced with explicit CPython 3.8–3.13
|
|
34
|
+
classifiers, so the metadata matches what is actually shipped.
|
|
35
|
+
- **CI:** bumped `actions/checkout` and `actions/setup-node` to v7 to move off
|
|
36
|
+
the deprecated Node 20 runtime; the new wheel jobs use `actions/upload-artifact`
|
|
37
|
+
v7 and `actions/download-artifact` v8. The `actions/setup-python` call site is
|
|
38
|
+
gone — `maturin-action` provides the interpreter.
|
|
39
|
+
- **Parsers (HDFC BA):** Holder names starting with `MRS` were mangled into `S <name>` because the honorific was stripped by a plain substring replace. Honorifics are now removed as whole leading tokens.
|
|
40
|
+
- **Parsers (SBI BA):** The honorific (`Mrs.`, `Mr.` ...) is now stripped from the holder name instead of being kept as part of it, and the column padding statements use is collapsed.
|
|
41
|
+
|
|
42
|
+
## [0.3.0] - 2026-08-27
|
|
43
|
+
|
|
44
|
+
### Added
|
|
45
|
+
- **Parsers:** Added a new parser for Axis Bank credit card statements (`credit_cards/axis.rs`).
|
|
46
|
+
- **Web App:** Integrated the Axis Bank credit card parser in the UI.
|
|
47
|
+
- **Python / WASM:** Exposed the `parse_axis_cc` function in Python and WASM bindings.
|
|
48
|
+
|
|
49
|
+
## [0.2.4] - 2026-08-15
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
- **Parsers (CAMS):** Fixed summary-level validation false failures on statements where CAMS' vertical document-generation watermark (rotated 90°, stamped along the page margin) coincidentally landed within the y-tolerance of an AMC heading line, fusing a stray character onto it and causing that AMC's holdings to be silently misattributed to the previous AMC. Non-upright glyphs are now dropped during character extraction so they can never fuse onto content lines, regardless of which line they happen to land near.
|
|
53
|
+
- **Parsers (CAMS):** Fixed nondeterministic ordering of `summary_level` validation checks (backed by a `HashMap`, whose iteration order is randomized per process) by sorting by AMC name before emitting checks, so serialized output is stable across runs — the same class of issue already fixed for the IBKR parser in 0.2.0.
|
|
54
|
+
- **Error Handling:** CAMS PDF decryption failures now surface as the typed `XfinaError::IncorrectPassword` / `XfinaError::PasswordRequired` variants instead of a generic string-wrapped `ParseError`.
|
|
55
|
+
|
|
56
|
+
### Changed
|
|
57
|
+
- **Testing:** The CAMS integration test's `passwords.json` lookup now accepts either a single password or an ordered list of candidate passwords per key (including `default`), trying each in turn until one succeeds. Supports CAMS rotating its PDF password over time without needing per-file or date-based entries.
|
|
58
|
+
|
|
59
|
+
## [0.2.3] - 2026-08-09
|
|
60
|
+
|
|
61
|
+
### Added
|
|
62
|
+
- **Web App:** Added a privacy-first Analytics Consent modal with 3 tracking levels (Off, Page View, Parser Usage).
|
|
63
|
+
|
|
64
|
+
### Fixed
|
|
65
|
+
- **CI/CD:** Fixed publish workflow skipping jobs on tag push due to missing remote tracking branch in GitHub Actions checkout.
|
|
66
|
+
|
|
67
|
+
## [0.2.2] - 2026-08-08
|
|
68
|
+
|
|
69
|
+
### Added
|
|
70
|
+
- **xtask:** Split release command into `prepare-release` and `tag-release` stages to support PR-based branch protection workflows.
|
|
71
|
+
|
|
72
|
+
### Changed
|
|
73
|
+
- Add `homepage` to package metadata pointing to `xfina.dev`
|
|
74
|
+
- Fix page title to just `Xfina`
|
|
75
|
+
|
|
76
|
+
## [0.2.1] - 2026-08-08
|
|
77
|
+
|
|
78
|
+
### Added
|
|
79
|
+
- **Parsers:** Added derived `computed_closing_balance` validation logic for Bank of Baroda statements.
|
|
80
|
+
- **Parsers:** Added `overall_invested_match` and `overall_value_match` summary checks for Mutual Funds (CAS) by extracting portfolio summaries.
|
|
81
|
+
|
|
82
|
+
### Changed
|
|
83
|
+
- **Web App:** Standardized the UI header components across all statement types and added visual validation badges.
|
|
84
|
+
|
|
85
|
+
### Fixed
|
|
86
|
+
- **Web App:** Corrected UI alignment issues for IBKR transaction badges and properly greyed out non-applicable row-level validations for Credit Cards.
|
|
87
|
+
|
|
88
|
+
## [0.2.0] - 2026-08-06
|
|
89
|
+
|
|
90
|
+
### Added
|
|
91
|
+
- **Validation Engine:** Added a comprehensive two-level validation engine (`src/models/validation.rs`) to detect parsing discrepancies.
|
|
92
|
+
- Row-level validation checks `opening balance + transaction amount = current balance`.
|
|
93
|
+
- Summary-level validation checks `computed_closing = declared_closing` and verifies total credits/debits against declared summaries in PDFs/XLS files.
|
|
94
|
+
- **CI/CD:** Added GitHub Actions test pipeline (`.github/workflows/test.yml`) to automatically run `cargo test` and compile the WASM build on pushes and pull requests to `main`.
|
|
95
|
+
- **Documentation:** Created a comprehensive `CONTRIBUTING.md` guide for adding new parsers and managing snapshots.
|
|
96
|
+
- **Documentation:** Added an architectural diagram to the main `README.md` and added rich metadata (keywords, categories, readme) to `Cargo.toml`.
|
|
97
|
+
|
|
98
|
+
### Changed
|
|
99
|
+
- **Breaking API Change:** All parsers across all crates (`bank_accounts`, `credit_cards`, `mutual_funds`, `intl_stocks`) now return a wrapped `ParseResult<T>` struct containing the parsed `data: T` alongside a `validation: ValidationReport` object, instead of returning the raw account `T` directly.
|
|
100
|
+
- **WASM / Python / CLI Output:** The output JSON schema is now wrapped in `{ "data": { ... }, "validation": { ... } }`.
|
|
101
|
+
- **Error Handling:** Completely re-architected error handling across all parsers using the `thiserror` crate. Parsers now return a strongly-typed `XfinaError` enum instead of stringly-typed errors, enabling programmatic error matching.
|
|
102
|
+
- **Bindings:** Updated FFI boundaries in `xfina-wasm` (JS) and `xfina-py` (Python) to properly propagate `XfinaError` types.
|
|
103
|
+
- **Web App:** Updated the website header to explicitly link to `sakthipriyan.com/building-wealth` instead of linking generically to GitHub.
|
|
104
|
+
|
|
105
|
+
### Fixed
|
|
106
|
+
- **Code Cleanup:** Resolved hundreds of compiler and clippy warnings across the workspace, including unused variables, non-idiomatic default struct reassignments, and dead code.
|
|
107
|
+
- **Testing:** Resolved integration test failures in CI by ensuring snapshot write/assertion tests are skipped via a `GITHUB_ACTIONS=true` environment check.
|
|
108
|
+
- **Testing:** Replaced `HashMap` with `BTreeMap` and `HashSet` with `BTreeSet` in the IBKR parser to ensure deterministic serialization order for consistent snapshot tests.
|
|
109
|
+
- **Code Cleanup:** Removed legacy, unused `f64`-based financial models (`Portfolio`, `Asset`, etc.) from `src/models/mod.rs`.
|
|
110
|
+
- **Documentation:** Fixed an inaccuracy in `wasm/README.md` to correctly state that the default parser output format is `"xfina"`, not `"rebit"`.
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
## [0.1.4] - 2026-08-05
|
|
114
|
+
|
|
115
|
+
### Added
|
|
116
|
+
- **Documentation:** Added package registry badges (Crates.io, PyPI, npm) to the `README.md`.
|
|
117
|
+
- **Documentation:** Updated deployment instructions to reflect the new `xtask deploy-site` flow.
|
|
118
|
+
|
|
119
|
+
### Fixed
|
|
120
|
+
- **CI/CD:** Updated the release script in `xtask` to ensure `Cargo.lock` is correctly synced and to safely allow dirty publishing.
|
|
121
|
+
|
|
122
|
+
## [0.1.3] - 2026-08-04
|
|
123
|
+
|
|
124
|
+
### Added
|
|
125
|
+
- **Deployment:** Re-architected website deployment pipeline via `cargo xtask deploy-site` to generate immutable, permanent archives for all minor releases in `gh-pages`.
|
|
126
|
+
- **Infrastructure:** Updated `.github/workflows/publish.yml` to trigger orchestrated GitHub Actions deployments and handle safe concurrency locking.
|
|
127
|
+
|
|
128
|
+
### Changed
|
|
129
|
+
- **Web App:** Configured Vite with `base: './'` for path-agnostic artifact generation.
|
|
130
|
+
- **Web App:** Transitioned from fetching version lists via GitHub API to a dynamically generated `versions.json` registry.
|
|
131
|
+
|
|
132
|
+
### Fixed
|
|
133
|
+
- **Web App:** Fixed Issue #23 where the version dropdown failed to properly display or navigate to the latest active version.
|
|
134
|
+
|
|
135
|
+
## [0.1.2] - 2026-08-03
|
|
136
|
+
|
|
137
|
+
## [0.1.1] - 2026-08-03
|
|
138
|
+
|
|
139
|
+
### Added
|
|
140
|
+
- **Parsers:** Added a new `format` parameter (`"rebit"` or `"xfina"`) to all WASM, Python, and CLI parsers to allow toggling between strict ReBIT AA schema compliance and extended Xfina schemas.
|
|
141
|
+
- **Python:** Fully implemented PyO3 bindings for all statement parsers in the `xfina` PyPI package (the previous release accidentally omitted them).
|
|
142
|
+
- **CLI:** Added the `--format` option to the CLI tool.
|
|
143
|
+
|
|
144
|
+
### Fixed
|
|
145
|
+
- **CI/CD:** Upgraded NPM in GitHub Actions to v11+ to fully support passwordless OIDC Trusted Publishing, fixing the `ENEEDAUTH` error.
|
|
146
|
+
- **Documentation:** Updated all READMEs (Rust, WASM, Python) with correct function signatures, new format parameters, and accurate code examples.
|
|
147
|
+
## [0.1.0] - 2026-08-03
|
|
148
|
+
|
|
149
|
+
### Added
|
|
150
|
+
- **Parsers:** Support for parsing PDF/XLS statements from major Indian financial institutions:
|
|
151
|
+
- Bank Accounts: HDFC, ICICI, SBI, Bank of Baroda, Axis Bank
|
|
152
|
+
- Credit Cards: HDFC, ICICI
|
|
153
|
+
- Mutual Funds: CAMS (CAS)
|
|
154
|
+
- International Stocks: Interactive Brokers (IBKR)
|
|
155
|
+
- **Data Models:** Centralized `xfina-models` package standardizing financial schema based on RBI Account Aggregator specifications.
|
|
156
|
+
- **CLI Tool:** Unified `xfina-cli` binary for parsing statements directly from the terminal and exporting to JSON.
|
|
157
|
+
- **Language Bindings:**
|
|
158
|
+
- `python`: Python bindings published to PyPI using PyO3/Maturin.
|
|
159
|
+
- `wasm`: WebAssembly module (`xfina-wasm`) published to NPM using `wasm-pack` for browser integration.
|
|
160
|
+
- **Web App:** Vue 3 + Tailwind CSS frontend interface demonstrating local, privacy-preserving WASM parsing.
|
|
161
|
+
- **CI/CD:** Automated GitHub Actions pipeline for testing and publishing to Crates.io, NPM, PyPI, and GitHub Pages.
|
|
162
|
+
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Contributing to Xfina
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing to Xfina! This project thrives on community contributions, especially for adding new parsers for various Indian financial institutions.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
1. **Fork the Repository**
|
|
8
|
+
2. **Install Rust**: Xfina is built in Rust. Install it via [rustup](https://rustup.rs/).
|
|
9
|
+
3. **Run the Setup**:
|
|
10
|
+
```bash
|
|
11
|
+
cargo build
|
|
12
|
+
cargo test
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Development Workflow
|
|
16
|
+
|
|
17
|
+
### Adding a New Parser
|
|
18
|
+
|
|
19
|
+
Xfina’s core parsing logic lives in the `xfina` crate, organized by domain:
|
|
20
|
+
- `bank-accounts/`
|
|
21
|
+
- `credit-cards/`
|
|
22
|
+
- `mutual-funds/`
|
|
23
|
+
- `intl-stocks/`
|
|
24
|
+
|
|
25
|
+
1. **Create the Parser**: Create a new module in the appropriate directory (e.g., `bank-accounts/newbank.rs`).
|
|
26
|
+
2. **Implement Error Handling**: All parsers must return `Result<T, crate::error::XfinaError>`. Use `?` for early returns.
|
|
27
|
+
3. **Map to Models**: Parse the raw data directly into the shared models in `src/models/`. These models are designed to map closely to the Sahamati AA / ReBIT specifications.
|
|
28
|
+
4. **Feature Flag**: Add your parser to `Cargo.toml` as a new feature flag and include it in the `all` feature list.
|
|
29
|
+
5. **Update Targets**:
|
|
30
|
+
- Export your parser in `src/lib.rs`
|
|
31
|
+
- Add it to the CLI in `src/main.rs`
|
|
32
|
+
- Add WASM bindings in `wasm/src/lib.rs`
|
|
33
|
+
- Add Python bindings in `python/src/lib.rs`
|
|
34
|
+
- Add UI support in `web/src/App.vue`
|
|
35
|
+
|
|
36
|
+
### Testing Requirements
|
|
37
|
+
|
|
38
|
+
Integration tests are mandatory for all parsers to ensure that future changes do not break existing snapshot outputs.
|
|
39
|
+
|
|
40
|
+
1. Create a new integration test in the `tests/` directory (e.g., `tests/bank_accounts_newbank_integration.rs`).
|
|
41
|
+
2. You will need sample financial statements (e.g., PDFs, Excel files, CSVs). Since these contain PII, **DO NOT commit test data to this repository.**
|
|
42
|
+
3. Test data is expected to reside in a sibling directory: `../xfina-test-data/`.
|
|
43
|
+
4. When writing your test, follow this strict snapshot pattern to ensure tests run reliably in CI and can be easily updated locally:
|
|
44
|
+
|
|
45
|
+
```rust
|
|
46
|
+
let update_expected = std::env::var("UPDATE_EXPECTED").unwrap_or_else(|_| "0".to_string());
|
|
47
|
+
if update_expected == "1" {
|
|
48
|
+
// Write new snapshots
|
|
49
|
+
fs::write(&expected_xfina_path, &xfina_json).unwrap();
|
|
50
|
+
fs::write(&expected_rebit_path, &rebit_json).unwrap();
|
|
51
|
+
} else {
|
|
52
|
+
// Assert against existing snapshots
|
|
53
|
+
let expected_xfina = fs::read_to_string(&expected_xfina_path).unwrap();
|
|
54
|
+
let expected_rebit = fs::read_to_string(&expected_rebit_path).unwrap();
|
|
55
|
+
assert_eq!(expected_xfina, xfina_json, "Xfina JSON mismatch");
|
|
56
|
+
assert_eq!(expected_rebit, rebit_json, "ReBIT JSON mismatch");
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
To update snapshots locally, run:
|
|
61
|
+
```bash
|
|
62
|
+
UPDATE_EXPECTED=1 cargo test
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Pull Request Process
|
|
66
|
+
|
|
67
|
+
1. Ensure your code passes all tests (`cargo test`).
|
|
68
|
+
2. Ensure your code is properly formatted (`cargo fmt`).
|
|
69
|
+
3. If modifying WASM interfaces, rebuild the WASM bundle (`cd wasm && wasm-pack build --target web`).
|
|
70
|
+
4. Update the `README.md` and `task.md` if applicable.
|
|
71
|
+
5. Submit a pull request to the `main` branch.
|
|
72
|
+
|
|
73
|
+
## License
|
|
74
|
+
|
|
75
|
+
By contributing to Xfina, you agree that your contributions will be licensed under the Apache 2.0 License.
|