diff --git a/CHANGELOG.md b/CHANGELOG.md index 65ed60aac3..8b904a82ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,13 +12,14 @@ Changes: - Rename `Base` type to `AbstractBase` (reflecting usage) - Instantiate `Compact/UInt/Int` with `number` when passed - Adjust name extraction in `PortableRegistry` (maintainability) +- Adjust string type path extraction (maintainability) ## 8.8.2 Jun 14, 2022 Changes: -- Aling historic `DispatchErrorModule` with `U8` variant +- Align historic `DispatchErrorModule` with `U8` variant - Extend lookup type name generation when conflicts arrise - Update to latest Substrate metadata diff --git a/packages/typegen/src/util/formatting.ts b/packages/typegen/src/util/formatting.ts index 02597bd5dd..18a1a7f819 100644 --- a/packages/typegen/src/util/formatting.ts +++ b/packages/typegen/src/util/formatting.ts @@ -3,7 +3,7 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ -import type { Registry } from '@polkadot/types/types'; +import type { AnyString, Registry } from '@polkadot/types/types'; import type { TypeDef } from '@polkadot/types-create/types'; import Handlebars from 'handlebars'; @@ -270,7 +270,7 @@ const formatters: Record, type: string | String | TypeDef, imports: TypeImports, withShortcut = false): string { +export function formatType (registry: Registry, definitions: Record, type: AnyString | TypeDef, imports: TypeImports, withShortcut = false): string { let typeDef: TypeDef; if (isString(type)) { diff --git a/packages/types-codec/src/utils/sanitize.spec.ts b/packages/types-codec/src/utils/sanitize.spec.ts index 157d8dfd85..87b2268f6f 100644 --- a/packages/types-codec/src/utils/sanitize.spec.ts +++ b/packages/types-codec/src/utils/sanitize.spec.ts @@ -53,10 +53,6 @@ describe('sanitize', (): void => { it('removes on embedded values (all)', (): void => { expect(fn('(T::AccountId, slashing::SpanIndex)')).toEqual('(AccountId, SpanIndex)'); }); - - it('keeps with allowNamespaces', (): void => { - expect(fn('::slashing::SpanIndex', { allowNamespaces: true })).toEqual('slashing::SpanIndex'); - }); }); describe('bounded', (): void => { diff --git a/packages/types-codec/src/utils/sanitize.ts b/packages/types-codec/src/utils/sanitize.ts index 7d1d9274dd..35a552e1e9 100644 --- a/packages/types-codec/src/utils/sanitize.ts +++ b/packages/types-codec/src/utils/sanitize.ts @@ -1,11 +1,9 @@ // Copyright 2017-2022 @polkadot/types-codec authors & contributors // SPDX-License-Identifier: Apache-2.0 -interface SanitizeOptions { - allowNamespaces?: boolean; -} +import { AnyString } from '../types'; -type Mapper = (value: string, options?: SanitizeOptions) => string; +type Mapper = (value: string) => string; const BOUNDED = ['BTreeMap', 'BTreeSet', 'HashMap', 'Vec']; const ALLOWED_BOXES = BOUNDED.concat(['Compact', 'DoNotConstruct', 'Int', 'Linkage', 'Range', 'RangeInclusive', 'Result', 'Option', 'UInt', 'WrapperKeepOpaque', 'WrapperOpaque']); @@ -165,7 +163,7 @@ export function removeExtensions (type: string, isSized: boolean): Mapper { } export function removeColons (): Mapper { - return (value: string, { allowNamespaces }: SanitizeOptions = {}): string => { + return (value: string): string => { let index = 0; while (index !== -1) { @@ -174,10 +172,6 @@ export function removeColons (): Mapper { if (index === 0) { value = value.substring(2); } else if (index !== -1) { - if (allowNamespaces) { - return value; - } - let start = index; while (start !== -1 && !BOX_PRECEDING.includes(value[start])) { @@ -203,7 +197,7 @@ export function removeGenerics (): Mapper { return ( ( start >= 0 && - value.substring(start, start + box.length) === box + value.substring(start, index) === box ) && ( // make sure it is stand-alone, i.e. don't catch ElectionResult<...> as Result<...> start === 0 || @@ -225,15 +219,12 @@ export function removeGenerics (): Mapper { }; } -/** @internal */ -function pairOfReplacer (v: string): string { - return `(${v},${v})`; -} - // remove the PairOf wrappers export function removePairOf (): Mapper { + const replacer = (v: string) => `(${v},${v})`; + return (value: string) => - replaceTagWith(value, 'PairOf<', pairOfReplacer); + replaceTagWith(value, 'PairOf<', replacer); } // remove the type traits @@ -269,39 +260,31 @@ export function removeTraits (): Mapper { }; } -/** @internal */ -function wrapReplacer (v: string): string { - return v; -} - // remove wrapping values, i.e. Box -> Proposal export function removeWrap (check: string): Mapper { + const replacer = (v: string) => v; + return (value: string) => - replaceTagWith(value, check, wrapReplacer); + replaceTagWith(value, check, replacer); } const sanitizeMap = new Map(); -// eslint-disable-next-line @typescript-eslint/ban-types -export function sanitize (value: String | string, options?: SanitizeOptions): string { +export function sanitize (value: AnyString): string { const startValue = value.toString(); + const memoized = sanitizeMap.get(startValue); + + if (memoized) { + return memoized; + } + let result = startValue; - if (!options) { - const memoized = sanitizeMap.get(startValue); - - if (memoized) { - return memoized; - } - } - for (let i = 0; i < mappings.length; i++) { - result = mappings[i](result, options); + result = mappings[i](result); } - if (!options) { - sanitizeMap.set(startValue, result); - } + sanitizeMap.set(startValue, result); return result; } diff --git a/packages/types-create/src/util/getTypeDef.ts b/packages/types-create/src/util/getTypeDef.ts index 0c1fd517df..c7f05ffb6b 100644 --- a/packages/types-create/src/util/getTypeDef.ts +++ b/packages/types-create/src/util/getTypeDef.ts @@ -1,6 +1,7 @@ // Copyright 2017-2022 @polkadot/types-create authors & contributors // SPDX-License-Identifier: Apache-2.0 +import type { AnyString } from '@polkadot/types-codec/types'; import type { TypeDef } from '@polkadot/types-create/types'; import { sanitize } from '@polkadot/types-codec'; @@ -15,6 +16,8 @@ interface TypeDefOptions { } const MAX_NESTED = 64; +const MAX_FIX_LEN = 2048; +const MAX_BIT_LEN = 8192; const KNOWN_INTERNALS = ['_alias', '_fallback']; function getTypeString (typeOrObj: any): string { @@ -132,8 +135,7 @@ function _decodeFixedVec (value: TypeDef, type: string, _: string, count: number const [strLength, displayName] = type.substring(index + 1, max).split(';'); const length = parseInt(strLength.trim(), 10); - // as a first round, only u8 via u8aFixed, we can add more support - assert(length <= 256, () => `${type}: Only support for [Type; ], where length <= 256`); + assert(length <= MAX_FIX_LEN, () => `${type}: Only support for [Type; ], where length <= ${MAX_FIX_LEN}`); value.displayName = displayName; value.length = length; @@ -157,8 +159,7 @@ function _decodeAnyInt (value: TypeDef, type: string, _: string, clazz: 'Int' | const [strLength, displayName] = type.substring(clazz.length + 1, type.length - 1).split(','); const length = parseInt(strLength.trim(), 10); - // as a first round, only u8 via u8aFixed, we can add more support - assert(length <= 8192 && (length % 8) === 0, () => `${type}: Only support for ${clazz}, where length <= 8192 and a power of 8, found ${length}`); + assert(length <= MAX_BIT_LEN && (length % 8) === 0, () => `${type}: Only support for ${clazz}, where length <= ${MAX_BIT_LEN} and a power of 8, found ${length}`); value.displayName = displayName; value.length = length; @@ -216,8 +217,7 @@ function extractSubType (type: string, [start, end]: [string, string, TypeDefInf return type.substring(start.length, type.length - end.length); } -// eslint-disable-next-line @typescript-eslint/ban-types -export function getTypeDef (_type: String | string, { displayName, name }: TypeDefOptions = {}, count = 0): TypeDef { +export function getTypeDef (_type: AnyString, { displayName, name }: TypeDefOptions = {}, count = 0): TypeDef { // create the type via Type, allowing types to be sanitized const type = sanitize(_type); const value: TypeDef = { displayName, info: TypeDefInfo.Plain, name, type }; diff --git a/packages/types-create/src/util/typeSplit.spec.ts b/packages/types-create/src/util/typeSplit.spec.ts index 4dffd64ba9..7a6dddd1fa 100644 --- a/packages/types-create/src/util/typeSplit.spec.ts +++ b/packages/types-create/src/util/typeSplit.spec.ts @@ -36,13 +36,13 @@ describe('typeSplit', (): void => { it('checks for unclosed vec', (): void => { expect( - (): string[] => typeSplit('Text, Vec typeSplit('Text, Vec { expect( - (): string[] => typeSplit('Text, (u64, u32') + () => typeSplit('Text, (u64, u32') ).toThrow(/Invalid definition/); }); }); diff --git a/packages/types-create/src/util/typeSplit.ts b/packages/types-create/src/util/typeSplit.ts index c8fed38070..c7f8d155c5 100644 --- a/packages/types-create/src/util/typeSplit.ts +++ b/packages/types-create/src/util/typeSplit.ts @@ -3,46 +3,51 @@ import { assert } from '@polkadot/util'; -function isNotNested (...counters: number[]): boolean { - return !counters.some((counter): boolean => counter !== 0); -} - // safely split a string on ', ' while taking care of any nested occurences export function typeSplit (type: string): string[] { - let [cDepth, fDepth, sDepth, tDepth, start] = [0, 0, 0, 0, 0]; - const result = []; + const result: string[] = []; - const extract = (index: number): void => { - if (isNotNested(cDepth, fDepth, sDepth, tDepth)) { - result.push(type.substring(start, index).trim()); - start = index + 1; - } - }; + // these are the depths of the various tokens: <, [, {, ( + let c = 0; + let f = 0; + let s = 0; + let t = 0; - for (let index = 0; index < type.length; index++) { - switch (type[index]) { + // current start position + let start = 0; + + for (let i = 0; i < type.length; i++) { + switch (type[i]) { // if we are not nested, add the type - case ',': extract(index); break; + case ',': { + if (!(c || f || s || t)) { + result.push(type.substring(start, i).trim()); + start = i + 1; + } + + break; + } // adjust compact/vec (and friends) depth - case '<': cDepth++; break; - case '>': cDepth--; break; + case '<': c++; break; + case '>': c--; break; // adjust fixed vec depths - case '[': fDepth++; break; - case ']': fDepth--; break; + case '[': f++; break; + case ']': f--; break; // adjust struct depth - case '{': sDepth++; break; - case '}': sDepth--; break; + case '{': s++; break; + case '}': s--; break; // adjust tuple depth - case '(': tDepth++; break; - case ')': tDepth--; break; + case '(': t++; break; + case ')': t--; break; } } - assert(isNotNested(cDepth, fDepth, sDepth, tDepth), () => `Invalid definition (missing terminators) found in ${type}`); + // ensure we have all the terminators taken care of + assert(!(c || f || s || t), () => `Invalid definition (missing terminators) found in ${type}`); // the final leg of the journey result.push(type.substring(start, type.length).trim());