chore: update to version 16.5.9, align with pezkuwichain brand and fix tests

This commit is contained in:
2026-01-11 11:32:15 +03:00
parent c97f94045f
commit c2f759f58d
136 changed files with 19370 additions and 2342 deletions
+5
View File
@@ -0,0 +1,5 @@
import type { Definitions } from '@pezkuwi/types/types';
import type { HexString } from '@pezkuwi/util/types';
import { type ExtraTypes } from './types.js';
/** @internal */
export declare function generateDefaultConsts(dest: string, data: HexString, extraTypes?: ExtraTypes, isStrict?: boolean, customLookupDefinitions?: Definitions): void;
+87
View File
@@ -0,0 +1,87 @@
import Handlebars from 'handlebars';
import * as defaultDefs from '@pezkuwi/types/interfaces/definitions';
import lookupDefinitions from '@pezkuwi/types-augment/lookup/definitions';
import { stringCamelCase } from '@pezkuwi/util';
import { compareName, createImports, formatType, initMeta, readTemplate, rebrandTypeName, setImports, writeFile } from '../util/index.js';
import { ignoreUnusedLookups } from './lookup.js';
import { getDeprecationNotice } from './types.js';
const generateForMetaTemplate = Handlebars.compile(readTemplate('consts'));
/** @internal */
function generateForMeta(meta, dest, extraTypes, isStrict, customLookupDefinitions) {
writeFile(dest, () => {
const allTypes = {
'@pezkuwi/types-augment': {
lookup: {
...lookupDefinitions,
...customLookupDefinitions
}
},
'@pezkuwi/types/interfaces': defaultDefs,
...extraTypes
};
const imports = createImports(allTypes);
const allDefs = Object.entries(allTypes).reduce((defs, [path, obj]) => {
return Object.entries(obj).reduce((defs, [key, value]) => ({ ...defs, [`${path}/${key}`]: value }), defs);
}, {});
const { lookup, pallets, registry } = meta.asLatest;
const usedTypes = new Set([]);
const modules = pallets
.filter(({ constants }) => constants.length > 0)
.map(({ constants, name }) => {
if (!isStrict) {
setImports(allDefs, imports, ['Codec']);
}
const items = constants
.map(({ deprecationInfo, docs, name, type }) => {
const typeDef = lookup.getTypeDef(type);
const returnType = rebrandTypeName(typeDef.lookupName || '') || formatType(registry, allDefs, typeDef, imports);
if (!deprecationInfo.isNotDeprecated) {
const deprecationNotice = getDeprecationNotice(deprecationInfo, stringCamelCase(name), 'Constant');
const items = docs.length
? ['', deprecationNotice]
: [deprecationNotice];
docs.push(...items.map((text) => registry.createType('Text', text)));
}
// Add the type to the list of used types
if (!(imports.primitiveTypes[returnType])) {
usedTypes.add(returnType);
}
setImports(allDefs, imports, [returnType]);
return {
docs,
name: stringCamelCase(name),
type: returnType
};
})
.sort(compareName);
return {
items,
name: stringCamelCase(name)
};
})
.sort(compareName);
// filter out the unused lookup types from imports
ignoreUnusedLookups([...usedTypes], imports);
return generateForMetaTemplate({
headerType: 'chain',
imports,
isStrict,
modules,
types: [
...Object.keys(imports.localTypes).sort().map((packagePath) => ({
file: packagePath.replace('@pezkuwi/types-augment', '@pezkuwi/types'),
types: Object.keys(imports.localTypes[packagePath])
})),
{
file: '@pezkuwi/api-base/types',
types: ['ApiTypes', 'AugmentedConst']
}
]
});
});
}
/** @internal */
export function generateDefaultConsts(dest, data, extraTypes = {}, isStrict = false, customLookupDefinitions) {
const { metadata } = initMeta(data, extraTypes);
return generateForMeta(metadata, dest, extraTypes, isStrict, customLookupDefinitions);
}
+4
View File
@@ -0,0 +1,4 @@
import type { HexString } from '@pezkuwi/util/types';
import { type ExtraTypes } from './types.js';
/** @internal */
export declare function generateDefaultErrors(dest: string, data: HexString, extraTypes?: ExtraTypes, isStrict?: boolean): void;
+55
View File
@@ -0,0 +1,55 @@
import Handlebars from 'handlebars';
import { stringCamelCase } from '@pezkuwi/util';
import { compareName, createImports, initMeta, readTemplate, writeFile } from '../util/index.js';
import { getDeprecationNotice } from './types.js';
const generateForMetaTemplate = Handlebars.compile(readTemplate('errors'));
/** @internal */
function generateForMeta(meta, dest, isStrict) {
writeFile(dest, () => {
const imports = createImports({});
const { lookup, pallets } = meta.asLatest;
const modules = pallets
.filter(({ errors }) => errors.isSome)
.map((data) => {
const name = data.name;
const errors = data.errors.unwrap();
const deprecationInfo = errors.deprecationInfo.toJSON();
return {
items: lookup.getSiType(errors.type).def.asVariant.variants
.map(({ docs, index, name }) => {
const rawStatus = deprecationInfo?.[index.toNumber()];
if (rawStatus) {
const deprecationVariantInfo = meta.registry.createTypeUnsafe('VariantDeprecationInfoV16', [rawStatus]);
const deprecationNotice = getDeprecationNotice(deprecationVariantInfo, name.toString());
const notice = docs.length ? ['', deprecationNotice] : [deprecationNotice];
docs.push(...notice.map((text) => meta.registry.createType('Text', text)));
}
return {
docs,
name: name.toString()
};
})
.sort(compareName),
name: stringCamelCase(name)
};
})
.sort(compareName);
return generateForMetaTemplate({
headerType: 'chain',
imports,
isStrict,
modules,
types: [
{
file: '@pezkuwi/api-base/types',
types: ['ApiTypes', 'AugmentedError']
}
]
});
});
}
/** @internal */
export function generateDefaultErrors(dest, data, extraTypes = {}, isStrict = false) {
const { metadata } = initMeta(data, extraTypes);
return generateForMeta(metadata, dest, isStrict);
}
+5
View File
@@ -0,0 +1,5 @@
import type { Definitions } from '@pezkuwi/types/types';
import type { HexString } from '@pezkuwi/util/types';
import { type ExtraTypes } from './types.js';
/** @internal */
export declare function generateDefaultEvents(dest: string, data: HexString, extraTypes?: ExtraTypes, isStrict?: boolean, customLookupDefinitions?: Definitions): void;
+135
View File
@@ -0,0 +1,135 @@
import Handlebars from 'handlebars';
import * as defaultDefs from '@pezkuwi/types/interfaces/definitions';
import lookupDefinitions from '@pezkuwi/types-augment/lookup/definitions';
import { stringCamelCase } from '@pezkuwi/util';
import { compareName, createImports, formatType, initMeta, readTemplate, rebrandTypeName, setImports, writeFile } from '../util/index.js';
import { ignoreUnusedLookups } from './lookup.js';
import { getDeprecationNotice } from './types.js';
const generateForMetaTemplate = Handlebars.compile(readTemplate('events'));
const ALIAS = [
'symbol',
'break',
'case',
'catch',
'class',
'const',
'continue',
'debugger',
'default',
'delete',
'do',
'else',
'export',
'extends',
'false',
'finally',
'for',
'function',
'if',
'import',
'in',
'instanceof',
'new',
'null',
'return',
'static',
'super',
'switch',
'this',
'throw',
'true',
'try',
'typeof',
'var',
'void',
'while',
'with',
'yield'
];
/** @internal */
function generateForMeta(meta, dest, extraTypes, isStrict, customLookupDefinitions) {
writeFile(dest, () => {
const allTypes = {
'@pezkuwi/types-augment': {
lookup: {
...lookupDefinitions,
...customLookupDefinitions
}
},
'@pezkuwi/types/interfaces': defaultDefs,
...extraTypes
};
const imports = createImports(allTypes);
const allDefs = Object.entries(allTypes).reduce((defs, [path, obj]) => {
return Object.entries(obj).reduce((defs, [key, value]) => ({ ...defs, [`${path}/${key}`]: value }), defs);
}, {});
const { lookup, pallets, registry } = meta.asLatest;
const usedTypes = new Set([]);
const modules = pallets
.filter(({ events }) => events.isSome)
.map((data) => {
const name = data.name;
const events = data.events.unwrap();
const deprecationInfo = events.deprecationInfo.toJSON();
return {
items: lookup.getSiType(events.type).def.asVariant.variants
.map(({ docs, fields, index, name }) => {
const rawStatus = deprecationInfo?.[index.toNumber()];
if (rawStatus) {
const deprecationVariantInfo = meta.registry.createTypeUnsafe('VariantDeprecationInfoV16', [rawStatus]);
const deprecationNotice = getDeprecationNotice(deprecationVariantInfo, name.toString());
const notice = docs.length ? ['', deprecationNotice] : [deprecationNotice];
docs.push(...notice.map((text) => meta.registry.createType('Text', text)));
}
const args = fields
.map(({ type }) => lookup.getTypeDef(type))
.map((typeDef) => {
const arg = rebrandTypeName(typeDef.lookupName || '') || formatType(registry, allDefs, typeDef, imports);
// Add the type to the list of used types
if (!(imports.primitiveTypes[arg])) {
usedTypes.add(arg);
}
return arg;
});
const names = fields
.map(({ name }) => registry.lookup.sanitizeField(name)[0])
.filter((n) => !!n);
setImports(allDefs, imports, args);
return {
docs,
name: name.toString(),
type: names.length !== 0 && names.length === args.length
? `[${names.map((n, i) => `${ALIAS.includes(n) ? `${n}_` : n}: ${args[i]}`).join(', ')}], { ${names.map((n, i) => `${n}: ${args[i]}`).join(', ')} }`
: `[${args.join(', ')}]`
};
})
.sort(compareName),
name: stringCamelCase(name)
};
})
.sort(compareName);
// filter out the unused lookup types from imports
ignoreUnusedLookups([...usedTypes], imports);
return generateForMetaTemplate({
headerType: 'chain',
imports,
isStrict,
modules,
types: [
...Object.keys(imports.localTypes).sort().map((packagePath) => ({
file: packagePath.replace('@pezkuwi/types-augment', '@pezkuwi/types'),
types: Object.keys(imports.localTypes[packagePath])
})),
{
file: '@pezkuwi/api-base/types',
types: ['ApiTypes', 'AugmentedEvent']
}
]
});
});
}
/** @internal */
export function generateDefaultEvents(dest, data, extraTypes = {}, isStrict = false, customLookupDefinitions) {
const { metadata } = initMeta(data, extraTypes);
return generateForMeta(metadata, dest, extraTypes, isStrict, customLookupDefinitions);
}
+4
View File
@@ -0,0 +1,4 @@
import type { ModuleTypes } from '../util/imports.js';
/** @internal */
export declare function generateInterfaceTypes(importDefinitions: Record<string, Record<string, ModuleTypes>>, dest: string): void;
export declare function generateDefaultInterface(): void;
@@ -0,0 +1,59 @@
import Handlebars from 'handlebars';
import { Json, Raw } from '@pezkuwi/types/codec';
import { TypeRegistry } from '@pezkuwi/types/create';
import * as defaultDefinitions from '@pezkuwi/types/interfaces/definitions';
import * as defaultPrimitives from '@pezkuwi/types/primitive';
import { createImports, readTemplate, setImports, writeFile } from '../util/index.js';
const primitiveClasses = {
...defaultPrimitives,
Json,
Raw
};
const generateInterfaceTypesTemplate = Handlebars.compile(readTemplate('interfaceRegistry'));
/** @internal */
export function generateInterfaceTypes(importDefinitions, dest) {
const registry = new TypeRegistry();
writeFile(dest, () => {
Object.entries(importDefinitions).reduce((acc, def) => Object.assign(acc, def), {});
const imports = createImports(importDefinitions);
const definitions = imports.definitions;
const items = [];
// first we create imports for our known classes from the API
Object
.keys(primitiveClasses)
.filter((name) => !name.includes('Generic'))
.forEach((primitiveName) => {
setImports(definitions, imports, [primitiveName]);
items.push(primitiveName);
});
const existingTypes = {};
// ensure we have everything registered since we will get the definition
// form the available types (so any unknown should show after this)
Object.values(definitions).forEach(({ types }) => {
registry.register(types);
});
// create imports for everything that we have available
Object.values(definitions).forEach(({ types }) => {
setImports(definitions, imports, Object.keys(types));
const uniqueTypes = Object.keys(types).filter((type) => !existingTypes[type]);
uniqueTypes.forEach((type) => {
existingTypes[type] = true;
items.push(type);
});
});
return generateInterfaceTypesTemplate({
headerType: 'defs',
imports,
items: items.sort((a, b) => a.localeCompare(b)),
types: [
...Object.keys(imports.localTypes).sort().map((packagePath) => ({
file: packagePath,
types: Object.keys(imports.localTypes[packagePath])
}))
]
});
});
}
export function generateDefaultInterface() {
generateInterfaceTypes({ '@pezkuwi/types/interfaces': defaultDefinitions }, 'packages/types-augment/src/registry/interfaces.ts');
}
+4
View File
@@ -0,0 +1,4 @@
import type { HexString } from '@pezkuwi/util/types';
import { type TypeImports } from '../util/index.js';
export declare function generateDefaultLookup(destDir?: string, staticData?: HexString): void;
export declare function ignoreUnusedLookups(usedTypes: string[], imports: TypeImports): void;
+235
View File
@@ -0,0 +1,235 @@
import Handlebars from 'handlebars';
import path from 'node:path';
import * as defaultDefinitions from '@pezkuwi/types/interfaces/definitions';
import staticAhDicle from '@pezkuwi/types-support/metadata/v15/asset-hub-dicle-hex';
import staticAhPezkuwi from '@pezkuwi/types-support/metadata/v15/asset-hub-pezkuwi-hex';
import staticBizinikiwi from '@pezkuwi/types-support/metadata/v15/bizinikiwi-hex';
import staticDicle from '@pezkuwi/types-support/metadata/v15/dicle-hex';
import staticPezkuwi from '@pezkuwi/types-support/metadata/v15/pezkuwi-hex';
import { isString, stringify } from '@pezkuwi/util';
import { createImports, exportInterface, initMeta, readTemplate, rebrandTypeName, writeFile } from '../util/index.js';
import { typeEncoders } from './tsDef.js';
function deepRebrandTypeDef(typeDef, isTopLevel = true) {
const rebrandedLookupName = typeDef.lookupName ? rebrandTypeName(typeDef.lookupName) : typeDef.lookupName;
const rebranded = {
...typeDef,
type: rebrandTypeName(typeDef.type),
// For top-level types: set name from lookupName (mimics original: typeDef.name = typeDef.lookupName)
// For sub types (enum variants, struct fields): preserve the original name (field/variant name)
name: isTopLevel ? (rebrandedLookupName || typeDef.name) : typeDef.name,
lookupName: rebrandedLookupName,
lookupNameRoot: typeDef.lookupNameRoot ? rebrandTypeName(typeDef.lookupNameRoot) : typeDef.lookupNameRoot
};
// Recursively rebrand sub types (mark as not top-level)
if (typeDef.sub) {
if (Array.isArray(typeDef.sub)) {
rebranded.sub = typeDef.sub.map((s) => deepRebrandTypeDef(s, false));
}
else {
rebranded.sub = deepRebrandTypeDef(typeDef.sub, false);
}
}
return rebranded;
}
const WITH_TYPEDEF = false;
const generateLookupDefsTmpl = Handlebars.compile(readTemplate('lookup/defs'));
const generateLookupDefsNamedTmpl = Handlebars.compile(readTemplate('lookup/defs-named'));
const generateLookupIndexTmpl = Handlebars.compile(readTemplate('lookup/index'));
const generateLookupTypesTmpl = Handlebars.compile(readTemplate('lookup/types'));
const generateRegistryTmpl = Handlebars.compile(readTemplate('interfaceRegistry'));
function generateParamType(registry, { name, type }) {
if (type.isSome) {
const link = registry.lookup.types[type.unwrap().toNumber()];
if (link.type.path.length) {
return generateTypeDocs(registry, null, link.type.path, link.type.params);
}
}
return name.toString();
}
function generateTypeDocs(registry, id, path, params) {
return `${id ? `${registry.createLookupType(id)}${path.length ? ': ' : ''}` : ''}${path.map((p) => p.toString()).join('::')}${params.length ? `<${params.map((p) => generateParamType(registry, p)).join(', ')}>` : ''}`;
}
function formatObject(lines) {
const max = lines.length - 1;
return [
'{',
...lines.map((l, index) => (l.endsWith(',') || l.endsWith('{') || index === max || lines[index + 1].endsWith('}') || lines[index + 1].endsWith('}'))
? l
: `${l},`),
'}'
];
}
function expandSet(parsed) {
return formatObject(Object.entries(parsed).reduce((all, [k, v]) => {
all.push(`${k}: ${v}`);
return all;
}, []));
}
function expandObject(parsed) {
if (parsed._set) {
return expandSet(parsed._set);
}
return formatObject(Object.entries(parsed).reduce((all, [k, v]) => {
const inner = isString(v)
? expandType(v)
: Array.isArray(v)
? [`[${v.map((e) => `'${e}'`).join(', ')}]`]
: expandObject(v);
inner.forEach((l, index) => {
all.push(`${index === 0
? `${k}: ${l}`
: `${l}`}`);
});
return all;
}, []));
}
function expandType(encoded) {
if (!encoded.startsWith('{')) {
return [`'${rebrandTypeName(encoded)}'`];
}
return expandObject(JSON.parse(encoded));
}
function expandDefToString({ lookupNameRoot, type }, indent) {
if (lookupNameRoot) {
return `'${rebrandTypeName(lookupNameRoot)}'`;
}
const lines = expandType(type);
let inc = 0;
return lines.map((l, index) => {
let r;
if (l.endsWith('{')) {
r = index === 0
? l
: `${' '.padStart(indent + inc)}${l}`;
inc += 2;
}
else {
if (l.endsWith('},') || l.endsWith('}')) {
inc -= 2;
}
r = index === 0
? l
: `${' '.padStart(indent + inc)}${l}`;
}
return r;
}).join('\n');
}
function getFilteredTypes(lookup, exclude = []) {
const named = lookup.types.filter(({ id }) => !!lookup.getTypeDef(id).lookupName);
const names = named.map(({ id }) => lookup.getName(id));
return named
.filter((_, index) => !names.some((n, iindex) => index > iindex &&
n === names[index]))
.map((p) => [p, lookup.getTypeDef(p.id)])
.filter(([, typeDef]) => !exclude.includes(typeDef.lookupName || '<invalid>'));
}
function generateLookupDefs(registry, filtered, destDir, subPath) {
writeFile(path.join(destDir, `${subPath || 'definitions'}.ts`), () => {
const all = filtered.map(([{ id, type: { params, path } }, typeDef]) => {
const typeLookup = registry.createLookupType(id);
const def = expandDefToString(typeDef, subPath ? 2 : 4);
return {
docs: [
generateTypeDocs(registry, id, path, params),
WITH_TYPEDEF
? `@typeDef ${stringify(typeDef)}`
: null
].filter((d) => !!d),
type: { def, typeLookup, typeName: typeDef.lookupName ? rebrandTypeName(typeDef.lookupName) : undefined }
};
});
const max = all.length - 1;
return (subPath ? generateLookupDefsNamedTmpl : generateLookupDefsTmpl)({
defs: all.map(({ docs, type }, i) => {
const { def, typeLookup, typeName } = type;
return {
defs: [
[typeName || typeLookup, `${def}${i !== max ? ',' : ''}`]
].map(([n, t]) => `${n}: ${t}`),
docs
};
}),
headerType: 'defs'
});
});
}
function generateLookupTypes(registry, filtered, destDir, subPath) {
const imports = {
...createImports({ '@pezkuwi/types/interfaces': defaultDefinitions }, { types: {} }),
interfaces: []
};
const items = filtered
.map(([, typeDef]) => {
// Deep rebrand the type names (including nested sub types) before generating interfaces
const rebranded = deepRebrandTypeDef(typeDef);
return rebranded.lookupNameRoot && rebranded.lookupName
? exportInterface(rebranded.lookupIndex, rebranded.lookupName, rebranded.lookupNameRoot)
: typeEncoders[rebranded.info](registry, imports.definitions, rebranded, imports);
})
.filter((t) => !!t)
.map((t) => t.replace(/\nexport /, '\n'));
writeFile(path.join(destDir, `types${subPath ? `-${subPath}` : ''}.ts`), () => generateLookupTypesTmpl({
headerType: 'defs',
imports,
items: items.map((l) => l
.split('\n')
.map((l) => l.length ? ` ${l}` : '')
.join('\n')),
types: [
...Object.keys(imports.localTypes).sort().map((packagePath) => ({
file: packagePath,
types: Object.keys(imports.localTypes[packagePath])
}))
]
}), true);
writeFile(path.join(destDir, 'index.ts'), () => generateLookupIndexTmpl({ headerType: 'defs' }), true);
}
function generateRegistry(_registry, filtered, destDir, subPath) {
writeFile(path.join(destDir, `${subPath}.ts`), () => {
const items = filtered
.map(([, { lookupName }]) => lookupName ? rebrandTypeName(lookupName) : lookupName)
.filter((n) => !!n)
.sort()
.reduce((all, n) => all.includes(n) ? all : all.concat(n), []);
const imports = createImports({}, { types: {} });
imports.lookupTypes = items.reduce((all, n) => ({ ...all, [n]: true }), {});
return generateRegistryTmpl({
headerType: 'defs',
imports,
items,
types: []
});
}, true);
}
function generateLookup(destDir, entries) {
entries.reduce((exclude, [subPath, staticMeta]) => {
const { lookup, registry } = initMeta(staticMeta).metadata.asLatest;
const filtered = getFilteredTypes(lookup, exclude);
generateLookupDefs(registry, filtered, destDir, subPath);
generateLookupTypes(registry, filtered, destDir, subPath);
generateRegistry(registry, filtered, destDir, subPath === 'lookup' ? 'registry' : `../registry/${subPath}`);
return exclude.concat(...filtered
.map(([, typeDef]) => typeDef.lookupName)
.filter((n) => !!n));
}, []);
}
export function generateDefaultLookup(destDir = 'packages/types-augment/src/lookup', staticData) {
generateLookup(destDir, staticData
? [['lookup', staticData]]
: [
['bizinikiwi', staticBizinikiwi],
['pezkuwi', staticPezkuwi],
['dicle', staticDicle],
['assetHubPezkuwi', staticAhPezkuwi],
['assetHubDicle', staticAhDicle]
]);
}
export function ignoreUnusedLookups(usedTypes, imports) {
const usedStringified = usedTypes.toString();
const [lookupKey, typeDefinitions] = Object.entries(imports.localTypes).find(([typeModule, _]) => typeModule.includes('/lookup')) || ['', {}];
Object.keys(typeDefinitions).forEach((typeDef) => {
if (!(usedStringified.includes(typeDef))) {
delete (imports.localTypes[lookupKey])[typeDef];
}
});
}
+5
View File
@@ -0,0 +1,5 @@
import type { Definitions } from '@pezkuwi/types/types';
import type { HexString } from '@pezkuwi/util/types';
import { type ExtraTypes } from './types.js';
/** @internal */
export declare function generateDefaultQuery(dest: string, data: HexString, extraTypes?: ExtraTypes, isStrict?: boolean, customLookupDefinitions?: Definitions): void;
+136
View File
@@ -0,0 +1,136 @@
import Handlebars from 'handlebars';
import * as defaultDefs from '@pezkuwi/types/interfaces/definitions';
import { unwrapStorageSi } from '@pezkuwi/types/util';
import lookupDefinitions from '@pezkuwi/types-augment/lookup/definitions';
import { stringCamelCase } from '@pezkuwi/util';
import { compareName, createImports, formatType, getSimilarTypes, initMeta, readTemplate, rebrandTypeName, setImports, writeFile } from '../util/index.js';
import { ignoreUnusedLookups } from './lookup.js';
import { getDeprecationNotice } from './types.js';
const generateForMetaTemplate = Handlebars.compile(readTemplate('query'));
/** @internal */
function entrySignature(lookup, allDefs, registry, section, storageEntry, imports) {
try {
const outputType = lookup.getTypeDef(unwrapStorageSi(storageEntry.type));
if (storageEntry.type.isPlain) {
const typeDef = lookup.getTypeDef(storageEntry.type.asPlain);
setImports(allDefs, imports, [
rebrandTypeName(typeDef.lookupName || typeDef.type),
storageEntry.modifier.isOptional
? 'Option'
: null
]);
return [storageEntry.modifier.isOptional, '', '', formatType(registry, allDefs, outputType, imports)];
}
else if (storageEntry.type.isMap) {
const { hashers, key, value } = storageEntry.type.asMap;
const keyDefs = hashers.length === 1
? [lookup.getTypeDef(key)]
: lookup.getSiType(key).def.asTuple.map((k) => lookup.getTypeDef(k));
const similarTypes = keyDefs.map((k) => getSimilarTypes(registry, allDefs, k.lookupName || k.type, imports));
const keyTypes = similarTypes.map((t) => t.join(' | '));
const defValue = lookup.getTypeDef(value);
setImports(allDefs, imports, [
...similarTypes.reduce((all, t) => all.concat(t), []),
storageEntry.modifier.isOptional
? 'Option'
: null,
rebrandTypeName(defValue.lookupName || defValue.type)
]);
return [
storageEntry.modifier.isOptional,
keyDefs.map((k) => formatType(registry, allDefs, k.lookupName || k.type, imports)).join(', '),
keyTypes.map((t, i) => `arg${keyTypes.length === 1 ? '' : (i + 1)}: ${t}`).join(', '),
rebrandTypeName(outputType.lookupName || '') || formatType(registry, allDefs, outputType, imports)
];
}
throw new Error(`Expected Plain or Map type, found ${storageEntry.type.type}`);
}
catch (error) {
throw new Error(`entrySignature: Cannot create signature for query ${section}.${storageEntry.name.toString()}:: ${error.message}`);
}
}
/** @internal */
function generateForMeta(registry, meta, dest, extraTypes, isStrict, customLookupDefinitions) {
writeFile(dest, () => {
const allTypes = {
'@pezkuwi/types-augment': {
lookup: {
...lookupDefinitions,
...customLookupDefinitions
}
},
'@pezkuwi/types/interfaces': defaultDefs,
...extraTypes
};
const imports = createImports(allTypes);
const allDefs = Object.entries(allTypes).reduce((defs, [path, obj]) => {
return Object.entries(obj).reduce((defs, [key, value]) => ({ ...defs, [`${path}/${key}`]: value }), defs);
}, {});
const { lookup, pallets } = meta.asLatest;
const usedTypes = new Set([]);
const modules = pallets
.filter(({ storage }) => storage.isSome)
.map(({ name, storage }) => {
const items = storage.unwrap().items
.map((storageEntry) => {
const { deprecationInfo, docs, name } = storageEntry;
const [isOptional, args, params, _returnType] = entrySignature(lookup, allDefs, registry, name.toString(), storageEntry, imports);
if (!deprecationInfo.isNotDeprecated) {
const deprecationNotice = getDeprecationNotice(deprecationInfo, stringCamelCase(name));
const items = docs.length
? ['', deprecationNotice]
: [deprecationNotice];
docs.push(...items.map((text) => registry.createType('Text', text)));
}
// Add the type and args to the list of used types
if (!(imports.primitiveTypes[_returnType])) {
usedTypes.add(_returnType);
}
if (!(imports.primitiveTypes[args])) {
usedTypes.add(args);
}
const returnType = isOptional
? `Option<${_returnType}>`
: _returnType;
return {
args,
docs,
entryType: 'AugmentedQuery',
name: stringCamelCase(storageEntry.name),
params,
returnType
};
})
.sort(compareName);
return {
items,
name: stringCamelCase(name)
};
})
.sort(compareName);
imports.typesTypes['Observable'] = true;
// filter out the unused lookup types from imports
ignoreUnusedLookups([...usedTypes], imports);
return generateForMetaTemplate({
headerType: 'chain',
imports,
isStrict,
modules,
types: [
...Object.keys(imports.localTypes).sort().map((packagePath) => ({
file: packagePath.replace('@pezkuwi/types-augment', '@pezkuwi/types'),
types: Object.keys(imports.localTypes[packagePath])
})),
{
file: '@pezkuwi/api-base/types',
types: ['ApiTypes', 'AugmentedQuery', 'QueryableStorageEntry']
}
]
});
});
}
/** @internal */
export function generateDefaultQuery(dest, data, extraTypes = {}, isStrict = false, customLookupDefinitions) {
const { metadata, registry } = initMeta(data, extraTypes);
return generateForMeta(registry, metadata, dest, extraTypes, isStrict, customLookupDefinitions);
}
+6
View File
@@ -0,0 +1,6 @@
import type { TypeRegistry } from '@pezkuwi/types/create';
import type { Definitions } from '@pezkuwi/types/types';
import type { ExtraTypes } from './types.js';
/** @internal */
export declare function generateRpcTypes(registry: TypeRegistry, importDefinitions: Record<string, Definitions>, dest: string, extraTypes: ExtraTypes): void;
export declare function generateDefaultRpc(dest?: string, extraTypes?: ExtraTypes): void;
+110
View File
@@ -0,0 +1,110 @@
import Handlebars from 'handlebars';
import * as defaultDefinitions from '@pezkuwi/types/interfaces/definitions';
import staticBizinikiwi from '@pezkuwi/types-support/metadata/static-bizinikiwi';
import { createImports, formatType, getSimilarTypes, initMeta, readTemplate, setImports, writeFile } from '../util/index.js';
const StorageKeyType = 'StorageKey | string | Uint8Array | any';
const generateRpcTypesTemplate = Handlebars.compile(readTemplate('rpc'));
/** @internal */
export function generateRpcTypes(registry, importDefinitions, dest, extraTypes) {
writeFile(dest, () => {
const allTypes = { '@pezkuwi/types/interfaces': importDefinitions, ...extraTypes };
const imports = createImports(allTypes);
const definitions = imports.definitions;
const allDefs = Object.entries(allTypes).reduce((defs, [path, obj]) => {
return Object.entries(obj).reduce((defs, [key, value]) => ({ ...defs, [`${path}/${key}`]: value }), defs);
}, {});
const rpcKeys = Object
.keys(definitions)
.filter((key) => Object.keys(definitions[key].rpc || {}).length !== 0)
.sort();
const additional = {};
const modules = rpcKeys.map((sectionFullName) => {
const rpc = definitions[sectionFullName].rpc || {};
const section = sectionFullName.split('/').pop();
const allMethods = Object.keys(rpc).sort().map((methodName) => {
const def = rpc[methodName];
let args;
let type;
let generic;
// These are too hard to type with generics, do manual overrides
if (section === 'state') {
setImports(allDefs, imports, ['Codec', 'Hash', 'StorageKey', 'Vec']);
if (methodName === 'getStorage') {
generic = 'T = Codec';
args = [`key: ${StorageKeyType}, block?: Hash | Uint8Array | string`];
type = 'T';
}
else if (methodName === 'queryStorage') {
generic = 'T = Codec[]';
args = [`keys: Vec<StorageKey> | (${StorageKeyType})[], fromBlock?: Hash | Uint8Array | string, toBlock?: Hash | Uint8Array | string`];
type = '[Hash, T][]';
}
else if (methodName === 'queryStorageAt') {
generic = 'T = Codec[]';
args = [`keys: Vec<StorageKey> | (${StorageKeyType})[], at?: Hash | Uint8Array | string`];
type = 'T';
}
else if (methodName === 'subscribeStorage') {
generic = 'T = Codec[]';
args = [`keys?: Vec<StorageKey> | (${StorageKeyType})[]`];
type = 'T';
}
}
if (args === undefined) {
setImports(allDefs, imports, [def.type]);
args = def.params.map((param) => {
const similarTypes = getSimilarTypes(registry, definitions, param.type, imports);
setImports(allDefs, imports, [param.type, ...similarTypes]);
return `${param.name}${param.isOptional ? '?' : ''}: ${similarTypes.join(' | ')}`;
});
type = formatType(registry, allDefs, def.type, imports);
generic = '';
}
const item = {
args: args.join(', '),
docs: def.deprecated
? [`@deprecated ${def.deprecated}`, def.description]
: [def.description],
generic,
name: methodName,
type
};
if (def.aliasSection) {
if (!additional[def.aliasSection]) {
additional[def.aliasSection] = {
items: [],
name: def.aliasSection
};
}
additional[def.aliasSection].items.push(item);
return null;
}
return item;
}).filter((item) => !!item);
return {
items: allMethods,
name: section || 'unknown'
};
}).concat(...Object.values(additional)).sort((a, b) => a.name.localeCompare(b.name));
imports.typesTypes['Observable'] = true;
return generateRpcTypesTemplate({
headerType: 'chain',
imports,
modules,
types: [
...Object.keys(imports.localTypes).sort().map((packagePath) => ({
file: packagePath.replace('@pezkuwi/types-augment', '@pezkuwi/types'),
types: Object.keys(imports.localTypes[packagePath])
})),
{
file: '@pezkuwi/rpc-core/types',
types: ['AugmentedRpc']
}
]
});
});
}
export function generateDefaultRpc(dest = 'packages/rpc-augment/src/augment/jsonrpc.ts', extraTypes = {}) {
const { registry } = initMeta(staticBizinikiwi, extraTypes);
generateRpcTypes(registry, defaultDefinitions, dest, extraTypes);
}
+7
View File
@@ -0,0 +1,7 @@
import type { Metadata } from '@pezkuwi/types/metadata/Metadata';
import type { Definitions, Registry } from '@pezkuwi/types/types';
import type { HexString } from '@pezkuwi/util/types';
import { type ExtraTypes } from './types.js';
/** @internal */
export declare function generateCallTypes(registry: Registry, meta: Metadata, dest: string, extraTypes: ExtraTypes, isStrict: boolean, customLookupDefinitions?: Definitions): void;
export declare function generateDefaultRuntime(dest: string, data: HexString, extraTypes?: ExtraTypes, isStrict?: boolean, customLookupDefinitions?: Definitions): void;
+228
View File
@@ -0,0 +1,228 @@
import Handlebars from 'handlebars';
import * as defaultDefs from '@pezkuwi/types/interfaces/definitions';
import lookupDefinitions from '@pezkuwi/types-augment/lookup/definitions';
import { objectSpread, stringCamelCase } from '@pezkuwi/util';
import { blake2AsHex } from '@pezkuwi/util-crypto';
import { createImports, formatType, getSimilarTypes, initMeta, readTemplate, rebrandTypeName, setImports, writeFile } from '../util/index.js';
import { getDeprecationNotice } from './types.js';
const generateCallsTypesTemplate = Handlebars.compile(readTemplate('calls'));
const aliases = {
AssetHubZagrosRuntimeRuntimeCall: 'RuntimeCall',
AssetHubPezkuwiRuntimeRuntimeCall: 'RuntimeCall',
AssetHubDicleRuntimeOriginCaller: 'OriginCaller',
AssetHubDicleRuntimeRuntimeCall: 'RuntimeCall',
DicleRuntimeConstantsProxyProxyType: 'ProxyType',
KitchensinkRuntimeRuntimeCall: 'RuntimeCall',
KitchensinkRuntimeRuntimeParametersKey: 'RuntimeParametersKey',
OpaqueValue: 'Bytes',
PezkuwiTeyrchainPrimitivesPrimitivesId: 'ParaId',
PezkuwiTeyrchainPrimitivesPrimitivesValidationCodeHash: 'ValidationCodeHash',
PezkuwiPrimitivesV7SlashingOpaqueKeyOwnershipProof: 'OpaqueKeyOwnershipProof',
PezkuwiPrimitivesV8SlashingOpaqueKeyOwnershipProof: 'OpaqueKeyOwnershipProof',
PezkuwiRuntimeRuntimeCall: 'RuntimeCall',
PrimitiveTypesH160: 'H160',
PrimitiveTypesH256: 'H256',
PrimitiveTypesU256: 'U256',
PezspConsensusBabeOpaqueKeyOwnershipProof: 'OpaqueKeyOwnershipProof',
PezspConsensusSlotsSlot: 'Slot',
PezspConsensusSlotsSlotDuration: 'SlotDuration',
PezspCoreCryptoAccountId32: 'AccountId32',
PezspCoreOpaqueMetadata: 'OpaqueMetadata',
PezspRuntimeOpaqueValue: 'Bytes',
PezspRuntimeUncheckedExtrinsic: 'Extrinsic',
StagingDicleRuntimeOriginCaller: 'OriginCaller',
StagingDicleRuntimeRuntimeCall: 'RuntimeCall',
StagingDicleRuntimeRuntimeParameters: 'RuntimeParameters',
StagingDicleRuntimeRuntimeParametersKey: 'RuntimeParametersKey',
StagingZagrosRuntimeRuntimeCall: 'RuntimeCall'
};
const getTypesViaAlias = (registry, id) => {
const rawTypeName = registry.lookup.getName(id) || registry.lookup.getTypeDef(id).type;
const typeName = rebrandTypeName(rawTypeName);
if (aliases[typeName]) {
return aliases[typeName];
}
return typeName;
};
/** @internal */
function getMethods(registry, methods) {
const result = {};
methods.forEach((m) => {
const { deprecationInfo, docs, inputs, name, output } = m;
let description = docs.map((d) => d.toString()).join();
if (!deprecationInfo.isNotDeprecated) {
const deprecationNotice = getDeprecationNotice(deprecationInfo, stringCamelCase(name));
const notice = description.length ? `\n * ${deprecationNotice}` : ` * ${deprecationNotice}`;
description += notice;
}
result[name.toString()] = {
description,
params: inputs.map(({ name, type }) => {
return { name: name.toString(), type: getTypesViaAlias(registry, type) };
}),
type: getTypesViaAlias(registry, output)
};
});
return result;
}
/** @internal */
function getRuntimeDefViaMetadata(registry) {
const result = {};
const { apis } = registry.metadata;
for (let i = 0, count = apis.length; i < count; i++) {
const { methods, name } = apis[i];
result[name.toString()] = [{
methods: getMethods(registry, methods),
// We set the version to 0 here since it will not be relevant when we are grabbing the runtime apis
// from the Metadata.
version: 0
}];
}
return Object.entries(result);
}
/** @internal */
function getDefs(apis, defs, registry) {
const named = {};
const all = Object.values(defs);
const isApiInMetadata = registry.metadata.apis.length > 0;
if (isApiInMetadata) {
const sections = getRuntimeDefViaMetadata(registry);
for (let j = 0, jcount = sections.length; j < jcount; j++) {
const [_section, secs] = sections[j];
const sec = secs[0];
const sectionHash = blake2AsHex(_section, 64);
const section = stringCamelCase(_section);
const methods = Object.entries(sec.methods);
if (!named[section]) {
named[section] = {};
}
for (let m = 0, mcount = methods.length; m < mcount; m++) {
const [_method, def] = methods[m];
const method = stringCamelCase(_method);
named[section][method] = objectSpread({ method, name: `${_section}_${_method}`, section, sectionHash }, def);
}
}
}
else {
for (let j = 0, jcount = all.length; j < jcount; j++) {
const set = all[j].runtime;
if (set) {
const sections = Object.entries(set);
for (let i = 0, scount = sections.length; i < scount; i++) {
const [_section, sec] = sections[i];
const sectionHash = blake2AsHex(_section, 64);
const api = apis?.find(([h]) => h === sectionHash);
if (api) {
const ver = sec.find(({ version }) => version === api[1]);
if (ver) {
const methods = Object.entries(ver.methods);
const mcount = methods.length;
if (mcount) {
const section = stringCamelCase(_section);
if (!named[section]) {
named[section] = {};
}
for (let m = 0; m < mcount; m++) {
const [_method, def] = methods[m];
const method = stringCamelCase(_method);
named[section][method] = objectSpread({ method, name: `${_section}_${method}`, section, sectionHash, version: ver.version }, def);
}
}
}
else {
console.warn(`Unable to find matching version for runtime ${_section}, expected ${api[1]}`);
}
}
}
}
}
}
return named;
}
/** @internal */
export function generateCallTypes(registry, meta, dest, extraTypes, isStrict, customLookupDefinitions) {
writeFile(dest, () => {
const allTypes = {
'@pezkuwi/types-augment': {
lookup: {
...lookupDefinitions,
...customLookupDefinitions
}
},
'@pezkuwi/types/interfaces': defaultDefs,
...extraTypes
};
const imports = createImports(allTypes);
// find the system.Version in metadata
let apis = null;
const sysp = meta.asLatest.pallets.find(({ name }) => name.eq('System'));
if (sysp) {
const verc = sysp.constants.find(({ name }) => name.eq('Version'));
if (verc) {
apis = registry.createType('RuntimeVersion', verc.value).apis.map(([k, v]) => [k.toHex(), v.toNumber()]);
}
else {
console.error('Unable to find System.Version pallet, skipping API extraction');
}
}
else {
console.error('Unable to find System pallet, skipping API extraction');
}
const allDefs = Object.entries(allTypes).reduce((defs, [path, obj]) => {
return Object.entries(obj).reduce((defs, [key, value]) => ({ ...defs, [`${path}/${key}`]: value }), defs);
}, {});
const definitions = getDefs(apis, imports.definitions, registry);
const callKeys = Object.keys(definitions);
const modules = callKeys.map((section) => {
const calls = definitions[section];
const allMethods = Object.keys(calls).sort().map((methodName) => {
const def = calls[methodName];
setImports(allDefs, imports, [def.type]);
const args = def.params.map((param) => {
const similarTypes = getSimilarTypes(registry, imports.definitions, param.type, imports);
setImports(allDefs, imports, [param.type, ...similarTypes]);
return `${param.name}: ${similarTypes.join(' | ')}`;
});
return {
args: args.join(', '),
docs: [def.description],
name: methodName,
sectionHash: def.sectionHash,
sectionName: def.section,
sectionVersion: def.version,
type: formatType(registry, allDefs, def.type, imports)
};
}).sort((a, b) => a.name.localeCompare(b.name));
return {
items: allMethods,
name: section || 'unknown',
sectionHash: allMethods.length && allMethods[0].sectionHash,
sectionName: allMethods.length && allMethods[0].sectionName,
sectionVersion: allMethods.length && allMethods[0].sectionVersion
};
}).filter(({ items }) => items.length).sort((a, b) => a.name.localeCompare(b.name));
if (modules.length) {
imports.typesTypes['Observable'] = true;
}
return generateCallsTypesTemplate({
headerType: 'chain',
imports,
isStrict,
modules,
types: [
...Object.keys(imports.localTypes).sort().map((packagePath) => ({
file: packagePath.replace('@pezkuwi/types-augment', '@pezkuwi/types'),
types: Object.keys(imports.localTypes[packagePath])
})),
{
file: '@pezkuwi/api-base/types',
types: ['ApiTypes', 'AugmentedCall', 'DecoratedCallBase']
}
]
});
});
}
export function generateDefaultRuntime(dest, data, extraTypes = {}, isStrict = false, customLookupDefinitions) {
const { metadata, registry } = initMeta(data, extraTypes);
generateCallTypes(registry, metadata, dest, extraTypes, isStrict, customLookupDefinitions);
}
+16
View File
@@ -0,0 +1,16 @@
import type { Registry } from '@pezkuwi/types/types';
import type { TypeDef } from '@pezkuwi/types-create/types';
import type { ModuleTypes } from '../util/imports.js';
import type { TypeImports } from '../util/index.js';
import { TypeDefInfo } from '@pezkuwi/types-create';
/** @internal */
export declare function createGetter(definitions: Record<string, ModuleTypes>, name: string | undefined, type: string, imports: TypeImports): string;
export declare const typeEncoders: Record<TypeDefInfo, (registry: Registry, definitions: Record<string, ModuleTypes>, def: TypeDef, imports: TypeImports) => string>;
/** @internal */
export declare function generateTsDefFor(registry: Registry, importDefinitions: Record<string, Record<string, ModuleTypes>>, defName: string, { types }: {
types: Record<string, any>;
}, outputDir: string): void;
/** @internal */
export declare function generateTsDef(importDefinitions: Record<string, Record<string, ModuleTypes>>, outputDir: string, generatingPackage: string): void;
/** @internal */
export declare function generateDefaultTsDef(): void;
+246
View File
@@ -0,0 +1,246 @@
import Handlebars from 'handlebars';
import path from 'node:path';
import { TypeRegistry } from '@pezkuwi/types/create';
import * as defaultDefinitions from '@pezkuwi/types/interfaces/definitions';
import { getTypeDef, TypeDefInfo } from '@pezkuwi/types-create';
import { assert, isString, stringify, stringPascalCase } from '@pezkuwi/util';
import { createImports, exportInterface, formatType, readTemplate, setImports, writeFile } from '../util/index.js';
const generateTsDefIndexTemplate = Handlebars.compile(readTemplate('tsDef/index'));
const generateTsDefModuleTypesTemplate = Handlebars.compile(readTemplate('tsDef/moduleTypes'));
const generateTsDefTypesTemplate = Handlebars.compile(readTemplate('tsDef/types'));
/** @internal */
export function createGetter(definitions, name = '', type, imports) {
setImports(definitions, imports, [type]);
return ` readonly ${name}: ${type};\n`;
}
/** @internal */
function errorUnhandled(_, _definitions, def, _imports) {
throw new Error(`Generate: ${def.name || ''}: Unhandled type ${TypeDefInfo[def.info]}`);
}
/** @internal */
function tsExport(registry, definitions, def, imports) {
return exportInterface(def.lookupIndex, def.name, formatType(registry, definitions, def, imports, false));
}
/** @internal */
function tsEnum(registry, definitions, { lookupIndex, name: enumName, sub }, imports, withShortcut = false) {
setImports(definitions, imports, ['Enum']);
const indent = withShortcut ? ' ' : '';
const named = sub.filter(({ name }) => !!name && !name.startsWith('__Unused'));
const keys = named.map((def) => {
const { info, lookupName, name = '', sub, type } = def;
const getter = stringPascalCase(name.replace(' ', '_'));
const isComplex = [TypeDefInfo.Option, TypeDefInfo.Range, TypeDefInfo.RangeInclusive, TypeDefInfo.Result, TypeDefInfo.Struct, TypeDefInfo.Tuple, TypeDefInfo.Vec, TypeDefInfo.VecFixed].includes(info);
let extractedLookupName;
// When the parent type does not have a lookupName, and the sub type is the same
// type as the parent we can take the lookupName from the sub.
// This is specific to `StagingXcmV4Junction`.
// see: https://github.com/pezkuwichain/pezkuwi-api/pull/5812
if (sub && !Array.isArray(sub) && type.includes(`${sub.type};`)) {
if (sub.lookupName === 'StagingXcmV4Junction') {
extractedLookupName = sub.lookupName;
}
else if (sub.lookupName === 'StagingXcmV5Junction') {
extractedLookupName = `Vec<${sub.lookupName}>`;
}
}
const asGetter = type === 'Null' || info === TypeDefInfo.DoNotConstruct
? ''
: createGetter(definitions, `as${getter}`, lookupName || extractedLookupName || (isComplex ? formatType(registry, definitions, info === TypeDefInfo.Struct ? def : type, imports, withShortcut) : type), imports);
const isGetter = info === TypeDefInfo.DoNotConstruct
? ''
: createGetter(definitions, `is${getter}`, 'boolean', imports);
switch (info) {
case TypeDefInfo.Compact:
case TypeDefInfo.Plain:
case TypeDefInfo.Range:
case TypeDefInfo.RangeInclusive:
case TypeDefInfo.Result:
case TypeDefInfo.Si:
case TypeDefInfo.Struct:
case TypeDefInfo.Tuple:
case TypeDefInfo.Vec:
case TypeDefInfo.BTreeMap:
case TypeDefInfo.BTreeSet:
case TypeDefInfo.Option:
case TypeDefInfo.VecFixed:
case TypeDefInfo.WrapperKeepOpaque:
case TypeDefInfo.WrapperOpaque:
return `${indent}${isGetter}${indent}${asGetter}`;
case TypeDefInfo.DoNotConstruct:
case TypeDefInfo.Null:
return `${indent}${isGetter}`;
default:
throw new Error(`Enum: ${enumName || 'undefined'}: Unhandled type ${TypeDefInfo[info]}, ${stringify(def)}`);
}
});
return exportInterface(lookupIndex, enumName, 'Enum', `${keys.join('')} ${indent}readonly type: ${named.map(({ name = '' }) => `'${stringPascalCase(name.replace(' ', '_'))}'`).join(' | ')};\n`, withShortcut);
}
function tsInt(_, definitions, def, imports, type = 'Int') {
setImports(definitions, imports, [type]);
return exportInterface(def.lookupIndex, def.name, type);
}
/** @internal */
function tsNull(_registry, definitions, { lookupIndex = -1, name }, imports) {
setImports(definitions, imports, ['Null']);
// * @description extends [[${base}]]
const doc = `/** @name ${name || ''}${lookupIndex !== -1 ? ` (${lookupIndex})` : ''} */\n`;
return `${doc}export type ${name || ''} = Null;`;
}
/** @internal */
function tsResultGetter(registry, definitions, resultName = '', getter, def, imports) {
const { info, lookupName, type } = def;
const asGetter = type === 'Null'
? ''
: createGetter(definitions, `as${getter}`, lookupName || (info === TypeDefInfo.Tuple ? formatType(registry, definitions, def, imports, false) : type), imports);
const isGetter = createGetter(definitions, `is${getter}`, 'boolean', imports);
switch (info) {
case TypeDefInfo.Option:
case TypeDefInfo.Plain:
case TypeDefInfo.Si:
case TypeDefInfo.Tuple:
case TypeDefInfo.Vec:
case TypeDefInfo.BTreeMap:
case TypeDefInfo.BTreeSet:
case TypeDefInfo.WrapperKeepOpaque:
case TypeDefInfo.WrapperOpaque:
return `${isGetter}${asGetter}`;
case TypeDefInfo.Null:
return `${isGetter}`;
default:
throw new Error(`Result: ${resultName}: Unhandled type ${TypeDefInfo[info]}, ${stringify(def)}`);
}
}
/** @internal */
function tsResult(registry, definitions, def, imports) {
const [okDef, errorDef] = def.sub;
const inner = [
tsResultGetter(registry, definitions, def.name, 'Err', errorDef, imports),
tsResultGetter(registry, definitions, def.name, 'Ok', okDef, imports)
].join('');
setImports(definitions, imports, [def.type]);
const fmtType = def.lookupName && def.name !== def.lookupName
? def.lookupName
: formatType(registry, definitions, def, imports, false);
return exportInterface(def.lookupIndex, def.name, fmtType, inner);
}
/** @internal */
function tsSi(_registry, _definitions, typeDef, _imports) {
// FIXME
return `// SI: ${stringify(typeDef)}`;
}
/** @internal */
function tsSet(_, definitions, { lookupIndex, name: setName, sub }, imports) {
setImports(definitions, imports, ['Set']);
const types = sub.map(({ name }) => {
assert(name, 'Invalid TypeDef found, no name specified');
return createGetter(definitions, `is${name}`, 'boolean', imports);
});
return exportInterface(lookupIndex, setName, 'Set', types.join(''));
}
/** @internal */
function tsStruct(registry, definitions, { lookupIndex, name: structName, sub }, imports) {
setImports(definitions, imports, ['Struct']);
const keys = sub.map((def) => {
const fmtType = def.lookupName && def.name !== def.lookupName
? def.lookupName
: def.info === TypeDefInfo.Enum
? `${tsEnum(registry, definitions, def, imports, true)} & Enum`
: formatType(registry, definitions, def, imports, false);
return createGetter(definitions, def.name, fmtType, imports);
});
return exportInterface(lookupIndex, structName, 'Struct', keys.join(''));
}
/** @internal */
function tsUInt(registry, definitions, def, imports) {
return tsInt(registry, definitions, def, imports, 'UInt');
}
/** @internal */
function tsVec(registry, definitions, def, imports) {
const type = def.sub.type;
if (type === 'u8') {
if (def.info === TypeDefInfo.VecFixed) {
setImports(definitions, imports, ['U8aFixed']);
return exportInterface(def.lookupIndex, def.name, 'U8aFixed');
}
else {
setImports(definitions, imports, ['Bytes']);
return exportInterface(def.lookupIndex, def.name, 'Bytes');
}
}
const fmtType = def.lookupName && def.name !== def.lookupName
? def.lookupName
: formatType(registry, definitions, def, imports, false);
return exportInterface(def.lookupIndex, def.name, fmtType);
}
export const typeEncoders = {
[TypeDefInfo.BTreeMap]: tsExport,
[TypeDefInfo.BTreeSet]: tsExport,
[TypeDefInfo.Compact]: tsExport,
[TypeDefInfo.DoNotConstruct]: tsExport,
[TypeDefInfo.Enum]: tsEnum,
[TypeDefInfo.HashMap]: tsExport,
[TypeDefInfo.Int]: tsInt,
[TypeDefInfo.Linkage]: errorUnhandled,
[TypeDefInfo.Null]: tsNull,
[TypeDefInfo.Option]: tsExport,
[TypeDefInfo.Plain]: tsExport,
[TypeDefInfo.Range]: tsExport,
[TypeDefInfo.RangeInclusive]: tsExport,
[TypeDefInfo.Result]: tsResult,
[TypeDefInfo.Set]: tsSet,
[TypeDefInfo.Si]: tsSi,
[TypeDefInfo.Struct]: tsStruct,
[TypeDefInfo.Tuple]: tsExport,
[TypeDefInfo.UInt]: tsUInt,
[TypeDefInfo.Vec]: tsVec,
[TypeDefInfo.VecFixed]: tsVec,
[TypeDefInfo.WrapperKeepOpaque]: tsExport,
[TypeDefInfo.WrapperOpaque]: tsExport
};
/** @internal */
function generateInterfaces(registry, definitions, { types }, imports) {
return Object.entries(types).map(([name, type]) => {
const def = getTypeDef(isString(type) ? type : stringify(type), { name });
return [name, typeEncoders[def.info](registry, definitions, def, imports)];
});
}
/** @internal */
export function generateTsDefFor(registry, importDefinitions, defName, { types }, outputDir) {
const imports = { ...createImports(importDefinitions, { types }), interfaces: [] };
const definitions = imports.definitions;
const interfaces = generateInterfaces(registry, definitions, { types }, imports);
const items = interfaces.sort((a, b) => a[0].localeCompare(b[0])).map(([, definition]) => definition);
writeFile(path.join(outputDir, defName, 'types.ts'), () => generateTsDefModuleTypesTemplate({
headerType: 'defs',
imports,
items,
name: defName,
types: [
...Object.keys(imports.localTypes).sort().map((packagePath) => ({
file: packagePath.replace('@pezkuwi/types/augment', '@pezkuwi/types'),
types: Object.keys(imports.localTypes[packagePath])
}))
]
}), true);
writeFile(path.join(outputDir, defName, 'index.ts'), () => generateTsDefIndexTemplate({ headerType: 'defs' }), true);
}
/** @internal */
export function generateTsDef(importDefinitions, outputDir, generatingPackage) {
const registry = new TypeRegistry();
writeFile(path.join(outputDir, 'types.ts'), () => {
const definitions = importDefinitions[generatingPackage];
Object.entries(definitions).forEach(([defName, obj]) => {
console.log(`\tExtracting interfaces for ${defName}`);
generateTsDefFor(registry, importDefinitions, defName, obj, outputDir);
});
return generateTsDefTypesTemplate({
headerType: 'defs',
items: Object.keys(definitions)
});
});
writeFile(path.join(outputDir, 'index.ts'), () => generateTsDefIndexTemplate({ headerType: 'defs' }), true);
}
/** @internal */
export function generateDefaultTsDef() {
generateTsDef({ '@pezkuwi/types/interfaces': defaultDefinitions }, 'packages/types/src/interfaces', '@pezkuwi/types/interfaces');
}
+5
View File
@@ -0,0 +1,5 @@
import type { Definitions } from '@pezkuwi/types/types';
import type { HexString } from '@pezkuwi/util/types';
import { type ExtraTypes } from './types.js';
/** @internal */
export declare function generateDefaultTx(dest: string, data: HexString, extraTypes?: ExtraTypes, isStrict?: boolean, customLookupDefinitions?: Definitions): void;
+117
View File
@@ -0,0 +1,117 @@
import Handlebars from 'handlebars';
import * as defaultDefs from '@pezkuwi/types/interfaces/definitions';
import lookupDefinitions from '@pezkuwi/types-augment/lookup/definitions';
import { stringCamelCase } from '@pezkuwi/util';
import { compareName, createImports, formatType, getSimilarTypes, initMeta, readTemplate, rebrandTypeName, setImports, writeFile } from '../util/index.js';
import { ignoreUnusedLookups } from './lookup.js';
import { getDeprecationNotice } from './types.js';
const MAPPED_NAMES = {
class: 'clazz',
new: 'updated'
};
const generateForMetaTemplate = Handlebars.compile(readTemplate('tx'));
function mapName(_name) {
const name = stringCamelCase(_name);
return MAPPED_NAMES[name] || name;
}
/** @internal */
function generateForMeta(registry, meta, dest, extraTypes, isStrict, customLookupDefinitions) {
writeFile(dest, () => {
const allTypes = {
'@pezkuwi/types-augment': {
lookup: {
...lookupDefinitions,
...customLookupDefinitions
}
},
'@pezkuwi/types/interfaces': defaultDefs,
...extraTypes
};
const imports = createImports(allTypes);
const allDefs = Object.entries(allTypes).reduce((defs, [path, obj]) => {
return Object.entries(obj).reduce((defs, [key, value]) => ({ ...defs, [`${path}/${key}`]: value }), defs);
}, {});
const { lookup, pallets } = meta.asLatest;
const usedTypes = new Set([]);
const modules = pallets
.sort(compareName)
.filter(({ calls }) => calls.isSome)
.map((data) => {
const name = data.name;
const calls = data.calls.unwrap();
const deprecationInfo = calls.deprecationInfo.toJSON();
setImports(allDefs, imports, ['SubmittableExtrinsic']);
const sectionName = stringCamelCase(name);
const items = lookup.getSiType(calls.type).def.asVariant.variants
.map(({ docs, fields, index, name }) => {
const rawStatus = deprecationInfo?.[index.toNumber()];
if (rawStatus) {
const deprecationVariantInfo = meta.registry.createTypeUnsafe('VariantDeprecationInfoV16', [rawStatus]);
const deprecationNotice = getDeprecationNotice(deprecationVariantInfo, name.toString(), 'Call');
const notice = docs.length ? ['', deprecationNotice] : [deprecationNotice];
docs.push(...notice.map((text) => meta.registry.createType('Text', text)));
}
const typesInfo = fields.map(({ name, type, typeName }, index) => {
const typeDef = registry.lookup.getTypeDef(type);
return [
name.isSome
? mapName(name.unwrap())
: `param${index}`,
rebrandTypeName(typeName.isSome
? typeName.toString()
: typeDef.type),
rebrandTypeName(typeDef.isFromSi
? typeDef.type
: typeDef.lookupName || typeDef.type)
];
});
const params = typesInfo
.map(([name, , typeStr]) => {
const similarTypes = getSimilarTypes(registry, allDefs, typeStr, imports);
setImports(allDefs, imports, [typeStr, ...similarTypes]);
// Add the type to the list of used types
if (!(imports.primitiveTypes[typeStr])) {
usedTypes.add(typeStr);
}
return `${name}: ${similarTypes.join(' | ')}`;
})
.join(', ');
return {
args: typesInfo.map(([, , typeStr]) => formatType(registry, allDefs, typeStr, imports)).join(', '),
docs,
name: stringCamelCase(name),
params
};
})
.sort(compareName);
return {
items,
name: sectionName
};
})
.sort(compareName);
// filter out the unused lookup types from imports
ignoreUnusedLookups([...usedTypes], imports);
return generateForMetaTemplate({
headerType: 'chain',
imports,
isStrict,
modules,
types: [
...Object.keys(imports.localTypes).sort().map((packagePath) => ({
file: packagePath.replace('@pezkuwi/types-augment', '@pezkuwi/types'),
types: Object.keys(imports.localTypes[packagePath])
})),
{
file: '@pezkuwi/api-base/types',
types: ['ApiTypes', 'AugmentedSubmittable', 'SubmittableExtrinsic', 'SubmittableExtrinsicFunction']
}
]
});
});
}
/** @internal */
export function generateDefaultTx(dest, data, extraTypes = {}, isStrict = false, customLookupDefinitions) {
const { metadata, registry } = initMeta(data, extraTypes);
return generateForMeta(registry, metadata, dest, extraTypes, isStrict, customLookupDefinitions);
}
+12
View File
@@ -0,0 +1,12 @@
import type { Option, Text } from '@pezkuwi/types-codec';
export type ExtraTypes = Record<string, Record<string, {
runtime?: Record<string, any>;
types: Record<string, any>;
}>>;
export declare function getDeprecationNotice<T extends {
isDeprecated: boolean;
asDeprecated: {
note: Text;
since: Option<Text>;
};
}>(deprecationInfo: T, name: string, label?: string): string;
+13
View File
@@ -0,0 +1,13 @@
export function getDeprecationNotice(deprecationInfo, name, label) {
let deprecationNotice = '@deprecated';
if (deprecationInfo.isDeprecated) {
const { note, since } = deprecationInfo.asDeprecated;
const sinceText = since.isSome ? ` Since ${since.unwrap().toString()}.` : '';
deprecationNotice += ` ${note.toString()}${sinceText}`;
}
else {
const labelText = label ? `${label} ` : '';
deprecationNotice += ` ${labelText}${name} has been deprecated`;
}
return deprecationNotice;
}