annotate api functions with types

This commit is contained in:
Ivan Tivonenko
2015-08-06 02:23:05 +03:00
parent 5ac1bcc414
commit 5cb63a258c
8 changed files with 272 additions and 32 deletions

View File

@@ -11,7 +11,7 @@ typecheck() {
lint() {
REPO_URL="https://raw.githubusercontent.com/ripple/javascript-style-guide"
curl "$REPO_URL/es6/eslintrc" > ./eslintrc
echo "plugins: [flowtype]" >> ./eslintrc
echo "parser: babel-eslint" >> ./eslintrc
node_modules/.bin/eslint -c ./eslintrc $(git --no-pager diff --name-only -M100% --diff-filter=AM --relative $(git merge-base FETCH_HEAD origin/HEAD) FETCH_HEAD | grep "\.js$")
}

View File

@@ -62,7 +62,7 @@
"prepublish": "npm run clean && npm run compile",
"test": "istanbul test _mocha",
"coveralls": "cat ./coverage/lcov.info | coveralls",
"lint": "if ! [ -f eslintrc ]; then curl -o eslintrc 'https://raw.githubusercontent.com/ripple/javascript-style-guide/es6/eslintrc'; echo 'plugins:\n - flowtype' >> eslintrc; fi; eslint -c eslintrc src/",
"lint": "if ! [ -f eslintrc ]; then curl -o eslintrc 'https://raw.githubusercontent.com/ripple/javascript-style-guide/es6/eslintrc'; echo 'parser: babel-eslint' >> eslintrc; fi; eslint -c eslintrc src/",
"perf": "./scripts/perf_test.sh"
},
"repository": {

View File

@@ -6,7 +6,43 @@ const removeUndefined = require('./parse/utils').removeUndefined;
const validate = utils.common.validate;
const composeAsync = utils.common.composeAsync;
function formatAccountInfo(response) {
type AccountData = {
Sequence: number,
Account: string,
Balance: string,
Flags: number,
LedgerEntryType: string,
OwnerCount: number,
PreviousTxnID: string,
AccountTxnID?: string,
PreviousTxnLgrSeq: number,
index: string
}
type AccountDataResponse = {
account_data: AccountData,
ledger_current_index?: number,
ledger_hash?: string,
ledger_index: number,
validated: boolean
}
type AccountInfoOptions = {
ledgerVersion?: number
}
type AccountInfoCallback = (err: any, data: AccountInfoResponse) => void
type AccountInfoResponse = {
sequence: number,
xrpBalance: string,
ownerCount: number,
previousInitiatedTransactionID: string,
previousAffectingTransactionID: string,
previousAffectingTransactionLedgerVersion: number
}
function formatAccountInfo(response: AccountDataResponse) {
const data = response.account_data;
return removeUndefined({
sequence: data.Sequence,
@@ -18,7 +54,9 @@ function formatAccountInfo(response) {
});
}
function getAccountInfoAsync(account, options, callback) {
function getAccountInfoAsync(account: string, options: AccountInfoOptions,
callback: AccountInfoCallback
) {
validate.address(account);
validate.getAccountInfoOptions(options);
@@ -31,7 +69,8 @@ function getAccountInfoAsync(account, options, callback) {
composeAsync(formatAccountInfo, callback));
}
function getAccountInfo(account: string, options={}) {
function getAccountInfo(account: string, options: AccountInfoOptions={}
): Promise<AccountInfoResponse> {
return utils.promisify(getAccountInfoAsync.bind(this))(account, options);
}

View File

@@ -0,0 +1,147 @@
/* @flow */
'use strict';
type Outcome = {
result: string,
timestamp?: string,
fee: string,
balanceChanges: Object,
orderbookChanges: Object,
ledgerVersion: number,
indexInLedger: number
}
type Adjustment = {
address: string,
amount: {
currency: string,
counterparty?: string,
value: string
},
tag?: number
}
type Trustline = {
currency: string,
counterparty: string,
limit: string,
qualityIn?: number,
qualityOut?: number,
ripplingDisabled?: boolean,
authorized?: boolean,
frozen?: boolean
}
type Settings = {
passwordSpent?: boolean,
requireDestinationTag?: boolean,
requireAuthorization?: boolean,
disallowIncomingXRP?: boolean,
disableMasterKey?: boolean,
enableTransactionIDTracking?: boolean,
noFreeze?: boolean,
globalFreeze?: boolean,
defaultRipple?: boolean,
emailHash?: string,
walletLocator?: string,
walletSize?: number,
messageKey?: string,
domain?: string,
transferRate?: number,
signers?: string,
regularKey?: string
}
type OrderCancellation = {
orderSequence: number
}
type Memo = {
type?: string,
format?: string,
data?: string
}
type Amount = {
value: string,
currency: string,
counterparty?: string
}
type Payment = {
source: Adjustment,
destination: Adjustment,
paths?: string,
memos?: Array<Memo>,
invoiceID?: string,
allowPartialPayment?: boolean,
noDirectRipple?: boolean,
limitQuality?: boolean
}
type PaymentTransaction = {
type: string,
specification: Payment,
outcome: Outcome,
id: string,
address: string,
sequence: number
}
type Order = {
direction: string,
quantity: Amount,
totalPrice: Amount,
immediateOrCancel?: boolean,
fillOrKill?: boolean,
passive?: boolean
}
type OrderTransaction = {
type: string,
specification: Order,
outcome: Outcome,
id: string,
address: string,
sequence: number
}
type OrderCancellationTransaction = {
type: string,
specification: OrderCancellation,
outcome: Outcome,
id: string,
address: string,
sequence: number
}
type TrustlineTransaction = {
type: string,
specification: Trustline,
outcome: Outcome,
id: string,
address: string,
sequence: number
}
type SettingsTransaction = {
type: string,
specification: Settings,
outcome: Outcome,
id: string,
address: string,
sequence: number
}
export type TransactionOptions = {
minLedgerVersion?: number,
maxLedgerVersion?: number
}
export type GetTransactionResponse = PaymentTransaction | OrderTransaction |
OrderCancellationTransaction | TrustlineTransaction | SettingsTransaction
export type GetTransactionResponseCallback =
(err?: ?Error, data?: GetTransactionResponse) => void
export type CallbackType = (err?: ?Error, data?: Object) => void

View File

@@ -8,7 +8,15 @@ const validate = utils.common.validate;
const errors = utils.common.errors;
const RippleError = require('../../core/rippleerror').RippleError;
function attachTransactionDate(remote, tx, callback) {
import type {Remote} from '../../core/remote';
import type {CallbackType, GetTransactionResponse,
GetTransactionResponseCallback, TransactionOptions}
from './transaction-types';
function attachTransactionDate(remote: Remote, tx: Object,
callback: CallbackType
) {
if (tx.date) {
callback(null, tx);
return;
@@ -29,22 +37,24 @@ function attachTransactionDate(remote, tx, callback) {
});
}
function isTransactionInRange(tx, options) {
function isTransactionInRange(tx: Object, options: TransactionOptions) {
return (!options.minLedgerVersion
|| tx.ledger_index >= options.minLedgerVersion)
&& (!options.maxLedgerVersion
|| tx.ledger_index <= options.maxLedgerVersion);
}
function getTransactionAsync(identifier, options, callback) {
function getTransactionAsync(identifier: string, options: TransactionOptions,
callback: GetTransactionResponseCallback
) {
validate.identifier(identifier);
validate.getTransactionOptions(options);
const remote = this.remote;
const maxLedgerVersion = Math.min(options.maxLedgerVersion,
const maxLedgerVersion = Math.min(options.maxLedgerVersion || Infinity,
remote.getLedgerSequence());
function callbackWrapper(error_, tx) {
function callbackWrapper(error_?: Error, tx?: Object) {
let error = error_;
if (error instanceof RippleError && error.remote &&
error.remote.error === 'txnNotFound') {
@@ -56,22 +66,27 @@ function getTransactionAsync(identifier, options, callback) {
options.minLedgerVersion, maxLedgerVersion)) {
callback(new errors.MissingLedgerHistoryError('Transaction not found,'
+ ' but the server\'s ledger history is incomplete'));
} else if (!error && !isTransactionInRange(tx, options)) {
} else if (!error && tx && !isTransactionInRange(tx, options)) {
callback(new errors.NotFoundError('Transaction not found'));
} else if (error) {
callback(error);
} else if (!tx) {
callback(new Error('Internal error'));
} else {
callback(error, parseTransaction(tx));
}
}
async.waterfall([
_.partial(remote.requestTx.bind(remote), {hash: identifier, binary: false}),
_.partial(remote.requestTx.bind(remote),
{hash: identifier, binary: false}),
_.partial(attachTransactionDate, remote)
], callbackWrapper);
}
function getTransaction(identifier: string, options={}) {
function getTransaction(identifier: string,
options: TransactionOptions={}
): Promise<GetTransactionResponse> {
return utils.promisify(getTransactionAsync.bind(this))(identifier, options);
}

View File

@@ -5,6 +5,7 @@ const assert = require('assert');
const common = require('../common');
const dropsToXrp = common.dropsToXrp;
const composeAsync = common.composeAsync;
import type {Remote} from '../../core/remote';
type Callback = (err: any, data: any) => void
@@ -13,8 +14,9 @@ function clamp(value: number, min: number, max: number): number {
return Math.min(Math.max(value, min), max);
}
function getXRPBalance(remote: any, address: string, ledgerVersion?: number,
callback: Callback): void {
function getXRPBalance(remote: Remote, address: string, ledgerVersion?: number,
callback: Callback
): void {
remote.requestAccountInfo({account: address, ledger: ledgerVersion},
composeAsync((data) => dropsToXrp(data.account_data.Balance), callback));
}
@@ -24,7 +26,8 @@ type Getter = (marker: ?string, limit: number, callback: Callback) => void
// If the marker is omitted from a response, you have reached the end
// getter(marker, limit, callback), callback(error, {marker, results})
function getRecursiveRecur(getter: Getter, marker?: string, limit: number,
callback: Callback): void {
callback: Callback
): void {
getter(marker, limit, (error, data) => {
if (error) {
return callback(error);
@@ -81,19 +84,21 @@ function signum(num) {
* @returns {Number} [-1, 0, 1]
*/
type Outcome = {outcome: {ledgerVersion: string, indexInLedger: string}};
type Outcome = {outcome: {ledgerVersion: number, indexInLedger: number}};
function compareTransactions(first: Outcome, second: Outcome): number {
if (first.outcome.ledgerVersion === second.outcome.ledgerVersion) {
return signum(Number(first.outcome.indexInLedger) -
Number(second.outcome.indexInLedger));
if (!first.outcome || !second.outcome) {
return 0;
}
return Number(first.outcome.ledgerVersion) <
Number(second.outcome.ledgerVersion) ? -1 : 1;
if (first.outcome.ledgerVersion === second.outcome.ledgerVersion) {
return signum(first.outcome.indexInLedger - second.outcome.indexInLedger);
}
return first.outcome.ledgerVersion < second.outcome.ledgerVersion ? -1 : 1;
}
function hasCompleteLedgerRange(remote: any, minLedgerVersion: number,
maxLedgerVersion: number): boolean {
function hasCompleteLedgerRange(remote: Remote, minLedgerVersion?: number,
maxLedgerVersion?: number
): boolean {
const firstLedgerVersion = 32570; // earlier versions have been lost
return remote.getServer().hasLedgerRange(
minLedgerVersion || firstLedgerVersion,

View File

@@ -4,11 +4,41 @@
const _ = require('lodash');
const common = require('../common');
import type {Remote} from '../../core/remote';
// If a ledger is not received in this time, consider the connection offline
const CONNECTION_TIMEOUT = 1000 * 30;
function isUpToDate(remote): boolean {
type GetServerInfoResponse = {
buildVersion: string,
completeLedgers: string,
hostid: string,
ioLatencyMs: number,
load?: {
jobTypes: Array<Object>,
threads: number
},
lastClose: {
convergeTimeS: number,
proposers: number
},
loadFactor: number,
peers: number,
pubkeyNode: string,
pubkeyValidator?: string,
serverState: string,
validatedLedger: {
age: number,
baseFeeXrp: number,
hash: string,
reserveBaseXrp: number,
reserveIncXrp: number,
seq: number
},
validationQuorum: number
}
function isUpToDate(remote: Remote): boolean {
const server = remote.getServer();
return Boolean(server) && (remote._stand_alone
|| (Date.now() - server._lastLedgerClose) <= CONNECTION_TIMEOUT);
@@ -18,13 +48,17 @@ function isConnected(): boolean {
return Boolean(this.remote._ledger_current_index) && isUpToDate(this.remote);
}
function getServerInfoAsync(callback: (err: any, data: any) => void): void {
function getServerInfoAsync(
callback: (err: any, data?: GetServerInfoResponse) => void
): void {
this.remote.requestServerInfo((error, response) => {
if (error) {
const message = _.get(error, ['remote', 'error_message'], error.message);
const message =
_.get(error, ['remote', 'error_message'], error.message);
callback(new common.errors.RippledNetworkError(message));
} else {
callback(null, common.convertKeysFromSnakeCaseToCamelCase(response.info));
callback(null,
common.convertKeysFromSnakeCaseToCamelCase(response.info));
}
});
}
@@ -37,19 +71,19 @@ function getLedgerVersion(): number {
return this.remote.getLedgerSequence();
}
function connect() {
function connect(): Promise<void> {
return common.promisify(callback => {
this.remote.connect(() => callback(null));
})();
}
function disconnect() {
function disconnect(): Promise<void> {
return common.promisify(callback => {
this.remote.disconnect(() => callback(null));
})();
}
function getServerInfo() {
function getServerInfo(): Promise<GetServerInfoResponse> {
return common.promisify(getServerInfoAsync.bind(this))();
}

View File

@@ -228,7 +228,7 @@ module.exports = function(request, options={}) {
marker: marker === undefined ? undefined : String(marker),
transactions: [
{
ledger_index: 348860 - Number(marker),
ledger_index: 348860 - Number(marker || 100),
tx_blob: SerializedObject.from_json(tx).to_hex(),
meta: SerializedObject.from_json(meta).to_hex(),
validated: options.validated