This is the main repository of SwiftBeanCount. It does not contain any code, but only documentation.
SwiftBeanCount is a double-entry accounting software written in Swift. It is inspired by beancount (hence the name) and therefore reads and writes plain text accounting files.
Beancount is an amazing project and I am an active user of it. I'd recommend it to everybody who is good in the commandline and wants to take control of their finances. My aim is not to create a competitor. I started this project and continue to work on it in my spare time for different reasons:
- Learn, practice and keep up to date with Swift
- Learn SwiftUI
- Do some native MacOS developement (normally I focus on iOS)
- Gain experience in GitHub Actions
- Practice TDD
As metioned above my goal is not to create a competitor to beancount. Beancount is used by a lot of people and has proven itself over years, while this project is the hobby of a single person.
The goal is to supplement my usage of beancount and fava. As it operates on plain text files, you can use them in beancount and SwiftBeanCount, perfoming operations in which tool better fits your needs, switching as often as you like. Therefore I aim to keep the syntax of SwiftBeanCount mostly a subset of the syntax beancount uses (read more about this below).
The project is split across several repositories, please consult their readmes to get more instructions:
Apps with a user interface:
- SwiftBeanCountImporterApp: App to import CSV files and texts from banks websites, as well as download data directly from there, and return the user transactions to add to their ledger
- SwiftBeanCountCLI: CLI tool for basic operations on the ledger
- SwiftBeanCountApp: GUI tool for basic operations on the ledger
The code is split up in several internal libraries, which allows functionality to be re-used across different apps:
- SwiftBeanCountModel: Model which holds all data as well as the logic
- SwiftBeanCountParser: Parser which reads the plain text and transforms it into an instance of the model
- SwiftBeanCountParserUtils: Utility functions for parsing, which are shared by the parser and some importers / mappers
- SwiftBeanCountImporter: Library to read CSV files and texts (e.g. from banks) and transform them into transactions
- SwiftBeanCountTax: Library to help calculate tax related values from your ledger
- SwiftBeanCountSheetSync: Library to sync transaction between a Google Sheet and a ledger
- GoogleAuthentication: Library to help authenticate to Google APIs
- WealthsimpleDownloader: Library to download data from Wealthsimple
- SwiftBeanCountWealthsimpleMapper: Library to convert downloaded data from Wealthsimple
- RogersBankDownloader: Library to download data from Rogers Bank
- SwiftBeanCountRogersBankMapper: Library to convert downloaded data from Rogers Bank
- TangerineDownloader: Library to download data from Tangerine
- SwiftBeanCountTangerineMapper: Library to convert downloaded data from Tangerine
- CompassCardDownloader: Library to download data from the CompassCard website
- SwiftBeanCountCompassCardMapper: Library to convert downloaded data from the CompassCard website
A simplified diagram of the package dependencies:
flowchart LR
subgraph Core
SwiftBeanCountModel
SwiftBeanCountParser
SwiftBeanCountParserUtils
SwiftBeanCountModel --> SwiftBeanCountParser
SwiftBeanCountParserUtils --> SwiftBeanCountParser
end
subgraph CompassCard
SwiftBeanCountCompassCardMapper
CompassCardDownloader
SwiftBeanCountCompassCardMapper ~~~ CompassCardDownloader
end
subgraph Tangerine
SwiftBeanCountTangerineMapper
TangerineDownloader
SwiftBeanCountTangerineMapper ~~~ TangerineDownloader
end
subgraph Wealthsimple
SwiftBeanCountWealthsimpleMapper
WealthsimpleDownloader
WealthsimpleDownloader --> SwiftBeanCountWealthsimpleMapper
end
subgraph Rogers
SwiftBeanCountRogersBankMapper
RogersBankDownloader
RogersBankDownloader --> SwiftBeanCountRogersBankMapper
end
subgraph GoogleSheets
SwiftBeanCountSheetSync
GoogleAuthentication
GoogleAuthentication --> SwiftBeanCountSheetSync
end
SwiftScraper --> TangerineDownloader
SwiftScraper --> CompassCardDownloader
CSV --> SwiftBeanCountCompassCardMapper
Wealthsimple --> SwiftBeanCountImporter
Tangerine ---> SwiftBeanCountImporter
CompassCard --> SwiftBeanCountImporter
Rogers --> SwiftBeanCountImporter
Core --> SwiftBeanCountRogersBankMapper
Core --> SwiftBeanCountImporter
Core --> SwiftBeanCountWealthsimpleMapper
Core --> SwiftBeanCountTangerineMapper
Core --> SwiftBeanCountCompassCardMapper
Core ---> SwiftBeanCountImporterApp
Core --> SwiftBeanCountSheetSync
SwiftBeanCountImporter --> SwiftBeanCountImporterApp
KeychainAccess ----> SwiftBeanCountImporterApp
KeychainAccess ---> GoogleAuthentication
OAuthSwift --> GoogleAuthentication
SwiftBeanCountSheetSync --> SwiftBeanCountImporter
Core ---> SwiftBeanCountTax
SwiftBeanCountTax --> SwiftBeanCountCLI
Core ----> SwiftBeanCountCLI
swift-argument-parser ---> SwiftBeanCountCLI
SwiftyTextTable ---> SwiftBeanCountCLI
Rainbow ---> SwiftBeanCountCLI
CSV --> SwiftBeanCountImporter
click SwiftBeanCountModel "https://github.com/Nef10/SwiftBeanCountModel"
click SwiftBeanCountParser "https://github.com/Nef10/SwiftBeanCountParser"
click SwiftBeanCountParserUtils "https://github.com/Nef10/SwiftBeanCountParserUtils"
click SwiftBeanCountTax "https://github.com/Nef10/SwiftBeanCountTax"
click SwiftBeanCountWealthsimpleMapper "https://github.com/Nef10/SwiftBeanCountWealthsimpleMapper"
click WealthsimpleDownloader "https://github.com/Nef10/WealthsimpleDownloader"
click SwiftBeanCountRogersBankMapper "https://github.com/Nef10/SwiftBeanCountRogersBankMapper"
click RogersBankDownloader "https://github.com/Nef10/RogersBankDownloader"
click SwiftBeanCountTangerineMapper "https://github.com/Nef10/SwiftBeanCountTangerineMapper"
click CompassCardDownloader "https://github.com/Nef10/CompassCardDownloader"
click SwiftBeanCountCompassCardMapper "https://github.com/Nef10/SwiftBeanCountCompassCardMapper"
click TangerineDownloader "https://github.com/Nef10/TangerineDownloader"
click SwiftBeanCountImporter "https://github.com/Nef10/SwiftBeanCountImporter"
click SwiftBeanCountImporterApp "https://github.com/Nef10/SwiftBeanCountImporterApp"
click SwiftBeanCountSheetSync "https://github.com/Nef10/SwiftBeanCountSheetSync"
click SwiftBeanCountCLI "https://github.com/Nef10/SwiftBeanCountCLI"
click GoogleAuthentication "https://github.com/Nef10/GoogleAuthentication"
click SwiftScraper "https://github.com/Nef10/SwiftScraper"
click swift-argument-parser "https://github.com/apple/swift-argument-parser"
click SwiftyTextTable "https://github.com/scottrhoyt/SwiftyTextTable"
click Rainbow "https://github.com/onevcat/Rainbow"
click OAuthSwift "https://github.com/OAuthSwift/OAuthSwift"
click KeychainAccess "https://github.com/kishikawakatsumi/KeychainAccess"
click CSV "https://github.com/yaslab/CSV.swift"
classDef default fill:#99CCFF;
classDef box fill:#F5F5F5;
classDef app fill:#99FF99;
classDef external fill:#FF99FF;
classDef cli fill:#FFCC99;
class Core,Rogers,Wealthsimple,Tangerine,CompassCard,GoogleSheets box;
class SwiftBeanCountImporterApp,App app;
class CSV,OAuthSwift,KeychainAccess,External,swift-argument-parser,SwiftyTextTable,Rainbow external;
class SwiftBeanCountCLI cli;
flowchart LR
subgraph Legend
Library
External[External Library]
CLI
App
end
classDef default fill:#99CCFF;
classDef box fill:#F5F5F5;
classDef app fill:#99FF99;
classDef external fill:#FF99FF;
classDef cli fill:#FFCC99;
class App app;
class External external;
class CLI cli;
class Legend box;
This project is in an alpha stage, please do not use unless you are open to experiment or contribute.
If you want to use SwiftBeanCount please make sure your ledger file does not include any of this:
- Date with slashes instead of dashes
- "txn" instead of * as ok flag
- Flags on Postings
- An optional pipe between payee and narration
- Leave out payee / narration field
- Amount Interpolation (Ticket)
- Inline math
- Links
- Pad (Ticket)
- Documents (Ticket)
- Options (Ticket)
- Notes (Ticket)
- Includes
- Plugins
- Tag stacks (Ticket)
- Balance checks on parent accounts
- Accounts with more than one defined commodity
- Lines with unrecognizable input (will output warning in SwiftBeanCount)
If you use this synax please note that your file will probably stop working in beancount. Threrefore I strongly recommend against using any of this:
- Full unicode support
- Commodities with more than 24 characters
- SwiftBeanCounts parsing is not (yet) optimized and therefore slow
- SwiftBeanCount count only support percision which without decimal point fits into UInt64 (should not be a problem in the real world)
Contributions in form of bug reports or pull requests are very welcome!