@clarigen/cli 0.3.6 → 1.0.0-next.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/clarinet-config.js +13 -14
- package/dist/commands/index.js +9 -9
- package/dist/config.js +42 -19
- package/dist/generate/declaration.js +49 -86
- package/dist/generate/files.js +36 -30
- package/dist/start.js +1 -1
- package/dist/utils.js +25 -28
- package/package.json +9 -7
- package/src/clarinet-config.ts +13 -8
- package/src/commands/index.ts +2 -2
- package/src/config.ts +50 -32
- package/src/generate/declaration.ts +33 -57
- package/src/generate/files.ts +39 -36
- package/src/utils.ts +13 -14
- package/dist/commands/contract.js +0 -33
- package/src/commands/contract.ts +0 -35
package/dist/clarinet-config.js
CHANGED
|
@@ -4,21 +4,22 @@ exports.getClarinetAccounts = exports.sortClarinetContracts = exports.getContrac
|
|
|
4
4
|
const j_toml_1 = require("@ltd/j-toml");
|
|
5
5
|
const path_1 = require("path");
|
|
6
6
|
const promises_1 = require("fs/promises");
|
|
7
|
-
const wallet_sdk_1 = require("
|
|
7
|
+
const wallet_sdk_1 = require("micro-stacks/wallet-sdk");
|
|
8
8
|
const toposort_1 = require("toposort");
|
|
9
|
+
const crypto_1 = require("micro-stacks/crypto");
|
|
9
10
|
async function getClarinetDevConfig(folder) {
|
|
10
|
-
const baseConfigPath = path_1.resolve(folder, 'settings', 'Devnet.toml');
|
|
11
|
-
const configContents = await promises_1.readFile(baseConfigPath, { encoding: 'utf-8' });
|
|
12
|
-
const config = j_toml_1.parse(configContents, 1.0, '\n', true, {
|
|
11
|
+
const baseConfigPath = (0, path_1.resolve)(folder, 'settings', 'Devnet.toml');
|
|
12
|
+
const configContents = await (0, promises_1.readFile)(baseConfigPath, { encoding: 'utf-8' });
|
|
13
|
+
const config = (0, j_toml_1.parse)(configContents, 1.0, '\n', true, {
|
|
13
14
|
longer: true,
|
|
14
15
|
});
|
|
15
16
|
return config;
|
|
16
17
|
}
|
|
17
18
|
exports.getClarinetDevConfig = getClarinetDevConfig;
|
|
18
19
|
async function getClarinetConfig(folder) {
|
|
19
|
-
const baseConfigPath = path_1.resolve(folder, 'Clarinet.toml');
|
|
20
|
-
const configContents = await promises_1.readFile(baseConfigPath, { encoding: 'utf-8' });
|
|
21
|
-
const config = j_toml_1.parse(configContents, 1.0, '\n', true);
|
|
20
|
+
const baseConfigPath = (0, path_1.resolve)(folder, 'Clarinet.toml');
|
|
21
|
+
const configContents = await (0, promises_1.readFile)(baseConfigPath, { encoding: 'utf-8' });
|
|
22
|
+
const config = (0, j_toml_1.parse)(configContents, 1.0, '\n', true);
|
|
22
23
|
return config;
|
|
23
24
|
}
|
|
24
25
|
exports.getClarinetConfig = getClarinetConfig;
|
|
@@ -26,12 +27,13 @@ async function getContractsFromClarinet(folder, accounts) {
|
|
|
26
27
|
const clarinetConfig = await getClarinetConfig(folder);
|
|
27
28
|
const deployerAddress = accounts.deployer.address;
|
|
28
29
|
const sortedContracts = sortClarinetContracts(clarinetConfig.contracts);
|
|
29
|
-
const contracts = sortedContracts.map(contractName => {
|
|
30
|
+
const contracts = sortedContracts.map((contractName) => {
|
|
30
31
|
const info = clarinetConfig.contracts[contractName];
|
|
31
32
|
const file = info.path.replace(/^contracts\//, '');
|
|
32
33
|
return {
|
|
33
34
|
file,
|
|
34
35
|
address: deployerAddress,
|
|
36
|
+
name: contractName,
|
|
35
37
|
};
|
|
36
38
|
});
|
|
37
39
|
return contracts;
|
|
@@ -44,19 +46,16 @@ function sortClarinetContracts(contractsConfig) {
|
|
|
44
46
|
nodes.push(contractName);
|
|
45
47
|
info.depends_on.forEach((dependency) => edges.push([contractName, dependency]));
|
|
46
48
|
});
|
|
47
|
-
const sorted = toposort_1.array(nodes, edges).reverse();
|
|
49
|
+
const sorted = (0, toposort_1.array)(nodes, edges).reverse();
|
|
48
50
|
return sorted;
|
|
49
51
|
}
|
|
50
52
|
exports.sortClarinetContracts = sortClarinetContracts;
|
|
51
53
|
async function getClarinetAccounts(folder) {
|
|
52
54
|
const devConfig = await getClarinetDevConfig(folder);
|
|
53
55
|
const accountEntries = await Promise.all(Object.entries(devConfig.accounts).map(async ([key, info]) => {
|
|
54
|
-
const wallet = await wallet_sdk_1.generateWallet(
|
|
55
|
-
secretKey: info.mnemonic,
|
|
56
|
-
password: 'password',
|
|
57
|
-
});
|
|
56
|
+
const wallet = await (0, wallet_sdk_1.generateWallet)(info.mnemonic, 'password');
|
|
58
57
|
const [account] = wallet.accounts;
|
|
59
|
-
const address = wallet_sdk_1.
|
|
58
|
+
const address = (0, wallet_sdk_1.getStxAddressFromAccount)(account, crypto_1.StacksNetworkVersion.testnetP2PKH);
|
|
60
59
|
return [
|
|
61
60
|
key,
|
|
62
61
|
{
|
package/dist/commands/index.js
CHANGED
|
@@ -15,12 +15,12 @@ class Generate extends command_1.Command {
|
|
|
15
15
|
const cwd = process.cwd();
|
|
16
16
|
if (flags.watch) {
|
|
17
17
|
const spinner = ora('Generating files').start();
|
|
18
|
-
const { contractsDir } = await config_1.
|
|
19
|
-
const watcher = chokidar_1.watch([contractsDir], {
|
|
18
|
+
const { contractsDir } = await (0, config_1.getProjectConfig)(cwd);
|
|
19
|
+
const watcher = (0, chokidar_1.watch)([contractsDir], {
|
|
20
20
|
cwd,
|
|
21
21
|
});
|
|
22
22
|
try {
|
|
23
|
-
await utils_1.generateProject(cwd);
|
|
23
|
+
await (0, utils_1.generateProject)(cwd);
|
|
24
24
|
spinner.succeed(`Finished generating files. Watching for changes.`);
|
|
25
25
|
}
|
|
26
26
|
catch (error) {
|
|
@@ -28,17 +28,17 @@ class Generate extends command_1.Command {
|
|
|
28
28
|
spinner.fail(`Error generating files.\n${error.message}`);
|
|
29
29
|
}
|
|
30
30
|
watcher.on('change', async (path) => {
|
|
31
|
-
const file = path_1.basename(path);
|
|
31
|
+
const file = (0, path_1.basename)(path);
|
|
32
32
|
spinner.clear();
|
|
33
|
-
spinner.start(`Change detected for ${chalk_1.green(file)}, generating.`);
|
|
33
|
+
spinner.start(`Change detected for ${(0, chalk_1.green)(file)}, generating.`);
|
|
34
34
|
try {
|
|
35
|
-
await utils_1.generateProject(cwd);
|
|
36
|
-
spinner.succeed(`Finished generating files for ${chalk_1.green(file)}. Watching for changes.`);
|
|
35
|
+
await (0, utils_1.generateProject)(cwd);
|
|
36
|
+
spinner.succeed(`Finished generating files for ${(0, chalk_1.green)(file)}. Watching for changes.`);
|
|
37
37
|
}
|
|
38
38
|
catch (error) {
|
|
39
39
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
40
40
|
const msg = error.message;
|
|
41
|
-
spinner.fail(`Error after saving ${chalk_1.red(file)}.\n${msg}`);
|
|
41
|
+
spinner.fail(`Error after saving ${(0, chalk_1.red)(file)}.\n${msg}`);
|
|
42
42
|
}
|
|
43
43
|
});
|
|
44
44
|
process.on('SIGINT', async () => {
|
|
@@ -47,7 +47,7 @@ class Generate extends command_1.Command {
|
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
49
|
else {
|
|
50
|
-
await utils_1.generateProject(cwd);
|
|
50
|
+
await (0, utils_1.generateProject)(cwd);
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
}
|
package/dist/config.js
CHANGED
|
@@ -1,31 +1,54 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getConfigFile = void 0;
|
|
3
|
+
exports.getProjectConfig = exports.getConfigFile = exports.configFileExists = exports.configFilePath = exports.defaultConfigFile = void 0;
|
|
4
4
|
const path_1 = require("path");
|
|
5
5
|
const promises_1 = require("fs/promises");
|
|
6
|
+
const fs_1 = require("fs");
|
|
6
7
|
const clarinet_config_1 = require("./clarinet-config");
|
|
8
|
+
exports.defaultConfigFile = {
|
|
9
|
+
outputDir: 'src/clarigen',
|
|
10
|
+
clarinet: '.',
|
|
11
|
+
};
|
|
12
|
+
function configFilePath(rootPath) {
|
|
13
|
+
return (0, path_1.resolve)(rootPath, 'clarigen.config.json');
|
|
14
|
+
}
|
|
15
|
+
exports.configFilePath = configFilePath;
|
|
16
|
+
async function configFileExists(configPath) {
|
|
17
|
+
try {
|
|
18
|
+
await (0, promises_1.access)(configPath, fs_1.constants.R_OK);
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.configFileExists = configFileExists;
|
|
7
26
|
async function getConfigFile(rootPath) {
|
|
8
|
-
const fullPath =
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if ('clarinet' in configFile) {
|
|
14
|
-
const clarinetPath = path_1.resolve(rootPath, configFile.clarinet);
|
|
15
|
-
const accounts = await clarinet_config_1.getClarinetAccounts(clarinetPath);
|
|
16
|
-
const contracts = await clarinet_config_1.getContractsFromClarinet(clarinetPath, accounts);
|
|
17
|
-
const contractsDir = path_1.relative(process.cwd(), path_1.join(configFile.clarinet, 'contracts'));
|
|
27
|
+
const fullPath = configFilePath(rootPath);
|
|
28
|
+
const exists = await configFileExists(fullPath);
|
|
29
|
+
if (exists) {
|
|
30
|
+
const configContents = await (0, promises_1.readFile)(fullPath, { encoding: 'utf-8' });
|
|
31
|
+
const configFile = JSON.parse(configContents);
|
|
18
32
|
return {
|
|
33
|
+
...exports.defaultConfigFile,
|
|
19
34
|
...configFile,
|
|
20
|
-
contracts,
|
|
21
|
-
contractsDir,
|
|
22
|
-
accounts,
|
|
23
35
|
};
|
|
24
36
|
}
|
|
25
|
-
|
|
26
|
-
throw new Error('Config file missing "contracts"');
|
|
27
|
-
if (!configFile.contractsDir)
|
|
28
|
-
throw new Error('Config file missing "contractDir"');
|
|
29
|
-
return configFile;
|
|
37
|
+
return exports.defaultConfigFile;
|
|
30
38
|
}
|
|
31
39
|
exports.getConfigFile = getConfigFile;
|
|
40
|
+
async function getProjectConfig(rootPath) {
|
|
41
|
+
const configFile = await getConfigFile(rootPath);
|
|
42
|
+
const clarinetPath = (0, path_1.resolve)(rootPath, configFile.clarinet || '.');
|
|
43
|
+
const accounts = await (0, clarinet_config_1.getClarinetAccounts)(clarinetPath);
|
|
44
|
+
const contracts = await (0, clarinet_config_1.getContractsFromClarinet)(clarinetPath, accounts);
|
|
45
|
+
const contractsDir = (0, path_1.relative)(process.cwd(), (0, path_1.join)(configFile.clarinet, 'contracts'));
|
|
46
|
+
return {
|
|
47
|
+
...configFile,
|
|
48
|
+
contracts,
|
|
49
|
+
contractsDir,
|
|
50
|
+
accounts,
|
|
51
|
+
clarinet: configFile.clarinet || '.',
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
exports.getProjectConfig = getProjectConfig;
|
|
@@ -1,57 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const transactions_1 = require("
|
|
3
|
+
exports.makePureTypes = exports.jsTypeFromAbiType = void 0;
|
|
4
|
+
const transactions_1 = require("micro-stacks/transactions");
|
|
5
5
|
const core_1 = require("@clarigen/core");
|
|
6
|
-
const
|
|
7
|
-
if (transactions_1.isClarityAbiPrimitive(val)) {
|
|
8
|
-
if (val === 'uint128') {
|
|
9
|
-
return 'ClarityTypes.UIntCV';
|
|
10
|
-
}
|
|
11
|
-
else if (val === 'int128') {
|
|
12
|
-
return 'ClarityTypes.IntCV';
|
|
13
|
-
}
|
|
14
|
-
else if (val === 'bool') {
|
|
15
|
-
return 'ClarityTypes.BooleanCV';
|
|
16
|
-
}
|
|
17
|
-
else if (val === 'principal') {
|
|
18
|
-
return 'ClarityTypes.PrincipalCV';
|
|
19
|
-
}
|
|
20
|
-
else if (val === 'none') {
|
|
21
|
-
return 'ClarityTypes.NoneCV';
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
throw new Error(`Unexpected Clarity ABI type primitive: ${JSON.stringify(val)}`);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
else if (transactions_1.isClarityAbiBuffer(val)) {
|
|
28
|
-
return 'ClarityTypes.BufferCV';
|
|
29
|
-
}
|
|
30
|
-
else if (transactions_1.isClarityAbiResponse(val)) {
|
|
31
|
-
return 'ClarityTypes.ResponseCV';
|
|
32
|
-
}
|
|
33
|
-
else if (transactions_1.isClarityAbiOptional(val)) {
|
|
34
|
-
return 'ClarityTypes.OptionalCV';
|
|
35
|
-
}
|
|
36
|
-
else if (transactions_1.isClarityAbiTuple(val)) {
|
|
37
|
-
return 'ClarityTypes.TupleCV';
|
|
38
|
-
}
|
|
39
|
-
else if (transactions_1.isClarityAbiList(val)) {
|
|
40
|
-
return 'ClarityTypes.ListCV';
|
|
41
|
-
}
|
|
42
|
-
else if (transactions_1.isClarityAbiStringAscii(val)) {
|
|
43
|
-
return 'ClarityTypes.StringAsciiCV';
|
|
44
|
-
}
|
|
45
|
-
else if (transactions_1.isClarityAbiStringUtf8(val)) {
|
|
46
|
-
return 'ClarityTypes.StringUtf8CV';
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
throw new Error(`Unexpected Clarity ABI type: ${JSON.stringify(val)}`);
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
exports.cvFromType = cvFromType;
|
|
6
|
+
const reserved_words_1 = require("reserved-words");
|
|
53
7
|
const jsTypeFromAbiType = (val, isArgument = false) => {
|
|
54
|
-
if (transactions_1.isClarityAbiPrimitive(val)) {
|
|
8
|
+
if ((0, transactions_1.isClarityAbiPrimitive)(val)) {
|
|
55
9
|
if (val === 'uint128') {
|
|
56
10
|
if (isArgument)
|
|
57
11
|
return 'number | bigint';
|
|
@@ -78,36 +32,36 @@ const jsTypeFromAbiType = (val, isArgument = false) => {
|
|
|
78
32
|
throw new Error(`Unexpected Clarity ABI type primitive: ${JSON.stringify(val)}`);
|
|
79
33
|
}
|
|
80
34
|
}
|
|
81
|
-
else if (transactions_1.isClarityAbiBuffer(val)) {
|
|
82
|
-
return '
|
|
35
|
+
else if ((0, transactions_1.isClarityAbiBuffer)(val)) {
|
|
36
|
+
return 'Uint8Array';
|
|
83
37
|
}
|
|
84
|
-
else if (transactions_1.isClarityAbiResponse(val)) {
|
|
85
|
-
const ok = exports.jsTypeFromAbiType(val.response.ok);
|
|
86
|
-
const err = exports.jsTypeFromAbiType(val.response.error);
|
|
38
|
+
else if ((0, transactions_1.isClarityAbiResponse)(val)) {
|
|
39
|
+
const ok = (0, exports.jsTypeFromAbiType)(val.response.ok);
|
|
40
|
+
const err = (0, exports.jsTypeFromAbiType)(val.response.error);
|
|
87
41
|
return `ClarityTypes.Response<${ok}, ${err}>`;
|
|
88
42
|
}
|
|
89
|
-
else if (transactions_1.isClarityAbiOptional(val)) {
|
|
90
|
-
const innerType = exports.jsTypeFromAbiType(val.optional);
|
|
43
|
+
else if ((0, transactions_1.isClarityAbiOptional)(val)) {
|
|
44
|
+
const innerType = (0, exports.jsTypeFromAbiType)(val.optional);
|
|
91
45
|
return `${innerType} | null`;
|
|
92
46
|
}
|
|
93
|
-
else if (transactions_1.isClarityAbiTuple(val)) {
|
|
47
|
+
else if ((0, transactions_1.isClarityAbiTuple)(val)) {
|
|
94
48
|
const tupleDefs = [];
|
|
95
49
|
val.tuple.forEach(({ name, type }) => {
|
|
96
|
-
const innerType = exports.jsTypeFromAbiType(type);
|
|
50
|
+
const innerType = (0, exports.jsTypeFromAbiType)(type);
|
|
97
51
|
tupleDefs.push(`"${name}": ${innerType}`);
|
|
98
52
|
});
|
|
99
53
|
return `{
|
|
100
54
|
${tupleDefs.join(';\n ')}
|
|
101
55
|
}`;
|
|
102
56
|
}
|
|
103
|
-
else if (transactions_1.isClarityAbiList(val)) {
|
|
104
|
-
const innerType = exports.jsTypeFromAbiType(val.list.type);
|
|
57
|
+
else if ((0, transactions_1.isClarityAbiList)(val)) {
|
|
58
|
+
const innerType = (0, exports.jsTypeFromAbiType)(val.list.type);
|
|
105
59
|
return `${innerType}[]`;
|
|
106
60
|
}
|
|
107
|
-
else if (transactions_1.isClarityAbiStringAscii(val)) {
|
|
61
|
+
else if ((0, transactions_1.isClarityAbiStringAscii)(val)) {
|
|
108
62
|
return 'string';
|
|
109
63
|
}
|
|
110
|
-
else if (transactions_1.isClarityAbiStringUtf8(val)) {
|
|
64
|
+
else if ((0, transactions_1.isClarityAbiStringUtf8)(val)) {
|
|
111
65
|
return 'string';
|
|
112
66
|
}
|
|
113
67
|
else if (val === 'trait_reference') {
|
|
@@ -118,40 +72,49 @@ const jsTypeFromAbiType = (val, isArgument = false) => {
|
|
|
118
72
|
}
|
|
119
73
|
};
|
|
120
74
|
exports.jsTypeFromAbiType = jsTypeFromAbiType;
|
|
121
|
-
|
|
75
|
+
// Check if it's a reserved word, and then camelCase
|
|
76
|
+
function getArgName(name) {
|
|
77
|
+
const camel = (0, core_1.toCamelCase)(name);
|
|
78
|
+
const prefix = (0, reserved_words_1.check)(camel, 6) ? '_' : '';
|
|
79
|
+
return `${prefix}${camel}`;
|
|
80
|
+
}
|
|
81
|
+
const accessToReturnType = {
|
|
82
|
+
public: 'Public',
|
|
83
|
+
read_only: 'ReadOnly',
|
|
84
|
+
private: 'Private',
|
|
85
|
+
};
|
|
86
|
+
function makePureTypes(abi) {
|
|
122
87
|
let typings = '';
|
|
123
88
|
abi.functions.forEach((func, index) => {
|
|
124
|
-
|
|
125
|
-
return;
|
|
126
|
-
let functionLine = `${core_1.toCamelCase(func.name)}: `;
|
|
89
|
+
let functionLine = `${(0, core_1.toCamelCase)(func.name)}: `;
|
|
127
90
|
const args = func.args.map((arg) => {
|
|
128
|
-
return `${
|
|
91
|
+
return `${getArgName(arg.name)}: ${(0, exports.jsTypeFromAbiType)(arg.type, true)}`;
|
|
129
92
|
});
|
|
130
93
|
functionLine += `(${args.join(', ')}) => `;
|
|
94
|
+
const funcType = accessToReturnType[func.access];
|
|
95
|
+
functionLine += `ContractCalls.${funcType}<`;
|
|
131
96
|
if (func.access === 'public') {
|
|
132
97
|
const { type } = func.outputs;
|
|
133
|
-
if (!transactions_1.isClarityAbiResponse(type))
|
|
98
|
+
if (!(0, transactions_1.isClarityAbiResponse)(type))
|
|
134
99
|
throw new Error('Expected response type for public function');
|
|
135
|
-
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
functionLine += `<${ok}, ${err}>;`;
|
|
100
|
+
const ok = (0, exports.jsTypeFromAbiType)(type.response.ok);
|
|
101
|
+
const err = (0, exports.jsTypeFromAbiType)(type.response.error);
|
|
102
|
+
functionLine += `${ok}, ${err}>;`;
|
|
139
103
|
}
|
|
140
104
|
else {
|
|
141
|
-
const
|
|
142
|
-
functionLine +=
|
|
143
|
-
// const { type } = func.outputs;
|
|
144
|
-
// if (isClarityAbiResponse(type)) {
|
|
145
|
-
// const ok = jsTypeFromAbiType(type.response.ok);
|
|
146
|
-
// const err = jsTypeFromAbiType(type.response.error);
|
|
147
|
-
// functionLine += `Promise<ClarityTypes.Response<${ok}, ${err}>>;`;
|
|
148
|
-
// } else {
|
|
149
|
-
// const jsType = jsTypeFromAbiType(func.outputs.type);
|
|
150
|
-
// functionLine += `Promise<${jsType}>;`;
|
|
151
|
-
// }
|
|
105
|
+
const returnType = (0, exports.jsTypeFromAbiType)(func.outputs.type);
|
|
106
|
+
functionLine += `${returnType}>;`;
|
|
152
107
|
}
|
|
153
108
|
typings += `${index === 0 ? '' : '\n'} ${functionLine}`;
|
|
154
109
|
});
|
|
110
|
+
abi.maps.forEach((map) => {
|
|
111
|
+
let functionLine = `${(0, core_1.toCamelCase)(map.name)}: `;
|
|
112
|
+
const keyType = (0, exports.jsTypeFromAbiType)(map.key, true);
|
|
113
|
+
const arg = `key: ${keyType}`;
|
|
114
|
+
const valType = (0, exports.jsTypeFromAbiType)(map.value);
|
|
115
|
+
functionLine += `(${arg}) => ContractCalls.Map<${keyType}, ${valType}>;`;
|
|
116
|
+
typings += `\n ${functionLine}`;
|
|
117
|
+
});
|
|
155
118
|
return typings;
|
|
156
|
-
}
|
|
157
|
-
exports.
|
|
119
|
+
}
|
|
120
|
+
exports.makePureTypes = makePureTypes;
|
package/dist/generate/files.js
CHANGED
|
@@ -3,11 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.generateProjectIndexFile = exports.generateTypesFile = exports.generateIndexFile = exports.generateInterfaceFile = exports.generateInterface = void 0;
|
|
4
4
|
const native_bin_1 = require("@clarigen/native-bin");
|
|
5
5
|
const core_1 = require("@clarigen/core");
|
|
6
|
-
const declaration_1 = require("./declaration");
|
|
7
6
|
const path_1 = require("path");
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
const contractName = core_1.getContractNameFromPath(contractFile);
|
|
7
|
+
const __1 = require("..");
|
|
8
|
+
const generateInterface = async ({ provider, contractFile, contractAddress, contractName, }) => {
|
|
11
9
|
const receipt = await provider.runCommand([
|
|
12
10
|
'launch',
|
|
13
11
|
`${contractAddress}.${contractName}`,
|
|
@@ -17,7 +15,7 @@ const generateInterface = async ({ provider: _provider, contractFile, contractAd
|
|
|
17
15
|
'--costs',
|
|
18
16
|
'--assets',
|
|
19
17
|
]);
|
|
20
|
-
if (native_bin_1.hasStdErr(receipt.stderr)) {
|
|
18
|
+
if ((0, native_bin_1.hasStdErr)(receipt.stderr)) {
|
|
21
19
|
throw new Error(`Error on ${contractFile}:
|
|
22
20
|
${receipt.stderr}
|
|
23
21
|
`);
|
|
@@ -47,10 +45,10 @@ const generateInterface = async ({ provider: _provider, contractFile, contractAd
|
|
|
47
45
|
return abi;
|
|
48
46
|
};
|
|
49
47
|
exports.generateInterface = generateInterface;
|
|
50
|
-
const generateInterfaceFile = ({
|
|
51
|
-
const
|
|
52
|
-
const
|
|
53
|
-
const abiString = JSON.stringify(
|
|
48
|
+
const generateInterfaceFile = ({ contractName, abi, }) => {
|
|
49
|
+
const variableName = (0, core_1.toCamelCase)(contractName, true);
|
|
50
|
+
const { clarity_version, ...rest } = abi;
|
|
51
|
+
const abiString = JSON.stringify(rest, null, 2);
|
|
54
52
|
const fileContents = `import { ClarityAbi } from '@clarigen/core';
|
|
55
53
|
|
|
56
54
|
// prettier-ignore
|
|
@@ -59,34 +57,39 @@ export const ${variableName}Interface: ClarityAbi = ${abiString};
|
|
|
59
57
|
return fileContents;
|
|
60
58
|
};
|
|
61
59
|
exports.generateInterfaceFile = generateInterfaceFile;
|
|
62
|
-
const generateIndexFile = ({ contractFile,
|
|
63
|
-
const
|
|
64
|
-
const
|
|
65
|
-
const varName = core_1.toCamelCase(contractName);
|
|
60
|
+
const generateIndexFile = ({ contractFile, contractAddress, contractName, }) => {
|
|
61
|
+
const contractTitle = (0, core_1.toCamelCase)(contractName, true);
|
|
62
|
+
const varName = (0, core_1.toCamelCase)(contractName);
|
|
66
63
|
const contractType = `${contractTitle}Contract`;
|
|
67
|
-
const
|
|
64
|
+
const interfaceVar = `${contractTitle}Interface`;
|
|
65
|
+
const fileContents = `import { pureProxy, Contract } from '@clarigen/core';
|
|
68
66
|
import type { ${contractType} } from './types';
|
|
69
|
-
import { ${
|
|
67
|
+
import { ${interfaceVar} } from './abi';
|
|
70
68
|
export type { ${contractType} } from './types';
|
|
71
69
|
|
|
72
|
-
export
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
70
|
+
export function ${varName}Contract(contractAddress: string, contractName: string) {
|
|
71
|
+
return pureProxy<${contractType}>({
|
|
72
|
+
abi: ${interfaceVar},
|
|
73
|
+
contractAddress,
|
|
74
|
+
contractName,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
76
77
|
|
|
77
78
|
export const ${varName}Info: Contract<${contractType}> = {
|
|
78
79
|
contract: ${varName}Contract,
|
|
79
|
-
address: '${
|
|
80
|
+
address: '${contractAddress}',
|
|
80
81
|
contractFile: '${contractFile}',
|
|
82
|
+
name: '${contractName}',
|
|
83
|
+
abi: ${interfaceVar},
|
|
81
84
|
};
|
|
82
85
|
`;
|
|
83
86
|
return fileContents;
|
|
84
87
|
};
|
|
85
88
|
exports.generateIndexFile = generateIndexFile;
|
|
86
89
|
const generateTypesFile = (abi, contractName) => {
|
|
87
|
-
const name = core_1.toCamelCase(contractName, true);
|
|
88
|
-
const typings =
|
|
89
|
-
const fileContents = `import { ClarityTypes,
|
|
90
|
+
const name = (0, core_1.toCamelCase)(contractName, true);
|
|
91
|
+
const typings = (0, __1.makePureTypes)(abi);
|
|
92
|
+
const fileContents = `import { ClarityTypes, ContractCalls } from '@clarigen/core';
|
|
90
93
|
|
|
91
94
|
// prettier-ignore
|
|
92
95
|
export interface ${name}Contract {
|
|
@@ -97,7 +100,9 @@ ${typings}
|
|
|
97
100
|
};
|
|
98
101
|
exports.generateTypesFile = generateTypesFile;
|
|
99
102
|
const generateProjectIndexFile = (config) => {
|
|
100
|
-
const imports = [
|
|
103
|
+
const imports = [
|
|
104
|
+
"import type { ContractInstances } from '@clarigen/core';",
|
|
105
|
+
];
|
|
101
106
|
const exports = [];
|
|
102
107
|
const contractMap = [];
|
|
103
108
|
let accounts = '';
|
|
@@ -116,12 +121,12 @@ export const accounts = {
|
|
|
116
121
|
};`;
|
|
117
122
|
}
|
|
118
123
|
config.contracts.forEach((contract) => {
|
|
119
|
-
const contractName =
|
|
120
|
-
const contractVar = core_1.toCamelCase(contractName);
|
|
124
|
+
const contractName = contract.name;
|
|
125
|
+
const contractVar = (0, core_1.toCamelCase)(contractName);
|
|
121
126
|
const contractInfo = `${contractVar}Info`;
|
|
122
|
-
const contractInterface = `${core_1.toCamelCase(contractName, true)}Contract`;
|
|
123
|
-
const dirName = path_1.dirname(contract.file);
|
|
124
|
-
const importPath = `'./${path_1.join(dirName || '.', contractName)}'`;
|
|
127
|
+
const contractInterface = `${(0, core_1.toCamelCase)(contractName, true)}Contract`;
|
|
128
|
+
const dirName = (0, path_1.dirname)(contract.file);
|
|
129
|
+
const importPath = `'./${(0, path_1.join)(dirName || '.', contractName)}'`;
|
|
125
130
|
const _import = `import { ${contractInfo} } from ${importPath};`;
|
|
126
131
|
imports.push(_import);
|
|
127
132
|
const _export = `export type { ${contractInterface} } from ${importPath};`;
|
|
@@ -129,9 +134,10 @@ export const accounts = {
|
|
|
129
134
|
const map = `${contractVar}: ${contractInfo},`;
|
|
130
135
|
contractMap.push(map);
|
|
131
136
|
});
|
|
137
|
+
const contractsType = `\nexport type Contracts = ContractInstances<typeof contracts>;\n`;
|
|
132
138
|
const file = `${imports.join('\n')}
|
|
133
139
|
${exports.join('\n')}
|
|
134
|
-
|
|
140
|
+
${contractsType}
|
|
135
141
|
export const contracts = {
|
|
136
142
|
${contractMap.join('\n ')}
|
|
137
143
|
};${accounts}
|
package/dist/start.js
CHANGED
|
@@ -6,4 +6,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const errors_1 = require("@oclif/errors");
|
|
7
7
|
const flush_1 = __importDefault(require("@oclif/command/flush"));
|
|
8
8
|
const index_1 = require("./index");
|
|
9
|
-
index_1.run().then(flush_1.default, errors_1.handle);
|
|
9
|
+
(0, index_1.run)().then(flush_1.default, errors_1.handle);
|
package/dist/utils.js
CHANGED
|
@@ -2,55 +2,52 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.generateProject = exports.generateFilesForContract = void 0;
|
|
4
4
|
const files_1 = require("./generate/files");
|
|
5
|
-
const core_1 = require("@clarigen/core");
|
|
6
5
|
const native_bin_1 = require("@clarigen/native-bin");
|
|
7
6
|
const path_1 = require("path");
|
|
8
7
|
const promises_1 = require("fs/promises");
|
|
9
8
|
const config_1 = require("./config");
|
|
10
|
-
const generateFilesForContract = async ({ contractFile: _contractFile, outputFolder, provider, contractAddress, dirName, }) => {
|
|
11
|
-
const contractFile = path_1.resolve(process.cwd(), _contractFile);
|
|
12
|
-
const
|
|
13
|
-
const abi = await files_1.generateInterface({
|
|
9
|
+
const generateFilesForContract = async ({ contractFile: _contractFile, outputFolder, provider, contractAddress, dirName, contractName, }) => {
|
|
10
|
+
const contractFile = (0, path_1.resolve)(process.cwd(), _contractFile);
|
|
11
|
+
const abi = await (0, files_1.generateInterface)({
|
|
14
12
|
contractFile,
|
|
15
13
|
provider,
|
|
16
14
|
contractAddress,
|
|
15
|
+
contractName,
|
|
17
16
|
});
|
|
18
|
-
const typesFile = files_1.generateTypesFile(abi, contractName);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
contractFile: path_1.relative(process.cwd(), contractFile),
|
|
24
|
-
address: contractAddress || '',
|
|
17
|
+
const typesFile = (0, files_1.generateTypesFile)(abi, contractName);
|
|
18
|
+
const indexFile = (0, files_1.generateIndexFile)({
|
|
19
|
+
contractFile: (0, path_1.relative)(process.cwd(), contractFile),
|
|
20
|
+
contractAddress: contractAddress,
|
|
21
|
+
contractName,
|
|
25
22
|
});
|
|
26
|
-
const abiFile = files_1.generateInterfaceFile({
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
await promises_1.
|
|
30
|
-
await promises_1.writeFile(path_1.resolve(outputPath, '
|
|
31
|
-
await promises_1.writeFile(path_1.resolve(outputPath, '
|
|
32
|
-
await promises_1.writeFile(path_1.resolve(outputPath, 'types.ts'), typesFile);
|
|
23
|
+
const abiFile = (0, files_1.generateInterfaceFile)({ contractName, abi });
|
|
24
|
+
const outputPath = (0, path_1.resolve)(outputFolder, dirName || '.', contractName);
|
|
25
|
+
await (0, promises_1.mkdir)(outputPath, { recursive: true });
|
|
26
|
+
await (0, promises_1.writeFile)((0, path_1.resolve)(outputPath, 'abi.ts'), abiFile);
|
|
27
|
+
await (0, promises_1.writeFile)((0, path_1.resolve)(outputPath, 'index.ts'), indexFile);
|
|
28
|
+
await (0, promises_1.writeFile)((0, path_1.resolve)(outputPath, 'types.ts'), typesFile);
|
|
33
29
|
};
|
|
34
30
|
exports.generateFilesForContract = generateFilesForContract;
|
|
35
31
|
const generateProject = async (projectPath) => {
|
|
36
|
-
const configFile = await config_1.
|
|
32
|
+
const configFile = await (0, config_1.getProjectConfig)(projectPath);
|
|
37
33
|
const { contractsDir, outputDir, contracts } = configFile;
|
|
38
|
-
const outputFolder = path_1.resolve(projectPath, outputDir);
|
|
39
|
-
const provider = await native_bin_1.createClarityBin();
|
|
34
|
+
const outputFolder = (0, path_1.resolve)(projectPath, outputDir);
|
|
35
|
+
const provider = await (0, native_bin_1.createClarityBin)();
|
|
40
36
|
// this needs to be serial
|
|
41
37
|
for (const contract of contracts) {
|
|
42
|
-
const contractFile = path_1.resolve(projectPath, contractsDir, contract.file);
|
|
43
|
-
const dirName = path_1.dirname(contract.file);
|
|
44
|
-
await exports.generateFilesForContract({
|
|
38
|
+
const contractFile = (0, path_1.resolve)(projectPath, contractsDir, contract.file);
|
|
39
|
+
const dirName = (0, path_1.dirname)(contract.file);
|
|
40
|
+
await (0, exports.generateFilesForContract)({
|
|
45
41
|
contractFile,
|
|
46
42
|
outputFolder: outputFolder,
|
|
47
43
|
provider,
|
|
48
44
|
contractAddress: contract.address,
|
|
49
45
|
dirName,
|
|
46
|
+
contractName: contract.name,
|
|
50
47
|
});
|
|
51
48
|
}
|
|
52
|
-
const indexFile = files_1.generateProjectIndexFile(configFile);
|
|
53
|
-
const indexPath = path_1.resolve(outputFolder, 'index.ts');
|
|
54
|
-
await promises_1.writeFile(indexPath, indexFile);
|
|
49
|
+
const indexFile = (0, files_1.generateProjectIndexFile)(configFile);
|
|
50
|
+
const indexPath = (0, path_1.resolve)(outputFolder, 'index.ts');
|
|
51
|
+
await (0, promises_1.writeFile)(indexPath, indexFile);
|
|
55
52
|
};
|
|
56
53
|
exports.generateProject = generateProject;
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@clarigen/cli",
|
|
3
3
|
"description": "A CLI for generating a Typescript interface for a Clarity contract.",
|
|
4
4
|
"author": "Hank Stoever",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "1.0.0-next.7",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"files": [
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"compile": "ncc build src/index.ts --no-source-map-register -e @oclif/command -e @oclif/errors",
|
|
20
20
|
"build-single-file": "yarn compile && oclif-dev readme",
|
|
21
21
|
"build": "rm -rf dist && tsc -b",
|
|
22
|
-
"test": "
|
|
22
|
+
"test": "jest",
|
|
23
23
|
"lint": "tsdx lint",
|
|
24
|
-
"typecheck": "tsc --noEmit",
|
|
24
|
+
"typecheck": "tsc --noEmit -p tsconfig-test.json",
|
|
25
25
|
"prepublishOnly": "yarn build"
|
|
26
26
|
},
|
|
27
27
|
"bin": {
|
|
@@ -40,26 +40,28 @@
|
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@oclif/dev-cli": "^1.26.0",
|
|
42
42
|
"@oclif/errors": "^1.3.4",
|
|
43
|
+
"@types/reserved-words": "0.1.0",
|
|
43
44
|
"@types/toposort": "2.0.3",
|
|
44
45
|
"@vercel/ncc": "0.27.0",
|
|
45
46
|
"oclif": "^1.16.1",
|
|
46
47
|
"ts-node": "^9.1.1"
|
|
47
48
|
},
|
|
48
49
|
"dependencies": {
|
|
49
|
-
"@clarigen/core": "0.
|
|
50
|
-
"@clarigen/native-bin": "0.
|
|
50
|
+
"@clarigen/core": "1.0.0-next.7",
|
|
51
|
+
"@clarigen/native-bin": "1.0.0-next.7",
|
|
51
52
|
"@ltd/j-toml": "1.12.2",
|
|
52
53
|
"@oclif/command": "^1.8.0",
|
|
53
54
|
"@oclif/config": "^1.17.0",
|
|
54
55
|
"@oclif/plugin-help": "3.2.3",
|
|
55
|
-
"@stacks/wallet-sdk": "1.0.0-wallet-sdk.4",
|
|
56
56
|
"chalk": "4.1.0",
|
|
57
57
|
"chokidar": "3.5.1",
|
|
58
|
+
"micro-stacks": "^0.2.0",
|
|
58
59
|
"ora": "5.4.0",
|
|
60
|
+
"reserved-words": "0.1.2",
|
|
59
61
|
"toposort": "2.0.2"
|
|
60
62
|
},
|
|
61
63
|
"publishConfig": {
|
|
62
64
|
"access": "public"
|
|
63
65
|
},
|
|
64
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "735a83b6632362a55f4849b23d6fb7a482a316ae"
|
|
65
67
|
}
|
package/src/clarinet-config.ts
CHANGED
|
@@ -2,8 +2,12 @@ import { parse } from '@ltd/j-toml';
|
|
|
2
2
|
import { resolve } from 'path';
|
|
3
3
|
import { readFile } from 'fs/promises';
|
|
4
4
|
import { ConfigContract } from './config';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
generateWallet,
|
|
7
|
+
getStxAddressFromAccount,
|
|
8
|
+
} from 'micro-stacks/wallet-sdk';
|
|
6
9
|
import { array as toposort } from 'toposort';
|
|
10
|
+
import { StacksNetworkVersion } from 'micro-stacks/crypto';
|
|
7
11
|
|
|
8
12
|
interface ClarinetConfigAccount {
|
|
9
13
|
mnemonic: string;
|
|
@@ -63,14 +67,15 @@ export async function getContractsFromClarinet(
|
|
|
63
67
|
const clarinetConfig = await getClarinetConfig(folder);
|
|
64
68
|
const deployerAddress = accounts.deployer.address;
|
|
65
69
|
const sortedContracts = sortClarinetContracts(clarinetConfig.contracts);
|
|
66
|
-
const contracts: ConfigContract[] = sortedContracts.map(contractName => {
|
|
70
|
+
const contracts: ConfigContract[] = sortedContracts.map((contractName) => {
|
|
67
71
|
const info = clarinetConfig.contracts[contractName];
|
|
68
72
|
const file = info.path.replace(/^contracts\//, '');
|
|
69
73
|
return {
|
|
70
74
|
file,
|
|
71
75
|
address: deployerAddress,
|
|
76
|
+
name: contractName,
|
|
72
77
|
};
|
|
73
|
-
})
|
|
78
|
+
});
|
|
74
79
|
return contracts;
|
|
75
80
|
}
|
|
76
81
|
|
|
@@ -102,12 +107,12 @@ export async function getClarinetAccounts(
|
|
|
102
107
|
const devConfig = await getClarinetDevConfig(folder);
|
|
103
108
|
const accountEntries = await Promise.all(
|
|
104
109
|
Object.entries(devConfig.accounts).map(async ([key, info]) => {
|
|
105
|
-
const wallet = await generateWallet(
|
|
106
|
-
secretKey: info.mnemonic,
|
|
107
|
-
password: 'password',
|
|
108
|
-
});
|
|
110
|
+
const wallet = await generateWallet(info.mnemonic, 'password');
|
|
109
111
|
const [account] = wallet.accounts;
|
|
110
|
-
const address =
|
|
112
|
+
const address = getStxAddressFromAccount(
|
|
113
|
+
account,
|
|
114
|
+
StacksNetworkVersion.testnetP2PKH
|
|
115
|
+
);
|
|
111
116
|
return [
|
|
112
117
|
key,
|
|
113
118
|
{
|
package/src/commands/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command, flags } from '@oclif/command';
|
|
2
2
|
import { generateProject } from '../utils';
|
|
3
|
-
import {
|
|
3
|
+
import { getProjectConfig } from '../config';
|
|
4
4
|
import { watch } from 'chokidar';
|
|
5
5
|
import { basename } from 'path';
|
|
6
6
|
import { red, green } from 'chalk';
|
|
@@ -28,7 +28,7 @@ export class Generate extends Command {
|
|
|
28
28
|
|
|
29
29
|
if (flags.watch) {
|
|
30
30
|
const spinner = ora('Generating files').start();
|
|
31
|
-
const { contractsDir } = await
|
|
31
|
+
const { contractsDir } = await getProjectConfig(cwd);
|
|
32
32
|
const watcher = watch([contractsDir], {
|
|
33
33
|
cwd,
|
|
34
34
|
});
|
package/src/config.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { resolve, join, relative } from 'path';
|
|
2
|
-
import { readFile } from 'fs/promises';
|
|
2
|
+
import { readFile, access } from 'fs/promises';
|
|
3
|
+
import { constants } from 'fs';
|
|
3
4
|
import {
|
|
4
5
|
ClarinetAccounts,
|
|
5
6
|
getClarinetAccounts,
|
|
@@ -9,52 +10,69 @@ import {
|
|
|
9
10
|
export interface ConfigContract {
|
|
10
11
|
address: string;
|
|
11
12
|
file: string;
|
|
13
|
+
name: string;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
|
-
export interface
|
|
16
|
+
export interface ConfigFileContents {
|
|
15
17
|
outputDir: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface ConfigFileWithClarinet extends ConfigFileBase {
|
|
19
18
|
clarinet: string;
|
|
20
19
|
}
|
|
21
20
|
|
|
22
|
-
export interface
|
|
21
|
+
export interface ConfigFile extends ConfigFileContents {
|
|
23
22
|
contractsDir: string;
|
|
24
23
|
contracts: ConfigContract[];
|
|
24
|
+
accounts: ClarinetAccounts;
|
|
25
|
+
clarinet: string;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
export
|
|
28
|
+
export const defaultConfigFile: ConfigFileContents = {
|
|
29
|
+
outputDir: 'src/clarigen',
|
|
30
|
+
clarinet: '.',
|
|
31
|
+
};
|
|
28
32
|
|
|
29
|
-
export
|
|
30
|
-
|
|
31
|
-
accounts: ClarinetAccounts;
|
|
33
|
+
export function configFilePath(rootPath: string) {
|
|
34
|
+
return resolve(rootPath, 'clarigen.config.json');
|
|
32
35
|
}
|
|
33
36
|
|
|
34
|
-
export
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
37
|
+
export async function configFileExists(configPath: string): Promise<boolean> {
|
|
38
|
+
try {
|
|
39
|
+
await access(configPath, constants.R_OK);
|
|
40
|
+
return true;
|
|
41
|
+
} catch (error) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function getConfigFile(
|
|
47
|
+
rootPath: string
|
|
48
|
+
): Promise<ConfigFileContents> {
|
|
49
|
+
const fullPath = configFilePath(rootPath);
|
|
50
|
+
const exists = await configFileExists(fullPath);
|
|
51
|
+
if (exists) {
|
|
52
|
+
const configContents = await readFile(fullPath, { encoding: 'utf-8' });
|
|
53
|
+
const configFile: ConfigFileContents = JSON.parse(configContents);
|
|
49
54
|
return {
|
|
55
|
+
...defaultConfigFile,
|
|
50
56
|
...configFile,
|
|
51
|
-
contracts,
|
|
52
|
-
contractsDir,
|
|
53
|
-
accounts,
|
|
54
57
|
};
|
|
55
58
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
return defaultConfigFile;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export async function getProjectConfig(rootPath: string): Promise<ConfigFile> {
|
|
63
|
+
const configFile = await getConfigFile(rootPath);
|
|
64
|
+
const clarinetPath = resolve(rootPath, configFile.clarinet || '.');
|
|
65
|
+
const accounts = await getClarinetAccounts(clarinetPath);
|
|
66
|
+
const contracts = await getContractsFromClarinet(clarinetPath, accounts);
|
|
67
|
+
const contractsDir = relative(
|
|
68
|
+
process.cwd(),
|
|
69
|
+
join(configFile.clarinet, 'contracts')
|
|
70
|
+
);
|
|
71
|
+
return {
|
|
72
|
+
...configFile,
|
|
73
|
+
contracts,
|
|
74
|
+
contractsDir,
|
|
75
|
+
accounts,
|
|
76
|
+
clarinet: configFile.clarinet || '.',
|
|
77
|
+
};
|
|
60
78
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
ClarityAbiType,
|
|
3
2
|
isClarityAbiBuffer,
|
|
4
3
|
isClarityAbiList,
|
|
5
4
|
isClarityAbiOptional,
|
|
@@ -8,44 +7,10 @@ import {
|
|
|
8
7
|
isClarityAbiStringAscii,
|
|
9
8
|
isClarityAbiStringUtf8,
|
|
10
9
|
isClarityAbiTuple,
|
|
11
|
-
} from '
|
|
10
|
+
} from 'micro-stacks/transactions';
|
|
11
|
+
import { ClarityAbiFunction, ClarityAbiType } from 'micro-stacks/clarity';
|
|
12
12
|
import { toCamelCase, ClarityAbi } from '@clarigen/core';
|
|
13
|
-
|
|
14
|
-
export const cvFromType = (val: ClarityAbiType) => {
|
|
15
|
-
if (isClarityAbiPrimitive(val)) {
|
|
16
|
-
if (val === 'uint128') {
|
|
17
|
-
return 'ClarityTypes.UIntCV';
|
|
18
|
-
} else if (val === 'int128') {
|
|
19
|
-
return 'ClarityTypes.IntCV';
|
|
20
|
-
} else if (val === 'bool') {
|
|
21
|
-
return 'ClarityTypes.BooleanCV';
|
|
22
|
-
} else if (val === 'principal') {
|
|
23
|
-
return 'ClarityTypes.PrincipalCV';
|
|
24
|
-
} else if (val === 'none') {
|
|
25
|
-
return 'ClarityTypes.NoneCV';
|
|
26
|
-
} else {
|
|
27
|
-
throw new Error(
|
|
28
|
-
`Unexpected Clarity ABI type primitive: ${JSON.stringify(val)}`
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
} else if (isClarityAbiBuffer(val)) {
|
|
32
|
-
return 'ClarityTypes.BufferCV';
|
|
33
|
-
} else if (isClarityAbiResponse(val)) {
|
|
34
|
-
return 'ClarityTypes.ResponseCV';
|
|
35
|
-
} else if (isClarityAbiOptional(val)) {
|
|
36
|
-
return 'ClarityTypes.OptionalCV';
|
|
37
|
-
} else if (isClarityAbiTuple(val)) {
|
|
38
|
-
return 'ClarityTypes.TupleCV';
|
|
39
|
-
} else if (isClarityAbiList(val)) {
|
|
40
|
-
return 'ClarityTypes.ListCV';
|
|
41
|
-
} else if (isClarityAbiStringAscii(val)) {
|
|
42
|
-
return 'ClarityTypes.StringAsciiCV';
|
|
43
|
-
} else if (isClarityAbiStringUtf8(val)) {
|
|
44
|
-
return 'ClarityTypes.StringUtf8CV';
|
|
45
|
-
} else {
|
|
46
|
-
throw new Error(`Unexpected Clarity ABI type: ${JSON.stringify(val)}`);
|
|
47
|
-
}
|
|
48
|
-
};
|
|
13
|
+
import { check } from 'reserved-words';
|
|
49
14
|
|
|
50
15
|
export const jsTypeFromAbiType = (
|
|
51
16
|
val: ClarityAbiType,
|
|
@@ -72,7 +37,7 @@ export const jsTypeFromAbiType = (
|
|
|
72
37
|
);
|
|
73
38
|
}
|
|
74
39
|
} else if (isClarityAbiBuffer(val)) {
|
|
75
|
-
return '
|
|
40
|
+
return 'Uint8Array';
|
|
76
41
|
} else if (isClarityAbiResponse(val)) {
|
|
77
42
|
const ok: any = jsTypeFromAbiType(val.response.ok);
|
|
78
43
|
const err: any = jsTypeFromAbiType(val.response.error);
|
|
@@ -103,38 +68,49 @@ export const jsTypeFromAbiType = (
|
|
|
103
68
|
}
|
|
104
69
|
};
|
|
105
70
|
|
|
106
|
-
|
|
71
|
+
// Check if it's a reserved word, and then camelCase
|
|
72
|
+
function getArgName(name: string) {
|
|
73
|
+
const camel = toCamelCase(name);
|
|
74
|
+
const prefix = check(camel, 6) ? '_' : '';
|
|
75
|
+
return `${prefix}${camel}`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const accessToReturnType = {
|
|
79
|
+
public: 'Public',
|
|
80
|
+
read_only: 'ReadOnly',
|
|
81
|
+
private: 'Private',
|
|
82
|
+
} as const;
|
|
83
|
+
|
|
84
|
+
export function makePureTypes(abi: ClarityAbi) {
|
|
107
85
|
let typings = '';
|
|
108
86
|
abi.functions.forEach((func, index) => {
|
|
109
|
-
if (func.access === 'private') return;
|
|
110
87
|
let functionLine = `${toCamelCase(func.name)}: `;
|
|
111
88
|
const args = func.args.map((arg) => {
|
|
112
|
-
return `${
|
|
89
|
+
return `${getArgName(arg.name)}: ${jsTypeFromAbiType(arg.type, true)}`;
|
|
113
90
|
});
|
|
114
91
|
functionLine += `(${args.join(', ')}) => `;
|
|
92
|
+
const funcType = accessToReturnType[func.access];
|
|
93
|
+
functionLine += `ContractCalls.${funcType}<`;
|
|
115
94
|
if (func.access === 'public') {
|
|
116
95
|
const { type } = func.outputs;
|
|
117
96
|
if (!isClarityAbiResponse(type))
|
|
118
97
|
throw new Error('Expected response type for public function');
|
|
119
|
-
functionLine += 'Transaction';
|
|
120
98
|
const ok = jsTypeFromAbiType(type.response.ok);
|
|
121
99
|
const err = jsTypeFromAbiType(type.response.error);
|
|
122
|
-
functionLine +=
|
|
100
|
+
functionLine += `${ok}, ${err}>;`;
|
|
123
101
|
} else {
|
|
124
|
-
const
|
|
125
|
-
functionLine +=
|
|
126
|
-
// const { type } = func.outputs;
|
|
127
|
-
// if (isClarityAbiResponse(type)) {
|
|
128
|
-
// const ok = jsTypeFromAbiType(type.response.ok);
|
|
129
|
-
// const err = jsTypeFromAbiType(type.response.error);
|
|
130
|
-
// functionLine += `Promise<ClarityTypes.Response<${ok}, ${err}>>;`;
|
|
131
|
-
// } else {
|
|
132
|
-
// const jsType = jsTypeFromAbiType(func.outputs.type);
|
|
133
|
-
// functionLine += `Promise<${jsType}>;`;
|
|
134
|
-
// }
|
|
102
|
+
const returnType = jsTypeFromAbiType(func.outputs.type);
|
|
103
|
+
functionLine += `${returnType}>;`;
|
|
135
104
|
}
|
|
136
105
|
typings += `${index === 0 ? '' : '\n'} ${functionLine}`;
|
|
137
106
|
});
|
|
138
|
-
|
|
107
|
+
abi.maps.forEach((map) => {
|
|
108
|
+
let functionLine = `${toCamelCase(map.name)}: `;
|
|
109
|
+
const keyType = jsTypeFromAbiType(map.key, true);
|
|
110
|
+
const arg = `key: ${keyType}`;
|
|
111
|
+
const valType = jsTypeFromAbiType(map.value);
|
|
112
|
+
functionLine += `(${arg}) => ContractCalls.Map<${keyType}, ${valType}>;`;
|
|
113
|
+
typings += `\n ${functionLine}`;
|
|
114
|
+
});
|
|
139
115
|
return typings;
|
|
140
|
-
}
|
|
116
|
+
}
|
package/src/generate/files.ts
CHANGED
|
@@ -1,28 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
createClarityBin,
|
|
4
|
-
hasStdErr,
|
|
5
|
-
} from '@clarigen/native-bin';
|
|
6
|
-
import {
|
|
7
|
-
ClarityAbi,
|
|
8
|
-
toCamelCase,
|
|
9
|
-
getContractNameFromPath,
|
|
10
|
-
} from '@clarigen/core';
|
|
11
|
-
import { makeTypes } from './declaration';
|
|
1
|
+
import { NativeClarityBinProvider, hasStdErr } from '@clarigen/native-bin';
|
|
2
|
+
import { ClarityAbi, toCamelCase } from '@clarigen/core';
|
|
12
3
|
import { ConfigContract, ConfigFile } from '../config';
|
|
13
4
|
import { dirname, resolve, join } from 'path';
|
|
5
|
+
import { makePureTypes } from '..';
|
|
14
6
|
|
|
15
7
|
export const generateInterface = async ({
|
|
16
|
-
provider
|
|
8
|
+
provider,
|
|
17
9
|
contractFile,
|
|
18
|
-
contractAddress
|
|
10
|
+
contractAddress,
|
|
11
|
+
contractName,
|
|
19
12
|
}: {
|
|
20
13
|
contractFile: string;
|
|
21
|
-
provider
|
|
22
|
-
contractAddress
|
|
14
|
+
provider: NativeClarityBinProvider;
|
|
15
|
+
contractAddress: string;
|
|
16
|
+
contractName: string;
|
|
23
17
|
}): Promise<ClarityAbi> => {
|
|
24
|
-
const provider = _provider || (await createClarityBin());
|
|
25
|
-
const contractName = getContractNameFromPath(contractFile);
|
|
26
18
|
const receipt = await provider.runCommand([
|
|
27
19
|
'launch',
|
|
28
20
|
`${contractAddress}.${contractName}`,
|
|
@@ -62,15 +54,15 @@ export const generateInterface = async ({
|
|
|
62
54
|
};
|
|
63
55
|
|
|
64
56
|
export const generateInterfaceFile = ({
|
|
65
|
-
|
|
57
|
+
contractName,
|
|
66
58
|
abi,
|
|
67
59
|
}: {
|
|
68
|
-
|
|
60
|
+
contractName: string;
|
|
69
61
|
abi: ClarityAbi;
|
|
70
62
|
}) => {
|
|
71
|
-
const contractName = getContractNameFromPath(contractFile);
|
|
72
63
|
const variableName = toCamelCase(contractName, true);
|
|
73
|
-
const
|
|
64
|
+
const { clarity_version, ...rest } = abi;
|
|
65
|
+
const abiString = JSON.stringify(rest, null, 2);
|
|
74
66
|
|
|
75
67
|
const fileContents = `import { ClarityAbi } from '@clarigen/core';
|
|
76
68
|
|
|
@@ -83,30 +75,37 @@ export const ${variableName}Interface: ClarityAbi = ${abiString};
|
|
|
83
75
|
|
|
84
76
|
export const generateIndexFile = ({
|
|
85
77
|
contractFile,
|
|
86
|
-
|
|
78
|
+
contractAddress,
|
|
79
|
+
contractName,
|
|
87
80
|
}: {
|
|
88
81
|
contractFile: string;
|
|
89
|
-
|
|
82
|
+
contractAddress: string;
|
|
83
|
+
contractName: string;
|
|
90
84
|
}) => {
|
|
91
|
-
const contractName = getContractNameFromPath(contractFile);
|
|
92
85
|
const contractTitle = toCamelCase(contractName, true);
|
|
93
86
|
const varName = toCamelCase(contractName);
|
|
94
87
|
const contractType = `${contractTitle}Contract`;
|
|
88
|
+
const interfaceVar = `${contractTitle}Interface`;
|
|
95
89
|
|
|
96
|
-
const fileContents = `import {
|
|
90
|
+
const fileContents = `import { pureProxy, Contract } from '@clarigen/core';
|
|
97
91
|
import type { ${contractType} } from './types';
|
|
98
|
-
import { ${
|
|
92
|
+
import { ${interfaceVar} } from './abi';
|
|
99
93
|
export type { ${contractType} } from './types';
|
|
100
94
|
|
|
101
|
-
export
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
95
|
+
export function ${varName}Contract(contractAddress: string, contractName: string) {
|
|
96
|
+
return pureProxy<${contractType}>({
|
|
97
|
+
abi: ${interfaceVar},
|
|
98
|
+
contractAddress,
|
|
99
|
+
contractName,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
105
102
|
|
|
106
103
|
export const ${varName}Info: Contract<${contractType}> = {
|
|
107
104
|
contract: ${varName}Contract,
|
|
108
|
-
address: '${
|
|
105
|
+
address: '${contractAddress}',
|
|
109
106
|
contractFile: '${contractFile}',
|
|
107
|
+
name: '${contractName}',
|
|
108
|
+
abi: ${interfaceVar},
|
|
110
109
|
};
|
|
111
110
|
`;
|
|
112
111
|
|
|
@@ -115,8 +114,8 @@ export const ${varName}Info: Contract<${contractType}> = {
|
|
|
115
114
|
|
|
116
115
|
export const generateTypesFile = (abi: ClarityAbi, contractName: string) => {
|
|
117
116
|
const name = toCamelCase(contractName, true);
|
|
118
|
-
const typings =
|
|
119
|
-
const fileContents = `import { ClarityTypes,
|
|
117
|
+
const typings = makePureTypes(abi);
|
|
118
|
+
const fileContents = `import { ClarityTypes, ContractCalls } from '@clarigen/core';
|
|
120
119
|
|
|
121
120
|
// prettier-ignore
|
|
122
121
|
export interface ${name}Contract {
|
|
@@ -128,7 +127,9 @@ ${typings}
|
|
|
128
127
|
};
|
|
129
128
|
|
|
130
129
|
export const generateProjectIndexFile = (config: ConfigFile) => {
|
|
131
|
-
const imports: string[] = [
|
|
130
|
+
const imports: string[] = [
|
|
131
|
+
"import type { ContractInstances } from '@clarigen/core';",
|
|
132
|
+
];
|
|
132
133
|
const exports: string[] = [];
|
|
133
134
|
const contractMap: string[] = [];
|
|
134
135
|
|
|
@@ -150,7 +151,7 @@ export const accounts = {
|
|
|
150
151
|
}
|
|
151
152
|
|
|
152
153
|
config.contracts.forEach((contract) => {
|
|
153
|
-
const contractName =
|
|
154
|
+
const contractName = contract.name;
|
|
154
155
|
const contractVar = toCamelCase(contractName);
|
|
155
156
|
const contractInfo = `${contractVar}Info`;
|
|
156
157
|
const contractInterface = `${toCamelCase(contractName, true)}Contract`;
|
|
@@ -167,9 +168,11 @@ export const accounts = {
|
|
|
167
168
|
contractMap.push(map);
|
|
168
169
|
});
|
|
169
170
|
|
|
171
|
+
const contractsType = `\nexport type Contracts = ContractInstances<typeof contracts>;\n`;
|
|
172
|
+
|
|
170
173
|
const file = `${imports.join('\n')}
|
|
171
174
|
${exports.join('\n')}
|
|
172
|
-
|
|
175
|
+
${contractsType}
|
|
173
176
|
export const contracts = {
|
|
174
177
|
${contractMap.join('\n ')}
|
|
175
178
|
};${accounts}
|
package/src/utils.ts
CHANGED
|
@@ -5,14 +5,13 @@ import {
|
|
|
5
5
|
generateProjectIndexFile,
|
|
6
6
|
generateTypesFile,
|
|
7
7
|
} from './generate/files';
|
|
8
|
-
import { getContractNameFromPath } from '@clarigen/core';
|
|
9
8
|
import {
|
|
10
9
|
NativeClarityBinProvider,
|
|
11
10
|
createClarityBin,
|
|
12
11
|
} from '@clarigen/native-bin';
|
|
13
12
|
import { resolve, relative, dirname } from 'path';
|
|
14
13
|
import { mkdir, writeFile } from 'fs/promises';
|
|
15
|
-
import {
|
|
14
|
+
import { getProjectConfig } from './config';
|
|
16
15
|
|
|
17
16
|
export const generateFilesForContract = async ({
|
|
18
17
|
contractFile: _contractFile,
|
|
@@ -20,33 +19,32 @@ export const generateFilesForContract = async ({
|
|
|
20
19
|
provider,
|
|
21
20
|
contractAddress,
|
|
22
21
|
dirName,
|
|
22
|
+
contractName,
|
|
23
23
|
}: {
|
|
24
24
|
contractFile: string;
|
|
25
|
-
outputFolder
|
|
26
|
-
provider
|
|
27
|
-
contractAddress
|
|
25
|
+
outputFolder: string;
|
|
26
|
+
provider: NativeClarityBinProvider;
|
|
27
|
+
contractAddress: string;
|
|
28
28
|
dirName?: string;
|
|
29
|
+
contractName: string;
|
|
29
30
|
}) => {
|
|
30
31
|
const contractFile = resolve(process.cwd(), _contractFile);
|
|
31
|
-
const contractName = getContractNameFromPath(contractFile);
|
|
32
32
|
|
|
33
33
|
const abi = await generateInterface({
|
|
34
34
|
contractFile,
|
|
35
35
|
provider,
|
|
36
36
|
contractAddress,
|
|
37
|
+
contractName,
|
|
37
38
|
});
|
|
38
39
|
const typesFile = generateTypesFile(abi, contractName);
|
|
39
|
-
if (!contractAddress && process.env.NODE_ENV !== 'test') {
|
|
40
|
-
console.warn('Please provide an address with every contract.');
|
|
41
|
-
}
|
|
42
40
|
const indexFile = generateIndexFile({
|
|
43
41
|
contractFile: relative(process.cwd(), contractFile),
|
|
44
|
-
|
|
42
|
+
contractAddress: contractAddress,
|
|
43
|
+
contractName,
|
|
45
44
|
});
|
|
46
|
-
const abiFile = generateInterfaceFile({
|
|
45
|
+
const abiFile = generateInterfaceFile({ contractName, abi });
|
|
47
46
|
|
|
48
|
-
const
|
|
49
|
-
const outputPath = resolve(baseDir, dirName || '.', contractName);
|
|
47
|
+
const outputPath = resolve(outputFolder, dirName || '.', contractName);
|
|
50
48
|
await mkdir(outputPath, { recursive: true });
|
|
51
49
|
|
|
52
50
|
await writeFile(resolve(outputPath, 'abi.ts'), abiFile);
|
|
@@ -55,7 +53,7 @@ export const generateFilesForContract = async ({
|
|
|
55
53
|
};
|
|
56
54
|
|
|
57
55
|
export const generateProject = async (projectPath: string) => {
|
|
58
|
-
const configFile = await
|
|
56
|
+
const configFile = await getProjectConfig(projectPath);
|
|
59
57
|
const { contractsDir, outputDir, contracts } = configFile;
|
|
60
58
|
const outputFolder = resolve(projectPath, outputDir);
|
|
61
59
|
const provider = await createClarityBin();
|
|
@@ -69,6 +67,7 @@ export const generateProject = async (projectPath: string) => {
|
|
|
69
67
|
provider,
|
|
70
68
|
contractAddress: contract.address,
|
|
71
69
|
dirName,
|
|
70
|
+
contractName: contract.name,
|
|
72
71
|
});
|
|
73
72
|
}
|
|
74
73
|
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Contract = void 0;
|
|
4
|
-
const command_1 = require("@oclif/command");
|
|
5
|
-
const utils_1 = require("../utils");
|
|
6
|
-
class Contract extends command_1.Command {
|
|
7
|
-
async run() {
|
|
8
|
-
const { argv, flags } = this.parse(Contract);
|
|
9
|
-
const [contractFile] = argv;
|
|
10
|
-
await utils_1.generateFilesForContract({
|
|
11
|
-
contractFile,
|
|
12
|
-
outputFolder: flags.output,
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
exports.Contract = Contract;
|
|
17
|
-
Contract.description = `Generate files for a single contract`;
|
|
18
|
-
Contract.strict = true;
|
|
19
|
-
Contract.hidden = true;
|
|
20
|
-
Contract.flags = {
|
|
21
|
-
help: command_1.flags.help({ char: 'h' }),
|
|
22
|
-
output: command_1.flags.string({
|
|
23
|
-
char: 'o',
|
|
24
|
-
description: 'Output destination folder',
|
|
25
|
-
default: 'clarion',
|
|
26
|
-
}),
|
|
27
|
-
};
|
|
28
|
-
Contract.args = [
|
|
29
|
-
{
|
|
30
|
-
name: 'contract',
|
|
31
|
-
description: 'The file path for your contract',
|
|
32
|
-
},
|
|
33
|
-
];
|
package/src/commands/contract.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { Command, flags } from '@oclif/command';
|
|
2
|
-
import { generateFilesForContract } from '../utils';
|
|
3
|
-
|
|
4
|
-
export class Contract extends Command {
|
|
5
|
-
static description = `Generate files for a single contract`;
|
|
6
|
-
static strict = true;
|
|
7
|
-
static hidden = true;
|
|
8
|
-
|
|
9
|
-
static flags = {
|
|
10
|
-
help: flags.help({ char: 'h' }),
|
|
11
|
-
output: flags.string({
|
|
12
|
-
char: 'o',
|
|
13
|
-
description: 'Output destination folder',
|
|
14
|
-
default: 'clarion',
|
|
15
|
-
}),
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
static args = [
|
|
19
|
-
{
|
|
20
|
-
name: 'contract',
|
|
21
|
-
description: 'The file path for your contract',
|
|
22
|
-
},
|
|
23
|
-
];
|
|
24
|
-
|
|
25
|
-
async run() {
|
|
26
|
-
const { argv, flags } = this.parse(Contract);
|
|
27
|
-
|
|
28
|
-
const [contractFile] = argv;
|
|
29
|
-
|
|
30
|
-
await generateFilesForContract({
|
|
31
|
-
contractFile,
|
|
32
|
-
outputFolder: flags.output,
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
}
|