diff --git a/src/model/Scraper/Format/CallSignature.ts b/src/model/Scraper/Format/CallSignature.ts index e5075aa8..88889e2d 100644 --- a/src/model/Scraper/Format/CallSignature.ts +++ b/src/model/Scraper/Format/CallSignature.ts @@ -3,6 +3,7 @@ import type { AnyJson } from '@w3ux/types'; import type { PalletItemScraped } from '../types'; +import { getShortLabel, verifyOption } from './Utils'; export class FormatCallSignature { // The raw input config to format. @@ -21,14 +22,11 @@ export class FormatCallSignature { // Formats `rawConfig` data into a string. format = () => { - const { - modifier, - type: { argTypes, returnType }, - } = this.#rawConfig; + const { modifier, argTypes, returnType } = this.#rawConfig; // Format arguments and return types. - const [argFormatted, returnFormatted] = [argTypes, returnType].map( - (section) => this.getTypeString(section) + const [argFormatted, returnFormatted] = [argTypes, returnType].map((arg) => + this.getTypeString(arg) ); // Format the call signature based on formatted types and modifier. @@ -80,77 +78,86 @@ export class FormatCallSignature { // A recursive function that formats a call signature by formatting its arguments and return // types. - getTypeString = (section: AnyJson) => { + getTypeString = (arg: AnyJson) => { let str = ''; - switch (section?.type) { + switch (arg?.type) { case 'array': - str = this.getTypeString(section.array.type); + str = this.getTypeString(arg.array.type); break; case 'compact': - str = this.getTypeString(section.sequence); + str = this.getTypeString(arg.compact); break; case 'composite': - str = this.getCompositeString(section); + str = this.getCompositeString(arg); break; case 'primitive': + str = arg.class.label(); + break; + case 'bitSequence': - str = this.getShortLabel(section.label); + str = getShortLabel(arg.class.label()); break; case 'sequence': - str = `Vec<${this.getTypeString(section.sequence)}>`; + str = `Vec<${this.getTypeString(arg.sequence)}>`; break; case 'tuple': - str = this.getTupleString(section); + str = this.getTupleString(arg); break; case 'variant': - str = this.getVariantType(section); + str = this.getVariantType(arg); break; } return str; }; // Formats a string from a composite type. - getCompositeString = ({ composite, label }: AnyJson) => { + getCompositeString = (arg: AnyJson) => { let str = ''; + const shortLabel = getShortLabel(arg.class.label()); // Expand type if short label is not defined, or if they've been defined in ignore list. - if (['', ...this.#ignoreLabels].includes(label.short)) { - str += composite.reduce((acc: string, field: AnyJson, index: number) => { - // Defensive: return if field type is missing. - if (!field?.type) { - return ''; - } - acc = acc + this.getTypeString(field.type); - if (index < composite.length - 1) { - acc += ', '; - } - return acc; - }, ''); + if (['', ...this.#ignoreLabels].includes(shortLabel)) { + str += arg.composite.reduce( + (acc: string, field: AnyJson, index: number) => { + // Defensive: return if field type is missing. + if (!field?.type) { + return ''; + } + acc = acc + this.getTypeString(field.type); + if (index < arg.composite.length - 1) { + acc += ', '; + } + return acc; + }, + '' + ); } else { - str = `${label.short}`; + str = `${shortLabel}`; } return str; }; // Formats a string from a variant type. - getVariantType = ({ variant, label }: AnyJson) => { - let str = `${label.short}`; + getVariantType = (arg: AnyJson) => { + const shortLabel = getShortLabel(arg.class.label()); + + let str = `${shortLabel}`; // If variant is `Option`, expand signature with its `Some` type. - if (this.verifyOption(label.short, variant)) { + if (verifyOption(shortLabel, arg.variant)) { str += - variant[1].fields.reduce( + arg.variant[1].fields.reduce( (acc: string, field: AnyJson, index: number) => { acc = acc + this.getTypeString(field.type); - if (index < variant[1].fields.length - 1) { + if (index < arg.variant[1].fields.length - 1) { acc += ', '; } return acc; @@ -172,22 +179,4 @@ export class FormatCallSignature { } return acc; }, ''); - - // ------------------------------------------------------ - // Class helpers - // ------------------------------------------------------ - - // Gets a short label from a label input. - getShortLabel = (input: string | { long: string; short: string }) => - typeof input === 'string' ? input : input.short; - - // Gets a long label from a label input. - getLongLabel = (input: string | { long: string; short: string }) => - typeof input === 'string' ? input : input.long; - - // Verify if a variant is an Option. - verifyOption = (shortLabel: string, variant: { name?: string }[]) => - shortLabel === 'Option' && - variant?.[0]?.name === 'None' && - variant?.[1]?.name === 'Some'; } diff --git a/src/model/Scraper/Format/InputFields.ts b/src/model/Scraper/Format/InputFields.ts index f620aa4b..34588e8f 100644 --- a/src/model/Scraper/Format/InputFields.ts +++ b/src/model/Scraper/Format/InputFields.ts @@ -3,6 +3,7 @@ import type { AnyJson } from '@w3ux/types'; import type { PalletItemScraped } from '../types'; +import { getShortLabel } from './Utils'; export class FormatInputFields { // The raw input config to format. @@ -18,9 +19,7 @@ export class FormatInputFields { // Formats `rawConfig` data into an input structure. format = () => { - const { - type: { argTypes }, - } = this.#rawConfig; + const { argTypes } = this.#rawConfig; // if there are no arg types, (no args to format) return an empty object. if (!argTypes) { @@ -52,7 +51,7 @@ export class FormatInputFields { case 'bitSequence': result.bitSequence = { - label: arg.label.short, + label: getShortLabel(arg.class.label()), // NOTE: Currently falling back to encoded hash until a custom input is created. form: 'Hash', }; @@ -60,7 +59,7 @@ export class FormatInputFields { case 'compact': result.compact = { - label: arg.compact.label, + label: getShortLabel(arg.compact.class.label()), form: this.getTypeInput(arg.compact), }; break; @@ -71,7 +70,7 @@ export class FormatInputFields { case 'primitive': result.primitive = { - label: arg.label, + label: arg.class.label(), // Treat unsigned integers as text inputs. NOTE: Could improve by allowing minus and // decimal in `number` input. form: [ @@ -87,9 +86,9 @@ export class FormatInputFields { 'u32', 'u64', 'u128', - ].includes(arg.label) + ].includes(arg.class.label()) ? 'text' - : arg.label === 'bool' + : arg.class.label() === 'bool' ? 'checkbox' : // Unsigned integers remain. 'number', @@ -98,7 +97,7 @@ export class FormatInputFields { case 'sequence': result.sequence = { - label: arg.sequence.label, + label: getShortLabel(arg.sequence.class.label()), form: this.getTypeInput(arg.sequence.type), }; break; @@ -119,8 +118,10 @@ export class FormatInputFields { // Formats a variant form input. getVariantInput(arg: AnyJson) { + const shortLabel = getShortLabel(arg.class.label()); + return { - label: arg.label.short, + label: shortLabel, form: 'select', forms: arg.variant.reduce((acc: AnyJson, { name, fields }: AnyJson) => { acc[name] = fields.map((field: AnyJson) => @@ -133,7 +134,7 @@ export class FormatInputFields { // Formats a composite form input. getCompositeInput(arg: AnyJson) { - let shortLabel = arg.label.short; + let shortLabel = getShortLabel(arg.class.label()); // If this composite is a sequence of u8s, then change the label to `Bytes`. if (this.checkCompositeIsBytes(shortLabel, arg)) { diff --git a/src/routes/Chain/Utils.ts b/src/model/Scraper/Format/Utils.ts similarity index 52% rename from src/routes/Chain/Utils.ts rename to src/model/Scraper/Format/Utils.ts index 23c08171..84be0b9a 100644 --- a/src/routes/Chain/Utils.ts +++ b/src/model/Scraper/Format/Utils.ts @@ -4,25 +4,18 @@ // Gets a short label from a label input. export const getShortLabel = ( input: string | { long: string; short: string } -) => { - let output; - if (typeof input === 'string') { - output = input; - } else { - output = input.short; - } - return output; -}; +) => (typeof input === 'string' ? input : input.short); // Gets a long label from a label input. export const getLongLabel = ( input: string | { long: string; short: string } -) => { - let output; - if (typeof input === 'string') { - output = input; - } else { - output = input.long; - } - return output; -}; +) => (typeof input === 'string' ? input : input.long); + +// Verify if a variant is an Option. +export const verifyOption = ( + shortLabel: string, + variant: { name?: string }[] +) => + shortLabel === 'Option' && + variant?.[0]?.name === 'None' && + variant?.[1]?.name === 'Some'; diff --git a/src/model/Scraper/Pallet.ts b/src/model/Scraper/Pallet.ts index c5d1b4c4..54edda66 100644 --- a/src/model/Scraper/Pallet.ts +++ b/src/model/Scraper/Pallet.ts @@ -145,7 +145,7 @@ export class PalletScraper extends MetadataScraper { docs, modifier, fallback, - type: scrapedType, + ...scrapedType, }; } @@ -264,7 +264,7 @@ export class PalletScraper extends MetadataScraper { name: item.name, docs: item.docs, modifier: '', - type: scrapedType, + ...scrapedType, }; return result; @@ -298,8 +298,8 @@ export class PalletScraper extends MetadataScraper { name, docs, modifier: '', // NOTE: This could be `null`. - type: scrapedType, value, + ...scrapedType, }; }); } diff --git a/src/model/Scraper/Types/Array.ts b/src/model/Scraper/Types/Array.ts index 025ca272..b7b7bba8 100644 --- a/src/model/Scraper/Types/Array.ts +++ b/src/model/Scraper/Types/Array.ts @@ -19,6 +19,10 @@ export class ArrayType implements MetadataType { this.array = array; } + label() { + return ''; + } + // Scrape array type. Overwrites `type` with scraped type. scrape(scraper: MetadataScraper, trailParam: TrailParam) { return scraper.getType(this.array.type, trailParam); diff --git a/src/model/Scraper/Types/BitSequence.ts b/src/model/Scraper/Types/BitSequence.ts index 4f00addb..31eaa432 100644 --- a/src/model/Scraper/Types/BitSequence.ts +++ b/src/model/Scraper/Types/BitSequence.ts @@ -5,6 +5,7 @@ import type { LookupItem } from '../Lookup/types'; import type { MetadataScraper } from '..'; import type { TrailParam } from '../types'; import type { BitSequenceType, MetadataType } from './types'; +import { Format } from '../Format'; // Class to hold a bit sequence type. export class BitSequence implements MetadataType { @@ -19,6 +20,15 @@ export class BitSequence implements MetadataType { this.bitSequence = bitSequence; } + // Get the labels of this bit sequence. + label() { + const { path, params } = this.lookup.type; + return { + long: Format.typeToString(path, params), + short: path[path.length - 1], + }; + } + // Scrape bitSequence type. Overwrites `bitStoreType` and `bitOrderType` with scraped types. scrape(scraper: MetadataScraper, { trailId }: TrailParam) { return { diff --git a/src/model/Scraper/Types/Compact.ts b/src/model/Scraper/Types/Compact.ts index 907d94c3..07dd9096 100644 --- a/src/model/Scraper/Types/Compact.ts +++ b/src/model/Scraper/Types/Compact.ts @@ -19,6 +19,10 @@ export class Compact implements MetadataType { this.type = compact.type; } + label() { + return ''; + } + // Scrape compact type. Overwrites `type` with scraped type. scrape(scraper: MetadataScraper, trailParam: TrailParam) { return scraper.getType(this.type, trailParam); diff --git a/src/model/Scraper/Types/Composite.ts b/src/model/Scraper/Types/Composite.ts index c3530b4b..5d9e1e13 100644 --- a/src/model/Scraper/Types/Composite.ts +++ b/src/model/Scraper/Types/Composite.ts @@ -5,6 +5,7 @@ import type { LookupItem } from '../Lookup/types'; import type { MetadataScraper } from '..'; import type { TrailParam } from '../types'; import type { CompositeField, CompositeType, MetadataType } from './types'; +import { Format } from '../Format'; // Class to hold a composite type. export class Composite implements MetadataType { @@ -19,6 +20,15 @@ export class Composite implements MetadataType { this.lookup = lookup; } + // Get the labels of this composite type. + label() { + const { path, params } = this.lookup.type; + return { + long: Format.typeToString(path, params), + short: path[path.length - 1], + }; + } + // Scrape composite fields. Overwrites `fields` with scraped fields. scrape(scraper: MetadataScraper, { trailId }: TrailParam) { return [...this.fields].map((field) => ({ diff --git a/src/model/Scraper/Types/Primitive.ts b/src/model/Scraper/Types/Primitive.ts index 350b114d..a2d19b99 100644 --- a/src/model/Scraper/Types/Primitive.ts +++ b/src/model/Scraper/Types/Primitive.ts @@ -17,6 +17,11 @@ export class Primitive implements MetadataType { this.primitive = primitive; } + // Get the label of this primitive. + label() { + return this.primitive.toLowerCase(); + } + // Scrape primitive type. Simply returns the type. scrape() { return this.primitive; diff --git a/src/model/Scraper/Types/Sequence.ts b/src/model/Scraper/Types/Sequence.ts index 340b198a..dc8c23df 100644 --- a/src/model/Scraper/Types/Sequence.ts +++ b/src/model/Scraper/Types/Sequence.ts @@ -19,6 +19,10 @@ export class Sequence implements MetadataType { this.type = sequence.type; } + label() { + return ''; + } + // Scrape sequence type. Overwrites `type` with scraped type. scrape(scraper: MetadataScraper, trailParam: TrailParam) { return scraper.getType(this.type, trailParam); diff --git a/src/model/Scraper/Types/Tuple.ts b/src/model/Scraper/Types/Tuple.ts index 751a0632..797c4b94 100644 --- a/src/model/Scraper/Types/Tuple.ts +++ b/src/model/Scraper/Types/Tuple.ts @@ -19,6 +19,10 @@ export class Tuple implements MetadataType { this.tuple = tuple; } + label() { + return ''; + } + // Scrape tuple types. Overwrites the type with scraped type at each index. scrape(scraper: MetadataScraper, { trailId }: TrailParam) { return this.tuple.map((id: number) => scraper.start(id, trailId)); diff --git a/src/model/Scraper/Types/Variant.ts b/src/model/Scraper/Types/Variant.ts index 5694b24d..63f8d4e4 100644 --- a/src/model/Scraper/Types/Variant.ts +++ b/src/model/Scraper/Types/Variant.ts @@ -5,6 +5,7 @@ import type { LookupItem } from '../Lookup/types'; import type { MetadataScraper } from '..'; import type { MetadataType, VariantItem } from './types'; import type { TrailParam } from '../types'; +import { Format } from '../Format'; // Class to hold a variant type. export class Variant implements MetadataType { @@ -19,6 +20,15 @@ export class Variant implements MetadataType { this.lookup = lookup; } + // Get the labels of this variant. + label() { + const { path, params } = this.lookup.type; + return { + long: Format.typeToString(path, params), + short: path[path.length - 1], + }; + } + // Scrape variant fields. Overwrites `fields` with scraped fields. scrape(scraper: MetadataScraper, { trailId }: TrailParam) { return [...this.items].map((item) => ({ diff --git a/src/model/Scraper/Types/types.ts b/src/model/Scraper/Types/types.ts index e1f70876..644eaebf 100644 --- a/src/model/Scraper/Types/types.ts +++ b/src/model/Scraper/Types/types.ts @@ -69,6 +69,9 @@ export abstract class MetadataType { // All metadata type classes must hold their lookup data. abstract lookup: LookupItem; + // All metadata type classes must return a label. + abstract label(): { long: string; short: string } | string; + // All metadata type classes must implement a `scrape` method, that converts type ids to actual // type metadata. abstract scrape(scraper: MetadataScraper, trailParam: TrailParam): AnyJson; diff --git a/src/model/Scraper/index.ts b/src/model/Scraper/index.ts index 849bc38d..1fcf3b2c 100644 --- a/src/model/Scraper/index.ts +++ b/src/model/Scraper/index.ts @@ -3,7 +3,6 @@ import type { AnyJson } from '@w3ux/types'; import type { MetadataVersion } from 'model/Metadata/types'; -import { Format } from './Format'; import type { ScraperConfig, ScraperOptions, @@ -16,20 +15,20 @@ import { Lookup } from './Lookup'; import { Variant } from './Types/Variant'; import type { VariantType, - CompositeType, SequenceType, IArrayType, BitSequenceType, CompactType, TupleType, + CompositeType, } from './Types/types'; -import { Composite } from './Types/Composite'; import { Sequence } from './Types/Sequence'; import { ArrayType } from './Types/Array'; import { BitSequence } from './Types/BitSequence'; import { Compact } from './Types/Compact'; import { Primitive } from './Types/Primitive'; import { Tuple } from './Types/Tuple'; +import { Composite } from './Types/Composite'; // Base metadata scraper class that accesses and recursively scrapes the metadata lookup. @@ -117,91 +116,56 @@ export class MetadataScraper { }; } - const { def, path, params }: AnyJson = lookup.type; + const { def }: AnyJson = lookup.type; const [type, value] = Object.entries(def).flat(); const result: AnyJson = { type, - path, - params, }; switch (type) { case 'array': - result.array = new ArrayType(value as IArrayType, lookup).scrape( - this, - trailParam - ); + result.class = new ArrayType(value as IArrayType, lookup); + result.array = result.class.scrape(this, trailParam); break; case 'bitSequence': - result.label = { - long: Format.typeToString(path, params), - short: path[path.length - 1], - }; - - if (labelsOnly) { - break; + result.class = new BitSequence(value as BitSequenceType, lookup); + if (!labelsOnly) { + result.bitsequence = result.class.scrape(this, trailParam); } - - result.bitsequence = new BitSequence( - value as BitSequenceType, - lookup - ).scrape(this, trailParam); break; case 'compact': - result.compact = new Compact(value as CompactType, lookup).scrape( - this, - trailParam - ); + result.class = new Compact(value as CompactType, lookup); + result.compact = result.class.scrape(this, trailParam); break; case 'composite': - result.label = { - long: Format.typeToString(path, params), - short: path[path.length - 1], - }; - result.composite = new Composite(value as CompositeType, lookup).scrape( - this, - trailParam - ); + result.class = new Composite(value as CompositeType, lookup); + result.composite = result.class.scrape(this, trailParam); break; case 'primitive': - result.label = (value as string).toLowerCase(); - result.primitive = new Primitive(value as string, lookup).scrape(); + result.class = new Primitive(value as string, lookup); + result.primitive = result.class.scrape(); break; case 'sequence': - result.sequence = new Sequence(value as SequenceType, lookup).scrape( - this, - trailParam - ); + result.class = new Sequence(value as SequenceType, lookup); + result.sequence = result.class.scrape(this, trailParam); break; case 'tuple': - result.tuple = new Tuple(value as TupleType, lookup).scrape( - this, - trailParam - ); + result.class = new Tuple(value as TupleType, lookup); + result.tuple = result.class.scrape(this, trailParam); break; case 'variant': - result.label = { - long: Format.typeToString(path, params), - short: path[path.length - 1], - }; - - if (labelsOnly) { - break; + result.class = new Variant((value as VariantType).variants, lookup); + if (!labelsOnly) { + result.variant = result.class.scrape(this, trailParam); } - - result.variant = new Variant( - (value as VariantType).variants, - lookup - ).scrape(this, trailParam); - break; default: diff --git a/src/model/Scraper/types.ts b/src/model/Scraper/types.ts index 5d469128..4bfc5b9d 100644 --- a/src/model/Scraper/types.ts +++ b/src/model/Scraper/types.ts @@ -42,8 +42,9 @@ export interface PalletItemScraped { docs: string[]; modifier: string; fallback?: string; - type: AnyJson; value?: string; + argTypes: AnyJson; + returnType: AnyJson; } export interface PalletItemScrapedWithSig extends PalletItemScraped {