XO Wallet Integration Part IV

This commit is contained in:
Jim Hamill
2025-05-27 23:17:41 +00:00
parent 25b58853a3
commit 2bfeed8587
15 changed files with 249 additions and 123 deletions
+58 -2
View File
@@ -35,6 +35,62 @@ A table of common prefixes (conventions) is below:
| revert | Reverts a previous commit |
## Coding Guidelines
These guidelines represent best practices. While exceptions may occasionally be necessary as "the lesser evil," strive to adhere to these principles whenever possible.
1. Try to minimize state
State is a complexity multiplier. Keep mutable class members to an absolute minimum, as each stateful property exponentially increases cognitive load and potential for bugs. When designing classes or components, first attempt a stateless approach, adding mutable properties only when demonstrably necessary.
2. Try to avoid `any` types
Use `unknown` instead, as it provides better type safety while maintaining flexibility when needed.
3. Prefer immutable patterns
Use immutable data structures where possible to improve code predictability and testability.
For example:
```ts
// GOOD:
const mappedData = originalData.map((item) => item.field);
// AVOID:
const mappedData = [];
for(let i = 0; i < originalData.length; i++) {
mappedData.push(originalData[i].field);
}
```
Do note that there are some cases where it may make more sense to mutate data inline (e.g. as an optimization for very large data structures).
Use your best judgement, but treat immutability as the general rule.
4. Avoid Typescript, Linter and Formatter Directives
These exceptional cases should be minimized as they:
- Create inconsistency in code standards
- Make maintenance more difficult
- Often mask underlying issues that should be properly resolved
- Can lead to unintended side-effects throughout the codebase
4. Avoid additional dependencies.
Try to avoid pulling in additional packages. Not only can this bloat the project, but can also cause compatibility issues between environments (Web, Node, ESM, etc). We want `@xocash/stack` to "just work" without devs having to tailor build configurations.
Obviously this is an ideal: Sometimes it is simply not feasible or sensible to rewrite complex functionality that can be better done by a well-built package. However, please try to adhere to the following:
- Ensure the package is of high quality (well-written, well-tested).
- Does not drag in additional dependencies itself (note that `devDependencies` are fine. These will not be installed when leveraged from our packages).
- If the package being used **is heavy** and we have no other choice but to use it, consider whether we should package it separately to avoid problems. For example, if we build a `BlockchainBCHN` adapter, we will likely want to package this on its own under `@xocash/blockchain-bchn` as it only works in NodeJS environments.
5. "When in Rome..."
For conventions not explicitly mentioned, follow the "when in Rome" principle. Try to identify and use the patterns and conventions that are already established elsewhere in the codebase.
## Patterns
### Dependency Injection
@@ -77,7 +133,7 @@ class SomeClass {
### Factory Patterns
When creating classes, create static `from(...)` (or `fromSpecificThing(...)`) methods.
When creating classes, create static `from(...)` (or `fromSpecificThing(...)`) methods and place these at the top of the class (so that they appear first in the generated documentation).
In Javascript, a `constructor` cannot be asynchronous and we want to ensure that we can `await` class instantiation to mitigate against stateful errors.
@@ -223,7 +279,7 @@ Avoid revalidation at every code-path: This is not only inefficient, but a giant
```ts
// You can accept other types (this is a nice convenience).
broadcastTransaction(transaction: Transaction | Uint8Array): Transaction {
broadcastTransaction(transaction: Transaction | Uint8Array | string): Transaction {
// ... but always cast to the Primitive (to ensure correctness).
if(!(transaction instanceof Transaction) {
transaction = Transaction.from(transaction);