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.
Files changed (133) hide show
  1. xfina-0.4.0/.cargo/config.toml +2 -0
  2. xfina-0.4.0/.github/workflows/deploy-unreleased.yml +43 -0
  3. xfina-0.4.0/.github/workflows/publish.yml +235 -0
  4. xfina-0.4.0/.github/workflows/test.yml +69 -0
  5. xfina-0.4.0/.gitignore +47 -0
  6. xfina-0.4.0/AGENTS.md +39 -0
  7. xfina-0.4.0/CHANGELOG.md +162 -0
  8. xfina-0.4.0/CONTRIBUTING.md +75 -0
  9. xfina-0.4.0/Cargo.lock +1792 -0
  10. xfina-0.4.0/Cargo.toml +85 -0
  11. xfina-0.4.0/LICENSE +201 -0
  12. xfina-0.4.0/PKG-INFO +137 -0
  13. xfina-0.4.0/README.md +254 -0
  14. xfina-0.4.0/pyproject.toml +28 -0
  15. xfina-0.4.0/python/Cargo.toml +20 -0
  16. xfina-0.4.0/python/README.md +119 -0
  17. xfina-0.4.0/python/src/lib.rs +88 -0
  18. xfina-0.4.0/src/bank_accounts/axis.rs +404 -0
  19. xfina-0.4.0/src/bank_accounts/bob.rs +453 -0
  20. xfina-0.4.0/src/bank_accounts/hdfc.rs +476 -0
  21. xfina-0.4.0/src/bank_accounts/icici.rs +301 -0
  22. xfina-0.4.0/src/bank_accounts/layout.rs +80 -0
  23. xfina-0.4.0/src/bank_accounts/pdf_parser.rs +98 -0
  24. xfina-0.4.0/src/bank_accounts/sbi.rs +632 -0
  25. xfina-0.4.0/src/credit_cards/axis.rs +403 -0
  26. xfina-0.4.0/src/credit_cards/hdfc.rs +514 -0
  27. xfina-0.4.0/src/credit_cards/icici.rs +495 -0
  28. xfina-0.4.0/src/error.rs +34 -0
  29. xfina-0.4.0/src/intl_stocks/ibkr.rs +523 -0
  30. xfina-0.4.0/src/lib.rs +79 -0
  31. xfina-0.4.0/src/main.rs +307 -0
  32. xfina-0.4.0/src/models/credit_card.rs +263 -0
  33. xfina-0.4.0/src/models/date_utils.rs +35 -0
  34. xfina-0.4.0/src/models/deposit.rs +330 -0
  35. xfina-0.4.0/src/models/equity.rs +318 -0
  36. xfina-0.4.0/src/models/mod.rs +135 -0
  37. xfina-0.4.0/src/models/mutual_funds.rs +403 -0
  38. xfina-0.4.0/src/models/request.rs +33 -0
  39. xfina-0.4.0/src/models/serializer.rs +61 -0
  40. xfina-0.4.0/src/models/validation.rs +342 -0
  41. xfina-0.4.0/src/mutual_funds/cams.rs +135 -0
  42. xfina-0.4.0/src/mutual_funds/cas.rs +1248 -0
  43. xfina-0.4.0/src/mutual_funds/layout.rs +83 -0
  44. xfina-0.4.0/tests/bank_accounts_axis_integration.rs +68 -0
  45. xfina-0.4.0/tests/bank_accounts_bob_integration.rs +70 -0
  46. xfina-0.4.0/tests/bank_accounts_hdfc_integration.rs +88 -0
  47. xfina-0.4.0/tests/bank_accounts_icici_integration.rs +90 -0
  48. xfina-0.4.0/tests/bank_accounts_sbi_integration.rs +86 -0
  49. xfina-0.4.0/tests/credit_cards_axis_integration.rs +91 -0
  50. xfina-0.4.0/tests/credit_cards_hdfc_integration.rs +107 -0
  51. xfina-0.4.0/tests/credit_cards_icici_integration.rs +99 -0
  52. xfina-0.4.0/tests/intl_stocks_ibkr_integration.rs +65 -0
  53. xfina-0.4.0/tests/mutual_funds_cams_integration.rs +132 -0
  54. xfina-0.4.0/web/.gitignore +28 -0
  55. xfina-0.4.0/web/.vscode/extensions.json +3 -0
  56. xfina-0.4.0/web/README.md +5 -0
  57. xfina-0.4.0/web/components.json +15 -0
  58. xfina-0.4.0/web/index.html +13 -0
  59. xfina-0.4.0/web/jsconfig.json +8 -0
  60. xfina-0.4.0/web/package-lock.json +4011 -0
  61. xfina-0.4.0/web/package.json +30 -0
  62. xfina-0.4.0/web/postcss.config.js +6 -0
  63. xfina-0.4.0/web/public/CNAME +1 -0
  64. xfina-0.4.0/web/public/favicon.svg +59 -0
  65. xfina-0.4.0/web/public/icons.svg +24 -0
  66. xfina-0.4.0/web/src/App.vue +1647 -0
  67. xfina-0.4.0/web/src/assets/hero.png +0 -0
  68. xfina-0.4.0/web/src/assets/vite.svg +1 -0
  69. xfina-0.4.0/web/src/assets/vue.svg +1 -0
  70. xfina-0.4.0/web/src/components/EquityStatementUI.txt +126 -0
  71. xfina-0.4.0/web/src/components/HelloWorld.vue +95 -0
  72. xfina-0.4.0/web/src/components/StatementHeader.vue +107 -0
  73. xfina-0.4.0/web/src/components/ui/accordion/Accordion.vue +25 -0
  74. xfina-0.4.0/web/src/components/ui/accordion/AccordionContent.vue +29 -0
  75. xfina-0.4.0/web/src/components/ui/accordion/AccordionItem.vue +28 -0
  76. xfina-0.4.0/web/src/components/ui/accordion/AccordionTrigger.vue +39 -0
  77. xfina-0.4.0/web/src/components/ui/accordion/index.js +4 -0
  78. xfina-0.4.0/web/src/components/ui/button/Button.vue +27 -0
  79. xfina-0.4.0/web/src/components/ui/button/index.js +34 -0
  80. xfina-0.4.0/web/src/components/ui/card/Card.vue +24 -0
  81. xfina-0.4.0/web/src/components/ui/card/CardContent.vue +17 -0
  82. xfina-0.4.0/web/src/components/ui/card/CardDescription.vue +17 -0
  83. xfina-0.4.0/web/src/components/ui/card/CardFooter.vue +17 -0
  84. xfina-0.4.0/web/src/components/ui/card/CardHeader.vue +17 -0
  85. xfina-0.4.0/web/src/components/ui/card/CardTitle.vue +21 -0
  86. xfina-0.4.0/web/src/components/ui/card/index.js +6 -0
  87. xfina-0.4.0/web/src/components/ui/dialog/Dialog.vue +19 -0
  88. xfina-0.4.0/web/src/components/ui/dialog/DialogClose.vue +14 -0
  89. xfina-0.4.0/web/src/components/ui/dialog/DialogContent.vue +62 -0
  90. xfina-0.4.0/web/src/components/ui/dialog/DialogDescription.vue +28 -0
  91. xfina-0.4.0/web/src/components/ui/dialog/DialogFooter.vue +24 -0
  92. xfina-0.4.0/web/src/components/ui/dialog/DialogHeader.vue +19 -0
  93. xfina-0.4.0/web/src/components/ui/dialog/DialogScrollContent.vue +75 -0
  94. xfina-0.4.0/web/src/components/ui/dialog/DialogTitle.vue +30 -0
  95. xfina-0.4.0/web/src/components/ui/dialog/DialogTrigger.vue +14 -0
  96. xfina-0.4.0/web/src/components/ui/dialog/index.js +9 -0
  97. xfina-0.4.0/web/src/components/ui/input/Input.vue +33 -0
  98. xfina-0.4.0/web/src/components/ui/input/index.js +1 -0
  99. xfina-0.4.0/web/src/components/ui/label/Label.vue +32 -0
  100. xfina-0.4.0/web/src/components/ui/label/index.js +1 -0
  101. xfina-0.4.0/web/src/components/ui/select/Select.vue +27 -0
  102. xfina-0.4.0/web/src/components/ui/select/SelectContent.vue +88 -0
  103. xfina-0.4.0/web/src/components/ui/select/SelectGroup.vue +23 -0
  104. xfina-0.4.0/web/src/components/ui/select/SelectItem.vue +50 -0
  105. xfina-0.4.0/web/src/components/ui/select/SelectItemText.vue +14 -0
  106. xfina-0.4.0/web/src/components/ui/select/SelectLabel.vue +23 -0
  107. xfina-0.4.0/web/src/components/ui/select/SelectScrollDownButton.vue +33 -0
  108. xfina-0.4.0/web/src/components/ui/select/SelectScrollUpButton.vue +33 -0
  109. xfina-0.4.0/web/src/components/ui/select/SelectSeparator.vue +24 -0
  110. xfina-0.4.0/web/src/components/ui/select/SelectTrigger.vue +39 -0
  111. xfina-0.4.0/web/src/components/ui/select/SelectValue.vue +15 -0
  112. xfina-0.4.0/web/src/components/ui/select/index.js +11 -0
  113. xfina-0.4.0/web/src/components/ui/table/Table.vue +19 -0
  114. xfina-0.4.0/web/src/components/ui/table/TableBody.vue +17 -0
  115. xfina-0.4.0/web/src/components/ui/table/TableCaption.vue +17 -0
  116. xfina-0.4.0/web/src/components/ui/table/TableCell.vue +19 -0
  117. xfina-0.4.0/web/src/components/ui/table/TableEmpty.vue +35 -0
  118. xfina-0.4.0/web/src/components/ui/table/TableFooter.vue +21 -0
  119. xfina-0.4.0/web/src/components/ui/table/TableHead.vue +24 -0
  120. xfina-0.4.0/web/src/components/ui/table/TableHeader.vue +17 -0
  121. xfina-0.4.0/web/src/components/ui/table/TableRow.vue +24 -0
  122. xfina-0.4.0/web/src/components/ui/table/index.js +9 -0
  123. xfina-0.4.0/web/src/components/ui/tooltip/Tooltip.vue +22 -0
  124. xfina-0.4.0/web/src/components/ui/tooltip/TooltipContent.vue +55 -0
  125. xfina-0.4.0/web/src/components/ui/tooltip/TooltipProvider.vue +19 -0
  126. xfina-0.4.0/web/src/components/ui/tooltip/TooltipTrigger.vue +15 -0
  127. xfina-0.4.0/web/src/components/ui/tooltip/index.js +4 -0
  128. xfina-0.4.0/web/src/lib/analytics.js +58 -0
  129. xfina-0.4.0/web/src/lib/utils.js +6 -0
  130. xfina-0.4.0/web/src/main.js +6 -0
  131. xfina-0.4.0/web/src/style.css +59 -0
  132. xfina-0.4.0/web/tailwind.config.js +75 -0
  133. xfina-0.4.0/web/vite.config.js +39 -0
@@ -0,0 +1,2 @@
1
+ [alias]
2
+ xtask = "run --package xtask --"
@@ -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).
@@ -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.