diff --git a/.c8rc.json b/.c8rc.json index e8d5d09..6c9f553 100644 --- a/.c8rc.json +++ b/.c8rc.json @@ -1,8 +1,8 @@ { "all": true, "include": ["src/**/*.ts"], - "exclude": ["src/**/*.d.ts", "src/**/*.test.ts", "src/types/*.ts", "src/tests/**/*.ts"], + "exclude": ["src/**/*.d.ts", "src/**/*.test.ts", "src/types/*.ts", "src/tests/**/*.ts", "docs/**/*.md"], "reporter": ["text", "lcov"], "extension": [".ts"], "report-dir": "./coverage" -} \ No newline at end of file +} diff --git a/.github/ci-scripts/update-sdk-docs.cjs b/.github/ci-scripts/update-sdk-docs.cjs new file mode 100644 index 0000000..332013c --- /dev/null +++ b/.github/ci-scripts/update-sdk-docs.cjs @@ -0,0 +1,194 @@ +const fs = require('fs/promises') +const path = require('path') +const simpleGit = require('simple-git') +const { execSync } = require('child_process') + +/** + * Recursively gets all files from a directory + */ +async function getFilesRecursively(dir) { + const items = await fs.readdir(dir, { withFileTypes: true }) + const files = await Promise.all( + items.map(async (item) => { + const filePath = path.join(dir, item.name) + return item.isDirectory() ? getFilesRecursively(filePath) : filePath + }) + ) + return files.flat() +} + +/** + * Cleans generated documentation folders: classes and type-aliases + */ +async function cleanGeneratedDocs(targetDir) { + const foldersToClean = ['classes', 'type-aliases'] + for (const folder of foldersToClean) { + const folderPath = path.join(targetDir, folder) + try { + await fs.rm(folderPath, { recursive: true, force: true }) + console.log(`✨ Cleared existing ${folder} folder`) + } catch (error) { + if (error.code !== 'ENOENT') { + console.error(`❌ Error clearing ${folder} folder:`, error) + } + } + } +} + +/** + * Copies documentation files while maintaining structure + */ +async function copyDocs(sourceDir, targetDir) { + try { + await fs.mkdir(targetDir, { recursive: true }) + await cleanGeneratedDocs(targetDir) + + const docFiles = await getFilesRecursively(sourceDir) + for (const file of docFiles) { + const relativePath = path.relative(sourceDir, file) + if (path.basename(file) === 'README.md') continue + + const targetPath = path.join(targetDir, relativePath) + await fs.mkdir(path.dirname(targetPath), { recursive: true }) + await fs.copyFile(file, targetPath) + console.log(`📄 Copied: ${relativePath}`) + } + } catch (error) { + console.error('❌ Error copying docs:', error) + throw error + } +} + +/** + * Processes and updates the index.html.md file + */ +async function updateIndexHtmlMd(docsDir, indexHtmlMdPath) { + try { + const content = await fs.readFile(indexHtmlMdPath, 'utf8') + const docFiles = await getFilesRecursively(docsDir) + + // Transform and validate files + const actualFiles = new Set( + docFiles.map((file) => path.relative(docsDir, file).replace(/\/_/g, '/').replace(/^_/, '').replace(/\.md$/, '')) + ) + + // Extract existing includes + const existingIncludesMatch = content.match(/^includes:\n((?: - .*\n)*)/m) + const existingIncludes = existingIncludesMatch + ? existingIncludesMatch[1] + .split('\n') + .map((line) => line.replace(' - ', '')) + .filter(Boolean) + : [] + + // Process new includes + const newIncludes = docFiles + .filter((file) => file.endsWith('.md')) + .filter((file) => !file.includes('README.md')) + .map((file) => { + const relativePath = path.relative(docsDir, file) + return relativePath.replace(/\/_/g, '/').replace(/^_/, '').replace(/\.md$/, '') + }) + + // Combine and validate includes + const allIncludes = [ + ...existingIncludes.filter((inc) => !inc.startsWith('classes/') && !inc.startsWith('type-aliases/')), + ...newIncludes, + ] + .filter((value, index, self) => self.indexOf(value) === index) + .filter((include) => { + if (include.startsWith('classes/') || include.startsWith('type-aliases/')) { + const exists = actualFiles.has(include) + if (!exists) console.log(`⚠ī¸ Warning: File not found for include: ${include}`) + return exists + } + return true + }) + + // Update content + const [frontmatterStart, ...rest] = content.split(/^includes:/m) + const remainingContent = rest.join('includes:').split('---') + const postFrontmatter = remainingContent.slice(1).join('---') + + const updatedContent = `${frontmatterStart}includes: +${allIncludes.map((file) => ` - ${file}`).join('\n')} +search: true +---${postFrontmatter}` + + await fs.writeFile(indexHtmlMdPath, updatedContent) + + console.log(`✅ Total includes: ${allIncludes.length}`) + } catch (error) { + console.error('❌ Error updating index.html.md:', error) + throw error + } +} + +/** + * Creates a PR in the sdk-docs repository + */ +async function createPullRequest(git, branchName) { + const prTitle = '[sdk:ci:bot] Update SDK Documentation' + const prBody = + '[sdk:ci:bot] Automated PR to update SDK documentation: [Actions](https://github.com/centrifuge/sdk/actions/workflows/update-docs.yml)' + + const prCommand = `gh pr create \ + --title "${prTitle}" \ + --body "${prBody}" \ + --base main \ + --head ${branchName} \ + --repo "centrifuge/sdk-docs"` + + execSync(prCommand, { + stdio: 'inherit', + env: { ...process.env, GH_TOKEN: process.env.PAT_TOKEN }, + }) +} + +async function hasChanges(git) { + try { + await git.fetch('origin', 'main') + + // Get the diff between current state and main branch + const diff = await git.diff(['origin/main']) + + return diff.length > 0 + } catch (error) { + console.error('❌ Error checking for changes:', error) + throw error + } +} + +async function main() { + try { + const git = simpleGit() + const repoUrl = `https://${process.env.PAT_TOKEN}@github.com/centrifuge/sdk-docs.git` + + await git.clone(repoUrl) + await git + .cwd('./sdk-docs') + .addConfig('user.name', 'github-actions[bot]') + .addConfig('user.email', 'github-actions[bot]@users.noreply.github.com') + + await copyDocs('./docs', './sdk-docs/source/includes') + await updateIndexHtmlMd('./docs', './sdk-docs/source/index.html.md') + + if (await hasChanges(git)) { + const branchName = `docs-update-${new Date().toISOString().slice(0, 19).replace(/[:-]/g, '').replace(' ', '-')}` + await git.checkoutLocalBranch(branchName) + await git.add('.').commit('Update SDK documentation') + await git.push('origin', branchName) + + await createPullRequest(git, branchName) + console.log('✅ Successfully created PR with documentation updates') + } else { + console.log('ℹī¸ No documentation changes detected') + } + process.exit(0) + } catch (error) { + console.error('❌ Failed to process docs:', error) + process.exit(1) + } +} + +main() diff --git a/.github/workflows/update-docs.yml b/.github/workflows/update-docs.yml new file mode 100644 index 0000000..72b80f9 --- /dev/null +++ b/.github/workflows/update-docs.yml @@ -0,0 +1,43 @@ +# This workflow will update the docs in the sdk-docs repo + +name: Update Docs + +on: + push: + branches: + - generate-docs + +jobs: + update-docs: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Setup Yarn + run: | + corepack enable + corepack prepare yarn@4.5.0 --activate + + - name: Install dependencies + run: yarn install + + - name: Run gen:docs command + run: yarn gen:docs + + - name: Install dependencies + run: yarn add simple-git + + - name: Setup GitHub CLI + run: | + gh auth login --with-token <<< "${{ secrets.GITHUB_TOKEN }}" + + - name: Update docs + env: + PAT_TOKEN: ${{ secrets.PAT_TOKEN }} + run: node ./.github/ci-scripts/update-sdk-docs.cjs diff --git a/README.md b/README.md index 906b148..9631396 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,10 @@ yarn test:single yarn test:simple:single # without setup file, faster and without tenderly setup ``` +## User Docs + +User docs are written and maintained in the [sdk-docs](https://github.com/centrifuge/sdk-docs) repository. On push to the `main` branch, a GitHub Action will run and update the docs with the auto-generated docs from this repository using ([typedoc](https://typedoc.org/)). + ### PR Naming Convention PR naming should follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification. diff --git a/package.json b/package.json index 95a8aa5..c48f373 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@centrifuge/sdk", - "version": "0.0.0-alpha.5", + "version": "0.0.0-alpha.6", "description": "", "homepage": "https://github.com/centrifuge/sdk/tree/main#readme", "author": "", @@ -33,7 +33,8 @@ "test:simple:single": "mocha --loader=ts-node/esm --exit --timeout 60000", "test:single": "mocha --loader=ts-node/esm --require $(pwd)/src/tests/setup.ts --exit --timeout 60000", "test:ci": "yarn test --reporter mocha-multi-reporters --reporter-options configFile=mocha-reporter-config.json", - "test:coverage": "c8 yarn test:ci" + "test:coverage": "c8 yarn test:ci", + "gen:docs": "typedoc" }, "dependencies": { "decimal.js-light": "^2.5.1", @@ -61,6 +62,8 @@ "sinon-chai": "^4.0.0", "source-map-support": "^0.5.21", "ts-node": "^10.9.2", + "typedoc": "^0.27.6", + "typedoc-plugin-markdown": "^4.4.1", "typescript": "~5.6.3", "typescript-eslint": "^8.8.1", "viem": "^2.21.25" diff --git a/src/Centrifuge.ts b/src/Centrifuge.ts index 5363854..288ff6b 100644 --- a/src/Centrifuge.ts +++ b/src/Centrifuge.ts @@ -24,7 +24,6 @@ import { type Abi, type Account as AccountType, type Chain, - type PublicClient, type WalletClient, type WatchEventOnLogsParameter, } from 'viem' @@ -34,7 +33,7 @@ import { chains } from './config/chains.js' import type { CurrencyMetadata } from './config/lp.js' import { PERMIT_TYPEHASH } from './constants.js' import { Pool } from './Pool.js' -import type { HexString } from './types/index.js' +import type { Client, DerivedConfig, EnvConfig, HexString, UserProvidedConfig } from './types/index.js' import type { CentrifugeQueryOptions, Query } from './types/query.js' import type { OperationStatus, Signer, Transaction, TransactionCallbackParams } from './types/transaction.js' import { Currency } from './utils/BigInt.js' @@ -42,23 +41,6 @@ import { hashKey } from './utils/query.js' import { makeThenable, repeatOnEvents, shareReplayWithDelayedReset } from './utils/rx.js' import { doTransaction, isLocalAccount } from './utils/transaction.js' -export type Config = { - environment: 'mainnet' | 'demo' | 'dev' - rpcUrls?: Record - indexerUrl: string - ipfsUrl: string -} - -export type UserProvidedConfig = Partial -type EnvConfig = { - indexerUrl: string - alchemyKey: string - infuraKey: string - defaultChain: number - ipfsUrl: string -} -type DerivedConfig = Config & EnvConfig - const envConfig = { mainnet: { indexerUrl: 'https://subql.embrio.tech/', @@ -93,7 +75,7 @@ export class Centrifuge { return this.#config } - #clients = new Map>() + #clients = new Map() getClient(chainId?: number) { return this.#clients.get(chainId ?? this.config.defaultChain) } @@ -134,8 +116,8 @@ export class Centrifuge { }) } - pool(id: string, metadataHash?: string) { - return this._query(null, () => of(new Pool(this, id, metadataHash))) + pool(id: string | number, metadataHash?: string) { + return this._query(null, () => of(new Pool(this, String(id), metadataHash))) } account(address: string, chainId?: number) { @@ -535,6 +517,7 @@ export class Centrifuge { * // { type: 'SigningTransaction', title: 'Invest' } * // { type: 'TransactionPending', title: 'Invest', hash: '0x123...abc' } * // { type: 'TransactionConfirmed', title: 'Invest', hash: '0x123...abc', receipt: { ... } } + * ``` * * @internal */ diff --git a/src/Entity.ts b/src/Entity.ts index 5935a77..45da064 100644 --- a/src/Entity.ts +++ b/src/Entity.ts @@ -4,9 +4,12 @@ import type { CentrifugeQueryOptions } from './types/query.js' export class Entity { #baseKeys: (string | number)[] + /** @internal */ _transact: Centrifuge['_transact'] + /** @internal */ _transactSequence: Centrifuge['_transactSequence'] constructor( + /** @internal */ protected _root: Centrifuge, queryKeys: (string | number)[] ) { @@ -15,6 +18,7 @@ export class Entity { this._transactSequence = this._root._transactSequence.bind(this._root) } + /** @internal */ protected _query( keys: (string | number | undefined)[] | null, observableCallback: () => Observable, diff --git a/src/Pool.ts b/src/Pool.ts index c4536e8..f9122c5 100644 --- a/src/Pool.ts +++ b/src/Pool.ts @@ -6,6 +6,7 @@ import { Reports } from './Reports/index.js' import { PoolMetadata } from './types/poolMetadata.js' export class Pool extends Entity { + /** @internal */ constructor( _root: Centrifuge, public id: string, @@ -19,7 +20,9 @@ export class Pool extends Entity { } metadata() { - return this.metadataHash ? this._root._queryIPFS(this.metadataHash) : of(undefined) + return this.metadataHash + ? this._root._queryIPFS(this.metadataHash) + : this._query(null, () => of(null)) } trancheIds() { diff --git a/src/PoolNetwork.ts b/src/PoolNetwork.ts index 2ebedd8..31ce974 100644 --- a/src/PoolNetwork.ts +++ b/src/PoolNetwork.ts @@ -14,6 +14,7 @@ import { Vault } from './Vault.js' * Query and interact with a pool on a specific network. */ export class PoolNetwork extends Entity { + /** @internal */ constructor( _root: Centrifuge, public pool: Pool, @@ -192,9 +193,10 @@ export class PoolNetwork extends Entity { /** * Get all Vaults for all tranches in the pool. + * @returns An object of tranche ID to Vault. */ vaultsByTranche() { - return this._query(null, () => + return this._query>(null, () => this.pool.trancheIds().pipe( switchMap((tranches) => { return combineLatest(tranches.map((trancheId) => this.vaults(trancheId))).pipe( diff --git a/src/Reports/Processor.ts b/src/Reports/Processor.ts index 85984e7..1ac765f 100644 --- a/src/Reports/Processor.ts +++ b/src/Reports/Processor.ts @@ -1,37 +1,37 @@ import { AssetTransaction } from '../IndexerQueries/assetTransactions.js' import { InvestorTransaction } from '../IndexerQueries/investorTransactions.js' -import { Currency, Price, Rate, Token } from '../utils/BigInt.js' -import { groupByPeriod } from '../utils/date.js' +import { PoolFeeTransaction } from '../IndexerQueries/poolFeeTransactions.js' import { + AssetListData, + AssetListReport, + AssetListReportFilter, + AssetListReportPrivateCredit, + AssetListReportPublicCredit, + AssetTransactionReport, + AssetTransactionReportFilter, + AssetTransactionsData, BalanceSheetData, BalanceSheetReport, CashflowData, CashflowReport, - ProfitAndLossReport, - ProfitAndLossData, - ReportFilter, + FeeTransactionReport, + FeeTransactionReportFilter, + FeeTransactionsData, + InvestorListData, + InvestorListReport, + InvestorListReportFilter, InvestorTransactionsData, InvestorTransactionsReport, InvestorTransactionsReportFilter, - AssetTransactionReport, - AssetTransactionsData, - AssetTransactionReportFilter, - FeeTransactionsData, - FeeTransactionReportFilter, - FeeTransactionReport, + ProfitAndLossData, + ProfitAndLossReport, + ReportFilter, + TokenPriceData, TokenPriceReport, TokenPriceReportFilter, - TokenPriceData, - AssetListReport, - AssetListReportFilter, - AssetListData, - AssetListReportPublicCredit, - AssetListReportPrivateCredit, - InvestorListData, - InvestorListReportFilter, - InvestorListReport, } from '../types/reports.js' -import { PoolFeeTransaction } from '../IndexerQueries/poolFeeTransactions.js' +import { Currency, Price, Rate, Token } from '../utils/BigInt.js' +import { groupByPeriod } from '../utils/date.js' export class Processor { /** @@ -299,7 +299,7 @@ export class Processor { if (Object.values(data.trancheSnapshots).length === 0) return [] const items = Object.entries(data.trancheSnapshots).map(([timestamp, snapshots]) => ({ type: 'tokenPrice' as const, - timestamp: timestamp, + timestamp, tranches: snapshots.map((snapshot) => ({ timestamp: snapshot.timestamp, id: snapshot.trancheId, @@ -327,7 +327,8 @@ export class Processor { return isMaturityDatePassed && isDebtZero } else if (filter?.status === 'overdue') { return isMaturityDatePassed && !isDebtZero - } else return true + } + return true }) .sort((a, b) => { // Sort by actualMaturityDate in descending order diff --git a/src/Reports/index.ts b/src/Reports/index.ts index bbd8b28..4c0e092 100644 --- a/src/Reports/index.ts +++ b/src/Reports/index.ts @@ -1,33 +1,31 @@ -import { Entity } from '../Entity.js' +import { combineLatest, map } from 'rxjs' import { Centrifuge } from '../Centrifuge.js' -import { combineLatest } from 'rxjs' -import { processor } from './Processor.js' - -import { map } from 'rxjs' +import { Entity } from '../Entity.js' +import { IndexerQueries } from '../IndexerQueries/index.js' +import { Pool } from '../Pool.js' +import { Query } from '../types/query.js' import { + AssetListReport, + AssetListReportFilter, + AssetTransactionReport, + AssetTransactionReportFilter, BalanceSheetReport, CashflowReport, - InvestorTransactionsReport, - ProfitAndLossReport, - ReportFilter, - Report, DataReport, DataReportFilter, - InvestorTransactionsReportFilter, - AssetTransactionReport, - AssetTransactionReportFilter, - TokenPriceReport, - TokenPriceReportFilter, FeeTransactionReport, FeeTransactionReportFilter, - AssetListReportFilter, - AssetListReport, - InvestorListReportFilter, InvestorListReport, + InvestorListReportFilter, + InvestorTransactionsReport, + InvestorTransactionsReportFilter, + ProfitAndLossReport, + Report, + ReportFilter, + TokenPriceReport, + TokenPriceReportFilter, } from '../types/reports.js' -import { Query } from '../types/query.js' -import { Pool } from '../Pool.js' -import { IndexerQueries } from '../IndexerQueries/index.js' +import { processor } from './Processor.js' const DEFAULT_FILTER: ReportFilter = { from: '2024-01-01T00:00:00.000Z', @@ -35,6 +33,7 @@ const DEFAULT_FILTER: ReportFilter = { } export class Reports extends Entity { private queries: IndexerQueries + /** @internal */ constructor( centrifuge: Centrifuge, public pool: Pool @@ -83,6 +82,8 @@ export class Reports extends Entity { * Reports are split into two types: * - A `Report` is a standard report: balanceSheet, cashflow, profitAndLoss * - A `DataReport` is a custom report: investorTransactions, assetTransactions, feeTransactions, tokenPrice, assetList, investorList + * + * @internal */ _generateReport(type: Report, filter?: ReportFilter): Query _generateReport(type: DataReport, filter?: DataReportFilter): Query diff --git a/src/Vault.ts b/src/Vault.ts index 4e2057a..93af418 100644 --- a/src/Vault.ts +++ b/src/Vault.ts @@ -28,6 +28,7 @@ export class Vault extends Entity { * The contract address of the vault. */ address: HexString + /** @internal */ constructor( _root: Centrifuge, public network: PoolNetwork, diff --git a/src/index.ts b/src/index.ts index 4046ac3..7e7462f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,53 @@ import { Centrifuge } from './Centrifuge.js' +export type { CurrencyMetadata } from './config/lp.js' export * from './Pool.js' export * from './PoolNetwork.js' -export * from './types/index.js' -export * from './types/query.js' -export * from './types/transaction.js' +export * from './Reports/index.js' +export type { Client, Config, HexString } from './types/index.js' +export type { Query } from './types/query.js' +export type { + AssetListReport, + AssetListReportBase, + AssetListReportFilter, + AssetListReportPrivateCredit, + AssetListReportPublicCredit, + AssetTransactionReport, + AssetTransactionReportFilter, + BalanceSheetReport, + CashflowReport, + CashflowReportBase, + CashflowReportPrivateCredit, + CashflowReportPublicCredit, + FeeTransactionReport, + FeeTransactionReportFilter, + InvestorListReport, + InvestorListReportFilter, + InvestorTransactionsReport, + InvestorTransactionsReportFilter, + ProfitAndLossReport, + ProfitAndLossReportBase, + ProfitAndLossReportPrivateCredit, + ProfitAndLossReportPublicCredit, + ReportFilter, + TokenPriceReport, + TokenPriceReportFilter, +} from './types/reports.js' +export type { + EIP1193ProviderLike, + OperationConfirmedStatus, + OperationPendingStatus, + OperationSignedMessageStatus, + OperationSigningMessageStatus, + OperationSigningStatus, + OperationStatus, + OperationStatusType, + OperationSwitchChainStatus, + Signer, + Transaction, +} from './types/transaction.js' +export { Currency, Perquintill, Price, Rate } from './utils/BigInt.js' +export type { GroupBy } from './utils/date.js' export * from './Vault.js' +export { Centrifuge } export default Centrifuge diff --git a/src/types/index.ts b/src/types/index.ts index e658391..a83d096 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1 +1,20 @@ +import { Chain, PublicClient } from 'viem' + +export type Config = { + environment: 'mainnet' | 'demo' | 'dev' + rpcUrls?: Record + indexerUrl: string + ipfsUrl: string +} + +export type UserProvidedConfig = Partial +export type EnvConfig = { + indexerUrl: string + alchemyKey: string + infuraKey: string + defaultChain: number + ipfsUrl: string +} +export type DerivedConfig = Config & EnvConfig +export type Client = PublicClient export type HexString = `0x${string}` diff --git a/src/types/reports.ts b/src/types/reports.ts index 9601c21..42db0b8 100644 --- a/src/types/reports.ts +++ b/src/types/reports.ts @@ -7,11 +7,10 @@ import { PoolSnapshot } from '../IndexerQueries/poolSnapshots.js' import { TrancheCurrencyBalance } from '../IndexerQueries/trancheCurrencyBalance.js' import { TrancheSnapshotsByDate } from '../IndexerQueries/trancheSnapshots.js' import { PoolMetadata } from '../types/poolMetadata.js' -import { Price, Rate, Token } from '../utils/BigInt.js' -import { Currency } from '../utils/BigInt.js' +import { Currency, Price, Rate, Token } from '../utils/BigInt.js' import { GroupBy } from '../utils/date.js' -export interface ReportFilter { +export type ReportFilter = { from?: string to?: string groupBy?: GroupBy @@ -61,7 +60,7 @@ export type BalanceSheetData = { /** * Cashflow types */ -type CashflowReportBase = { +export type CashflowReportBase = { type: 'cashflow' timestamp: string principalPayments: Currency @@ -76,13 +75,13 @@ type CashflowReportBase = { endCashBalance: { balance: Currency } } -type CashflowReportPublicCredit = CashflowReportBase & { +export type CashflowReportPublicCredit = CashflowReportBase & { subtype: 'publicCredit' realizedPL?: Currency assetPurchases?: Currency } -type CashflowReportPrivateCredit = CashflowReportBase & { +export type CashflowReportPrivateCredit = CashflowReportBase & { subtype: 'privateCredit' assetFinancing?: Currency } @@ -92,7 +91,7 @@ export type CashflowReport = CashflowReportPublicCredit | CashflowReportPrivateC export type CashflowData = { poolSnapshots: PoolSnapshot[] poolFeeSnapshots: PoolFeeSnapshotsByDate - metadata: PoolMetadata | undefined + metadata: PoolMetadata | undefined | null } /** @@ -125,7 +124,7 @@ export type ProfitAndLossReport = ProfitAndLossReportPublicCredit | ProfitAndLos export type ProfitAndLossData = { poolSnapshots: PoolSnapshot[] poolFeeSnapshots: PoolFeeSnapshotsByDate - metadata: PoolMetadata | undefined + metadata: PoolMetadata | undefined | null } /** @@ -226,7 +225,7 @@ export type TokenPriceReportFilter = { */ export type AssetListData = { assetSnapshots: AssetSnapshot[] - metadata: PoolMetadata | undefined + metadata: PoolMetadata | undefined | null } export type AssetListReportBase = { diff --git a/src/utils/BigInt.ts b/src/utils/BigInt.ts index 58920f0..efd17eb 100644 --- a/src/utils/BigInt.ts +++ b/src/utils/BigInt.ts @@ -31,6 +31,7 @@ export class DecimalWrapper extends BigIntWrapper { this.decimals = decimals } + /** @internal */ static _fromFloat(num: Numeric, decimals: number) { const n = Dec(num.toString()).mul(Dec(10).pow(decimals)) if (Dec(n).gt(0) && Dec(n).lt(1)) { @@ -47,11 +48,13 @@ export class DecimalWrapper extends BigIntWrapper { return this.toDecimal().toNumber() } + /** @internal */ _add(value: bigint | (T extends DecimalWrapper ? T : never)): T { const val = typeof value === 'bigint' ? value : value.toBigInt() return new (this.constructor as any)(this.value + val, this.decimals) } + /** @internal */ _sub(value: bigint | (T extends DecimalWrapper ? T : never)): T { const val = typeof value === 'bigint' ? value : value.toBigInt() return this._add(-val) @@ -63,6 +66,8 @@ export class DecimalWrapper extends BigIntWrapper { * Currency.fromFloat(1, 6).mul(Price.fromFloat(1.01)) * // Price has 18 decimals * // returns Currency with 6 decimals (1_010_000n or 1.01) + * + * @internal */ _mul(value: bigint | (T extends DecimalWrapper ? T : never)): T { let val: any @@ -76,6 +81,7 @@ export class DecimalWrapper extends BigIntWrapper { return new (this.constructor as any)(this.toDecimal().mul(val), this.decimals) as T } + /** @internal */ _div(value: bigint | (T extends BigIntWrapper ? T : never)): T { if (!value) { throw new Error(`Division by zero`) diff --git a/tsconfig.json b/tsconfig.json index 22e2a14..7be37d5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,7 +16,8 @@ "noImplicitOverride": true, "lib": ["es2023", "dom", "dom.iterable"], "outDir": "dist", - "allowSyntheticDefaultImports": true + "allowSyntheticDefaultImports": true, + "stripInternal": true }, "include": ["src", "src/**/*.d.ts"], "exclude": ["**/*.test.ts"] diff --git a/typedoc-plugin.mjs b/typedoc-plugin.mjs new file mode 100644 index 0000000..53bf505 --- /dev/null +++ b/typedoc-plugin.mjs @@ -0,0 +1,57 @@ +// @ts-check +import url from 'node:url' +import { MarkdownPageEvent } from 'typedoc-plugin-markdown' +import fs from 'node:fs/promises' +import path from 'node:path' + +/** + * @param {import('typedoc-plugin-markdown').MarkdownApplication} app + */ +export function load(app) { + app.renderer.on(MarkdownPageEvent.END, (page) => { + page.contents = page.contents + ?.replace(/(^.*?)(?=\n?#\s)/s, '') + .replace(/^(# .*)(\\<.*?>)/m, (_, heading) => heading.replace(/\\<.*?>/, '').trim()) + .replace('# Type Alias', '# Type') + .replaceAll('# ', '## ') + page.filename = page.filename?.replace(/\/([^\/]+)$/, '/_$1') + page.contents = rewriteMarkdownLinks(page.contents ?? '', page.url) + }) + + app.renderer.postRenderAsyncJobs.push(async (renderer) => { + console.log(renderer.urls?.map((u) => u.url).join('\n')) + + try { + // Delete the README.md + await fs.unlink(path.join(process.cwd(), 'docs', '_README.md')) + // Delete _global.md + await fs.unlink(path.join(process.cwd(), 'docs', '_globals.md')) + } catch (error) { + if (error.code !== 'ENOENT') { + console.error('Error deleting README.md:', error) + } + } + }) +} + +/** + * @param {string} markdownContent + * @param {string} pageUrl + */ +function rewriteMarkdownLinks(markdownContent, pageUrl) { + const linkRegex = /\[([^\]]+)\]\(([^)]+\.md)\)/g + const markdown = markdownContent.replace(linkRegex, (_, linkName, relativePath) => { + const resolvedUrl = url + .resolve(pageUrl, relativePath) + .replace(/\.md$/, '') + .replace(/:/, '') + .replace(/[\s\/]/, '-') + .replace(/^classes/, 'class') + .replace(/^type-aliases/, 'type') + .toLowerCase() + + return `[${linkName}](#${resolvedUrl})` + }) + + return markdown +} diff --git a/typedoc.json b/typedoc.json new file mode 100644 index 0000000..44d4e31 --- /dev/null +++ b/typedoc.json @@ -0,0 +1,18 @@ +{ + "plugin": [ + "typedoc-plugin-markdown", + "./typedoc-plugin.mjs" + ], + "exclude": [ + "**/README.md", + "**/node_modules/**", + "**/*.test.ts" + ], + "entryPoints": [ + "src/index.ts" + ], + "entryPointStrategy": "expand", + "skipErrorChecking": true, + "excludeExternals": true, + "out": "docs" +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 1df25ed..51f62af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -46,6 +46,8 @@ __metadata: sinon-chai: "npm:^4.0.0" source-map-support: "npm:^0.5.21" ts-node: "npm:^10.9.2" + typedoc: "npm:^0.27.6" + typedoc-plugin-markdown: "npm:^4.4.1" typescript: "npm:~5.6.3" typescript-eslint: "npm:^8.8.1" viem: "npm:^2.21.25" @@ -139,6 +141,17 @@ __metadata: languageName: node linkType: hard +"@gerrit0/mini-shiki@npm:^1.24.0": + version: 1.26.1 + resolution: "@gerrit0/mini-shiki@npm:1.26.1" + dependencies: + "@shikijs/engine-oniguruma": "npm:^1.26.1" + "@shikijs/types": "npm:^1.26.1" + "@shikijs/vscode-textmate": "npm:^10.0.1" + checksum: 10c0/044ff495b39105c63e0a8fdd9f46891761a89019e318ffc472a0bd25e632f8593b158efb24a00e6654d8021c7ffd4e8dbbdfe96823da85360e66ebe45e4b8538 + languageName: node + linkType: hard + "@humanfs/core@npm:^0.19.1": version: 0.19.1 resolution: "@humanfs/core@npm:0.19.1" @@ -383,6 +396,33 @@ __metadata: languageName: node linkType: hard +"@shikijs/engine-oniguruma@npm:^1.26.1": + version: 1.26.1 + resolution: "@shikijs/engine-oniguruma@npm:1.26.1" + dependencies: + "@shikijs/types": "npm:1.26.1" + "@shikijs/vscode-textmate": "npm:^10.0.1" + checksum: 10c0/ea5b222459346ad77a0504d27b1e5b47953062a2954d7cdd0632851b0b163fe9bc62c78b505056c5fb0152b12bbb5d076829ffcb3b2440f545287d1283da6a6a + languageName: node + linkType: hard + +"@shikijs/types@npm:1.26.1, @shikijs/types@npm:^1.26.1": + version: 1.26.1 + resolution: "@shikijs/types@npm:1.26.1" + dependencies: + "@shikijs/vscode-textmate": "npm:^10.0.1" + "@types/hast": "npm:^3.0.4" + checksum: 10c0/7f47a071c3ae844936a00b09ae1c973e5e2c9e501f7027a162bdfafc04c5a25ce8c5d593cdd5d83113254b3cda016e4d9fc9498e7808e96167e94e35f44d4f7b + languageName: node + linkType: hard + +"@shikijs/vscode-textmate@npm:^10.0.1": + version: 10.0.1 + resolution: "@shikijs/vscode-textmate@npm:10.0.1" + checksum: 10c0/acdbcf1b00d2503620ab50c2a23c7876444850ae0610c8e8b85a29587a333be40c9b98406ff17b9f87cbc64674dac6a2ada680374bde3e51a890e16cf1407490 + languageName: node + linkType: hard + "@sinonjs/commons@npm:^3.0.1": version: 3.0.1 resolution: "@sinonjs/commons@npm:3.0.1" @@ -470,6 +510,15 @@ __metadata: languageName: node linkType: hard +"@types/hast@npm:^3.0.4": + version: 3.0.4 + resolution: "@types/hast@npm:3.0.4" + dependencies: + "@types/unist": "npm:*" + checksum: 10c0/3249781a511b38f1d330fd1e3344eed3c4e7ea8eff82e835d35da78e637480d36fad37a78be5a7aed8465d237ad0446abc1150859d0fde395354ea634decf9f7 + languageName: node + linkType: hard + "@types/istanbul-lib-coverage@npm:^2.0.1": version: 2.0.6 resolution: "@types/istanbul-lib-coverage@npm:2.0.6" @@ -526,6 +575,13 @@ __metadata: languageName: node linkType: hard +"@types/unist@npm:*": + version: 3.0.3 + resolution: "@types/unist@npm:3.0.3" + checksum: 10c0/2b1e4adcab78388e088fcc3c0ae8700f76619dbcb4741d7d201f87e2cb346bfc29a89003cfea2d76c996e1061452e14fcd737e8b25aacf949c1f2d6b2bc3dd60 + languageName: node + linkType: hard + "@typescript-eslint/eslint-plugin@npm:8.17.0": version: 8.17.0 resolution: "@typescript-eslint/eslint-plugin@npm:8.17.0" @@ -1301,6 +1357,13 @@ __metadata: languageName: node linkType: hard +"entities@npm:^4.4.0": + version: 4.5.0 + resolution: "entities@npm:4.5.0" + checksum: 10c0/5b039739f7621f5d1ad996715e53d964035f75ad3b9a4d38c6b3804bb226e282ffeae2443624d8fdd9c47d8e926ae9ac009c54671243f0c3294c26af7cc85250 + languageName: node + linkType: hard + "env-paths@npm:^2.2.0": version: 2.2.1 resolution: "env-paths@npm:2.2.1" @@ -2557,6 +2620,15 @@ __metadata: languageName: node linkType: hard +"linkify-it@npm:^5.0.0": + version: 5.0.0 + resolution: "linkify-it@npm:5.0.0" + dependencies: + uc.micro: "npm:^2.0.0" + checksum: 10c0/ff4abbcdfa2003472fc3eb4b8e60905ec97718e11e33cca52059919a4c80cc0e0c2a14d23e23d8c00e5402bc5a885cdba8ca053a11483ab3cc8b3c7a52f88e2d + languageName: node + linkType: hard + "load-json-file@npm:^4.0.0": version: 4.0.0 resolution: "load-json-file@npm:4.0.0" @@ -2662,6 +2734,13 @@ __metadata: languageName: node linkType: hard +"lunr@npm:^2.3.9": + version: 2.3.9 + resolution: "lunr@npm:2.3.9" + checksum: 10c0/77d7dbb4fbd602aac161e2b50887d8eda28c0fa3b799159cee380fbb311f1e614219126ecbbd2c3a9c685f1720a8109b3c1ca85cc893c39b6c9cc6a62a1d8a8b + languageName: node + linkType: hard + "make-dir@npm:^4.0.0": version: 4.0.0 resolution: "make-dir@npm:4.0.0" @@ -2698,6 +2777,29 @@ __metadata: languageName: node linkType: hard +"markdown-it@npm:^14.1.0": + version: 14.1.0 + resolution: "markdown-it@npm:14.1.0" + dependencies: + argparse: "npm:^2.0.1" + entities: "npm:^4.4.0" + linkify-it: "npm:^5.0.0" + mdurl: "npm:^2.0.0" + punycode.js: "npm:^2.3.1" + uc.micro: "npm:^2.1.0" + bin: + markdown-it: bin/markdown-it.mjs + checksum: 10c0/9a6bb444181d2db7016a4173ae56a95a62c84d4cbfb6916a399b11d3e6581bf1cc2e4e1d07a2f022ae72c25f56db90fbe1e529fca16fbf9541659dc53480d4b4 + languageName: node + linkType: hard + +"mdurl@npm:^2.0.0": + version: 2.0.0 + resolution: "mdurl@npm:2.0.0" + checksum: 10c0/633db522272f75ce4788440669137c77540d74a83e9015666a9557a152c02e245b192edc20bc90ae953bbab727503994a53b236b4d9c99bdaee594d0e7dd2ce0 + languageName: node + linkType: hard + "memorystream@npm:^0.3.1": version: 0.3.1 resolution: "memorystream@npm:0.3.1" @@ -2740,7 +2842,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^9.0.4": +"minimatch@npm:^9.0.4, minimatch@npm:^9.0.5": version: 9.0.5 resolution: "minimatch@npm:9.0.5" dependencies: @@ -3312,6 +3414,13 @@ __metadata: languageName: node linkType: hard +"punycode.js@npm:^2.3.1": + version: 2.3.1 + resolution: "punycode.js@npm:2.3.1" + checksum: 10c0/1d12c1c0e06127fa5db56bd7fdf698daf9a78104456a6b67326877afc21feaa821257b171539caedd2f0524027fa38e67b13dd094159c8d70b6d26d2bea4dfdb + languageName: node + linkType: hard + "punycode@npm:^2.1.0": version: 2.3.1 resolution: "punycode@npm:2.3.1" @@ -4042,6 +4151,32 @@ __metadata: languageName: node linkType: hard +"typedoc-plugin-markdown@npm:^4.4.1": + version: 4.4.1 + resolution: "typedoc-plugin-markdown@npm:4.4.1" + peerDependencies: + typedoc: 0.27.x + checksum: 10c0/54c9a25aed64d07258033c4d060acac15a618ee0494cbb2bc70fd10d03c82b3434715b6db01fbeb09d672cff736340666d70da1be83188e3a994048a0a0c6b65 + languageName: node + linkType: hard + +"typedoc@npm:^0.27.6": + version: 0.27.6 + resolution: "typedoc@npm:0.27.6" + dependencies: + "@gerrit0/mini-shiki": "npm:^1.24.0" + lunr: "npm:^2.3.9" + markdown-it: "npm:^14.1.0" + minimatch: "npm:^9.0.5" + yaml: "npm:^2.6.1" + peerDependencies: + typescript: 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x + bin: + typedoc: bin/typedoc + checksum: 10c0/74af856fc2b9ca151567db8e08737a6ab8b29efb611414510eb833f80723245bc6ade00f2be7a410e335833cfd5e3deb1ae1ecfdb4da3a13c65faedd1f1805b0 + languageName: node + linkType: hard + "typescript-eslint@npm:^8.8.1": version: 8.17.0 resolution: "typescript-eslint@npm:8.17.0" @@ -4078,6 +4213,13 @@ __metadata: languageName: node linkType: hard +"uc.micro@npm:^2.0.0, uc.micro@npm:^2.1.0": + version: 2.1.0 + resolution: "uc.micro@npm:2.1.0" + checksum: 10c0/8862eddb412dda76f15db8ad1c640ccc2f47cdf8252a4a30be908d535602c8d33f9855dfcccb8b8837855c1ce1eaa563f7fa7ebe3c98fd0794351aab9b9c55fa + languageName: node + linkType: hard + "unbox-primitive@npm:^1.0.2": version: 1.0.2 resolution: "unbox-primitive@npm:1.0.2" @@ -4378,6 +4520,15 @@ __metadata: languageName: node linkType: hard +"yaml@npm:^2.6.1": + version: 2.7.0 + resolution: "yaml@npm:2.7.0" + bin: + yaml: bin.mjs + checksum: 10c0/886a7d2abbd70704b79f1d2d05fe9fb0aa63aefb86e1cb9991837dced65193d300f5554747a872b4b10ae9a12bc5d5327e4d04205f70336e863e35e89d8f4ea9 + languageName: node + linkType: hard + "yargs-parser@npm:^20.2.2, yargs-parser@npm:^20.2.9": version: 20.2.9 resolution: "yargs-parser@npm:20.2.9"