Make api.rpc.*.* typed (#1237)
* Generate correctly * Fix rpc-core * Flexible types * Make types work! * Lint * Fix grumble * Re generate * Fix lint * Fix small bugs * Maybe really fix lint? * Fix lint again * Fix lint * Small ordering & formatting changes while playing...
This commit is contained in:
@@ -24,7 +24,7 @@ import { drr } from '../util/drr';
|
||||
*/
|
||||
export function bestNumber (api: ApiInterfaceRx): () => Observable<BlockNumber> {
|
||||
return (): Observable<BlockNumber> =>
|
||||
(api.rpc.chain.subscribeNewHead() as Observable<Header>)
|
||||
api.rpc.chain.subscribeNewHead()
|
||||
.pipe(
|
||||
filter((header: Header): boolean => !!header && !!header.number),
|
||||
map((header: Header): BlockNumber => header.number.unwrap()),
|
||||
|
||||
@@ -25,7 +25,7 @@ import { drr } from '../util/drr';
|
||||
*/
|
||||
export function bestNumberFinalized (api: ApiInterfaceRx): () => Observable<BlockNumber> {
|
||||
return (): Observable<BlockNumber> =>
|
||||
(api.rpc.chain.subscribeFinalizedHeads() as Observable<Header>)
|
||||
api.rpc.chain.subscribeFinalizedHeads()
|
||||
.pipe(
|
||||
filter((header: Header): boolean => !!header && !!header.number),
|
||||
map((header: Header): BlockNumber => header.number.unwrap()),
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { Header } from '@polkadot/types/interfaces';
|
||||
|
||||
import { Observable, combineLatest, of } from 'rxjs';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
import { ApiInterfaceRx } from '@polkadot/api/types';
|
||||
@@ -30,7 +28,7 @@ export function getHeader (api: ApiInterfaceRx): (hash: Uint8Array | string) =>
|
||||
return (hash: Uint8Array | string): Observable<HeaderExtended | undefined> =>
|
||||
// tslint:disable-next-line
|
||||
(combineLatest([
|
||||
api.rpc.chain.getHeader(hash) as Observable<Header>,
|
||||
api.rpc.chain.getHeader(hash),
|
||||
api.query.session
|
||||
? api.query.session.validators.at(hash)
|
||||
: of([])
|
||||
|
||||
+21
-16
@@ -2,6 +2,7 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { RpcInterface } from '@polkadot/rpc-core/jsonrpc.types';
|
||||
import { ProviderInterface } from '@polkadot/rpc-provider/types';
|
||||
import { Hash, RuntimeVersion, SignedBlock } from '@polkadot/types/interfaces';
|
||||
import { AnyFunction, CallFunction, Codec, CodecArg, ModulesWithCalls, RegistryTypes } from '@polkadot/types/types';
|
||||
@@ -87,7 +88,7 @@ export default abstract class ApiBase<ApiType> {
|
||||
|
||||
private _queryMulti: QueryableStorageMulti<ApiType>;
|
||||
|
||||
private _rpc: DecoratedRpc<ApiType>;
|
||||
private _rpc: DecoratedRpc<ApiType, RpcInterface>;
|
||||
|
||||
protected _rpcCore: RpcCore;
|
||||
|
||||
@@ -318,7 +319,7 @@ export default abstract class ApiBase<ApiType> {
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
public get rpc (): DecoratedRpc<ApiType> {
|
||||
public get rpc (): DecoratedRpc<ApiType, RpcInterface> {
|
||||
return this._rpc;
|
||||
}
|
||||
|
||||
@@ -451,7 +452,7 @@ export default abstract class ApiBase<ApiType> {
|
||||
* implemented by transforming the Observable to Stream/Iterator/Kefir/Bacon
|
||||
* via `deocrateMethod`.
|
||||
*/
|
||||
protected abstract decorateMethod (method: (...args: any[]) => Observable<any>, options?: DecorateMethodOptions): any;
|
||||
protected abstract decorateMethod(method: (...args: any[]) => Observable<any>, options?: DecorateMethodOptions): any;
|
||||
|
||||
private emit (type: ApiInterfaceEvents, ...args: any[]): void {
|
||||
this._eventemitter.emit(type, ...args);
|
||||
@@ -577,19 +578,22 @@ export default abstract class ApiBase<ApiType> {
|
||||
return output;
|
||||
}
|
||||
|
||||
private decorateRpc<ApiType> (rpc: RpcCore, decorateMethod: ApiBase<ApiType>['decorateMethod']): DecoratedRpc<ApiType> {
|
||||
return ['author', 'chain', 'state', 'system'].reduce((result, _sectionName): DecoratedRpc<ApiType> => {
|
||||
const sectionName = _sectionName as keyof DecoratedRpc<ApiType>;
|
||||
private decorateRpc<ApiType> (rpc: RpcCore, decorateMethod: ApiBase<ApiType>['decorateMethod']): DecoratedRpc<ApiType, RpcInterface> {
|
||||
return ['author', 'chain', 'state', 'system'].reduce((result, _sectionName): DecoratedRpc<ApiType, RpcInterface> => {
|
||||
const sectionName = _sectionName as keyof DecoratedRpc<ApiType, RpcInterface>;
|
||||
|
||||
result[sectionName] = Object.keys(rpc[sectionName]).reduce((section, methodName): DecoratedRpcSection<ApiType> => {
|
||||
// @ts-ignore Hard to type these correctly, I don't understand the TS errors
|
||||
result[sectionName] = Object.keys(rpc[sectionName]).reduce((section, methodName): DecoratedRpcSection<ApiType, RpcInterface[typeof sectionName]> => {
|
||||
// @ts-ignore
|
||||
const method = rpc[sectionName][methodName];
|
||||
// @ts-ignore
|
||||
section[methodName] = decorateMethod(method, { methodName });
|
||||
|
||||
return section;
|
||||
}, {} as unknown as DecoratedRpcSection<ApiType>);
|
||||
}, {} as unknown as DecoratedRpcSection<ApiType, RpcInterface[typeof sectionName]>);
|
||||
|
||||
return result;
|
||||
}, {} as unknown as DecoratedRpc<ApiType>);
|
||||
}, {} as unknown as DecoratedRpc<ApiType, RpcInterface>);
|
||||
}
|
||||
|
||||
private decorateMulti<ApiType> (decorateMethod: ApiBase<ApiType>['decorateMethod']): QueryableStorageMulti<ApiType> {
|
||||
@@ -652,10 +656,11 @@ export default abstract class ApiBase<ApiType> {
|
||||
(...args: any[]): Observable<Codec> => {
|
||||
return this._rpcCore.state
|
||||
// Unfortunately for one-shot calls we also use .subscribeStorage here
|
||||
.subscribeStorage([
|
||||
creator.meta.type.isDoubleMap
|
||||
? [creator, args]
|
||||
: [creator, ...args]])
|
||||
.subscribeStorage<[Codec]>([
|
||||
creator.meta.type.isDoubleMap
|
||||
? [creator, args]
|
||||
: [creator, ...args]
|
||||
])
|
||||
.pipe(
|
||||
// state_storage returns an array of values, since we have just subscribed to
|
||||
// a single entry, we pull that from the array and return it as-is
|
||||
@@ -720,7 +725,7 @@ export default abstract class ApiBase<ApiType> {
|
||||
// entries can be re-linked in the middle of a list, we subscribe here to make
|
||||
// sure we catch any updates, no matter the list position
|
||||
const getNext = (key: Codec): Observable<LinkageResult> => {
|
||||
return this._rpcCore.state.subscribeStorage([[creator, key]])
|
||||
return this._rpcCore.state.subscribeStorage<[[Codec, Linkage<Codec>]]>([[creator, key]])
|
||||
.pipe(
|
||||
switchMap(([data]: [[Codec, Linkage<Codec>]]): Observable<LinkageResult> => {
|
||||
const linkage = data[1];
|
||||
@@ -784,12 +789,12 @@ export default abstract class ApiBase<ApiType> {
|
||||
(...args: any[]): Observable<LinkageResult | [Codec, Linkage<Codec>]> =>
|
||||
args.length
|
||||
? this._rpcCore.state
|
||||
.subscribeStorage([[creator, ...args]])
|
||||
.subscribeStorage<[[Codec, Linkage<Codec>]]>([[creator, ...args]])
|
||||
.pipe(
|
||||
map(([data]): [Codec, Linkage<Codec>] => data)
|
||||
)
|
||||
: this._rpcCore.state
|
||||
.subscribeStorage([creator.headKey])
|
||||
.subscribeStorage<[LinkageResult]>([creator.headKey])
|
||||
.pipe(
|
||||
switchMap(([key]): Observable<LinkageResult> => {
|
||||
head = key;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
// Simple non-runnable checks to test type definitions in the editor itself
|
||||
|
||||
import { Header, Index } from '@polkadot/types/interfaces';
|
||||
import { Balance, Header, Index } from '@polkadot/types/interfaces';
|
||||
|
||||
import { ApiPromise } from '@polkadot/api';
|
||||
import { HeaderExtended } from '@polkadot/api-derive';
|
||||
@@ -32,18 +32,16 @@ export default async function test (): Promise<void> {
|
||||
multiUnsub();
|
||||
});
|
||||
|
||||
await api.query.staking.intentions((intentions): void => {
|
||||
console.log('intentions:', intentions);
|
||||
});
|
||||
|
||||
await api.rpc.chain.subscribeNewHead<Header>((header): void => {
|
||||
console.log('current blockNumber:', header.number);
|
||||
});
|
||||
|
||||
// rpc section
|
||||
await api.rpc.chain.subscribeNewHead((header: Header): void => {
|
||||
console.log('current blockNumber:', header.number);
|
||||
});
|
||||
|
||||
await api.rpc.state.subscribeStorage<[Balance]>(['my_balance_key'], ([balance]): void => {
|
||||
console.log('current balance:', balance.toString());
|
||||
});
|
||||
|
||||
// derives
|
||||
await api.derive.chain.subscribeNewHead((header: HeaderExtended): void => {
|
||||
console.log('current author:', header.author);
|
||||
});
|
||||
@@ -52,6 +50,10 @@ export default async function test (): Promise<void> {
|
||||
console.log('current author:', header.author);
|
||||
});
|
||||
|
||||
await api.query.staking.intentions((intentions): void => {
|
||||
console.log('intentions:', intentions);
|
||||
});
|
||||
|
||||
// constants has actual value & metadata
|
||||
console.log(
|
||||
api.consts.balances.creationFee.toHex(),
|
||||
|
||||
+13
-31
@@ -9,6 +9,7 @@ import BN from 'bn.js';
|
||||
import { Observable } from 'rxjs';
|
||||
import { DeriveCustom } from '@polkadot/api-derive';
|
||||
import { Constants } from '@polkadot/api-metadata/consts/types';
|
||||
import { RpcInterface } from '@polkadot/rpc-core/jsonrpc.types';
|
||||
import { ProviderInterface, ProviderInterfaceEmitted } from '@polkadot/rpc-provider/types';
|
||||
import { u64 } from '@polkadot/types';
|
||||
import { StorageEntry } from '@polkadot/types/primitive/StorageKey';
|
||||
@@ -57,45 +58,26 @@ export interface DecorateMethodOptions {
|
||||
// Also use these for api.rpc.* https://github.com/polkadot-js/api/issues/1009
|
||||
export type RxResult<F extends AnyFunction> = (...args: Parameters<F>) => Observable<ObsInnerType<ReturnType<F>>>;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-interface
|
||||
export type PromiseResult<F extends AnyFunction> = {
|
||||
export interface PromiseResult<F extends AnyFunction> {
|
||||
(...args: Parameters<F>): Promise<ObsInnerType<ReturnType<F>>>;
|
||||
(...args: Push<Parameters<F>, Callback<ObsInnerType<ReturnType<F>>>>): UnsubscribePromise;
|
||||
};
|
||||
<T>(...args: Parameters<F>): Promise<T>;
|
||||
<T>(...args: Push<Parameters<F>, Callback<T>>): UnsubscribePromise;
|
||||
}
|
||||
|
||||
// FIXME The day TS has higher-kinded types, we can remove this hardcoded stuff
|
||||
export type MethodResult<ApiType, F extends AnyFunction> = ApiType extends 'rxjs'
|
||||
? RxResult<F>
|
||||
: PromiseResult<F>;
|
||||
|
||||
type DecoratedRpcMethod<ApiType> = ApiType extends 'rxjs'
|
||||
? {
|
||||
(arg1?: CodecArg, arg2?: CodecArg, arg3?: CodecArg): Observable<Codec>;
|
||||
<T extends Codec>(arg1?: CodecArg, arg2?: CodecArg, arg3?: CodecArg): Observable<T>;
|
||||
}
|
||||
: {
|
||||
// These signatures are allowed and exposed here (bit or a stoopid way, but checked
|
||||
// RPCs and we have 3 max args, with subs max one arg... YMMV) -
|
||||
// (arg1?: CodecArg, arg2?: CodecArg, arg3?: CodecArg): Promise<Codec>;
|
||||
// (arg1: CodecArg, callback: Callback<Codec>): UnsubscribePromise;
|
||||
// (callback: Callback<Codec>): UnsubscribePromise;
|
||||
(arg1?: CodecArg, arg2?: CodecArg, arg3?: CodecArg): Promise<Codec>;
|
||||
<T extends Codec>(arg1?: CodecArg, arg2?: CodecArg, arg3?: CodecArg): Promise<T>;
|
||||
<T extends Codec>(callback: Callback<T>): UnsubscribePromise;
|
||||
<T extends Codec>(arg: CodecArg, callback: Callback<T>): UnsubscribePromise;
|
||||
};
|
||||
|
||||
// FIXME https://github.com/polkadot-js/api/issues/1009
|
||||
export interface DecoratedRpcSection<ApiType> {
|
||||
[index: string]: DecoratedRpcMethod<ApiType>;
|
||||
export type DecoratedRpcSection<ApiType, Section> = {
|
||||
[Method in keyof Section]: Section[Method] extends AnyFunction
|
||||
? MethodResult<ApiType, Section[Method]>
|
||||
: never
|
||||
}
|
||||
|
||||
// FIXME https://github.com/polkadot-js/api/issues/1009
|
||||
export interface DecoratedRpc<ApiType> {
|
||||
author: DecoratedRpcSection<ApiType>;
|
||||
chain: DecoratedRpcSection<ApiType>;
|
||||
state: DecoratedRpcSection<ApiType>;
|
||||
system: DecoratedRpcSection<ApiType>;
|
||||
export type DecoratedRpc<ApiType, AllSections> = {
|
||||
[Section in keyof AllSections]: DecoratedRpcSection<ApiType, AllSections[Section]>
|
||||
}
|
||||
|
||||
export interface StorageEntryObservable {
|
||||
@@ -216,7 +198,7 @@ export interface ApiInterfaceRx {
|
||||
runtimeVersion: RuntimeVersion;
|
||||
query: QueryableStorage<'rxjs'>;
|
||||
queryMulti: QueryableStorageMulti<'rxjs'>;
|
||||
rpc: DecoratedRpc<'rxjs'>;
|
||||
rpc: DecoratedRpc<'rxjs', RpcInterface>;
|
||||
tx: SubmittableExtrinsics<'rxjs'>;
|
||||
signer?: Signer;
|
||||
}
|
||||
@@ -299,7 +281,7 @@ export interface Signer {
|
||||
/**
|
||||
* @description signs an extrinsic payload from a serialized form
|
||||
*/
|
||||
signPayload (payload: SignerPayload): Promise<SignerResult>;
|
||||
signPayload(payload: SignerPayload): Promise<SignerResult>;
|
||||
|
||||
/**
|
||||
* @description Receives an update for the extrinsic signed by a `signer.sign`
|
||||
|
||||
@@ -127,7 +127,7 @@ describeE2E()('Promise e2e queries', (wsUrl: string): void => {
|
||||
|
||||
it('gets correct key', async (): Promise<void> => {
|
||||
const key = api.query.session.currentIndex.key();
|
||||
const sessionIndexData = await api.rpc.state.getStorage(key) as Option<any>;
|
||||
const sessionIndexData = await api.rpc.state.getStorage<Option<any>>(key);
|
||||
const sessionIndexRPC = createType('SessionIndex', sessionIndexData.unwrapOr(undefined));
|
||||
|
||||
expect(sessionIndexRPC.toNumber()).toBeGreaterThanOrEqual(0);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { SignedBlock, StorageChangeSet } from '@polkadot/types/interfaces';
|
||||
import { BlockNumber, Index, SignedBlock } from '@polkadot/types/interfaces';
|
||||
|
||||
import storage from '@polkadot/api-metadata/storage/static';
|
||||
import WsProvider from '@polkadot/rpc-provider/ws';
|
||||
@@ -28,11 +28,11 @@ describeE2E({
|
||||
|
||||
it('subscribes to storage', (done): void => {
|
||||
rpc.state
|
||||
.subscribeStorage([
|
||||
[storage.system.accountNonce, randomAccount],
|
||||
[storage.session.currentIndex]
|
||||
])
|
||||
.subscribe((data: StorageChangeSet): void => {
|
||||
.subscribeStorage<[BlockNumber, Index]>([
|
||||
[storage.system.accountNonce, randomAccount],
|
||||
[storage.session.currentIndex]
|
||||
])
|
||||
.subscribe((data): void => {
|
||||
expect(data).toHaveLength(2);
|
||||
expect(data).toEqual(
|
||||
expect.arrayContaining([
|
||||
|
||||
@@ -139,7 +139,7 @@ describeE2E({
|
||||
|
||||
rpc.state
|
||||
.getChildStorageSize(storageKeys[0], childStorageKeys[0])
|
||||
.subscribe((storage: StorageData): void => {
|
||||
.subscribe((storage): void => {
|
||||
expect(storage.toString()).toBe('4');
|
||||
done();
|
||||
});
|
||||
|
||||
@@ -49,9 +49,9 @@ describeE2E({
|
||||
describe('test-suite getStorage()', (): void => {
|
||||
it('retrieves code', (done): void => {
|
||||
rpc.state
|
||||
.getStorage([
|
||||
storage.substrate.code
|
||||
])
|
||||
.getStorage<Bytes>([
|
||||
storage.substrate.code
|
||||
])
|
||||
.subscribe((code: Bytes): void => {
|
||||
expect(code).toBeDefined();
|
||||
expect(code).toBeInstanceOf(Bytes);
|
||||
@@ -61,10 +61,10 @@ describeE2E({
|
||||
|
||||
it('retrieves balances', (done): void => {
|
||||
rpc.state
|
||||
.getStorage([
|
||||
storage.balances.freeBalance, BOB_STASH
|
||||
])
|
||||
.subscribe((balance: Balance): void => {
|
||||
.getStorage<Balance>([
|
||||
storage.balances.freeBalance, BOB_STASH
|
||||
])
|
||||
.subscribe((balance): void => {
|
||||
expect(balance.isZero()).not.toEqual(true);
|
||||
done();
|
||||
});
|
||||
@@ -72,9 +72,9 @@ describeE2E({
|
||||
|
||||
it('retrieves timestamp', (done): void => {
|
||||
rpc.state
|
||||
.getStorage([
|
||||
storage.timestamp.now
|
||||
])
|
||||
.getStorage<Moment>([
|
||||
storage.timestamp.now
|
||||
])
|
||||
.subscribe((moment: Moment): void => {
|
||||
expect(moment.toNumber()).not.toEqual(0);
|
||||
done();
|
||||
|
||||
@@ -6,7 +6,7 @@ import testingPairs from '@polkadot/keyring/testingPairs';
|
||||
import WsProvider from '@polkadot/rpc-provider/ws';
|
||||
import storage from '@polkadot/api-metadata/storage/static';
|
||||
import Rpc from '@polkadot/rpc-core';
|
||||
import { StorageChangeSet } from '@polkadot/types/interfaces';
|
||||
import { Index, Moment, SessionIndex } from '@polkadot/types/interfaces';
|
||||
import { ClassOf } from '@polkadot/types';
|
||||
|
||||
import { describeE2E } from '../../util';
|
||||
@@ -27,11 +27,11 @@ describeE2E({
|
||||
|
||||
it('subscribes to storage', (done): void => {
|
||||
rpc.state
|
||||
.subscribeStorage([
|
||||
[storage.system.accountNonce, keyring.eve.address],
|
||||
[storage.session.currentIndex]
|
||||
])
|
||||
.subscribe((data: StorageChangeSet): void => {
|
||||
.subscribeStorage<[Index, SessionIndex]>([
|
||||
[storage.system.accountNonce, keyring.eve.address],
|
||||
[storage.session.currentIndex]
|
||||
])
|
||||
.subscribe((data): void => {
|
||||
expect(data).toHaveLength(2);
|
||||
expect(data).toEqual(
|
||||
expect.arrayContaining([
|
||||
@@ -48,8 +48,8 @@ describeE2E({
|
||||
let count = 0;
|
||||
|
||||
rpc.state
|
||||
.subscribeStorage([[storage.timestamp.now]])
|
||||
.subscribe((data: StorageChangeSet): void => {
|
||||
.subscribeStorage<Moment>([[storage.timestamp.now]])
|
||||
.subscribe((data): void => {
|
||||
expect(data).toBeDefined();
|
||||
|
||||
if (++count === 3) {
|
||||
|
||||
@@ -17,8 +17,8 @@ describe('Cached Observables', (): void => {
|
||||
});
|
||||
|
||||
it('creates a single observable for subscriptions (multiple calls)', (): void => {
|
||||
const observable1 = rpc.chain.subscribeNewHead(123);
|
||||
const observable2 = rpc.chain.subscribeNewHead(123);
|
||||
const observable1 = rpc.state.subscribeStorage([123]);
|
||||
const observable2 = rpc.state.subscribeStorage([123]);
|
||||
|
||||
expect(observable2).toBe(observable1);
|
||||
});
|
||||
@@ -31,15 +31,15 @@ describe('Cached Observables', (): void => {
|
||||
});
|
||||
|
||||
it('creates a single observable (multiple calls, different arguments that should be cached together)', (): void => {
|
||||
const observable1 = rpc.chain.subscribeNewHead(keyring.alice.address);
|
||||
const observable2 = rpc.chain.subscribeNewHead(createType('AccountId', keyring.alice.address));
|
||||
const observable1 = rpc.state.subscribeStorage([keyring.alice.address]);
|
||||
const observable2 = rpc.state.subscribeStorage([createType('AccountId', keyring.alice.address)]);
|
||||
|
||||
expect(observable2).toBe(observable1);
|
||||
});
|
||||
|
||||
it('creates multiple observables for different values', (): void => {
|
||||
const observable1 = rpc.chain.subscribeNewHead(123);
|
||||
const observable2 = rpc.chain.subscribeNewHead(456);
|
||||
const observable1 = rpc.chain.getBlockHash(123);
|
||||
const observable2 = rpc.chain.getBlockHash(456);
|
||||
|
||||
expect(observable2).not.toBe(observable1);
|
||||
});
|
||||
@@ -63,15 +63,16 @@ describe('Cached Observables', (): void => {
|
||||
});
|
||||
|
||||
it('creates different observables for different methods but same arguments', (): void => {
|
||||
const observable1 = rpc.chain.subscribeNewHead(123);
|
||||
const observable2 = rpc.state.subscribeStorage(123);
|
||||
// @ts-ignore
|
||||
const observable1 = rpc.chain.subscribeNewHead([123]);
|
||||
const observable2 = rpc.state.subscribeStorage([123]);
|
||||
|
||||
expect(observable2).not.toBe(observable1);
|
||||
});
|
||||
|
||||
it('creates multiple observables for one-shots', (): void => {
|
||||
const observable1 = rpc.system.chain(123);
|
||||
const observable2 = rpc.system.chain(123);
|
||||
const observable1 = rpc.chain.getBlockHash(123);
|
||||
const observable2 = rpc.chain.getBlockHash(123);
|
||||
|
||||
expect(observable2).not.toBe(observable1);
|
||||
});
|
||||
|
||||
@@ -79,7 +79,7 @@ function formattingTests (version: string, storage: Storage, encodedValues: [str
|
||||
|
||||
it('encodes key (with params), decoding response', (done): void => {
|
||||
api.state
|
||||
.getStorage([storage.balances.freeBalance, ADDR_ONE])
|
||||
.getStorage<Balance>([storage.balances.freeBalance, ADDR_ONE])
|
||||
.subscribe((value): void => {
|
||||
expect(
|
||||
provider.send
|
||||
@@ -102,12 +102,12 @@ function formattingTests (version: string, storage: Storage, encodedValues: [str
|
||||
});
|
||||
|
||||
it('encodes multiple keys, decoding multiple results', (done): void => {
|
||||
api.state.subscribeStorage(
|
||||
api.state.subscribeStorage<[Balance, Balance]>(
|
||||
[
|
||||
[storage.balances.freeBalance, ADDR_ONE],
|
||||
[storage.balances.freeBalance, ADDR_TWO]
|
||||
]
|
||||
).subscribe((value: Balance[]): void => {
|
||||
).subscribe((value): void => {
|
||||
// console.error(value);
|
||||
|
||||
expect(
|
||||
@@ -173,7 +173,7 @@ function formattingTests (version: string, storage: Storage, encodedValues: [str
|
||||
|
||||
api.state
|
||||
.subscribeStorage([[storage.staking.validators, '0x00']])
|
||||
.subscribe((value: Codec): void => {
|
||||
.subscribe(([value]: Codec[]): void => {
|
||||
expect(value).toBeDefined();
|
||||
// console.error('linked falklback', value);
|
||||
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { ProviderInterface } from '@polkadot/rpc-provider/types';
|
||||
import { RpcSection, RpcMethod } from '@polkadot/jsonrpc/types';
|
||||
import { RpcMethod } from '@polkadot/jsonrpc/types';
|
||||
import { StorageChangeSet } from '@polkadot/types/interfaces';
|
||||
import { AnyJson, Codec } from '@polkadot/types/types';
|
||||
import { RpcInterface, RpcInterfaceMethod, RpcInterfaceSection } from './types';
|
||||
import { RpcInterface } from './jsonrpc.types';
|
||||
import { RpcInterfaceMethod } from './types';
|
||||
|
||||
import memoizee from 'memoizee';
|
||||
import { combineLatest, from, Observable, Observer, of, throwError } from 'rxjs';
|
||||
@@ -55,13 +56,13 @@ export default class Rpc implements RpcInterface {
|
||||
|
||||
public readonly provider: ProviderInterface;
|
||||
|
||||
public readonly author: RpcInterfaceSection;
|
||||
public readonly author: RpcInterface['author'];
|
||||
|
||||
public readonly chain: RpcInterfaceSection;
|
||||
public readonly chain: RpcInterface['chain'];
|
||||
|
||||
public readonly state: RpcInterfaceSection;
|
||||
public readonly state: RpcInterface['state'];
|
||||
|
||||
public readonly system: RpcInterfaceSection;
|
||||
public readonly system: RpcInterface['system'];
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
@@ -73,10 +74,10 @@ export default class Rpc implements RpcInterface {
|
||||
|
||||
this.provider = provider;
|
||||
|
||||
this.author = this.createInterface(interfaces.author);
|
||||
this.chain = this.createInterface(interfaces.chain);
|
||||
this.state = this.createInterface(interfaces.state);
|
||||
this.system = this.createInterface(interfaces.system);
|
||||
this.author = this.createInterface('author');
|
||||
this.chain = this.createInterface('chain');
|
||||
this.state = this.createInterface('state');
|
||||
this.system = this.createInterface('system');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,18 +114,26 @@ export default class Rpc implements RpcInterface {
|
||||
return `${Rpc.signature(method)}:: ${error.message}`;
|
||||
}
|
||||
|
||||
private createInterface ({ methods }: RpcSection): RpcInterfaceSection {
|
||||
private createInterface<Section extends keyof RpcInterface> (section: Section): RpcInterface[Section] {
|
||||
const { methods } = interfaces[section];
|
||||
|
||||
return Object
|
||||
.keys(methods)
|
||||
.reduce((exposed, methodName): RpcInterfaceSection => {
|
||||
.reduce((exposed, methodName): RpcInterface[Section] => {
|
||||
const def = methods[methodName];
|
||||
|
||||
exposed[methodName] = def.isSubscription
|
||||
// FIXME Remove any here
|
||||
// To do so, remove `RpcInterfaceMethod` from './types.ts', and refactor
|
||||
// every method inside this class to take:
|
||||
// `<S extends keyof RpcInterface, M extends keyof RpcInterface[S]>`
|
||||
// Not doing so, because it makes this class a little bit less readable,
|
||||
// and leaving it as-is doesn't harm much
|
||||
(exposed as any)[methodName] = def.isSubscription
|
||||
? this.createMethodSubscribe(def)
|
||||
: this.createMethodSend(def);
|
||||
|
||||
return exposed;
|
||||
}, {} as unknown as RpcInterfaceSection);
|
||||
}, {} as unknown as RpcInterface[Section]);
|
||||
}
|
||||
|
||||
private createMethodSend (method: RpcMethod): RpcInterfaceMethod {
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
// Auto-generated via `yarn build:interfaces`, do not edit
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
import { Vec } from '@polkadot/types/codec';
|
||||
import { Bytes, Metadata, StorageData, StorageKey, Text, u64 } from '@polkadot/types';
|
||||
import { BlockNumber, Extrinsic, Hash, Header, SignedBlock } from '@polkadot/types/interfaces/runtime';
|
||||
import { ChainProperties, ExtrinsicOrHash, ExtrinsicStatus, Health, NetworkState, PeerInfo, RuntimeVersion, StorageChangeSet } from '@polkadot/types/interfaces/rpc';
|
||||
import { Codec, IExtrinsic } from '@polkadot/types/types';
|
||||
|
||||
export interface RpcInterface {
|
||||
author: {
|
||||
removeExtrinsic(bytesOrHash: (ExtrinsicOrHash)[]): Observable<Vec<Hash>>;
|
||||
pendingExtrinsics(): Observable<Vec<Extrinsic>>;
|
||||
submitExtrinsic(extrinsic: IExtrinsic): Observable<Hash>;
|
||||
submitAndWatchExtrinsic(extrinsic: IExtrinsic): Observable<ExtrinsicStatus>;
|
||||
};
|
||||
chain: {
|
||||
getBlock(hash?: Hash | Uint8Array | string): Observable<SignedBlock>;
|
||||
getBlockHash(blockNumber?: BlockNumber | Uint8Array | number | string): Observable<Hash>;
|
||||
getFinalizedHead(): Observable<Hash>;
|
||||
getHeader(hash?: Hash | Uint8Array | string): Observable<Header>;
|
||||
getRuntimeVersion(hash?: Hash | Uint8Array | string): Observable<RuntimeVersion>;
|
||||
subscribeFinalizedHeads(): Observable<Header>;
|
||||
subscribeRuntimeVersion(): Observable<RuntimeVersion>;
|
||||
subscribeNewHead(): Observable<Header>;
|
||||
};
|
||||
state: {
|
||||
call(method: Text | string, data: Bytes | Uint8Array | string, block?: Hash | Uint8Array | string): Observable<Bytes>;
|
||||
getChildKeys(childStorageKey: any, prefix: any, block?: Hash | Uint8Array | string): Observable<Vec<StorageKey>>;
|
||||
getChildStorage(childStorageKey: any, key: any, block?: Hash | Uint8Array | string): Observable<StorageData>;
|
||||
getChildStorageHash(childStorageKey: any, key: any, block?: Hash | Uint8Array | string): Observable<Hash>;
|
||||
getChildStorageSize(childStorageKey: any, key: any, block?: Hash | Uint8Array | string): Observable<u64>;
|
||||
getKeys(prefix: any, block?: Hash | Uint8Array | string): Observable<Vec<StorageKey>>;
|
||||
getMetadata(block?: Hash | Uint8Array | string): Observable<Metadata>;
|
||||
getRuntimeVersion(hash?: Hash | Uint8Array | string): Observable<RuntimeVersion>;
|
||||
getStorage<T = Codec>(key: any, block?: Hash | Uint8Array | string): Observable<T>;
|
||||
getStorageHash(key: any, block?: Hash | Uint8Array | string): Observable<Hash>;
|
||||
getStorageSize(key: any, block?: Hash | Uint8Array | string): Observable<u64>;
|
||||
queryStorage(keys: (any)[], startBlock: Hash | Uint8Array | string, block?: Hash | Uint8Array | string): Observable<Vec<StorageChangeSet>>;
|
||||
subscribeStorage<T = Codec[]>(keys: any[]): Observable<T>;
|
||||
};
|
||||
system: {
|
||||
chain(): Observable<Text>;
|
||||
health(): Observable<Health>;
|
||||
name(): Observable<Text>;
|
||||
networkState(): Observable<NetworkState>;
|
||||
peers(): Observable<Vec<PeerInfo>>;
|
||||
properties(): Observable<ChainProperties>;
|
||||
version(): Observable<Text>;
|
||||
};
|
||||
}
|
||||
@@ -15,8 +15,10 @@ describe('replay', (): void => {
|
||||
});
|
||||
|
||||
it('subscribes via the rpc section', (done): void => {
|
||||
// @ts-ignore
|
||||
rpc.chain.getBlockHash = jest.fn((): Observable<number> => of(1));
|
||||
|
||||
// @ts-ignore
|
||||
rpc.chain.getBlockHash(123, false).subscribe((): void => {
|
||||
expect(
|
||||
rpc.chain.getBlockHash
|
||||
|
||||
@@ -7,12 +7,3 @@ import { Observable } from 'rxjs';
|
||||
export interface RpcInterfaceMethod {
|
||||
(...params: any[]): Observable<any>;
|
||||
}
|
||||
|
||||
export type RpcInterfaceSection = Record<string, RpcInterfaceMethod>;
|
||||
|
||||
export interface RpcInterface {
|
||||
readonly author: RpcInterfaceSection;
|
||||
readonly chain: RpcInterfaceSection;
|
||||
readonly state: RpcInterfaceSection;
|
||||
readonly system: RpcInterfaceSection;
|
||||
}
|
||||
|
||||
@@ -3,16 +3,19 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { TypeDef, TypeDefInfo, TypeDefExtVecFixed } from '../codec/types';
|
||||
import { Constructor } from '../types';
|
||||
|
||||
import fs from 'fs';
|
||||
import { isString, stringCamelCase, stringUpperFirst } from '@polkadot/util';
|
||||
|
||||
import { getTypeDef } from '../codec/createType';
|
||||
import interfaces from '../../../type-jsonrpc/src';
|
||||
import { ClassOfUnsafe, getTypeDef } from '../codec/createType';
|
||||
import * as codecClasses from '../codec';
|
||||
import AbstractInt from '../codec/AbstractInt';
|
||||
import { COMPACT_ENCODABLE } from '../codec/Compact';
|
||||
import * as primitiveClasses from '../primitive';
|
||||
import Vec from '../codec/Vec';
|
||||
import * as definitions from '../interfaces/definitions';
|
||||
import { Constructor } from '../types';
|
||||
import * as primitiveClasses from '../primitive';
|
||||
|
||||
// these map all the codec and primitive types for import, see the TypeImports below. If
|
||||
// we have an unseen type, it is `undefined`/`false`, if we need to import it, it is `true`
|
||||
@@ -23,10 +26,11 @@ type TypeExist = Record<string, boolean>;
|
||||
type LocalExist = Record<string, TypeExist>;
|
||||
|
||||
interface TypeImports {
|
||||
codecTypes: TypeExist;
|
||||
codecTypes: TypeExist; // `import {} from '@polkadot/types/codec`
|
||||
localTypes: LocalExist;
|
||||
ownTypes: string[];
|
||||
primitiveTypes: TypeExist;
|
||||
primitiveTypes: TypeExist; // `import {} from '@polkadot/types/primitive`
|
||||
typesTypes: TypeExist; // `import {} from '@polkadot/types/types`
|
||||
}
|
||||
|
||||
const HEADER = '// Auto-generated via `yarn build:interfaces`, do not edit\n\n';
|
||||
@@ -34,13 +38,15 @@ const FOOTER = '\n';
|
||||
|
||||
// Maps the types as found to the source location. This is used to generate the
|
||||
// imports in the output file, dep-duped and sorted
|
||||
function setImports ({ codecTypes, localTypes, ownTypes, primitiveTypes }: TypeImports, types: string[]): void {
|
||||
function setImports ({ codecTypes, localTypes, ownTypes, primitiveTypes, typesTypes }: TypeImports, types: string[]): void {
|
||||
types.forEach((type): void => {
|
||||
if (ownTypes.includes(type)) {
|
||||
// do nothing
|
||||
} else if (['Codec', 'IExtrinsic'].includes(type)) {
|
||||
typesTypes[type] = true;
|
||||
} else if ((codecClasses as any)[type]) {
|
||||
codecTypes[type] = true;
|
||||
} else if ((primitiveClasses as any)[type]) {
|
||||
} else if ((primitiveClasses as any)[type] || type === 'Metadata') {
|
||||
primitiveTypes[type] = true;
|
||||
} else {
|
||||
// find this module inside the exports from the rest
|
||||
@@ -67,7 +73,9 @@ function isChildClass (Parent: Constructor<any>, Child: Constructor<any>): boole
|
||||
|
||||
function isCompactEncodable (Child: Constructor<any>): boolean {
|
||||
// @ts-ignore AbstractInt is abstract, we shouldn't isChildClass it here, but it works
|
||||
return Object.values(COMPACT_ENCODABLE).some((CompactEncodable): boolean => isChildClass(CompactEncodable, Child));
|
||||
return Object.values(COMPACT_ENCODABLE).some((CompactEncodable): boolean =>
|
||||
isChildClass(CompactEncodable, Child)
|
||||
);
|
||||
}
|
||||
|
||||
// helper to generate a `export interface <Name> extends <Base> {<Body>}
|
||||
@@ -257,11 +265,14 @@ function createImportCode (header: string, checks: { file: string; types: string
|
||||
function getDerivedTypes (type: string, primitiveName: string, imports: TypeImports, indent: number = 2): string {
|
||||
// `primitiveName` represents the actual primitive type our type is mapped to
|
||||
const isCompact = isCompactEncodable((primitiveClasses as any)[primitiveName]);
|
||||
|
||||
setImports(imports, ['Option', 'Vec', isCompact ? 'Compact' : '']);
|
||||
|
||||
return [
|
||||
`${type}: ${type};`,
|
||||
isCompact ? `'Compact<${type}>': Compact<${type}>;` : undefined,
|
||||
isCompact
|
||||
? `'Compact<${type}>': Compact<${type}>;`
|
||||
: undefined,
|
||||
`'Option<${type}>': Option<${type}>;`,
|
||||
`'Vec<${type}>': Vec<${type}>;`
|
||||
]
|
||||
@@ -270,7 +281,13 @@ function getDerivedTypes (type: string, primitiveName: string, imports: TypeImpo
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
function generateTsDef (defName: string, { types }: { types: Record<string, any> }): void {
|
||||
interface Imports extends TypeImports {
|
||||
|
||||
interfaces: [string, string][];
|
||||
}
|
||||
|
||||
// Create an Imports object, prefilled with types (if necessary)
|
||||
function createImports ({ types }: { types: Record<string, any> } = { types: {} }): Imports {
|
||||
// handlers are defined externally to use - this means that when we do a
|
||||
// `generators[typedef.info](...)` TS will show any unhandled types. Rather
|
||||
// we are being explicit in having no handlers where we do not support (yet)
|
||||
@@ -297,29 +314,38 @@ function generateTsDef (defName: string, { types }: { types: Record<string, any>
|
||||
}, {});
|
||||
const ownTypes = Object.keys(types);
|
||||
const primitiveTypes: TypeExist = {};
|
||||
const typesTypes: TypeExist = {};
|
||||
const interfaces = Object.entries(types).map(([name, type]): [string, string] => {
|
||||
const def = getTypeDef(isString(type) ? type.toString() : JSON.stringify(type), name);
|
||||
|
||||
return [name, generators[def.info](def, { codecTypes, localTypes, ownTypes, primitiveTypes })];
|
||||
return [name, generators[def.info](def, { codecTypes, localTypes, ownTypes, primitiveTypes, typesTypes })];
|
||||
});
|
||||
|
||||
const sortedDefs = interfaces.sort((a, b): number => a[0].localeCompare(b[0])).map(([, definition]): string => definition).join('\n\n');
|
||||
const imports = { codecTypes, localTypes, ownTypes, primitiveTypes, typesTypes, interfaces };
|
||||
|
||||
return imports;
|
||||
}
|
||||
|
||||
function generateTsDef (defName: string, { types }: { types: Record<string, any> }): void {
|
||||
const imports = createImports({ types });
|
||||
|
||||
const sortedDefs = imports.interfaces.sort((a, b): number => a[0].localeCompare(b[0])).map(([, definition]): string => definition).join('\n\n');
|
||||
const header = createImportCode(HEADER, [
|
||||
{
|
||||
file: '../../types',
|
||||
types: codecTypes['Tuple'] ? ['Codec'] : []
|
||||
types: imports.codecTypes['Tuple'] ? ['Codec'] : []
|
||||
},
|
||||
{
|
||||
file: '../../codec',
|
||||
types: Object.keys(codecTypes).filter((name): boolean => name !== 'Tuple')
|
||||
types: Object.keys(imports.codecTypes).filter((name): boolean => name !== 'Tuple')
|
||||
},
|
||||
{
|
||||
file: '../../primitive',
|
||||
types: Object.keys(primitiveTypes)
|
||||
types: Object.keys(imports.primitiveTypes)
|
||||
},
|
||||
...Object.keys(localTypes).map((moduleName): { file: string; types: string[] } => ({
|
||||
...Object.keys(imports.localTypes).map((moduleName): { file: string; types: string[] } => ({
|
||||
file: `../${moduleName}`,
|
||||
types: Object.keys(localTypes[moduleName])
|
||||
types: Object.keys(imports.localTypes[moduleName])
|
||||
}))
|
||||
]);
|
||||
|
||||
@@ -338,18 +364,9 @@ console.log(`Writing interfaces/types.ts`);
|
||||
fs.writeFileSync(`packages/types/src/interfaces/types.ts`, HEADER.concat(Object.keys(definitions).map((moduleName): string => `export * from './${moduleName}/types';`).join('\n')).concat(FOOTER), { flag: 'w' });
|
||||
fs.writeFileSync(`packages/types/src/interfaces/index.ts`, HEADER.concat(`export * from './types';`).concat(FOOTER), { flag: 'w' });
|
||||
|
||||
// Generate `packages/types/src/interfaceRegistry.ts`, the registry of all interfaces
|
||||
function generateInterfaceRegistry (): void {
|
||||
const codecTypes: TypeExist = {};
|
||||
const localTypes: LocalExist = Object.keys(definitions).reduce((localTypes: Record<string, TypeExist>, moduleName): Record<string, TypeExist> => {
|
||||
localTypes[moduleName] = {};
|
||||
|
||||
return localTypes;
|
||||
}, {});
|
||||
const ownTypes: string[] = [];
|
||||
const primitiveTypes: TypeExist = {};
|
||||
const substrateTypes: TypeExist = {};
|
||||
|
||||
const imports = { codecTypes, localTypes, ownTypes, primitiveTypes, substrateTypes };
|
||||
const imports = createImports();
|
||||
|
||||
const primitives = Object
|
||||
.keys(primitiveClasses)
|
||||
@@ -371,22 +388,24 @@ function generateInterfaceRegistry (): void {
|
||||
|
||||
return [
|
||||
accumulator,
|
||||
...Object.keys(types).map((type): string => getDerivedTypes(type, (types as any)[type], imports, 2))
|
||||
...Object.keys(types).map((type): string =>
|
||||
getDerivedTypes(type, (types as any)[type], imports, 2)
|
||||
)
|
||||
].join('\n');
|
||||
}, '');
|
||||
|
||||
const header = createImportCode(HEADER, [
|
||||
{
|
||||
file: './codec',
|
||||
types: Object.keys(codecTypes).filter((name): boolean => name !== 'Tuple')
|
||||
types: Object.keys(imports.codecTypes).filter((name): boolean => name !== 'Tuple')
|
||||
},
|
||||
{
|
||||
file: './primitive',
|
||||
types: Object.keys(primitiveTypes)
|
||||
types: Object.keys(imports.primitiveTypes)
|
||||
},
|
||||
...Object.keys(localTypes).map((moduleName): { file: string; types: string[] } => ({
|
||||
...Object.keys(imports.localTypes).map((moduleName): { file: string; types: string[] } => ({
|
||||
file: `./interfaces/${moduleName}`,
|
||||
types: Object.keys(localTypes[moduleName])
|
||||
types: Object.keys(imports.localTypes[moduleName])
|
||||
}))
|
||||
]);
|
||||
|
||||
@@ -403,3 +422,116 @@ function generateInterfaceRegistry (): void {
|
||||
console.log(`Writing interfaceRegistry.ts`);
|
||||
|
||||
generateInterfaceRegistry();
|
||||
|
||||
// Make types a little bit more flexible
|
||||
// - if param instanceof AbstractInt, then param: u64 | Uint8array | string | number
|
||||
// etc
|
||||
function getSimilarTypes (imports: Imports, type: string): string[] {
|
||||
const possibleTypes = [type];
|
||||
|
||||
if (type === 'Extrinsic') {
|
||||
setImports(imports, ['IExtrinsic']);
|
||||
return ['IExtrinsic'];
|
||||
}
|
||||
|
||||
if (isChildClass(Vec, ClassOfUnsafe(type))) {
|
||||
return [`(${getSimilarTypes(imports, ((getTypeDef(type).sub) as TypeDef).type).join(' | ')})[]`];
|
||||
}
|
||||
|
||||
// FIXME This is a hack, it's hard to correctly type StorageKeys in the
|
||||
// current state
|
||||
if (type === 'StorageKey') {
|
||||
return ['any'];
|
||||
}
|
||||
|
||||
// @ts-ignore Cannot get isChildClass of abstract class, but it works
|
||||
if (isChildClass(AbstractInt, ClassOfUnsafe(type))) {
|
||||
possibleTypes.push('Uint8Array', 'number', 'string');
|
||||
} else if (isChildClass(Uint8Array, ClassOfUnsafe(type))) {
|
||||
possibleTypes.push('Uint8Array', 'string');
|
||||
} else if (isChildClass(String, ClassOfUnsafe(type))) {
|
||||
possibleTypes.push('string');
|
||||
}
|
||||
|
||||
return possibleTypes;
|
||||
}
|
||||
|
||||
// Generate `packages/types-jsonrpc/src/jsonrpc.types.ts`
|
||||
function generateRpcTypes (): void {
|
||||
// Inject all types so that types-jsonrpc can use them
|
||||
require('../injector');
|
||||
|
||||
// Get all imported types by types-jsonrpc
|
||||
const allImportedTypes = Object.keys(interfaces).reduce<string[]>((allSections, section): string[] => {
|
||||
return allSections.concat(
|
||||
...Object.values(interfaces[section].methods).map((method): string[] =>
|
||||
[...method.params.map(({ type }): string => type), method.type])
|
||||
);
|
||||
}, []);
|
||||
|
||||
const imports = createImports({ types: allImportedTypes });
|
||||
|
||||
const body = Object.keys(interfaces).reduce<string[]>((allSections, section): string[] => {
|
||||
const allMethods = Object.values(interfaces[section].methods).map((method): string => {
|
||||
// FIXME These 2 are too hard to type, I give up
|
||||
if (method.method === 'getStorage') {
|
||||
setImports(imports, ['Codec']);
|
||||
return ` getStorage<T = Codec>(key: any, block?: Hash | Uint8Array | string): Observable<T>;`;
|
||||
} else if (method.method === 'subscribeStorage') {
|
||||
return ` subscribeStorage<T = Codec[]>(keys: any[]): Observable<T>;`;
|
||||
}
|
||||
|
||||
const args = method.params.map((param): string => {
|
||||
const similarTypes = getSimilarTypes(imports, param.type);
|
||||
setImports(imports, similarTypes);
|
||||
|
||||
return `${param.name}${param.isOptional ? '?' : ''}: ${similarTypes.join(' | ')}`;
|
||||
});
|
||||
|
||||
return ` ${method.method}(${args.join(', ')}): Observable<${method.type}>;`;
|
||||
});
|
||||
|
||||
return allSections.concat(
|
||||
[
|
||||
` ${section}: {`,
|
||||
...allMethods,
|
||||
` };`
|
||||
].join('\n')
|
||||
);
|
||||
}, []).join('\n');
|
||||
|
||||
const header = createImportCode(HEADER, [
|
||||
{
|
||||
file: 'rxjs',
|
||||
types: ['Observable']
|
||||
},
|
||||
{
|
||||
file: '@polkadot/types/codec',
|
||||
types: Object.keys(imports.codecTypes).filter((name): boolean => name !== 'Tuple')
|
||||
},
|
||||
{
|
||||
file: '@polkadot/types',
|
||||
types: Object.keys(imports.primitiveTypes)
|
||||
},
|
||||
...Object.keys(imports.localTypes).map((moduleName): { file: string; types: string[] } => ({
|
||||
file: `@polkadot/types/interfaces/${moduleName}`,
|
||||
types: Object.keys(imports.localTypes[moduleName])
|
||||
})),
|
||||
{
|
||||
file: '@polkadot/types/types',
|
||||
types: Object.keys(imports.typesTypes)
|
||||
}
|
||||
]);
|
||||
const interfaceStart = 'export interface RpcInterface {\n';
|
||||
const interfaceEnd = '\n}';
|
||||
|
||||
fs.writeFileSync(
|
||||
`packages/rpc-core/src/jsonrpc.types.ts`,
|
||||
header.concat(interfaceStart).concat(body).concat(interfaceEnd).concat(FOOTER)
|
||||
, { flag: 'w' }
|
||||
);
|
||||
}
|
||||
|
||||
console.log(`Writing packages/rpc-core/jsonrpc.types.ts`);
|
||||
|
||||
generateRpcTypes();
|
||||
|
||||
Reference in New Issue
Block a user