Expand enum & struct defnitions, generator strict mode (#1798)

This commit is contained in:
Jaco Greeff
2020-02-03 11:56:06 +01:00
committed by GitHub
parent 328630fb17
commit 2ee3afcd61
14 changed files with 128 additions and 85 deletions
+8 -1
View File
@@ -203,6 +203,13 @@ export default class Enum extends Base<Codec> {
return this.raw instanceof Null;
}
/**
* @description The available keys for this enum
*/
public get defEntries (): string[] {
return Object.keys(this._def);
}
/**
* @description The available keys for this enum
*/
@@ -275,7 +282,7 @@ export default class Enum extends Base<Codec> {
*/
protected toRawStruct (): string[] | Record<string, string> {
return this._isBasic
? Object.keys(this._def)
? this.defKeys
: Struct.typesToMap(this.registry, this._def);
}
+7
View File
@@ -139,6 +139,13 @@ export default class Struct<
};
}
/**
* @description The available keys for this enum
*/
public get defKeys (): string[] {
return Object.keys(this._Types);
}
/**
* @description Checks if the value is an empty value
*/
@@ -13,7 +13,7 @@ import { FOOTER, HEADER, TypeImports, createDocComments, createImportCode, creat
// Generate types for one module
/** @internal */
function generateModule (allDefs: object, { constants, name }: ModuleMetadataLatest, imports: TypeImports): string[] {
function generateModule (allDefs: object, { constants, name }: ModuleMetadataLatest, imports: TypeImports, isStrict: boolean): string[] {
if (!constants.length) {
return [];
}
@@ -21,18 +21,18 @@ function generateModule (allDefs: object, { constants, name }: ModuleMetadataLat
setImports(allDefs, imports, ['Codec']);
return [indent(4)(`${stringCamelCase(name.toString())}: {`)]
.concat(indent(6)('[index: string]: Codec;'))
.concat(isStrict ? '' : indent(6)('[index: string]: Codec;'))
.concat(constants.map(({ documentation, name, type }): string => {
setImports(allDefs, imports, [type.toString()]);
return createDocComments(documentation).map((d): string => indent(6)(d)).join('\n') +
return createDocComments(6, documentation) +
indent(6)(`${stringCamelCase(name.toString())}: AugmentedConst<${type}>;`);
}))
.concat([indent(4)('};')]);
}
/** @internal */
function generateForMeta (meta: Metadata, dest: string, extraTypes: Record<string, Record<string, object>>): void {
function generateForMeta (meta: Metadata, dest: string, extraTypes: Record<string, Record<string, object>>, isStrict: boolean): void {
writeFile(dest, (): string => {
const allTypes: Record<string, Record<string, object>> = { '@polkadot/types/interfaces': defaultDefs, ...extraTypes };
const imports = createImports(allTypes);
@@ -40,7 +40,7 @@ function generateForMeta (meta: Metadata, dest: string, extraTypes: Record<strin
return Object.entries(obj).reduce((defs, [key, value]) => ({ ...defs, [key]: value }), defs);
}, {});
const body = meta.asLatest.modules.reduce((acc, mod): string[] => {
return acc.concat(generateModule(allDefs, mod, imports));
return acc.concat(generateModule(allDefs, mod, imports, isStrict));
}, [] as string[]);
const header = createImportCode(HEADER, imports, [
...Object.keys(imports.localTypes).map((moduleName): { file: string; types: string[] } => ({
@@ -49,7 +49,7 @@ function generateForMeta (meta: Metadata, dest: string, extraTypes: Record<strin
}))
]);
const interfaceStart = [
"declare module '@polkadot/metadata/Decorated/types' {",
"declare module '@polkadot/metadata/Decorated/consts/types' {",
indent(2)('export interface Constants {\n')
].join('\n');
const interfaceEnd = `\n${indent(2)('}')}\n}`;
@@ -64,8 +64,8 @@ function generateForMeta (meta: Metadata, dest: string, extraTypes: Record<strin
// Call `generateForMeta()` with current static metadata
/** @internal */
export default function generateConsts (dest = 'packages/api/src/types/augment/consts.ts', data = staticData, extraTypes: Record<string, Record<string, object>> = {}): void {
export default function generateConsts (dest = 'packages/api/src/types/augment/consts.ts', data = staticData, extraTypes: Record<string, Record<string, object>> = {}, isStrict = false): void {
const registry = new TypeRegistry();
return generateForMeta(new Metadata(registry, data), dest, extraTypes);
return generateForMeta(new Metadata(registry, data), dest, extraTypes, isStrict);
}
+7 -7
View File
@@ -68,24 +68,24 @@ function entrySignature (allDefs: object, registry: Registry, storageEntry: Stor
// Generate types for one module
/** @internal */
function generateModule (allDefs: object, registry: Registry, { name, storage }: ModuleMetadataLatest, imports: TypeImports): string[] {
function generateModule (allDefs: object, registry: Registry, { name, storage }: ModuleMetadataLatest, imports: TypeImports, isStrict: boolean): string[] {
if (storage.isNone) {
return [];
}
return [indent(4)(`${stringLowerFirst(name.toString())}: {`)]
.concat(indent(6)('[index: string]: QueryableStorageEntry<ApiType>;'))
.concat(isStrict ? '' : indent(6)('[index: string]: QueryableStorageEntry<ApiType>;'))
.concat(storage.unwrap().items.map((storageEntry): string => {
const [args, returnType] = entrySignature(allDefs, registry, storageEntry, imports);
return createDocComments(storageEntry.documentation).map((d): string => indent(6)(d)).join('\n') +
return createDocComments(6, storageEntry.documentation) +
indent(6)(`${stringLowerFirst(storageEntry.name.toString())}: AugmentedQuery<ApiType, (${args}) => Observable<${returnType}>> & QueryableStorageEntry<ApiType>;`);
}))
.concat([indent(4)('};')]);
}
/** @internal */
function generateForMeta (registry: Registry, meta: Metadata, dest: string, extraTypes: Record<string, Record<string, object>>): void {
function generateForMeta (registry: Registry, meta: Metadata, dest: string, extraTypes: Record<string, Record<string, object>>, isStrict: boolean): void {
writeFile(dest, (): string => {
const allTypes: Record<string, Record<string, object>> = { '@polkadot/types/interfaces': defaultDefs, ...extraTypes };
const imports = createImports(allTypes);
@@ -93,7 +93,7 @@ function generateForMeta (registry: Registry, meta: Metadata, dest: string, extr
return Object.entries(obj).reduce((defs, [key, value]) => ({ ...defs, [key]: value }), defs);
}, {});
const body = meta.asLatest.modules.reduce((acc, mod): string[] => {
return acc.concat(generateModule(allDefs, registry, mod, imports));
return acc.concat(generateModule(allDefs, registry, mod, imports, isStrict));
}, [] as string[]);
const header = createImportCode(HEADER, imports, [
...Object.keys(imports.localTypes).map((moduleName): { file: string; types: string[] } => ({
@@ -121,8 +121,8 @@ function generateForMeta (registry: Registry, meta: Metadata, dest: string, extr
// Call `generateForMeta()` with current static metadata
/** @internal */
export default function generateQuery (dest = 'packages/api/src/types/augment/query.ts', data = staticData, extraTypes: Record<string, Record<string, object>> = {}): void {
export default function generateQuery (dest = 'packages/api/src/types/augment/query.ts', data = staticData, extraTypes: Record<string, Record<string, object>> = {}, isStrict = false): void {
const registry = new TypeRegistry();
return generateForMeta(registry, new Metadata(registry, data), dest, extraTypes);
return generateForMeta(registry, new Metadata(registry, data), dest, extraTypes, isStrict);
}
+2 -2
View File
@@ -5,7 +5,7 @@
import interfaces from '../../../../type-jsonrpc/src';
import * as definitions from '../../interfaces/definitions';
import { TypeRegistry } from '../../codec/create';
import { FOOTER, HEADER, createImportCode, createImports, getSimilarTypes, setImports, writeFile } from '../util';
import { FOOTER, HEADER, createDocComments, createImportCode, createImports, getSimilarTypes, setImports, writeFile, indent } from '../util';
/** @internal */
export default function generateRpcTypes (dest = 'packages/api/src/types/augment/rpc.ts'): void {
@@ -35,7 +35,7 @@ export default function generateRpcTypes (dest = 'packages/api/src/types/augment
return `${param.name}${param.isOptional ? '?' : ''}: ${similarTypes.join(' | ')}`;
});
return ` /**\n * ${method.description}\n **/\n ${method.method}(${args.join(', ')}): Observable<${method.type}>;`;
return createDocComments(6, [method.description]) + indent(6)(`${method.method}(${args.join(', ')}): Observable<${method.type}>;`);
});
return allSections.concat(
+22 -19
View File
@@ -26,7 +26,7 @@ function mapName (_name: Text): string {
// Generate types for one module
/** @internal */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function generateModule (registry: Registry, allDefs: object, { calls, name }: ModuleMetadataLatest, imports: TypeImports): string[] {
function generateModule (registry: Registry, allDefs: object, { calls, name }: ModuleMetadataLatest, imports: TypeImports, isStrict: boolean): string[] {
const allCalls = calls.unwrapOr(null);
if (!allCalls?.length) {
@@ -37,30 +37,33 @@ function generateModule (registry: Registry, allDefs: object, { calls, name }: M
// NOTE Not removing this concat yet, first see the fallout
return [indent(4)(`${stringCamelCase(name.toString())}: {`)]
.concat(indent(6)('[index: string]: SubmittableExtrinsicFunction<ApiType>;'))
.concat(isStrict ? '' : indent(6)('[index: string]: SubmittableExtrinsicFunction<ApiType>;'))
.concat(allCalls.map(({ args, documentation, name }): string => {
const params = args.map(({ name, type }): [string, string, string] => {
const typeStr = type.toString();
const similarTypes = getSimilarTypes(allDefs, registry, typeStr, imports).map((type): string =>
type.startsWith('(') || type.startsWith('{')
? type
: formatType(allDefs, type, imports)
);
const nameStr = mapName(name);
const params = args
.map(({ name, type }): [string, string, string] => {
const typeStr = type.toString();
const similarTypes = getSimilarTypes(allDefs, registry, typeStr, imports).map((type): string =>
type.startsWith('(') || type.startsWith('{')
? type
: formatType(allDefs, type, imports)
);
const nameStr = mapName(name);
setImports(allDefs, imports, [...similarTypes.filter((type): boolean => !type.startsWith('(') && !type.startsWith('{')), typeStr]);
setImports(allDefs, imports, [...similarTypes.filter((type): boolean => !type.startsWith('(') && !type.startsWith('{')), typeStr]);
return [`${nameStr}: ${similarTypes.join(' | ')}`, nameStr, typeStr];
});
return [`${nameStr}: ${similarTypes.join(' | ')}`, nameStr, typeStr];
})
.map(([full]): string => full)
.join(', ');
return createDocComments(documentation).map((d): string => indent(6)(d)).join('\n') +
indent(6)(`${stringCamelCase(name.toString())}: AugmentedSubmittable<(${params.map(([full]): string => full).join(', ')}) => SubmittableExtrinsic<ApiType>>;`);
return createDocComments(6, documentation) +
indent(6)(`${stringCamelCase(name.toString())}: AugmentedSubmittable<(${params}) => SubmittableExtrinsic<ApiType>>;`);
}))
.concat([indent(4)('};')]);
}
/** @internal */
function generateForMeta (registry: Registry, meta: Metadata, dest: string, extraTypes: Record<string, Record<string, object>>): void {
function generateForMeta (registry: Registry, meta: Metadata, dest: string, extraTypes: Record<string, Record<string, object>>, isStrict: boolean): void {
writeFile(dest, (): string => {
const allTypes: Record<string, Record<string, object>> = { '@polkadot/types/interfaces': defaultDefs, ...extraTypes };
const imports = createImports(allTypes);
@@ -68,7 +71,7 @@ function generateForMeta (registry: Registry, meta: Metadata, dest: string, extr
return Object.entries(obj).reduce((defs, [key, value]) => ({ ...defs, [key]: value }), defs);
}, {});
const body = meta.asLatest.modules.reduce((acc, mod): string[] => {
return acc.concat(generateModule(registry, allDefs, mod, imports));
return acc.concat(generateModule(registry, allDefs, mod, imports, isStrict));
}, [] as string[]);
const header = createImportCode(HEADER, imports, [
...Object.keys(imports.localTypes).map((moduleName): { file: string; types: string[] } => ({
@@ -96,8 +99,8 @@ function generateForMeta (registry: Registry, meta: Metadata, dest: string, extr
// Call `generateForMeta()` with current static metadata
/** @internal */
export default function generateTx (dest = 'packages/api/src/types/augment/tx.ts', data = staticData, extraTypes: Record<string, Record<string, object>> = {}): void {
export default function generateTx (dest = 'packages/api/src/types/augment/tx.ts', data = staticData, extraTypes: Record<string, Record<string, object>> = {}, isStrict = false): void {
const registry = new TypeRegistry();
return generateForMeta(registry, new Metadata(registry, data), dest, extraTypes);
return generateForMeta(registry, new Metadata(registry, data), dest, extraTypes, isStrict);
}
@@ -27,7 +27,7 @@ const generateConst = require('./generate/consts').default;
const generateQuery = require('./generate/query').default;
const generateTx = require('./generate/tx').default;
const { endpoint, output, package } = yargs.strict().options({
const { endpoint, output, package, strict: isStrict } = yargs.strict().options({
endpoint: {
description: 'The endpoint to connect to, e.g. wss://kusama-rpc.polkadot.io or relative file to JSON output',
type: 'string',
@@ -40,6 +40,10 @@ const { endpoint, output, package } = yargs.strict().options({
},
package: {
description: 'Optional package in output location (for extra definitions)'
},
strinct: {
description: 'Turns on stirct mode, not outputting genric versions',
type: 'boolean'
}
}).argv;
let websocket = null;
@@ -51,9 +55,9 @@ function generate (metaHex) {
? { [package]: require(path.join(process.cwd(), output, 'definitions')) }
: {};
generateConst(path.join(process.cwd(), output, 'augment.consts.ts'), metaHex, extraTypes);
generateQuery(path.join(process.cwd(), output, 'augment.query.ts'), metaHex, extraTypes);
generateTx(path.join(process.cwd(), output, 'augment.tx.ts'), metaHex, extraTypes);
generateConst(path.join(process.cwd(), output, 'augment.consts.ts'), metaHex, extraTypes, isStrict);
generateQuery(path.join(process.cwd(), output, 'augment.query.ts'), metaHex, extraTypes, isStrict);
generateTx(path.join(process.cwd(), output, 'augment.tx.ts'), metaHex, extraTypes, isStrict);
process.exit(0);
}
+14 -4
View File
@@ -5,6 +5,7 @@
import { TypeDef, TypeDefInfo } from '../../codec/types';
import { Constructor, Registry } from '../../types';
import { stringLowerFirst } from '@polkadot/util';
import { isChildClass, isCompactEncodable } from './class';
import { ClassOf, ClassOfUnsafe, getTypeDef } from '../../codec/create';
import AbstractInt from '../../codec/AbstractInt';
@@ -13,6 +14,7 @@ import Enum from '../../codec/Enum';
import Option from '../../codec/Option';
import Struct from '../../codec/Struct';
import Vec from '../../codec/Vec';
import Null from '../../primitive/Null';
import Vote, { convictionNames as _voteConvictions } from '../../primitive/Generic/Vote';
import * as primitiveClasses from '../../primitive';
import { formatType } from './formatting';
@@ -94,19 +96,27 @@ export function getSimilarTypes (definitions: object, registry: Registry, type:
const e = new Clazz(registry) as Enum;
if (e.isBasic) {
possibleTypes.push(arrayToStrType(e.defKeys), 'number', 'Uint8Array');
possibleTypes.push(arrayToStrType(e.defKeys), 'number');
} else {
// TODO Handle this more gracefully (expand actual options)
possibleTypes.push('object', 'number', 'Uint8Array', 'string');
// TODO We don't really want any here, these should be expanded
possibleTypes.push(...e.defKeys.map((key): string => `{ ${stringLowerFirst(key)}: any }`), 'string');
}
possibleTypes.push('Uint8Array');
} else if (isChildClass(AbstractInt as unknown as Constructor<any>, Clazz) || isChildClass(Compact, Clazz)) {
possibleTypes.push('AnyNumber', 'Uint8Array');
} else if (isChildClass(ClassOf(registry, 'Address'), Clazz)) {
possibleTypes.push('string', 'AccountId', 'AccountIndex', 'Uint8Array');
} else if (isChildClass(ClassOf(registry, 'bool'), Clazz)) {
possibleTypes.push('boolean', 'Uint8Array');
} else if (isChildClass(Null, Clazz)) {
possibleTypes.push('null');
} else if (isChildClass(Struct, Clazz)) {
possibleTypes.push('object', 'string', 'Uint8Array');
// TODO We don't really want any here, these should be expanded
const s = new Clazz(registry) as Struct;
const obj = s.defKeys.map((key): string => `${key}?: any`).join('; ');
possibleTypes.push(`{ ${obj} }`, 'string', 'Uint8Array');
} else if (isChildClass(Option, Clazz)) {
// TODO inspect container
possibleTypes.push('null', 'object', 'string', 'Uint8Array');
+11 -6
View File
@@ -4,15 +4,20 @@
import { Text } from '@polkadot/types';
type Arg = [Text | string, Text | string];
import { indent } from './formatting';
export function createDocComments (docs: Text[], args: Arg[] = []): string[] {
type AnyString = Text | string;
type Arg = [AnyString, AnyString];
export function createDocComments (spaces: number, docs: AnyString[], args: Arg[] = []): string {
const contents = [
...docs.map((doc): string => doc.toString().trim()).filter((doc): boolean => !!doc).map((doc): string => ` * ${doc}`),
...args.map(([name, type]): string => ` * @param ${name} ${type}`)
];
...docs.map((doc): string => doc.toString().trim()).filter((doc): boolean => !!doc),
...args.map(([name, type]): string => `@param ${name} ${type}`)
].map((d): string => ` * ${d}`);
return contents.length
? ['/**', ...contents, ' **/\n']
: [];
.map((s): string => indent(spaces)(s))
.join('\n')
: '';
}