From 12be027b182c8547052754c03cd851221b06fdd1 Mon Sep 17 00:00:00 2001 From: Jaco Date: Fri, 7 May 2021 11:47:09 +0300 Subject: [PATCH] Allow for `Bounded*` type usage (#3504) * Allow for `Bounded*` type usage * Adjust start index after found * Adjust * Add tests for bounded * Bounded with length value * adjust --- CHANGELOG.md | 1 + packages/types/src/create/sanitize.spec.ts | 36 +++++++++++----- packages/types/src/create/sanitize.ts | 49 ++++++++++++---------- 3 files changed, 54 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8ac2855a8..ef45ea51b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ Contributed: Changes: +- Allow for `Bounded*` type usage (as per latest Substrate) - Adjust internal TS definitions for providers diff --git a/packages/types/src/create/sanitize.spec.ts b/packages/types/src/create/sanitize.spec.ts index 814e476a09..3e75ede3e1 100644 --- a/packages/types/src/create/sanitize.spec.ts +++ b/packages/types/src/create/sanitize.spec.ts @@ -1,32 +1,32 @@ // Copyright 2017-2021 @polkadot/types authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { alias, removeColons } from './sanitize'; +import { alias, removeBounded, removeColons } from './sanitize'; describe('sanitize', (): void => { describe('alias', (): void => { - const exec = alias('String', 'Text'); + const fn = alias('String', 'Text'); it('replaces all occurrences for types', (): void => { - expect(exec('(String,Address,MasterString,String)')).toEqual( + expect(fn('(String,Address,MasterString,String)')).toEqual( '(Text,Address,MasterString,Text)' ); }); it('replaces actual types, but leaves struct names', (): void => { - expect(exec('{"system":"String","versionString":"String"}')).toEqual( + expect(fn('{"system":"String","versionString":"String"}')).toEqual( '{"system":"Text","versionString":"Text"}' ); }); it('handles the preceding correctly', (): void => { // NOTE This type doesn't make sense - expect(exec('String String (String,[String;32],String)"String')).toEqual( + expect(fn('String String (String,[String;32],String)"String')).toEqual( 'Text Text (Text,[Text;32],Text)"Text' ); }); - it('handles emdedded Vec/Tuples', (): void => { + it('handles embedded Vec/Tuples', (): void => { const ann = alias('Announcement', 'ProxyAnnouncement'); expect(ann('(Vec,BalanceOf)')).toEqual( @@ -36,24 +36,38 @@ describe('sanitize', (): void => { }); describe('removeColons', (): void => { + const fn = removeColons(); + it('removes preceding ::Text -> Text', (): void => { - expect(removeColons()('::Text')).toEqual('Text'); + expect(fn('::Text')).toEqual('Text'); }); it('removes middle voting::TallyType -> TallyType', (): void => { - expect(removeColons()('voting::TallyType')).toEqual('TallyType'); + expect(fn('voting::TallyType')).toEqual('TallyType'); }); it('removes on embedded values (one)', (): void => { - expect(removeColons()('(T::AccountId, SpanIndex)')).toEqual('(AccountId, SpanIndex)'); + expect(fn('(T::AccountId, SpanIndex)')).toEqual('(AccountId, SpanIndex)'); }); it('removes on embedded values (all)', (): void => { - expect(removeColons()('(T::AccountId, slashing::SpanIndex)')).toEqual('(AccountId, SpanIndex)'); + expect(fn('(T::AccountId, slashing::SpanIndex)')).toEqual('(AccountId, SpanIndex)'); }); it('keeps with allowNamespaces', (): void => { - expect(removeColons()('::slashing::SpanIndex', { allowNamespaces: true })).toEqual('slashing::SpanIndex'); + expect(fn('::slashing::SpanIndex', { allowNamespaces: true })).toEqual('slashing::SpanIndex'); + }); + }); + + describe('bounded', (): void => { + const fn = removeBounded(); + + it('correctly cleans up bounded values', (): void => { + expect(fn('BoundedVec')).toEqual('Vec'); + }); + + it('correctly cleans up nested bounded values', (): void => { + expect(fn('BoundedBTreeMap, 2>, BoundedBTreeSet, 4>, 5>')).toEqual('BTreeMap>, BTreeSet>>'); }); }); }); diff --git a/packages/types/src/create/sanitize.ts b/packages/types/src/create/sanitize.ts index 8cde02e275..44327b7c1d 100644 --- a/packages/types/src/create/sanitize.ts +++ b/packages/types/src/create/sanitize.ts @@ -7,7 +7,8 @@ interface SanitizeOptions { type Mapper = (value: string, options?: SanitizeOptions) => string; -const ALLOWED_BOXES = ['BTreeMap', 'BTreeSet', 'Compact', 'DoNotConstruct', 'HashMap', 'Int', 'Linkage', 'Result', 'Option', 'UInt', 'Vec']; +const BOUNDED = ['BTreeMap', 'BTreeSet', 'HashMap', 'Vec']; +const ALLOWED_BOXES = BOUNDED.concat(['Compact', 'DoNotConstruct', 'Int', 'Linkage', 'Result', 'Option', 'UInt']); const BOX_PRECEDING = ['<', '(', '[', '"', ',', ' ']; // start of vec, tuple, fixed array, part of struct def or in tuple const mappings: Mapper[] = [ @@ -17,7 +18,7 @@ const mappings: Mapper[] = [ // cleanupCompact(), // Change BoundedVec to Vec - removeBoundedVec(), + removeBounded(), // Remove all the trait prefixes removeTraits(), // remove PairOf -> (T, T) @@ -77,14 +78,12 @@ export function alias (src: string, dest: string, withChecks = true): Mapper { export function cleanupCompact (): Mapper { return (value: string): string => { for (let index = 0; index < value.length; index++) { - if (value[index] !== '<') { - continue; - } + if (value[index] === '<') { + const end = findClosing(value, index + 1) - 14; - const end = findClosing(value, index + 1) - 14; - - if (value.substr(end, 14) === ' as HasCompact') { - value = `Compact<${value.substr(index + 1, end - index - 1)}>`; + if (value.substr(end, 14) === ' as HasCompact') { + value = `Compact<${value.substr(index + 1, end - index - 1)}>`; + } } } @@ -98,24 +97,32 @@ export function flattenSingleTuple (): Mapper { } function replaceTagWith (value: string, matcher: string, replacer: (inner: string) => string): string { - for (let index = 0; index < value.length; index++) { - if (value.substr(index, matcher.length) === matcher) { - const start = index + matcher.length; - const end = findClosing(value, start); + let index = -1; - value = `${value.substr(0, index)}${replacer(value.substr(start, end - start))}${value.substr(end + 1)}`; + while (true) { + index = value.indexOf(matcher, index + 1); + + if (index === -1) { + return value; } - } - return value; + const start = index + matcher.length; + const end = findClosing(value, start); + + value = `${value.substr(0, index)}${replacer(value.substr(start, end - start))}${value.substr(end + 1)}`; + } } -// remove the BoundedVec wrappers -export function removeBoundedVec (): Mapper { - const replacer = (inner: string) => `Vec<${inner.split(',')[0]}>`; - +// remove the Bounded* wrappers +export function removeBounded (): Mapper { return (value: string) => - replaceTagWith(value, 'BoundedVec<', replacer); + BOUNDED.reduce((value, tag) => + replaceTagWith(value, `Bounded${tag}<`, (inner: string): string => { + const parts = inner.split(','); + + return `${tag}<${parts.filter((_, i) => i !== parts.length - 1).join(',')}>`; + }), value + ); } export function removeColons (): Mapper {