Allow optional params (#68)
* Allow optional params * Don't double-up on method signature * Cleanup formatters/util
This commit is contained in:
@@ -44,22 +44,15 @@ function formatArrayType (formatters: FormattersFunctionMap, type: FormattersFun
|
||||
});
|
||||
}
|
||||
|
||||
function format (formatters: FormattersFunctionMap, type: FormattersFunctionType, value: mixed | Array<mixed>): mixed {
|
||||
if (arrayTypeRegex.test(type)) {
|
||||
// $FlowFixMe array type
|
||||
return formatArrayType(formatters, type, value);
|
||||
}
|
||||
module.exports = function format (formatters: FormattersFunctionMap, types: Array<FormattersFunctionType>, values: Array<mixed>): Array<mixed> {
|
||||
return values.map((value, index): mixed => {
|
||||
const type = types[index];
|
||||
|
||||
return formatSingleType(formatters, type, value);
|
||||
}
|
||||
if (arrayTypeRegex.test(type)) {
|
||||
// $FlowFixMe array type
|
||||
return formatArrayType(formatters, type, value);
|
||||
}
|
||||
|
||||
function formatArray (formatters: FormattersFunctionMap, types: Array<FormattersFunctionType>, values: Array<mixed>): Array<mixed> {
|
||||
return types.map((type, index): mixed => {
|
||||
return format(formatters, type, values[index]);
|
||||
return formatSingleType(formatters, type, value);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
format,
|
||||
formatArray
|
||||
};
|
||||
@@ -0,0 +1,78 @@
|
||||
// Copyright 2017-2018 Jaco Greeff
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
const format = require('./format');
|
||||
const echo = require('./echo');
|
||||
|
||||
describe('format', () => {
|
||||
let formatters;
|
||||
let echoSpy;
|
||||
let warnSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
echoSpy = jest.fn(echo);
|
||||
warnSpy = jest.spyOn(console, 'warn');
|
||||
|
||||
formatters = {
|
||||
'Address': echoSpy,
|
||||
'Address[]': echoSpy,
|
||||
'Exception': () => {
|
||||
throw new Error('something went wrong');
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
echoSpy.mockRestore();
|
||||
warnSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('formats unknown types with a fallback', () => {
|
||||
expect(
|
||||
format(formatters, ['Unknown'], ['test'])
|
||||
).toEqual(['test']);
|
||||
});
|
||||
|
||||
it('logs a warning with unknown types', () => {
|
||||
format(formatters, ['Unknown'], ['test']);
|
||||
expect(warnSpy).toHaveBeenCalledWith(
|
||||
expect.anything(), expect.anything(), "Unable to find default formatter for 'Unknown', falling back to echo"
|
||||
);
|
||||
});
|
||||
|
||||
it('wraps exceptions with the type', () => {
|
||||
expect(
|
||||
() => format(formatters, ['Exception'], ['test'])
|
||||
).toThrow(/Error formatting 'test' as 'Exception'/);
|
||||
});
|
||||
|
||||
describe('primitives', () => {
|
||||
it('formats known types using the supplied formatter', () => {
|
||||
format(formatters, ['Address'], ['0xaddress']);
|
||||
|
||||
expect(echoSpy).toHaveBeenCalledWith('0xaddress');
|
||||
});
|
||||
});
|
||||
|
||||
describe('primitive[]', () => {
|
||||
it('formats using the primitive type', () => {
|
||||
format(formatters, ['Address[]'], [['0x123', '0x234']]);
|
||||
|
||||
expect(echoSpy).toHaveBeenCalledWith('0x123');
|
||||
expect(echoSpy).toHaveBeenCalledWith('0x234');
|
||||
});
|
||||
|
||||
it('returns formatted values as arrays', () => {
|
||||
expect(
|
||||
format(formatters, ['Address[]'], [['0x123', '0x234']])
|
||||
).toEqual([['0x123', '0x234']]);
|
||||
});
|
||||
});
|
||||
|
||||
it('formats each value in an array', () => {
|
||||
expect(
|
||||
format(formatters, ['Unknown', 'Unknown'], ['test', 'blah'])
|
||||
).toEqual(['test', 'blah']);
|
||||
});
|
||||
});
|
||||
@@ -8,7 +8,7 @@ import type { InterfaceInputType } from '@polkadot/api-jsonrpc/types';
|
||||
const bytesEncode = require('@polkadot/primitives-json/bytes/encode');
|
||||
const hashEncode = require('@polkadot/primitives-json/hash/encode');
|
||||
|
||||
const util = require('./util');
|
||||
const format = require('./format');
|
||||
|
||||
const formatters = {
|
||||
'Bytes': bytesEncode,
|
||||
@@ -19,5 +19,5 @@ const formatters = {
|
||||
module.exports = function formatInputs (inputs: Array<InterfaceInputType>, values: Array<mixed>): Array<mixed> {
|
||||
const types = inputs.map(({ type }) => type);
|
||||
|
||||
return util.formatArray(formatters, types, values);
|
||||
return format(formatters, types, values);
|
||||
};
|
||||
|
||||
@@ -11,7 +11,7 @@ const headerDecode = require('@polkadot/primitives-json/header/decode');
|
||||
const isNull = require('@polkadot/util/is/null');
|
||||
const isUndefined = require('@polkadot/util/is/undefined');
|
||||
|
||||
const util = require('./util');
|
||||
const format = require('./format');
|
||||
|
||||
const formatters = {
|
||||
'BlockNumber': bnDecode,
|
||||
@@ -25,5 +25,5 @@ module.exports = function formatOutput (output: InterfaceOutputType, value?: mix
|
||||
return value;
|
||||
}
|
||||
|
||||
return util.format(formatters, output.type, value);
|
||||
return format(formatters, [output.type], [value])[0];
|
||||
};
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
// Copyright 2017-2018 Jaco Greeff
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
const { format, formatArray } = require('./util');
|
||||
const echo = require('./echo');
|
||||
|
||||
describe('util', () => {
|
||||
let formatters;
|
||||
let echoSpy;
|
||||
let warnSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
echoSpy = jest.fn(echo);
|
||||
warnSpy = jest.spyOn(console, 'warn');
|
||||
|
||||
formatters = {
|
||||
'Address': echoSpy,
|
||||
'Address[]': echoSpy,
|
||||
'Exception': () => {
|
||||
throw new Error('something went wrong');
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
echoSpy.mockRestore();
|
||||
warnSpy.mockRestore();
|
||||
});
|
||||
|
||||
describe('format', () => {
|
||||
it('formats unknown types with a fallback', () => {
|
||||
expect(
|
||||
format(formatters, 'Unknown', 'test')
|
||||
).toEqual('test');
|
||||
});
|
||||
|
||||
it('logs a warning with unknown types', () => {
|
||||
format(formatters, 'Unknown', 'test');
|
||||
expect(warnSpy).toHaveBeenCalledWith(
|
||||
expect.anything(), expect.anything(), "Unable to find default formatter for 'Unknown', falling back to echo"
|
||||
);
|
||||
});
|
||||
|
||||
it('wraps exceptions with the type', () => {
|
||||
expect(
|
||||
() => format(formatters, 'Exception', 'test')
|
||||
).toThrow(/Error formatting 'test' as 'Exception'/);
|
||||
});
|
||||
|
||||
describe('primitives', () => {
|
||||
it('formats known types using the supplied formatter', () => {
|
||||
format(formatters, 'Address', '0xaddress');
|
||||
|
||||
expect(echoSpy).toHaveBeenCalledWith('0xaddress');
|
||||
});
|
||||
});
|
||||
|
||||
describe('primitive[]', () => {
|
||||
it('formats using the primitive type', () => {
|
||||
format(formatters, 'Address[]', ['0x123', '0x234']);
|
||||
|
||||
expect(echoSpy).toHaveBeenCalledWith('0x123');
|
||||
expect(echoSpy).toHaveBeenCalledWith('0x234');
|
||||
});
|
||||
|
||||
it('returns formatted values as arrays', () => {
|
||||
expect(
|
||||
format(formatters, 'Address[]', ['0x123', '0x234'])
|
||||
).toEqual(['0x123', '0x234']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatArray', () => {
|
||||
it('formats each value in an array', () => {
|
||||
expect(
|
||||
formatArray(formatters, ['Unknown', 'Unknown'], ['test', 'blah'])
|
||||
).toEqual(['test', 'blah']);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -19,6 +19,7 @@ module.exports = ({
|
||||
type: 'H256'
|
||||
},
|
||||
{
|
||||
isOptional: true,
|
||||
name: 'blockHash',
|
||||
type: 'HeaderHash'
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ export type FormatInputType = 'Bytes' | 'H256' | 'HeaderHash' | 'String';
|
||||
export type FormatOutputType = 'BlockNumber' | 'Bytes' | 'Header' | 'HeaderHash' | 'U64';
|
||||
|
||||
export type InterfaceInputType = {
|
||||
isOptional?: boolean,
|
||||
name: string,
|
||||
type: FormatInputType
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@ module.exports = function createMethodSend (provider: ProviderInterface, rpcName
|
||||
const call = async (..._params: Array<mixed>): Promise<mixed> => {
|
||||
// TODO: Deprecated warning
|
||||
try {
|
||||
const params = createParams(rpcName, _params, inputs);
|
||||
const params = createParams(_params, inputs);
|
||||
const result = await provider.send(rpcName, params);
|
||||
|
||||
return formatOutput(output, result);
|
||||
|
||||
@@ -41,7 +41,7 @@ describe('methodCall', () => {
|
||||
const method = createMethod(provider, 'test_bleh', 'bleh', methods.bleh);
|
||||
|
||||
return method(1).catch((error) => {
|
||||
expect(error.message).toMatch(/0 params expected, found 1 instead/);
|
||||
expect(error.message).toMatch(/no params expected, found 1 instead/);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ module.exports = function methodSubscribe (provider: ProviderInterface, rpcName:
|
||||
|
||||
assert(isFunction(cb), `Expected callback in last position of params`);
|
||||
|
||||
const params = createParams(rpcName, _params, inputs);
|
||||
const params = createParams(_params, inputs);
|
||||
const update = (error: ?Error, result?: mixed) => {
|
||||
cb(error, formatOutput(output, result));
|
||||
};
|
||||
|
||||
@@ -8,8 +8,13 @@ import type { InterfaceInputType } from '@polkadot/api-jsonrpc/types';
|
||||
const formatInputs = require('@polkadot/api-format/input');
|
||||
const assert = require('@polkadot/util/assert');
|
||||
|
||||
module.exports = function createParams (rpcName: string, params: Array<mixed>, inputs: Array<InterfaceInputType>): Array<mixed> {
|
||||
assert(inputs.length === params.length, `${rpcName}: ${inputs.length} params expected, found ${params.length} instead`);
|
||||
module.exports = function createParams (params: Array<mixed>, inputs: Array<InterfaceInputType>): Array<mixed> {
|
||||
const required = inputs.filter(({ isOptional }) => !isOptional);
|
||||
const optionalText = inputs.length
|
||||
? ` (${(inputs.length - required.length) || 'none'} optional)`
|
||||
: '';
|
||||
|
||||
assert(params.length >= required.length && params.length <= inputs.length, `${inputs.length || 'no'} params expected${optionalText}, found ${params.length} instead`);
|
||||
|
||||
return formatInputs(inputs, params);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright 2017-2018 Jaco Greeff
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
const params = require('./params');
|
||||
|
||||
describe('params', () => {
|
||||
let methods;
|
||||
|
||||
beforeEach(() => {
|
||||
methods = {
|
||||
blah: {
|
||||
inputs: [
|
||||
{ name: 'foo', type: 'Bytes' }
|
||||
],
|
||||
output: { type: 'Bytes' }
|
||||
},
|
||||
bleh: {
|
||||
inputs: [
|
||||
{ name: 'foo', type: 'Bytes', isOptional: true }
|
||||
],
|
||||
output: { type: 'Bytes' }
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
it('check against params', () => {
|
||||
expect(
|
||||
() => params([], methods.blah.inputs)
|
||||
).toThrow(/params expected/);
|
||||
});
|
||||
|
||||
it('check against params (required)', () => {
|
||||
expect(
|
||||
params([], methods.bleh.inputs)
|
||||
).toBeDefined();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user