Split generation scripts into @polkadot/typegen (#1875)
* Split generation scripts into @polkadot/typegen * Remove moved files * CC overrides * interfaces typo * Cleanup imports * Some import combinations * Updates * Generation updates * Cleanups, split js wrapper & ts logic * Rename jiggle 1 * Rename jiggle 2 * Style cleanups * Expose enry function for scripts * Typo * Update script copy & include locations * CC exclude location * Minor adjustments * argv parsing into main
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,3 @@
|
||||
# @polkadot/typegen
|
||||
|
||||
A collection of type generation scripts, allowing the input of metadata and definitions for the creation of TS outputs.
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"name": "@polkadot/typegen",
|
||||
"version": "1.3.0-beta.5",
|
||||
"description": "Type generation scripts",
|
||||
"main": "index.js",
|
||||
"bin": {
|
||||
"polkadot-types-chain-info": "./scripts/polkadot-types-chain-info.js",
|
||||
"polkadot-types-from-chain": "./scripts/polkadot-types-from-chain.js",
|
||||
"polkadot-types-from-defs": "./scripts/polkadot-types-from-defs.js",
|
||||
"polkadot-types-internal-interfaces": "./scripts/polkadot-types-internal-interfaces.js",
|
||||
"polkadot-types-internal-metadata": "./scripts/polkadot-types-internal-metadata.js"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://registry.npmjs.org"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/polkadot-js/api.git"
|
||||
},
|
||||
"keywords": [
|
||||
"Polkadot",
|
||||
"JsonRPC"
|
||||
],
|
||||
"author": "Jaco Greeff <jacogr@gmail.com>",
|
||||
"maintainers": [
|
||||
"Jaco Greeff <jacogr@gmail.com>"
|
||||
],
|
||||
"contributors": [],
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/polkadot-js/api/issues"
|
||||
},
|
||||
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/typegen#readme",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.8.3",
|
||||
"@babel/register": "^7.8.3",
|
||||
"@babel/runtime": "^7.8.4",
|
||||
"@polkadot/api": "^1.3.0-beta.5",
|
||||
"@polkadot/jsonrpc": "^1.3.0-beta.5",
|
||||
"@polkadot/metadata": "^1.3.0-beta.5",
|
||||
"@polkadot/types": "^1.3.0-beta.5",
|
||||
"@polkadot/util": "^2.3.1",
|
||||
"websocket": "^1.0.31",
|
||||
"yargs": "^15.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/yargs": "^15.0.3"
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env node
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
|
||||
let main;
|
||||
|
||||
try {
|
||||
main = require('../extractChain').default;
|
||||
} catch (error) {
|
||||
require('@babel/register')({
|
||||
extensions: ['.js', '.ts'],
|
||||
plugins: [
|
||||
['module-resolver', {
|
||||
alias: {
|
||||
'^@polkadot/api-derive(.*)': './packages/api-derive/src\\1',
|
||||
'^@polkadot/metadata(.*)': './packages/metadata/src\\1',
|
||||
'^@polkadot/api(.*)': './packages/api/src/\\1',
|
||||
'^@polkadot/jsonrpc(.*)': './packages/jsonrpc/src\\1',
|
||||
'^@polkadot/rpc-core(.*)': './packages/rpc-core/src\\1',
|
||||
'^@polkadot/rpc-provider(.*)': './packages/rpc-provider/src\\1',
|
||||
'^@polkadot/types(.*)': './packages/types/src\\1'
|
||||
}
|
||||
}]
|
||||
]
|
||||
});
|
||||
|
||||
main = require('../src/extractChain.ts').default;
|
||||
}
|
||||
|
||||
main();
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env node
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
|
||||
let main;
|
||||
|
||||
try {
|
||||
main = require('../fromChain').default;
|
||||
} catch (error) {
|
||||
require('@babel/register')({
|
||||
extensions: ['.js', '.ts'],
|
||||
plugins: [
|
||||
['module-resolver', {
|
||||
alias: {
|
||||
'^@polkadot/metadata(.*)': './packages/metadata/src\\1',
|
||||
'^@polkadot/types(.*)': './packages/types/src\\1'
|
||||
}
|
||||
}]
|
||||
]
|
||||
});
|
||||
|
||||
main = require('../src/fromChain').default;
|
||||
}
|
||||
|
||||
main();
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env node
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
|
||||
let main;
|
||||
|
||||
try {
|
||||
main = require('../fromDefs').default;
|
||||
} catch (error) {
|
||||
require('@babel/register')({
|
||||
extensions: ['.js', '.ts'],
|
||||
plugins: [
|
||||
['module-resolver', {
|
||||
alias: {
|
||||
'^@polkadot/metadata(.*)': './packages/metadata/src\\1',
|
||||
'^@polkadot/typegen(.*)': './packages/typegen/src\\1',
|
||||
'^@polkadot/types(.*)': './packages/types/src\\1'
|
||||
}
|
||||
}]
|
||||
]
|
||||
});
|
||||
|
||||
main = require('../sr/fromDefs.ts').default;
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env node
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
|
||||
let main;
|
||||
|
||||
try {
|
||||
main = require('../interfacesTs').default;
|
||||
} catch (error) {
|
||||
require('@babel/register')({
|
||||
extensions: ['.js', '.ts'],
|
||||
plugins: [
|
||||
['module-resolver', {
|
||||
alias: {
|
||||
'^@polkadot/jsonrpc(.*)': './packages/jsonrpc/src\\1',
|
||||
'^@polkadot/metadata(.*)': './packages/metadata/src\\1',
|
||||
'^@polkadot/types(.*)': './packages/types/src\\1'
|
||||
}
|
||||
}]
|
||||
]
|
||||
});
|
||||
|
||||
main = require('../src/interfacesTs.ts').default;
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env node
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
|
||||
let main;
|
||||
|
||||
try {
|
||||
main = require('../metadataMd').default;
|
||||
} catch (error) {
|
||||
require('@babel/register')({
|
||||
extensions: ['.js', '.ts'],
|
||||
plugins: [
|
||||
['module-resolver', {
|
||||
alias: {
|
||||
'^@polkadot/jsonrpc(.*)': './packages/jsonrpc/src\\1',
|
||||
'^@polkadot/metadata(.*)': './packages/metadata/src\\1',
|
||||
'^@polkadot/types(.*)': './packages/types/src\\1'
|
||||
}
|
||||
}]
|
||||
]
|
||||
});
|
||||
|
||||
main = require('../src/metadataMd.ts').default;
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
// Connects to the local chain and outputs a re-usable calls-only chain definition in the form
|
||||
// export default { chain: 'Development', genesisHash: '0x27b6d5e0f4fdce1c4d20b82406f193acacce0c19e0d2c0e7ca47725c2572a06a', ss58Format: 42, tokenDecimals: 0, tokenSymbol: 'UNIT'; metaCalls: 'bWV0...4AAA==' };
|
||||
|
||||
import process from 'process';
|
||||
import yargs from 'yargs';
|
||||
import { ApiPromise, WsProvider } from '@polkadot/api/index';
|
||||
|
||||
/** @internal */
|
||||
async function run (ws: string): Promise<void> {
|
||||
const provider = new WsProvider(ws);
|
||||
const api = await ApiPromise.create({ provider });
|
||||
const [chain, props] = await Promise.all([
|
||||
api.rpc.system.chain(),
|
||||
api.rpc.system.properties()
|
||||
]);
|
||||
|
||||
// output the chain info, for easy re-use
|
||||
console.error(`// Generated via 'yarn run chain:info ${ws}'\n\nexport default {\n chain: '${chain.toString()}',\n genesisHash: '${api.genesisHash.toHex()}',\n specVersion: ${api.runtimeVersion.specVersion.toNumber()},\n ss58Format: ${props.ss58Format.unwrapOr(42)},\n tokenDecimals: ${props.tokenDecimals.unwrapOr(0)},\n tokenSymbol: '${props.tokenSymbol.unwrapOr('UNIT')}',\n metaCalls: '${Buffer.from(api.runtimeMetadata.asCallsOnly.toU8a()).toString('base64')}'\n};`);
|
||||
|
||||
// show any missing types
|
||||
api.runtimeMetadata.getUniqTypes(false);
|
||||
}
|
||||
|
||||
export default function main (): void {
|
||||
// retrieve and parse arguments - we do this globally, since this is a single command
|
||||
const { ws } = yargs
|
||||
.usage('Usage: [options]')
|
||||
.wrap(120)
|
||||
.options({
|
||||
ws: {
|
||||
default: 'ws://127.0.0.1:9944',
|
||||
description: 'The API endpoint to connect to, e.g. wss://poc3-rpc.polkadot.io',
|
||||
type: 'string',
|
||||
required: true
|
||||
}
|
||||
}).argv;
|
||||
|
||||
run(ws)
|
||||
.then((): void => {
|
||||
process.exit(0);
|
||||
})
|
||||
.catch((error: Error) => {
|
||||
console.error('FATAL:', error.message);
|
||||
process.exit(-1);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import path from 'path';
|
||||
import yargs from 'yargs';
|
||||
import { formatNumber } from '@polkadot/util';
|
||||
|
||||
import generateConst from './generate/consts';
|
||||
import generateQuery from './generate/query';
|
||||
import generateTx from './generate/tx';
|
||||
|
||||
if (typeof WebSocket === 'undefined') {
|
||||
(global as any).WebSocket = require('websocket').w3cwebsocket;
|
||||
}
|
||||
|
||||
let websocket: any = null;
|
||||
|
||||
function generate (metaHex: string, pkg: string | undefined, output: string, isStrict?: boolean): void {
|
||||
console.log(`Generating from metadata, ${formatNumber((metaHex.length - 2) / 2)} bytes`);
|
||||
|
||||
const extraTypes = pkg
|
||||
? { [pkg]: require(path.join(process.cwd(), output, 'definitions')) }
|
||||
: {};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
function onSocketClose (event: any): void {
|
||||
console.error(`disconnected, code: '${event.code}' reason: '${event.reason}'`);
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function onSocketError (event: any): void {
|
||||
console.error(event);
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function onSocketOpen (): boolean {
|
||||
console.log('connected');
|
||||
|
||||
websocket.send('{"id":"1","jsonrpc":"2.0","method":"state_getMetadata","params":[]}');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export default function main (): void {
|
||||
const { endpoint, output, package: pkg, 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',
|
||||
required: true
|
||||
},
|
||||
output: {
|
||||
description: 'The target directory to write the data to',
|
||||
type: 'string',
|
||||
required: true
|
||||
},
|
||||
package: {
|
||||
description: 'Optional package in output location (for extra definitions)',
|
||||
type: 'string'
|
||||
},
|
||||
strict: {
|
||||
description: 'Turns on stirct mode, not outputting genric versions',
|
||||
type: 'boolean'
|
||||
}
|
||||
}).argv;
|
||||
|
||||
if (endpoint.startsWith('wss://') || endpoint.startsWith('ws://')) {
|
||||
websocket = new WebSocket(endpoint);
|
||||
websocket.onclose = onSocketClose;
|
||||
websocket.onerror = onSocketError;
|
||||
websocket.onopen = onSocketOpen;
|
||||
websocket.onmessage = (message: any): void => {
|
||||
generate(JSON.parse(message.data).result, pkg, output, isStrict);
|
||||
};
|
||||
} else {
|
||||
generate(require(path.join(process.cwd(), endpoint)).result, pkg, output, isStrict);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import path from 'path';
|
||||
import yargs from 'yargs';
|
||||
import * as substrateDefs from '@polkadot/types/interfaces/definitions';
|
||||
|
||||
import { generateInterfaceRegistry } from './generate/interfaceRegistry';
|
||||
import { generateTsDef } from './generate/tsDef';
|
||||
|
||||
export default function main (): void {
|
||||
const { input, package: pkg } = yargs.strict().options({
|
||||
input: {
|
||||
description: 'The directory to use for the user definitions',
|
||||
type: 'string',
|
||||
required: true
|
||||
},
|
||||
package: {
|
||||
description: 'The package name & path to use for the user types',
|
||||
type: 'string',
|
||||
required: true
|
||||
}
|
||||
}).argv;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const userDefs = require(path.join(process.cwd(), input, 'definitions.ts'));
|
||||
const userKeys = Object.keys(userDefs);
|
||||
const filteredBase = Object
|
||||
.entries(substrateDefs)
|
||||
.filter(([key]) => {
|
||||
if (userKeys.includes(key)) {
|
||||
console.warn(`Override found for ${key} in user types, ignoring in @polkadot/types`);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.reduce((defs: any, [key, value]) => {
|
||||
defs[key] = value;
|
||||
|
||||
return defs;
|
||||
}, {});
|
||||
|
||||
const allDefs = {
|
||||
'@polkadot/types/interfaces': filteredBase,
|
||||
[pkg]: userDefs
|
||||
};
|
||||
|
||||
generateTsDef(allDefs, path.join(process.cwd(), input), pkg);
|
||||
generateInterfaceRegistry(allDefs, path.join(process.cwd(), input, 'interfaceRegistry.ts'));
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { ModuleMetadataLatest } from '@polkadot/types/interfaces/metadata';
|
||||
import * as defaultDefs from '@polkadot/types/interfaces/definitions';
|
||||
|
||||
import staticData from '@polkadot/metadata/Metadata/static';
|
||||
import Metadata from '@polkadot/metadata/Metadata';
|
||||
import { TypeRegistry } from '@polkadot/types/create';
|
||||
import { stringCamelCase } from '@polkadot/util';
|
||||
|
||||
import { FOOTER, HEADER, TypeImports, createDocComments, createImportCode, createImports, indent, setImports, writeFile } from '../util';
|
||||
|
||||
// Generate types for one module
|
||||
/** @internal */
|
||||
function generateModule (allDefs: object, { constants, name }: ModuleMetadataLatest, imports: TypeImports, isStrict: boolean): string[] {
|
||||
if (!constants.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
setImports(allDefs, imports, ['Codec']);
|
||||
|
||||
return [indent(4)(`${stringCamelCase(name.toString())}: {`)]
|
||||
.concat(isStrict ? '' : indent(6)('[index: string]: Codec;'))
|
||||
.concat(constants.map(({ documentation, name, type }): string => {
|
||||
setImports(allDefs, imports, [type.toString()]);
|
||||
|
||||
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>>, isStrict: boolean): void {
|
||||
writeFile(dest, (): string => {
|
||||
const allTypes: Record<string, Record<string, object>> = { '@polkadot/types/interfaces': defaultDefs, ...extraTypes };
|
||||
const imports = createImports(allTypes);
|
||||
const allDefs = Object.entries(allTypes).reduce((defs, [, obj]) => {
|
||||
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, isStrict));
|
||||
}, [] as string[]);
|
||||
const header = createImportCode(HEADER, imports, [
|
||||
...Object.keys(imports.localTypes).map((moduleName): { file: string; types: string[] } => ({
|
||||
file: `${imports.moduleToPackage[moduleName]}/${moduleName}`,
|
||||
types: Object.keys(imports.localTypes[moduleName])
|
||||
}))
|
||||
]);
|
||||
const interfaceStart = [
|
||||
"declare module '@polkadot/metadata/Decorated/consts/types' {",
|
||||
indent(2)('export interface Constants {\n')
|
||||
].join('\n');
|
||||
const interfaceEnd = `\n${indent(2)('}')}\n}`;
|
||||
|
||||
return header
|
||||
.concat(interfaceStart)
|
||||
.concat(body.join('\n'))
|
||||
.concat(interfaceEnd)
|
||||
.concat(FOOTER);
|
||||
});
|
||||
}
|
||||
|
||||
// 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>> = {}, isStrict = false): void {
|
||||
const registry = new TypeRegistry();
|
||||
|
||||
return generateForMeta(new Metadata(registry, data), dest, extraTypes, isStrict);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import Raw from '@polkadot/types/codec/Raw';
|
||||
import * as defaultDefinitions from '@polkadot/types/interfaces/definitions';
|
||||
import * as defaultPrimitives from '@polkadot/types/primitive';
|
||||
|
||||
import { FOOTER, HEADER, createImportCode, createImports, getDerivedTypes, indent, setImports, writeFile } from '../util';
|
||||
|
||||
const primitiveClasses = {
|
||||
...defaultPrimitives,
|
||||
Raw
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
export function generateInterfaceRegistry (importDefinitions: { [importPath: string]: object }, dest: string): void {
|
||||
writeFile(dest, (): string => {
|
||||
Object.entries(importDefinitions).reduce((acc, def) => Object.assign(acc, def), {} as object);
|
||||
|
||||
const imports = createImports(importDefinitions);
|
||||
const definitions = imports.definitions;
|
||||
|
||||
const primitives = Object
|
||||
.keys(primitiveClasses)
|
||||
.filter((name): boolean => !!name.indexOf('Generic'))
|
||||
.reduce((accumulator, primitiveName): string => {
|
||||
setImports(definitions, imports, [primitiveName]);
|
||||
|
||||
return [
|
||||
accumulator,
|
||||
getDerivedTypes(definitions, primitiveName, primitiveName, imports).map(indent(2)).join('\n')
|
||||
].join('\n');
|
||||
}, '');
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const srml = Object.entries(definitions).reduce((accumulator, [_defName, { types }]): string => {
|
||||
setImports(definitions, imports, Object.keys(types));
|
||||
|
||||
return [
|
||||
accumulator,
|
||||
...Object.keys(types).map((type): string =>
|
||||
getDerivedTypes(definitions, type, types[type], imports).map(indent(2)).join('\n')
|
||||
)
|
||||
].join('\n');
|
||||
}, '');
|
||||
|
||||
const header = createImportCode(HEADER, imports, [
|
||||
...Object.keys(imports.localTypes).map((moduleName): { file: string; types: string[] } => ({
|
||||
file: `${imports.moduleToPackage[moduleName]}/${moduleName}`,
|
||||
types: Object.keys(imports.localTypes[moduleName])
|
||||
}))
|
||||
]);
|
||||
|
||||
const interfaceStart = 'export interface InterfaceRegistry {';
|
||||
const interfaceEnd = '\n}';
|
||||
|
||||
return header
|
||||
.concat(interfaceStart)
|
||||
.concat(primitives)
|
||||
.concat(srml)
|
||||
.concat(interfaceEnd)
|
||||
.concat(FOOTER);
|
||||
});
|
||||
}
|
||||
|
||||
// Generate `packages/types/src/interfaceRegistry.ts`, the registry of all interfaces
|
||||
export default function generateDefaultInterfaceRegistry (): void {
|
||||
generateInterfaceRegistry(
|
||||
{ '@polkadot/types/interfaces': defaultDefinitions },
|
||||
'packages/types/src/interfaceRegistry.ts'
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { ModuleMetadataLatest, StorageEntryMetadataLatest } from '@polkadot/types/interfaces/metadata';
|
||||
import { Registry } from '@polkadot/types/types';
|
||||
import * as defaultDefs from '@polkadot/types/interfaces/definitions';
|
||||
|
||||
import staticData from '@polkadot/metadata/Metadata/static';
|
||||
import Metadata from '@polkadot/metadata/Metadata';
|
||||
import { TypeRegistry } from '@polkadot/types/create';
|
||||
import { stringLowerFirst } from '@polkadot/util';
|
||||
|
||||
import { FOOTER, HEADER, TypeImports, createDocComments, createImportCode, createImports, formatType, getSimilarTypes, indent, setImports, writeFile } from '../util';
|
||||
|
||||
// If the StorageEntry returns T, output `Option<T>` if the modifier is optional
|
||||
/** @internal */
|
||||
function addModifier (storageEntry: StorageEntryMetadataLatest, returnType: string): string {
|
||||
if (storageEntry.modifier.isOptional) {
|
||||
return `Option<${returnType}>`;
|
||||
}
|
||||
|
||||
return returnType;
|
||||
}
|
||||
|
||||
// From a storage entry metadata, we return [args, returnType]
|
||||
/** @internal */
|
||||
function entrySignature (allDefs: object, registry: Registry, storageEntry: StorageEntryMetadataLatest, imports: TypeImports): [string, string] {
|
||||
if (storageEntry.type.isPlain) {
|
||||
setImports(allDefs, imports, [storageEntry.type.asPlain.toString()]);
|
||||
|
||||
return ['', formatType(allDefs, addModifier(storageEntry, storageEntry.type.asPlain.toString()), imports)];
|
||||
} else if (storageEntry.type.isMap) {
|
||||
// Find similar types of the `key` type
|
||||
const similarTypes = getSimilarTypes(allDefs, registry, storageEntry.type.asMap.key.toString(), imports);
|
||||
|
||||
setImports(allDefs, imports, [
|
||||
...similarTypes,
|
||||
storageEntry.type.asMap.value.toString()
|
||||
]);
|
||||
|
||||
return [
|
||||
`arg: ${similarTypes.map((type) => formatType(allDefs, type, imports)).join(' | ')}`,
|
||||
formatType(allDefs, addModifier(storageEntry, storageEntry.type.asMap.value.toString()), imports)
|
||||
];
|
||||
} else if (storageEntry.type.isDoubleMap) {
|
||||
// Find similartypes of `key1` and `key2` types
|
||||
const similarTypes1 = getSimilarTypes(allDefs, registry, storageEntry.type.asDoubleMap.key1.toString(), imports);
|
||||
const similarTypes2 = getSimilarTypes(allDefs, registry, storageEntry.type.asDoubleMap.key2.toString(), imports);
|
||||
|
||||
setImports(allDefs, imports, [
|
||||
...similarTypes1,
|
||||
...similarTypes2,
|
||||
storageEntry.type.asDoubleMap.value.toString()
|
||||
]);
|
||||
|
||||
const key1Types = similarTypes1.map((type) => formatType(allDefs, type, imports)).join(' | ');
|
||||
const key2Types = similarTypes2.map((type) => formatType(allDefs, type, imports)).join(' | ');
|
||||
|
||||
return [
|
||||
`key1: ${key1Types}, key2: ${key2Types}`,
|
||||
formatType(allDefs, addModifier(storageEntry, storageEntry.type.asDoubleMap.value.toString()), imports)
|
||||
];
|
||||
}
|
||||
|
||||
throw new Error(`entryArgs: Cannot parse args of entry ${storageEntry.name}`);
|
||||
}
|
||||
|
||||
// Generate types for one module
|
||||
/** @internal */
|
||||
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(isStrict ? '' : indent(6)('[index: string]: QueryableStorageEntry<ApiType>;'))
|
||||
.concat(storage.unwrap().items.map((storageEntry): string => {
|
||||
const [args, returnType] = entrySignature(allDefs, registry, storageEntry, imports);
|
||||
let entryType = 'AugmentedQuery';
|
||||
const entryTypeArgs: string[] = ['ApiType', `(${args}) => Observable<${returnType}>`];
|
||||
|
||||
if (storageEntry.type.isDoubleMap) {
|
||||
entryType = `${entryType}DoubleMap`;
|
||||
const firstKeyTypes = /^key1: (.*), key2/.exec(args)![1];
|
||||
entryTypeArgs.push(firstKeyTypes);
|
||||
}
|
||||
|
||||
return createDocComments(6, storageEntry.documentation) +
|
||||
indent(6)(`${stringLowerFirst(storageEntry.name.toString())}: ${entryType}<${entryTypeArgs.join(', ')}> & QueryableStorageEntry<ApiType>;`);
|
||||
}))
|
||||
.concat([indent(4)('};')]);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
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);
|
||||
const allDefs = Object.entries(allTypes).reduce((defs, [, obj]) => {
|
||||
return Object.entries(obj).reduce((defs, [key, value]) => ({ ...defs, [key]: value }), defs);
|
||||
}, {});
|
||||
const body = meta.asLatest.modules.reduce((acc: string[], mod): string[] => {
|
||||
return acc.concat(generateModule(allDefs, registry, mod, imports, isStrict));
|
||||
}, []);
|
||||
const header = createImportCode(HEADER, imports, [
|
||||
...Object.keys(imports.localTypes).map((moduleName): { file: string; types: string[] } => ({
|
||||
file: `${imports.moduleToPackage[moduleName]}/${moduleName}`,
|
||||
types: Object.keys(imports.localTypes[moduleName])
|
||||
})),
|
||||
{
|
||||
file: 'rxjs',
|
||||
types: ['Observable']
|
||||
}
|
||||
]);
|
||||
const interfaceStart = [
|
||||
"declare module '@polkadot/api/types/storage' {",
|
||||
indent(2)('export interface AugmentedQueries<ApiType> {\n')
|
||||
].join('\n');
|
||||
const interfaceEnd = `\n${indent(2)('}')}\n}`;
|
||||
|
||||
return header
|
||||
.concat(interfaceStart)
|
||||
.concat(body.join('\n'))
|
||||
.concat(interfaceEnd)
|
||||
.concat(FOOTER);
|
||||
});
|
||||
}
|
||||
|
||||
// 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>> = {}, isStrict = false): void {
|
||||
const registry = new TypeRegistry();
|
||||
|
||||
return generateForMeta(registry, new Metadata(registry, data), dest, extraTypes, isStrict);
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import interfaces from '@polkadot/jsonrpc';
|
||||
import * as definitions from '@polkadot/types/interfaces/definitions';
|
||||
import { TypeRegistry } from '@polkadot/types/create';
|
||||
|
||||
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 {
|
||||
writeFile(dest, (): string => {
|
||||
const registry = new TypeRegistry();
|
||||
const imports = createImports({ '@polkadot/types/interfaces': definitions });
|
||||
const body = Object.keys(interfaces).sort().reduce<string[]>((allSections, section): string[] => {
|
||||
const allMethods = Object.keys(interfaces[section].methods).sort().map((key): string => {
|
||||
const method = interfaces[section].methods[key];
|
||||
|
||||
setImports(definitions, imports, [method.type]);
|
||||
|
||||
// FIXME These 2 are too hard to type, I give up
|
||||
if (section === 'state') {
|
||||
if (method.method === 'getStorage') {
|
||||
setImports(definitions, imports, ['Codec']);
|
||||
return ' getStorage<T = Codec>(key: any, block?: Hash | Uint8Array | string): Observable<T>;';
|
||||
} else if (method.method === 'subscribeStorage') {
|
||||
return ' subscribeStorage<T = Codec[]>(keys: any[]): Observable<T>;';
|
||||
}
|
||||
}
|
||||
|
||||
const args = method.params.map((param): string => {
|
||||
const similarTypes = getSimilarTypes(definitions, registry, param.type, imports);
|
||||
setImports(definitions, imports, [param.type, ...similarTypes]);
|
||||
|
||||
return `${param.name}${param.isOptional ? '?' : ''}: ${similarTypes.join(' | ')}`;
|
||||
});
|
||||
|
||||
return createDocComments(6, [method.description]) + indent(6)(`${method.method}(${args.join(', ')}): Observable<${method.type}>;`);
|
||||
});
|
||||
|
||||
return allSections.concat(
|
||||
[
|
||||
` ${section}: {`,
|
||||
...allMethods,
|
||||
' };'
|
||||
].join('\n')
|
||||
);
|
||||
}, []).join('\n');
|
||||
|
||||
const header = createImportCode(HEADER, imports, [
|
||||
...Object.keys(imports.localTypes).map((moduleName): { file: string; types: string[] } => ({
|
||||
file: `@polkadot/types/interfaces/${moduleName}`,
|
||||
types: Object.keys(imports.localTypes[moduleName])
|
||||
})),
|
||||
{
|
||||
file: 'rxjs',
|
||||
types: ['Observable']
|
||||
}
|
||||
]);
|
||||
const interfaceStart = "declare module '@polkadot/rpc-core/types.jsonrpc' {\n export interface RpcInterface {\n";
|
||||
const interfaceEnd = '\n }\n}';
|
||||
|
||||
return header
|
||||
.concat(interfaceStart)
|
||||
.concat(body)
|
||||
.concat(interfaceEnd)
|
||||
.concat(FOOTER);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { TypeDef, TypeDefInfo, TypeDefExtVecFixed } from '@polkadot/types/create/types';
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { getTypeDef } from '@polkadot/types/create';
|
||||
import * as defaultDefinitions from '@polkadot/types/interfaces/definitions';
|
||||
import { isString, stringCamelCase, stringUpperFirst } from '@polkadot/util';
|
||||
|
||||
import { FOOTER, HEADER, TypeImports, createImportCode, createImports, exportInterface, exportType, formatType, setImports, writeFile } from '../util';
|
||||
|
||||
interface Imports extends TypeImports {
|
||||
interfaces: [string, string][];
|
||||
}
|
||||
|
||||
// helper to generate a `readonly <Name>: <Type>;` getter
|
||||
/** @internal */
|
||||
export function createGetter (definitions: object, name = '', type: string, imports: TypeImports): string {
|
||||
setImports(definitions, imports, [type]);
|
||||
|
||||
return ` readonly ${name}: ${type};\n`;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
function errorUnhandled (definitions: object, def: TypeDef, imports: TypeImports): string {
|
||||
throw new Error(`Generate: ${name}: Unhandled type ${TypeDefInfo[def.info]}`);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function tsExport (definitions: object, def: TypeDef, imports: TypeImports): string {
|
||||
return exportInterface(def.name, formatType(definitions, def, imports));
|
||||
}
|
||||
|
||||
const tsBTreeMap = tsExport;
|
||||
const tsBTreeSet = tsExport;
|
||||
const tsCompact = tsExport;
|
||||
const tsOption = tsExport;
|
||||
const tsPlain = tsExport;
|
||||
const tsTuple = tsExport;
|
||||
|
||||
/** @internal */
|
||||
function tsEnum (definitions: object, { name: enumName, sub }: TypeDef, imports: TypeImports): string {
|
||||
setImports(definitions, imports, ['Enum']);
|
||||
|
||||
const keys = (sub as TypeDef[]).map(({ info, name = '', type }): string => {
|
||||
const getter = stringUpperFirst(stringCamelCase(name.replace(' ', '_')));
|
||||
const asGetter = type === 'Null'
|
||||
? ''
|
||||
: createGetter(definitions, `as${getter}`, type, imports);
|
||||
const isGetter = createGetter(definitions, `is${getter}`, 'boolean', imports);
|
||||
|
||||
switch (info) {
|
||||
case TypeDefInfo.Plain:
|
||||
case TypeDefInfo.Vec:
|
||||
return `${isGetter}${asGetter}`;
|
||||
|
||||
default:
|
||||
throw new Error(`Enum: ${enumName}: Unhandled type ${TypeDefInfo[info]}`);
|
||||
}
|
||||
});
|
||||
|
||||
return exportInterface(enumName, 'Enum', keys.join(''));
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function tsResultGetter (definitions: object, resultName = '', getter: 'Ok' | 'Error', def: TypeDef, imports: TypeImports): string {
|
||||
const { info, type } = def;
|
||||
const asGetter = type === 'Null'
|
||||
? ''
|
||||
: createGetter(definitions, `as${getter}`, info === TypeDefInfo.Tuple ? formatType(definitions, def, imports) : type, imports);
|
||||
const isGetter = createGetter(definitions, `is${getter}`, 'boolean', imports);
|
||||
|
||||
switch (info) {
|
||||
case TypeDefInfo.Plain:
|
||||
case TypeDefInfo.Tuple:
|
||||
case TypeDefInfo.Vec:
|
||||
return `${isGetter}${asGetter}`;
|
||||
|
||||
default:
|
||||
throw new Error(`Result: ${resultName}: Unhandled type ${TypeDefInfo[info]}`);
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function tsResult (definitions: object, def: TypeDef, imports: TypeImports): string {
|
||||
const [okDef, errorDef] = (def.sub as TypeDef[]);
|
||||
const inner = [
|
||||
tsResultGetter(definitions, def.name, 'Error', errorDef, imports),
|
||||
tsResultGetter(definitions, def.name, 'Ok', okDef, imports)
|
||||
].join('');
|
||||
|
||||
setImports(definitions, imports, [def.type]);
|
||||
|
||||
return exportInterface(def.name, formatType(definitions, def, imports), inner);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function tsSet (definitions: object, { name: setName, sub }: TypeDef, imports: TypeImports): string {
|
||||
setImports(definitions, imports, ['Set']);
|
||||
|
||||
const types = (sub as TypeDef[]).map(({ name }): string =>
|
||||
createGetter(definitions, `is${name}`, 'boolean', imports)
|
||||
);
|
||||
|
||||
return exportInterface(setName, 'Set', types.join(''));
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function tsStruct (definitions: object, { name: structName, sub }: TypeDef, imports: TypeImports): string {
|
||||
setImports(definitions, imports, ['Struct']);
|
||||
|
||||
const keys = (sub as TypeDef[]).map((typedef): string => {
|
||||
const returnType = formatType(definitions, typedef, imports);
|
||||
|
||||
return createGetter(definitions, typedef.name, returnType, imports);
|
||||
});
|
||||
|
||||
return exportInterface(structName, 'Struct', keys.join(''));
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function tsVec (definitions: object, def: TypeDef, imports: TypeImports): string {
|
||||
const type = def.info === TypeDefInfo.VecFixed
|
||||
? (def.ext as TypeDefExtVecFixed).type
|
||||
: (def.sub as TypeDef).type;
|
||||
|
||||
// FIXME This should be a VecFixed
|
||||
// FIXME Technically Vec has length prefix, so for others this is not 100%
|
||||
if (def.info === TypeDefInfo.VecFixed && type === 'u8') {
|
||||
setImports(definitions, imports, ['Codec']);
|
||||
|
||||
return exportType(def.name, 'Uint8Array, Codec');
|
||||
}
|
||||
|
||||
return exportInterface(def.name, formatType(definitions, def, imports));
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function generateInterfaces (definitions: object, { types }: { types: Record<string, any> }, imports: Imports): [string, string][] {
|
||||
// handlers are defined externally to use - this means that when we do a
|
||||
// `generators[typedef.info](...)` TS will show any unhandled types. Rather
|
||||
// we are being explicit in having no handlers where we do not support (yet)
|
||||
const generators = {
|
||||
[TypeDefInfo.BTreeMap]: tsBTreeMap,
|
||||
[TypeDefInfo.BTreeSet]: tsBTreeSet,
|
||||
[TypeDefInfo.Compact]: tsCompact,
|
||||
[TypeDefInfo.Enum]: tsEnum,
|
||||
[TypeDefInfo.Linkage]: errorUnhandled,
|
||||
[TypeDefInfo.Null]: errorUnhandled,
|
||||
[TypeDefInfo.Option]: tsOption,
|
||||
[TypeDefInfo.Plain]: tsPlain,
|
||||
[TypeDefInfo.Result]: tsResult,
|
||||
[TypeDefInfo.Set]: tsSet,
|
||||
[TypeDefInfo.Struct]: tsStruct,
|
||||
[TypeDefInfo.Tuple]: tsTuple,
|
||||
[TypeDefInfo.Vec]: tsVec,
|
||||
[TypeDefInfo.VecFixed]: tsVec
|
||||
};
|
||||
|
||||
return Object.entries(types).map(([name, type]): [string, string] => {
|
||||
const def = getTypeDef(isString(type) ? type.toString() : JSON.stringify(type), { name });
|
||||
|
||||
return [name, generators[def.info](definitions, def, imports)];
|
||||
});
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function generateTsDefFor (importDefinitions: { [importPath: string]: object }, defName: string, { types }: { types: Record<string, any> }, outputDir: string): void {
|
||||
const imports = { ...createImports(importDefinitions, { types }), interfaces: [] } as Imports;
|
||||
const definitions = imports.definitions;
|
||||
const interfaces = generateInterfaces(definitions, { types }, imports);
|
||||
const sortedDefs = interfaces.sort((a, b): number => a[0].localeCompare(b[0])).map(([, definition]): string => definition).join('\n\n');
|
||||
|
||||
const header = createImportCode(HEADER, imports, [
|
||||
...Object.keys(imports.localTypes).map((moduleName): { file: string; types: string[] } => ({
|
||||
file: `${imports.moduleToPackage[moduleName]}/${moduleName}`,
|
||||
types: Object.keys(imports.localTypes[moduleName])
|
||||
}))
|
||||
]);
|
||||
|
||||
fs.writeFileSync(path.join(outputDir, defName, 'types.ts'), header.concat(sortedDefs).concat(FOOTER), { flag: 'w' });
|
||||
fs.writeFileSync(path.join(outputDir, defName, 'index.ts'), HEADER.concat('export * from \'./types\';').concat(FOOTER), { flag: 'w' });
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function generateTsDef (importDefinitions: { [importPath: string]: object }, outputDir: string, generatingPackage: string): void {
|
||||
writeFile(path.join(outputDir, 'types.ts'), (): string => {
|
||||
const definitions = importDefinitions[generatingPackage];
|
||||
|
||||
Object.entries(definitions).forEach(([defName, obj]): void => {
|
||||
console.log(`\tExtracting interfaces for ${defName}`);
|
||||
|
||||
generateTsDefFor(importDefinitions, defName, obj, outputDir);
|
||||
});
|
||||
|
||||
return HEADER
|
||||
.concat(
|
||||
Object
|
||||
.keys(definitions)
|
||||
.map((moduleName): string => `export * from './${moduleName}/types';`)
|
||||
.join('\n')
|
||||
)
|
||||
.concat(FOOTER);
|
||||
});
|
||||
|
||||
fs.writeFileSync(path.join(outputDir, 'index.ts'), HEADER.concat('export * from \'./types\';').concat(FOOTER), { flag: 'w' });
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export default function generateTsDefDefault (): void {
|
||||
generateTsDef(
|
||||
{ '@polkadot/types/interfaces': defaultDefinitions },
|
||||
'packages/types/src/interfaces',
|
||||
'@polkadot/types/interfaces'
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { ModuleMetadataLatest } from '@polkadot/types/interfaces/metadata';
|
||||
import * as defaultDefs from '@polkadot/types/interfaces/definitions';
|
||||
import { Registry } from '@polkadot/types/types';
|
||||
|
||||
import staticData from '@polkadot/metadata/Metadata/static';
|
||||
import Metadata from '@polkadot/metadata/Metadata';
|
||||
import { Text } from '@polkadot/types/primitive';
|
||||
import { TypeRegistry } from '@polkadot/types/create';
|
||||
import { stringCamelCase } from '@polkadot/util';
|
||||
|
||||
import { FOOTER, HEADER, TypeImports, createDocComments, createImportCode, createImports, formatType, getSimilarTypes, indent, setImports, writeFile } from '../util';
|
||||
|
||||
const MAPPED_NAMES: Record<string, string> = {
|
||||
new: 'updated'
|
||||
};
|
||||
|
||||
function mapName (_name: Text): string {
|
||||
const name = stringCamelCase(_name.toString());
|
||||
|
||||
return MAPPED_NAMES[name] || name;
|
||||
}
|
||||
|
||||
// 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, isStrict: boolean): string[] {
|
||||
const allCalls = calls.unwrapOr(null);
|
||||
|
||||
if (!allCalls?.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
setImports(allDefs, imports, ['SubmittableExtrinsic']);
|
||||
|
||||
// NOTE Not removing this concat yet, first see the fallout
|
||||
return [indent(4)(`${stringCamelCase(name.toString())}: {`)]
|
||||
.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);
|
||||
|
||||
setImports(allDefs, imports, [...similarTypes.filter((type): boolean => !type.startsWith('(') && !type.startsWith('{')), typeStr]);
|
||||
|
||||
return [`${nameStr}: ${similarTypes.join(' | ')}`, nameStr, typeStr];
|
||||
})
|
||||
.map(([full]): string => full)
|
||||
.join(', ');
|
||||
|
||||
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>>, isStrict: boolean): void {
|
||||
writeFile(dest, (): string => {
|
||||
const allTypes: Record<string, Record<string, object>> = { '@polkadot/types/interfaces': defaultDefs, ...extraTypes };
|
||||
const imports = createImports(allTypes);
|
||||
const allDefs = Object.entries(allTypes).reduce((defs, [, obj]) => {
|
||||
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, isStrict));
|
||||
}, [] as string[]);
|
||||
const header = createImportCode(HEADER, imports, [
|
||||
...Object.keys(imports.localTypes).map((moduleName): { file: string; types: string[] } => ({
|
||||
file: `${imports.moduleToPackage[moduleName]}/${moduleName}`,
|
||||
types: Object.keys(imports.localTypes[moduleName])
|
||||
})),
|
||||
{
|
||||
file: '@polkadot/api/submittable/types',
|
||||
types: ['SubmittableExtrinsic']
|
||||
}
|
||||
]);
|
||||
const interfaceStart = [
|
||||
"declare module '@polkadot/api/types/submittable' {",
|
||||
indent(2)('export interface AugmentedSubmittables<ApiType> {\n')
|
||||
].join('\n');
|
||||
const interfaceEnd = `\n${indent(2)('}')}\n}`;
|
||||
|
||||
return header
|
||||
.concat(interfaceStart)
|
||||
.concat(body.join('\n'))
|
||||
.concat(interfaceEnd)
|
||||
.concat(FOOTER);
|
||||
});
|
||||
}
|
||||
|
||||
// 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>> = {}, isStrict = false): void {
|
||||
const registry = new TypeRegistry();
|
||||
|
||||
return generateForMeta(registry, new Metadata(registry, data), dest, extraTypes, isStrict);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
export { formatType } from './util/formatting';
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import generateConstsTypes from './generate/consts';
|
||||
import generateInterfaceRegistry from './generate/interfaceRegistry';
|
||||
import generateQueryTypes from './generate/query';
|
||||
import generateRpcTypes from './generate/rpc';
|
||||
import generateTsDef from './generate/tsDef';
|
||||
import generateTxTypes from './generate/tx';
|
||||
|
||||
export default function main (): void {
|
||||
generateInterfaceRegistry();
|
||||
|
||||
generateConstsTypes();
|
||||
generateQueryTypes();
|
||||
generateTxTypes();
|
||||
generateRpcTypes();
|
||||
|
||||
generateTsDef();
|
||||
}
|
||||
@@ -0,0 +1,302 @@
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { MetadataLatest } from '@polkadot/types/interfaces/metadata';
|
||||
|
||||
import fs from 'fs';
|
||||
import interfaces from '@polkadot/jsonrpc';
|
||||
import Decorated from '@polkadot/metadata/Decorated';
|
||||
import rpcdata from '@polkadot/metadata/Metadata/static';
|
||||
import { unwrapStorageType } from '@polkadot/types/primitive/StorageKey';
|
||||
import Call from '@polkadot/types/primitive/Generic/Call';
|
||||
import { TypeRegistry } from '@polkadot/types/create';
|
||||
import { Vec } from '@polkadot/types/codec';
|
||||
import { Text } from '@polkadot/types/primitive';
|
||||
import { stringCamelCase, stringLowerFirst } from '@polkadot/util';
|
||||
|
||||
interface Page {
|
||||
title: string;
|
||||
description: string;
|
||||
sections: {
|
||||
name: string;
|
||||
description?: string;
|
||||
items: {
|
||||
name: string;
|
||||
[bullet: string]: string | Vec<Text>;
|
||||
}[];
|
||||
}[];
|
||||
}
|
||||
|
||||
const STATIC_TEXT = '\n\n(NOTE: These were generated from a static/snapshot view of a recent Substrate master node. Some items may not be available in older nodes, or in any customized implementations.)';
|
||||
|
||||
const DESC_CONSTANTS = `The following sections contain the module constants, also known as parameter types. These can only be changed as part of a runtime upgrade. On the api, these are exposed via \`api.consts.<module>.<method>\`. ${STATIC_TEXT}`;
|
||||
const DESC_EXTRINSICS = `The following sections contain Extrinsics methods are part of the default Substrate runtime. On the api, these are exposed via \`api.tx.<module>.<method>\`. ${STATIC_TEXT}`;
|
||||
const DESC_ERRORS = `This page lists the errors that can be encountered in the different modules. ${STATIC_TEXT}`;
|
||||
const DESC_EVENTS = `Events are emitted for certain operations on the runtime. The following sections describe the events that are part of the default Substrate runtime. ${STATIC_TEXT}`;
|
||||
const DESC_RPC = 'The following sections contain RPC methods that are Remote Calls available by default and allow you to interact with the actual node, query, and submit.';
|
||||
const DESC_STORAGE = `The following sections contain Storage methods are part of the default Substrate runtime. On the api, these are exposed via \`api.query.<module>.<method>\`. ${STATIC_TEXT}`;
|
||||
|
||||
/** @internal */
|
||||
function documentationVecToMarkdown (docLines: Vec<Text>, indent = 0): string {
|
||||
const md = docLines
|
||||
.map((docLine) => docLine && docLine.substring(1)) // trim the leading space
|
||||
.reduce((md, docLine): string => // generate paragraphs
|
||||
!docLine.trim().length
|
||||
? `${md}\n\n` // empty line
|
||||
: /^[*-]/.test(docLine.trimStart()) && !md.endsWith('\n\n')
|
||||
? `${md}\n\n${docLine}` // line calling for a preceding linebreak
|
||||
: `${md}${docLine // line continuing the preceding line
|
||||
.replace(/^# <weight>$/g, '\\# \\<weight>\n\n')
|
||||
.replace(/^# <\/weight>$/g, '\n\n\\# \\</weight>')
|
||||
.replace(/^#{1,3} /, '#### ')} `
|
||||
, '');
|
||||
// prefix each line with indentation
|
||||
return md && md.split('\n\n').map(line => `${' '.repeat(indent)}${line}`).join('\n\n');
|
||||
}
|
||||
|
||||
function renderPage (page: Page): string {
|
||||
let md = `## ${page.title}\n\n`;
|
||||
|
||||
if (page.description) {
|
||||
md += `${page.description}\n\n`;
|
||||
}
|
||||
|
||||
// index
|
||||
page.sections.forEach(section => {
|
||||
md += `- **[${stringCamelCase(section.name)}](#${stringCamelCase(section.name).toLowerCase()})**\n\n`;
|
||||
});
|
||||
|
||||
// contents
|
||||
page.sections.forEach(section => {
|
||||
md += `\n___\n\n\n## ${section.name}\n`;
|
||||
if (section.description) { md += `\n_${section.description}_\n`; }
|
||||
|
||||
section.items.forEach((item) => {
|
||||
md += ` \n### ${item.name}`;
|
||||
|
||||
Object.keys(item).filter(i => i !== 'name').forEach(bullet => {
|
||||
md += `\n- **${bullet}**: ${item[bullet] instanceof Vec ? documentationVecToMarkdown(item[bullet] as Vec<Text>, 2) : item[bullet]}`;
|
||||
});
|
||||
|
||||
md += '\n';
|
||||
});
|
||||
});
|
||||
|
||||
return md;
|
||||
}
|
||||
|
||||
function sortByName<T extends { name: any }> (a: T, b: T): number {
|
||||
// case insensitive (all-uppercase) sorting
|
||||
return a.name.toString().toUpperCase().localeCompare(b.name.toString().toUpperCase());
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function addRpc (): string {
|
||||
return renderPage({
|
||||
title: 'JSON-RPC',
|
||||
description: DESC_RPC,
|
||||
sections: Object.keys(interfaces)
|
||||
.sort()
|
||||
.map((sectionName) => {
|
||||
const section = interfaces[sectionName];
|
||||
|
||||
return {
|
||||
name: sectionName,
|
||||
description: section.description,
|
||||
items: Object.keys(section.methods)
|
||||
.sort()
|
||||
.map((methodName) => {
|
||||
const method = section.methods[methodName];
|
||||
const args = method.params.map(({ name, isOptional, type }): string => {
|
||||
return name + (isOptional ? '?' : '') + ': `' + type + '`';
|
||||
}).join(', ');
|
||||
const type = '`' + method.type + '`';
|
||||
|
||||
return {
|
||||
name: `${methodName}(${args}): ${type}`,
|
||||
jsonrpc: `${sectionName}_${methodName}`,
|
||||
interface: `api.rpc.${sectionName}.${methodName}`,
|
||||
...(method.description && { summary: method.description })
|
||||
};
|
||||
})
|
||||
};
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function addConstants (metadata: MetadataLatest): string {
|
||||
return renderPage({
|
||||
title: 'Constants',
|
||||
description: DESC_CONSTANTS,
|
||||
sections: metadata.modules
|
||||
.sort(sortByName)
|
||||
.filter((moduleMetadata) => !moduleMetadata.constants.isEmpty)
|
||||
.map((moduleMetadata) => {
|
||||
const sectionName = stringLowerFirst(moduleMetadata.name.toString());
|
||||
|
||||
return {
|
||||
name: sectionName,
|
||||
items: moduleMetadata.constants
|
||||
.sort(sortByName)
|
||||
.map((func) => {
|
||||
const methodName = stringCamelCase(func.name.toString());
|
||||
|
||||
return {
|
||||
name: `${methodName}: ` + '`' + func.type + '`',
|
||||
interface: `api.consts.${sectionName}.${methodName}`,
|
||||
...(func.documentation.length && { summary: func.documentation })
|
||||
};
|
||||
})
|
||||
};
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function addStorage (metadata: MetadataLatest): string {
|
||||
const moduleSections = metadata.modules
|
||||
.sort(sortByName)
|
||||
.filter((moduleMetadata) => !moduleMetadata.storage.isNone)
|
||||
.map((moduleMetadata) => {
|
||||
const sectionName = stringLowerFirst(moduleMetadata.name.toString());
|
||||
|
||||
return {
|
||||
name: sectionName,
|
||||
items: moduleMetadata.storage.unwrap().items
|
||||
.sort(sortByName)
|
||||
.map((func) => {
|
||||
const arg = func.type.isMap
|
||||
? ('`' + func.type.asMap.key.toString() + '`')
|
||||
: func.type.isDoubleMap
|
||||
? ('`' + func.type.asDoubleMap.key1.toString() + ', ' + func.type.asDoubleMap.key2.toString() + '`')
|
||||
: '';
|
||||
const methodName = stringLowerFirst(func.name.toString());
|
||||
let result = unwrapStorageType(func.type);
|
||||
|
||||
if (func.modifier.isOptional) {
|
||||
result = `Option<${result}>`;
|
||||
}
|
||||
|
||||
return {
|
||||
name: `${methodName}(${arg}): ` + '`' + result + '`',
|
||||
interface: `api.query.${sectionName}.${methodName}`,
|
||||
...(func.documentation.length && { summary: func.documentation })
|
||||
};
|
||||
})
|
||||
};
|
||||
});
|
||||
|
||||
const options = { flags: 'r', encoding: 'utf8' };
|
||||
const knownSection = JSON.parse(fs.readFileSync('docs/substrate/storage-known-section.json', options));
|
||||
|
||||
return renderPage({
|
||||
title: 'Storage',
|
||||
description: DESC_STORAGE,
|
||||
sections: moduleSections.concat([knownSection])
|
||||
});
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function addExtrinsics (metadata: MetadataLatest): string {
|
||||
return renderPage({
|
||||
title: 'Extrinsics',
|
||||
description: DESC_EXTRINSICS,
|
||||
sections: metadata.modules
|
||||
.sort(sortByName)
|
||||
.filter((meta) => !meta.calls.isNone && meta.calls.unwrap().length)
|
||||
.map((meta) => {
|
||||
const sectionName = stringCamelCase(meta.name.toString());
|
||||
|
||||
return {
|
||||
name: sectionName,
|
||||
items: meta.calls.unwrap()
|
||||
.sort(sortByName)
|
||||
.map((func) => {
|
||||
const methodName = stringCamelCase(func.name.toString());
|
||||
const args = Call.filterOrigin(func).map(({ name, type }): string => `${name}: ` + '`' + type + '`').join(', ');
|
||||
|
||||
return {
|
||||
name: `${methodName}(${args})`,
|
||||
interface: `api.tx.${sectionName}.${methodName}`,
|
||||
...(func.documentation.length && { summary: func.documentation })
|
||||
};
|
||||
})
|
||||
};
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function addEvents (metadata: MetadataLatest): string {
|
||||
return renderPage({
|
||||
title: 'Events',
|
||||
description: DESC_EVENTS,
|
||||
sections: metadata.modules
|
||||
.sort(sortByName)
|
||||
.filter((meta) => !meta.events.isNone && meta.events.unwrap().length)
|
||||
.map((meta) => ({
|
||||
name: stringCamelCase(meta.name.toString()),
|
||||
items: meta.events.unwrap()
|
||||
.sort(sortByName)
|
||||
.map((func) => {
|
||||
const methodName = func.name.toString();
|
||||
const args = func.args.map((type): string => '`' + type + '`').join(', ');
|
||||
|
||||
return {
|
||||
name: `${methodName}(${args})`,
|
||||
...(func.documentation.length && { summary: func.documentation })
|
||||
};
|
||||
})
|
||||
}))
|
||||
});
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function addErrors (metadata: MetadataLatest): string {
|
||||
return renderPage({
|
||||
title: 'Errors',
|
||||
description: DESC_ERRORS,
|
||||
sections: metadata.modules
|
||||
.sort(sortByName)
|
||||
.filter((moduleMetadata) => !moduleMetadata.errors.isEmpty)
|
||||
.map((moduleMetadata) => ({
|
||||
name: stringLowerFirst(moduleMetadata.name.toString()),
|
||||
items: moduleMetadata.errors
|
||||
.sort(sortByName)
|
||||
.map((error) => ({
|
||||
name: error.name.toString(),
|
||||
...(error.documentation.length && { summary: error.documentation })
|
||||
}))
|
||||
}))
|
||||
});
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function writeFile (name: string, ...chunks: any[]): void {
|
||||
const options = { flags: 'w', encoding: 'utf8' };
|
||||
const writeStream = fs.createWriteStream(name, options);
|
||||
|
||||
writeStream.on('finish', (): void => {
|
||||
console.log(`Completed writing ${name}`);
|
||||
});
|
||||
|
||||
chunks.forEach((chunk): void => {
|
||||
writeStream.write(chunk);
|
||||
});
|
||||
|
||||
writeStream.end();
|
||||
}
|
||||
|
||||
export default function main (): void {
|
||||
const registry = new TypeRegistry();
|
||||
const metadata = new Decorated(registry, rpcdata).metadata.asLatest;
|
||||
|
||||
writeFile('docs/substrate/rpc.md', addRpc());
|
||||
writeFile('docs/substrate/constants.md', addConstants(metadata));
|
||||
writeFile('docs/substrate/storage.md', addStorage(metadata));
|
||||
writeFile('docs/substrate/extrinsics.md', addExtrinsics(metadata));
|
||||
writeFile('docs/substrate/events.md', addEvents(metadata));
|
||||
writeFile('docs/substrate/errors.md', addErrors(metadata));
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { Constructor } from '@polkadot/types/types';
|
||||
|
||||
import UInt from '@polkadot/types/codec/UInt';
|
||||
|
||||
// See if a class is child of another class
|
||||
// FIMXE This could go in util some day
|
||||
/** @internal */
|
||||
export function isChildClass (Parent: Constructor<any>, Child: Constructor<any>): boolean {
|
||||
// https://stackoverflow.com/questions/30993434/check-if-a-constructor-inherits-another-in-es6/30993664
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
return Parent === Child || Parent.isPrototypeOf(Child);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function isCompactEncodable (Child: Constructor<any>): boolean {
|
||||
return isChildClass(UInt, Child);
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
// Copyright 2017-2020 @polkadot/types authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { TypeDef, TypeDefInfo } from '@polkadot/types/create/types';
|
||||
import { Constructor, Registry } from '@polkadot/types/types';
|
||||
|
||||
import { stringLowerFirst } from '@polkadot/util';
|
||||
import { isChildClass, isCompactEncodable } from './class';
|
||||
import { ClassOf, ClassOfUnsafe, getTypeDef } from '@polkadot/types/create';
|
||||
import AbstractInt from '@polkadot/types/codec/AbstractInt';
|
||||
import Compact from '@polkadot/types/codec/Compact';
|
||||
import Enum from '@polkadot/types/codec/Enum';
|
||||
import Option from '@polkadot/types/codec/Option';
|
||||
import Struct from '@polkadot/types/codec/Struct';
|
||||
import Vec from '@polkadot/types/codec/Vec';
|
||||
import GenericAccountId from '@polkadot/types/primitive/Generic/AccountId';
|
||||
import GenericAddress from '@polkadot/types/primitive/Generic/Address';
|
||||
import Vote, { convictionNames as _voteConvictions } from '@polkadot/types/primitive/Generic/Vote';
|
||||
import Null from '@polkadot/types/primitive/Null';
|
||||
import * as primitiveClasses from '@polkadot/types/primitive';
|
||||
|
||||
import { formatType } from './formatting';
|
||||
import { setImports, TypeImports } from './imports';
|
||||
|
||||
function arrayToStrType (arr: string[]): string {
|
||||
return `(${arr.map((c): string => `'${c}'`).join(' | ')})`;
|
||||
}
|
||||
|
||||
const voteConvictions = arrayToStrType(_voteConvictions);
|
||||
|
||||
// From `T`, generate `Compact<T>, Option<T>, Vec<T>`
|
||||
/** @internal */
|
||||
export function getDerivedTypes (definitions: object, type: string, primitiveName: string, imports: TypeImports): string[] {
|
||||
// `primitiveName` represents the actual primitive type our type is mapped to
|
||||
const isCompact = isCompactEncodable((primitiveClasses as any)[primitiveName]);
|
||||
const def = getTypeDef(type);
|
||||
|
||||
setImports(definitions, imports, ['Option', 'Vec', isCompact ? 'Compact' : '']);
|
||||
|
||||
const types = [
|
||||
{
|
||||
info: TypeDefInfo.Option,
|
||||
type,
|
||||
sub: def
|
||||
},
|
||||
{
|
||||
info: TypeDefInfo.Vec,
|
||||
type,
|
||||
sub: def
|
||||
}
|
||||
];
|
||||
if (isCompact) {
|
||||
types.unshift({
|
||||
info: TypeDefInfo.Compact,
|
||||
type,
|
||||
sub: def
|
||||
});
|
||||
}
|
||||
|
||||
const result = types.map(t => formatType(definitions, t, imports)).map(t => `'${t}': ${t};`);
|
||||
result.unshift(`${type}: ${type};`);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Make types a little bit more flexible
|
||||
// - if param instanceof AbstractInt, then param: u64 | Uint8array | AnyNumber
|
||||
// etc
|
||||
/** @internal */
|
||||
export function getSimilarTypes (definitions: object, registry: Registry, type: string, imports: TypeImports): string[] {
|
||||
const possibleTypes = [type];
|
||||
|
||||
if (type === 'Extrinsic') {
|
||||
setImports(definitions, imports, ['IExtrinsic']);
|
||||
return ['IExtrinsic'];
|
||||
} else if (type === 'StorageKey') {
|
||||
// TODO We can do better
|
||||
return ['StorageKey', 'string', 'Uint8Array', 'any'];
|
||||
}
|
||||
|
||||
const Clazz = ClassOfUnsafe(registry, type);
|
||||
|
||||
if (isChildClass(Vec, Clazz)) {
|
||||
const subDef = (getTypeDef(type).sub) as TypeDef;
|
||||
|
||||
if (subDef.info === TypeDefInfo.Plain) {
|
||||
possibleTypes.push(`(${getSimilarTypes(definitions, registry, subDef.type, imports).join(' | ')})[]`);
|
||||
} else if (subDef.info === TypeDefInfo.Tuple) {
|
||||
const subs = (subDef.sub as TypeDef[]).map(({ type }): string =>
|
||||
getSimilarTypes(definitions, registry, type, imports).join(' | ')
|
||||
);
|
||||
|
||||
possibleTypes.push(`([${subs.join(', ')}])[]`);
|
||||
} else {
|
||||
throw new Error(`Unhandled subtype in Vec, ${JSON.stringify(subDef)}`);
|
||||
}
|
||||
} else if (isChildClass(Enum, Clazz)) {
|
||||
const e = new Clazz(registry) as Enum;
|
||||
|
||||
if (e.isBasic) {
|
||||
possibleTypes.push(arrayToStrType(e.defKeys), 'number');
|
||||
} else {
|
||||
// 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(GenericAddress, Clazz)) {
|
||||
possibleTypes.push('Address', 'AccountId', 'AccountIndex', 'string', 'Uint8Array');
|
||||
} else if (isChildClass(GenericAccountId, Clazz)) {
|
||||
possibleTypes.push('string', '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)) {
|
||||
// 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');
|
||||
} else if (isChildClass(Vote, Clazz)) {
|
||||
possibleTypes.push(`{ aye: boolean; conviction?: ${voteConvictions} | number }`, 'boolean', 'string', 'Uint8Array');
|
||||
} else if (isChildClass(Uint8Array, Clazz)) {
|
||||
possibleTypes.push('string', 'Uint8Array');
|
||||
} else if (isChildClass(String, Clazz)) {
|
||||
possibleTypes.push('string');
|
||||
}
|
||||
|
||||
return possibleTypes;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { Text } from '@polkadot/types';
|
||||
|
||||
import { indent } from './formatting';
|
||||
|
||||
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),
|
||||
...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')
|
||||
: '';
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import fs from 'fs';
|
||||
|
||||
export function writeFile (dest: string, generator: () => string): void {
|
||||
console.log(`${dest}\n\tGenerating`);
|
||||
|
||||
const generated = generator();
|
||||
|
||||
console.log('\tWriting');
|
||||
|
||||
fs.writeFileSync(dest, generated, { flag: 'w' });
|
||||
|
||||
console.log('');
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { indent } from './formatting';
|
||||
|
||||
describe('formatting', () => {
|
||||
it('should indent correctly', () => {
|
||||
expect(indent(2)('foo')).toBe(' foo');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,203 @@
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { TypeDef, TypeDefInfo, TypeDefExtVecFixed } from '@polkadot/types/create/types';
|
||||
|
||||
import { getTypeDef } from '@polkadot/types/create';
|
||||
import { paramsNotation } from '@polkadot/types/codec/utils';
|
||||
|
||||
import { setImports, TypeImports } from './imports';
|
||||
|
||||
export const HEADER = '// Auto-generated via `yarn polkadot-types-from-defs`, do not edit\n/* eslint-disable @typescript-eslint/no-empty-interface */\n\n';
|
||||
export const FOOTER = '\n';
|
||||
|
||||
const TYPES_NON_PRIMITIVE = ['Metadata'];
|
||||
|
||||
// creates the import lines
|
||||
/** @internal */
|
||||
export function createImportCode (header: string, imports: TypeImports, checks: { file: string; types: string[] }[]): string {
|
||||
return [
|
||||
{
|
||||
file: '@polkadot/types/types',
|
||||
types: Object.keys(imports.typesTypes)
|
||||
},
|
||||
{
|
||||
file: '@polkadot/types/codec',
|
||||
types: Object
|
||||
.keys(imports.codecTypes)
|
||||
.filter((name): boolean => name !== 'Tuple')
|
||||
},
|
||||
{
|
||||
file: '@polkadot/types/primitive',
|
||||
types: Object
|
||||
.keys(imports.primitiveTypes)
|
||||
.filter((name): boolean => !TYPES_NON_PRIMITIVE.includes(name))
|
||||
},
|
||||
{
|
||||
file: '@polkadot/types',
|
||||
types: Object
|
||||
.keys(imports.primitiveTypes)
|
||||
.filter((name): boolean => TYPES_NON_PRIMITIVE.includes(name))
|
||||
},
|
||||
...checks
|
||||
].reduce((result, { file, types }): string => {
|
||||
return types.length
|
||||
? `${result}import { ${types.sort().join(', ')} } from '${file}';\n`
|
||||
: result;
|
||||
}, header) + '\n';
|
||||
}
|
||||
|
||||
// helper to generate a `export interface <Name> extends <Base> {<Body>}
|
||||
/** @internal */
|
||||
export function exportInterface (name = '', base: string, body = ''): string {
|
||||
// * @description extends [[${base}]]
|
||||
const doc = `/** @name ${name} */\n`;
|
||||
|
||||
return `${doc}export interface ${name} extends ${base} {${body.length ? '\n' : ''}${body}}`;
|
||||
}
|
||||
|
||||
// helper to create an `export type <Name> = <Base>`
|
||||
// but since we don't want type alias (TS doesn't preserve names) we use
|
||||
// interface here.
|
||||
/** @internal */
|
||||
export function exportType (name = '', base: string): string {
|
||||
return exportInterface(name, base);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the inner `K` & `V`, return a `BTreeMap<K, V>` string
|
||||
*/
|
||||
/** @internal */
|
||||
function formatBTreeMap (key: string, val: string): string {
|
||||
return `BTreeMap<${key}, ${val}>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the inner `V`, return a `BTreeSet<V>` string
|
||||
*/
|
||||
/** @internal */
|
||||
function formatBTreeSet (val: string): string {
|
||||
return `BTreeSet<${val}>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the inner `T`, return a `Compact<T>` string
|
||||
*/
|
||||
/** @internal */
|
||||
function formatCompact (inner: string): string {
|
||||
return paramsNotation('Compact', inner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the inner `O` & `E`, return a `Result<O, E>` string
|
||||
*/
|
||||
/** @internal */
|
||||
function formatResult (innerOk: string, innerError: string): string {
|
||||
return `Result<${innerOk}, ${innerError}>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the inner `T`, return a `Option<T>` string
|
||||
*/
|
||||
/** @internal */
|
||||
function formatOption (inner: string): string {
|
||||
return paramsNotation('Option', inner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the inners `T[]`, return a `ITuple<...T>` string
|
||||
*/
|
||||
/** @internal */
|
||||
function formatTuple (inners: string[]): string {
|
||||
return paramsNotation('ITuple', `[${inners.join(', ')}]`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the inner `T`, return a `Vec<T>` string
|
||||
*/
|
||||
/** @internal */
|
||||
function formatVec (inner: string): string {
|
||||
return paramsNotation('Vec', inner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Correctly format a given type
|
||||
*/
|
||||
/** @internal */
|
||||
export function formatType (definitions: object, type: string | TypeDef, imports: TypeImports): string {
|
||||
let typeDef: TypeDef;
|
||||
|
||||
if (typeof type === 'string') {
|
||||
typeDef = getTypeDef(type);
|
||||
} else {
|
||||
typeDef = type;
|
||||
}
|
||||
|
||||
setImports(definitions, imports, [typeDef.type]);
|
||||
|
||||
switch (typeDef.info) {
|
||||
case TypeDefInfo.Compact: {
|
||||
setImports(definitions, imports, ['Compact']);
|
||||
return formatCompact(formatType(definitions, (typeDef.sub as TypeDef).type, imports));
|
||||
}
|
||||
case TypeDefInfo.Option: {
|
||||
setImports(definitions, imports, ['Option']);
|
||||
return formatOption(formatType(definitions, (typeDef.sub as TypeDef).type, imports));
|
||||
}
|
||||
case TypeDefInfo.Plain: {
|
||||
return typeDef.type;
|
||||
}
|
||||
case TypeDefInfo.Vec: {
|
||||
setImports(definitions, imports, ['Vec']);
|
||||
return formatVec(formatType(definitions, (typeDef.sub as TypeDef).type, imports));
|
||||
}
|
||||
case TypeDefInfo.Tuple: {
|
||||
setImports(definitions, imports, ['ITuple']);
|
||||
|
||||
// `(a,b)` gets transformed into `ITuple<[a, b]>`
|
||||
return formatTuple(
|
||||
((typeDef.sub as TypeDef[])
|
||||
.map((sub): string => formatType(definitions, sub.type, imports)))
|
||||
);
|
||||
}
|
||||
case TypeDefInfo.VecFixed: {
|
||||
if ((typeDef.ext as TypeDefExtVecFixed).type === 'u8') {
|
||||
setImports(definitions, imports, ['Raw']);
|
||||
|
||||
// `[u8, 32]` gets transformed into Raw
|
||||
return 'Raw';
|
||||
}
|
||||
setImports(definitions, imports, ['Vec']);
|
||||
return formatVec(formatType(definitions, (typeDef.ext as TypeDefExtVecFixed).type, imports));
|
||||
}
|
||||
case TypeDefInfo.BTreeMap: {
|
||||
setImports(definitions, imports, ['BTreeMap']);
|
||||
const [keyDef, valDef] = (typeDef.sub as TypeDef[]);
|
||||
return formatBTreeMap(formatType(definitions, keyDef.type, imports), formatType(definitions, valDef.type, imports));
|
||||
}
|
||||
case TypeDefInfo.BTreeSet: {
|
||||
setImports(definitions, imports, ['BTreeSet']);
|
||||
const valDef = typeDef.sub as TypeDef;
|
||||
return formatBTreeSet(formatType(definitions, valDef.type, imports));
|
||||
}
|
||||
case TypeDefInfo.Result: {
|
||||
setImports(definitions, imports, ['Result']);
|
||||
const [okDef, errorDef] = (typeDef.sub as TypeDef[]);
|
||||
return formatResult(formatType(definitions, okDef.type, imports), formatType(definitions, errorDef.type, imports));
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Cannot format ${type}.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indent a string with `n` spaces before.
|
||||
*/
|
||||
/** @internal */
|
||||
export function indent (n: number, char = ' '): (str: string) => string {
|
||||
return function (str: string): string {
|
||||
return `${char.repeat(n)}${str}`;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { TypeDefInfo } from '@polkadot/types/create/types';
|
||||
|
||||
import * as codecClasses from '@polkadot/types/codec';
|
||||
import { getTypeDef } from '@polkadot/types/create';
|
||||
import * as primitiveClasses from '@polkadot/types/primitive';
|
||||
|
||||
// these map all the codec and primitive types for import, see the TypeImports below. If
|
||||
// we have an unseen type, it is `undefined`/`false`, if we need to import it, it is `true`
|
||||
type TypeExist = Record<string, boolean>;
|
||||
|
||||
// local and absolute imports map to this format
|
||||
// { [moduleName]: { [typeName]: true } }
|
||||
type TypeExistMap = Record<string, TypeExist>;
|
||||
|
||||
export interface TypeImports {
|
||||
codecTypes: TypeExist; // `import {} from '@polkadot/types/codec`
|
||||
localTypes: TypeExistMap; // `import {} from '../something'`
|
||||
ignoredTypes: string[]; // No need to import these types
|
||||
primitiveTypes: TypeExist; // `import {} from '@polkadot/types/primitive`
|
||||
typesTypes: TypeExist; // `import {} from '@polkadot/types/types`
|
||||
definitions: object; // all definitions
|
||||
typeToModule: Record<string, string>;
|
||||
moduleToPackage: Record<string, string>;
|
||||
}
|
||||
|
||||
// Maps the types as found to the source location. This is used to generate the
|
||||
// imports in the output file, dep-duped and sorted
|
||||
/** @internal */
|
||||
export function setImports (allDefs: object, imports: TypeImports, types: string[]): void {
|
||||
const { codecTypes, localTypes, ignoredTypes, primitiveTypes, typesTypes } = imports;
|
||||
|
||||
types.forEach((type): void => {
|
||||
if (ignoredTypes.includes(type)) {
|
||||
// do nothing
|
||||
} else if (['AnyNumber', 'CallFunction', 'Codec', 'IExtrinsic', 'ITuple'].includes(type)) {
|
||||
typesTypes[type] = true;
|
||||
} else if ((codecClasses as any)[type]) {
|
||||
codecTypes[type] = true;
|
||||
} else if ((primitiveClasses as any)[type] || type === 'Metadata') {
|
||||
primitiveTypes[type] = true;
|
||||
} else if (type.includes('<') || type.includes('(') || type.includes('[')) {
|
||||
// If the type is a bit special (tuple, fixed u8, nested type...), then we
|
||||
// need to parse it with `getTypeDef`.
|
||||
const typeDef = getTypeDef(type);
|
||||
|
||||
setImports(allDefs, imports, [TypeDefInfo[typeDef.info]]);
|
||||
|
||||
// TypeDef.sub is a `TypeDef | TypeDef[]`
|
||||
if (Array.isArray(typeDef.sub)) {
|
||||
typeDef.sub.forEach((subType): void => setImports(allDefs, imports, [subType.type]));
|
||||
} else if (typeDef.sub) {
|
||||
// typeDef.sub is a TypeDef in this case
|
||||
setImports(allDefs, imports, [typeDef.sub.type]);
|
||||
}
|
||||
} else {
|
||||
// find this module inside the exports from the rest
|
||||
const [moduleName] = Object.entries(allDefs).find(([, { types }]): boolean =>
|
||||
Object.keys(types).includes(type)
|
||||
) || [null];
|
||||
|
||||
if (moduleName) {
|
||||
localTypes[moduleName][type] = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Create an Imports object, can be prefilled with `ignoredTypes`
|
||||
/** @internal */
|
||||
export function createImports (importDefinitions: Record<string, object>, { types }: { types: Record<string, any> } = { types: {} }): TypeImports {
|
||||
const definitions = {} as Record<string, object>;
|
||||
const typeToModule = {} as Record<string, string>;
|
||||
const moduleToPackage = {} as Record<string, string>;
|
||||
|
||||
Object.entries(importDefinitions).forEach(([packagePath, packageDef]): void => {
|
||||
Object.entries(packageDef).forEach(([name, moduleDef]): void => {
|
||||
if (definitions[name]) {
|
||||
throw new Error(`Duplicated module: ${name}. Packages: ${packagePath}, ${moduleToPackage[name]}`);
|
||||
}
|
||||
|
||||
definitions[name] = moduleDef;
|
||||
moduleToPackage[name] = packagePath;
|
||||
|
||||
Object.keys(moduleDef.types).forEach((type): void => {
|
||||
if (typeToModule[type]) {
|
||||
throw new Error(`Duplicated type: ${type}. Modules: ${name}, ${typeToModule[type]}`);
|
||||
}
|
||||
|
||||
typeToModule[type] = name;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
codecTypes: {},
|
||||
localTypes: Object.keys(definitions).reduce((local: Record<string, TypeExist>, mod): Record<string, TypeExist> => {
|
||||
local[mod] = {};
|
||||
|
||||
return local;
|
||||
}, {}),
|
||||
ignoredTypes: Object.keys(types),
|
||||
primitiveTypes: {},
|
||||
typesTypes: {},
|
||||
definitions,
|
||||
typeToModule,
|
||||
moduleToPackage
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// Copyright 2017-2020 @polkadot/typegen authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
export * from './derived';
|
||||
export * from './docs';
|
||||
export * from './file';
|
||||
export * from './formatting';
|
||||
export * from './imports';
|
||||
Reference in New Issue
Block a user