@ton/blueprint 0.40.0 โ 0.41.0
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/CHANGELOG.md +10 -0
- package/README.md +20 -12
- package/dist/cli/cli.js +16 -23
- package/dist/cli/constants.d.ts +7 -0
- package/dist/cli/constants.js +44 -14
- package/dist/cli/create.d.ts +2 -0
- package/dist/cli/create.js +22 -2
- package/dist/cli/rename.js +9 -2
- package/dist/cli/test.d.ts +2 -0
- package/dist/cli/test.js +11 -0
- package/dist/cli/verify.js +1 -1
- package/dist/jest/CoverageReporter.d.ts +11 -0
- package/dist/jest/CoverageReporter.js +77 -0
- package/dist/jest/coverageSetup.d.ts +1 -0
- package/dist/jest/coverageSetup.js +53 -0
- package/dist/network/Explorer.d.ts +1 -0
- package/dist/network/Explorer.js +2 -0
- package/dist/network/NetworkProvider.d.ts +6 -0
- package/dist/network/createNetworkProvider.js +52 -75
- package/dist/network/send/DeeplinkProvider.d.ts +2 -1
- package/dist/network/send/DeeplinkProvider.js +12 -27
- package/dist/network/send/MnemonicProvider.d.ts +5 -1
- package/dist/network/send/MnemonicProvider.js +13 -31
- package/dist/network/send/TonConnectProvider.d.ts +3 -1
- package/dist/network/send/TonConnectProvider.js +28 -46
- package/dist/network/storage/FSStorage.d.ts +3 -1
- package/dist/network/storage/FSStorage.js +18 -31
- package/dist/templates/tolk/empty/contracts/contract.tolk.template +1 -1
- package/dist/ui/InquirerUIProvider.d.ts +1 -1
- package/dist/ui/InquirerUIProvider.js +5 -19
- package/dist/utils/string.utils.d.ts +1 -1
- package/dist/utils/string.utils.js +6 -5
- package/dist/utils/ton.utils.d.ts +3 -2
- package/package.json +7 -6
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.41.0] - 2025-09-23
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Added `blueprint test --coverage` command
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- When creating a contract, if the input contract name is invalid, blueprint does not exit, but asks for the name again
|
|
17
|
+
|
|
8
18
|
## [0.40.0] - 2025-08-18
|
|
9
19
|
|
|
10
20
|
### Added
|
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ npm create ton@latest
|
|
|
41
41
|
|
|
42
42
|
## Overview
|
|
43
43
|
|
|
44
|
-
Blueprint is an all-in-one development environment designed to enhance the process of creating, testing, and deploying smart contracts on TON blockchain using [
|
|
44
|
+
Blueprint is an all-in-one development environment designed to enhance the process of creating, testing, and deploying smart contracts on TON blockchain using [Tolk](https://docs.ton.org/develop/tolk/overview), [FunC](https://docs.ton.org/develop/func/overview), and [Tact](https://docs.tact-lang.org/) languages.
|
|
45
45
|
|
|
46
46
|
### Core features
|
|
47
47
|
|
|
@@ -52,8 +52,8 @@ Blueprint is an all-in-one development environment designed to enhance the proce
|
|
|
52
52
|
|
|
53
53
|
### Tech stack
|
|
54
54
|
|
|
55
|
-
1. Compiling
|
|
56
|
-
2. Compiling
|
|
55
|
+
1. Compiling Tolk with https://github.com/ton-blockchain/tolk-js
|
|
56
|
+
2. Compiling FunC with https://github.com/ton-community/func-js
|
|
57
57
|
3. Compiling Tact with https://github.com/tact-lang/tact
|
|
58
58
|
* Uses [`tact.config.json`](https://docs.tact-lang.org/book/config/) as the build configuration file
|
|
59
59
|
4. Testing smart contracts with https://github.com/ton-org/sandbox
|
|
@@ -63,9 +63,9 @@ Blueprint is an all-in-one development environment designed to enhance the proce
|
|
|
63
63
|
|
|
64
64
|
* [Node.js](https://nodejs.org) with a recent version like v18. Version can be verified with `node -v`
|
|
65
65
|
* IDE with TON support:
|
|
66
|
-
* [Visual Studio Code](https://code.visualstudio.com/) with the [
|
|
66
|
+
* [Visual Studio Code](https://code.visualstudio.com/) with the [TON plugin](https://marketplace.visualstudio.com/items?itemName=ton-core.vscode-ton) or [Tact plugin](https://marketplace.visualstudio.com/items?itemName=tonstudio.vscode-tact)
|
|
67
67
|
* [IntelliJ IDEA](https://www.jetbrains.com/idea/)
|
|
68
|
-
* [TON Development plugin](https://plugins.jetbrains.com/plugin/23382-ton) for
|
|
68
|
+
* [TON Development plugin](https://plugins.jetbrains.com/plugin/23382-ton) for Tolk, FunC and Fift
|
|
69
69
|
* [Tact plugin by TON Studio](https://plugins.jetbrains.com/plugin/27290-tact) for Tact
|
|
70
70
|
|
|
71
71
|
## Features overview
|
|
@@ -139,9 +139,13 @@ Start by adding the following environment variables to your `.env` file:
|
|
|
139
139
|
|
|
140
140
|
Once your environment is set up, you can use the mnemonic wallet for deployment with the appropriate configuration.
|
|
141
141
|
|
|
142
|
+
### Updating Tolk version
|
|
143
|
+
|
|
144
|
+
Tolk version can be updated to the latest using `npm update/yarn upgrade @ton/tolk-js` command
|
|
145
|
+
|
|
142
146
|
### Updating FunC version
|
|
143
147
|
|
|
144
|
-
FunC version can be updated using `npx/yarn blueprint set func` command
|
|
148
|
+
FunC version can be updated to a specific version using `npx/yarn blueprint set func` command, or to the latest using `npm update/yarn upgrade @ton-community/func-js` command
|
|
145
149
|
|
|
146
150
|
### Updating Tact version
|
|
147
151
|
|
|
@@ -158,8 +162,8 @@ Before developing, make sure that your current working directory is located in t
|
|
|
158
162
|
### Creating contracts
|
|
159
163
|
|
|
160
164
|
1. Run interactive: `npx blueprint create` or `yarn blueprint create`
|
|
161
|
-
2. Non-interactive: `npx/yarn blueprint create <CONTRACT> --type <TYPE>` (type can be `
|
|
162
|
-
* Example: `yarn blueprint create MyNewContract --type
|
|
165
|
+
2. Non-interactive: `npx/yarn blueprint create <CONTRACT> --type <TYPE>` (type can be `tolk-empty`, `func-empty`, `tact-empty`, `tolk-counter`, `func-counter`, `tact-counter`)
|
|
166
|
+
* Example: `yarn blueprint create MyNewContract --type tolk-empty`
|
|
163
167
|
|
|
164
168
|
### Renaming contracts
|
|
165
169
|
|
|
@@ -169,15 +173,15 @@ Before developing, make sure that your current working directory is located in t
|
|
|
169
173
|
|
|
170
174
|
### Writing contract code
|
|
171
175
|
|
|
176
|
+
#### Tolk
|
|
177
|
+
1. Implement the contract in `contracts/<CONTRACT>.tolk`; if you wish, split into multiple files
|
|
178
|
+
2. Implement wrapper TypeScript class in `wrappers/<CONTRACT>.ts` to encode messages and decode getters
|
|
179
|
+
|
|
172
180
|
#### FunC
|
|
173
181
|
1. Implement the standalone FunC root contract in `contracts/<CONTRACT>.fc`
|
|
174
182
|
2. Implement shared FunC imports (if breaking code to multiple files) in `contracts/imports/*.fc`
|
|
175
183
|
3. Implement wrapper TypeScript class in `wrappers/<CONTRACT>.ts` to encode messages and decode getters
|
|
176
184
|
|
|
177
|
-
#### Tolk
|
|
178
|
-
1. Implement the contract in `contracts/<CONTRACT>.tolk`; if you wish, split into multiple files
|
|
179
|
-
2. Implement wrapper TypeScript class in `wrappers/<CONTRACT>.ts` to encode messages and decode getters
|
|
180
|
-
|
|
181
185
|
#### Tact
|
|
182
186
|
1. Implement the contract in `contracts/<CONTRACT>.tact`
|
|
183
187
|
2. Wrappers will be automatically generated in `build/<CONTRACT>/tact_<CONTRACT>.ts`
|
|
@@ -187,6 +191,10 @@ Before developing, make sure that your current working directory is located in t
|
|
|
187
191
|
1. Implement TypeScript tests in `tests/<CONTRACT>.spec.ts`
|
|
188
192
|
2. Rely on the wrapper TypeScript class from `wrappers/<CONTRACT>.ts` to interact with the contract
|
|
189
193
|
|
|
194
|
+
#### Collecting coverage
|
|
195
|
+
|
|
196
|
+
To collect coverage run `blueprint test --coverage`. Coverage will appear in coverage directory.
|
|
197
|
+
|
|
190
198
|
> Learn more about writing tests from the Sandbox's documentation - [here](https://github.com/ton-org/sandbox#writing-tests).
|
|
191
199
|
|
|
192
200
|
### Publishing Wrapper Code
|
package/dist/cli/cli.js
CHANGED
|
@@ -55,6 +55,7 @@ const InquirerUIProvider_1 = require("../ui/InquirerUIProvider");
|
|
|
55
55
|
const Runner_1 = require("./Runner");
|
|
56
56
|
const utils_1 = require("../config/utils");
|
|
57
57
|
const rename_1 = require("./rename");
|
|
58
|
+
const constants_1 = require("./constants");
|
|
58
59
|
const runners = {
|
|
59
60
|
create: create_1.create,
|
|
60
61
|
run: run_1.run,
|
|
@@ -121,34 +122,26 @@ main()
|
|
|
121
122
|
.then(() => process.exit(0));
|
|
122
123
|
function showHelp() {
|
|
123
124
|
console.log(chalk_1.default.blueBright(`
|
|
124
|
-
____ _ _ _ _____ ____ ____ ___ _ _ _____
|
|
125
|
+
____ _ _ _ _____ ____ ____ ___ _ _ _____
|
|
125
126
|
| __ )| | | | | | ____| _ \\| _ \\|_ _| \\ | |_ _|
|
|
126
|
-
| _ \\| | | | | | _| | |_) | |_) || || \\| | | |
|
|
127
|
-
| |_) | |__| |_| | |___| __/| _ < | || |\\ | | |
|
|
127
|
+
| _ \\| | | | | | _| | |_) | |_) || || \\| | | |
|
|
128
|
+
| |_) | |__| |_| | |___| __/| _ < | || |\\ | | |
|
|
128
129
|
|____/|_____\\___/|_____|_| |_| \\_\\___|_| \\_| |_| `));
|
|
129
130
|
console.log(chalk_1.default.blue(` TON development for professionals`));
|
|
130
131
|
console.log(``);
|
|
131
132
|
console.log(` Usage: blueprint [OPTIONS] COMMAND [ARGS]`);
|
|
132
133
|
console.log(``);
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
chalk_1.default.
|
|
144
|
-
|
|
145
|
-
console.log(chalk_1.default.cyanBright(` blueprint run `) +
|
|
146
|
-
`\t` +
|
|
147
|
-
chalk_1.default.whiteBright(`runs a script from 'scripts' directory (eg. a deploy script)`));
|
|
148
|
-
console.log(`\t\t\t` + chalk_1.default.gray(`blueprint run deployContractName`));
|
|
149
|
-
console.log(chalk_1.default.cyanBright(` blueprint help`) +
|
|
150
|
-
`\t` +
|
|
151
|
-
chalk_1.default.whiteBright(`shows more detailed help, also see https://github.com/ton-org/blueprint`));
|
|
152
|
-
console.log(`\t\t\t` + chalk_1.default.gray(`blueprint help`));
|
|
134
|
+
const mainPageCommands = new Set(['create', 'build', 'test', 'run', 'help']);
|
|
135
|
+
for (const cmd of constants_1.availableCommands) {
|
|
136
|
+
if (!mainPageCommands.has(cmd.name)) {
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
const commandName = ` blueprint ${cmd.name}`;
|
|
140
|
+
const description = cmd.description;
|
|
141
|
+
const cmdPadding = ' '.repeat(Math.max(0, 24 - commandName.length));
|
|
142
|
+
const examplePadding = ' '.repeat(cmdPadding.length + commandName.length);
|
|
143
|
+
console.log(chalk_1.default.cyanBright(commandName) + cmdPadding + chalk_1.default.whiteBright(description));
|
|
144
|
+
console.log(examplePadding + chalk_1.default.gray(cmd.example));
|
|
145
|
+
}
|
|
153
146
|
console.log(``);
|
|
154
147
|
}
|
package/dist/cli/constants.d.ts
CHANGED
|
@@ -6,6 +6,13 @@ export declare const helpArgs: {
|
|
|
6
6
|
'--help': BooleanConstructor;
|
|
7
7
|
'-h': string;
|
|
8
8
|
};
|
|
9
|
+
export type KnownCommandName = 'create' | 'run' | 'build' | 'set' | 'help' | 'test' | 'verify' | 'convert' | 'rename' | 'pack' | 'snapshot';
|
|
10
|
+
export interface CommandInfo {
|
|
11
|
+
readonly name: KnownCommandName;
|
|
12
|
+
readonly description: string;
|
|
13
|
+
readonly example: string;
|
|
14
|
+
}
|
|
15
|
+
export declare const availableCommands: CommandInfo[];
|
|
9
16
|
export declare const helpMessages: {
|
|
10
17
|
help: string;
|
|
11
18
|
create: string;
|
package/dist/cli/constants.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.helpMessages = exports.helpArgs = exports.templateTypes = void 0;
|
|
6
|
+
exports.helpMessages = exports.availableCommands = exports.helpArgs = exports.templateTypes = void 0;
|
|
7
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
8
|
exports.templateTypes = [
|
|
9
9
|
{
|
|
@@ -32,18 +32,46 @@ exports.templateTypes = [
|
|
|
32
32
|
},
|
|
33
33
|
];
|
|
34
34
|
exports.helpArgs = { '--help': Boolean, '-h': '--help' };
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
'
|
|
35
|
+
exports.availableCommands = [
|
|
36
|
+
{
|
|
37
|
+
name: 'create',
|
|
38
|
+
description: 'create a new contract with .fc source, .ts wrapper, .spec.ts test',
|
|
39
|
+
example: 'blueprint create ContractName',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'build',
|
|
43
|
+
description: 'builds a contract that has a .compile.ts file',
|
|
44
|
+
example: 'blueprint build ContractName',
|
|
45
|
+
},
|
|
46
|
+
{ name: 'test', description: 'run the full project test suite with all .spec.ts files', example: 'blueprint test' },
|
|
47
|
+
{
|
|
48
|
+
name: 'run',
|
|
49
|
+
description: "runs a script from 'scripts' directory (eg. a deploy script)",
|
|
50
|
+
example: 'blueprint run deployContractName',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'help',
|
|
54
|
+
description: 'shows more detailed help, also see https://github.com/ton-org/blueprint',
|
|
55
|
+
example: 'blueprint help',
|
|
56
|
+
},
|
|
57
|
+
{ name: 'set', description: 'sets configuration values', example: 'blueprint set' },
|
|
58
|
+
{ name: 'verify', description: 'verifies a deployed contract on verifier.ton.org', example: 'blueprint verify' },
|
|
59
|
+
{
|
|
60
|
+
name: 'convert',
|
|
61
|
+
description: 'converts legacy bash build scripts to Blueprint wrappers',
|
|
62
|
+
example: 'blueprint convert',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'rename',
|
|
66
|
+
description: 'renames contract by matching in wrappers, scripts and tests',
|
|
67
|
+
example: 'blueprint rename',
|
|
68
|
+
},
|
|
69
|
+
{ name: 'pack', description: 'builds and prepares a publish-ready package of wrappers', example: 'blueprint pack' },
|
|
70
|
+
{
|
|
71
|
+
name: 'snapshot',
|
|
72
|
+
description: 'creates snapshots with gas usage and cells sizes',
|
|
73
|
+
example: 'blueprint snapshot',
|
|
74
|
+
},
|
|
47
75
|
];
|
|
48
76
|
exports.helpMessages = {
|
|
49
77
|
help: `${chalk_1.default.bold('Usage:')} blueprint ${chalk_1.default.cyan('help')} [${chalk_1.default.yellow('command')}]
|
|
@@ -54,7 +82,9 @@ Blueprint is generally invoked as follows:
|
|
|
54
82
|
${chalk_1.default.cyan('blueprint')} ${chalk_1.default.yellow('[command]')} ${chalk_1.default.gray('[command-args]')} ${chalk_1.default.gray('[flags]')}
|
|
55
83
|
|
|
56
84
|
${chalk_1.default.bold('List of available commands:')}
|
|
57
|
-
${availableCommands.map((c) =>
|
|
85
|
+
${exports.availableCommands.map((c) => ` ${chalk_1.default.cyanBright(c.name)}${' '.repeat(Math.max(0, 20 - c.name.length))}${c.description}`).join('\n')}
|
|
86
|
+
|
|
87
|
+
To get more information about a command, run ${chalk_1.default.cyan('blueprint help <command>')}`,
|
|
58
88
|
create: `${chalk_1.default.bold('Usage:')} blueprint ${chalk_1.default.cyan('create')} ${chalk_1.default.yellow('[contract name]')} ${chalk_1.default.gray('[flags]')}
|
|
59
89
|
|
|
60
90
|
Creates a new contract together with supporting files according to a template.
|
package/dist/cli/create.d.ts
CHANGED
package/dist/cli/create.js
CHANGED
|
@@ -4,10 +4,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.create = void 0;
|
|
7
|
+
exports.requestContractName = requestContractName;
|
|
7
8
|
const path_1 = __importDefault(require("path"));
|
|
8
9
|
const posix_1 = __importDefault(require("path/posix"));
|
|
9
10
|
const promises_1 = require("fs/promises");
|
|
10
11
|
const arg_1 = __importDefault(require("arg"));
|
|
12
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
11
13
|
const utils_1 = require("../config/utils");
|
|
12
14
|
const tact_config_1 = require("../config/tact.config");
|
|
13
15
|
const Runner_1 = require("./Runner");
|
|
@@ -80,8 +82,14 @@ const create = async (_args, ui) => {
|
|
|
80
82
|
ui.write(constants_1.helpMessages['create']);
|
|
81
83
|
return;
|
|
82
84
|
}
|
|
83
|
-
const
|
|
84
|
-
(
|
|
85
|
+
const argName = (0, Runner_1.extractFirstArg)(localArgs);
|
|
86
|
+
if (argName !== undefined) {
|
|
87
|
+
const error = (0, utils_2.validateContractName)(argName);
|
|
88
|
+
if (error) {
|
|
89
|
+
throw new Error(error);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const name = argName ?? (await requestContractName('Contract name (PascalCase)', ui));
|
|
85
93
|
const which = (await (0, utils_2.selectOption)(constants_1.templateTypes, {
|
|
86
94
|
ui,
|
|
87
95
|
msg: 'What type of contract do you want to create?',
|
|
@@ -109,3 +117,15 @@ const create = async (_args, ui) => {
|
|
|
109
117
|
}
|
|
110
118
|
};
|
|
111
119
|
exports.create = create;
|
|
120
|
+
async function requestContractName(message, ui) {
|
|
121
|
+
while (true) {
|
|
122
|
+
const name = await ui.input(message);
|
|
123
|
+
const error = (0, utils_2.validateContractName)(name);
|
|
124
|
+
if (error !== undefined) {
|
|
125
|
+
ui.write(chalk_1.default.redBright(`Error: `) + error);
|
|
126
|
+
// ask user again
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
return name;
|
|
130
|
+
}
|
|
131
|
+
}
|
package/dist/cli/rename.js
CHANGED
|
@@ -13,6 +13,7 @@ const Runner_1 = require("./Runner");
|
|
|
13
13
|
const utils_1 = require("../utils");
|
|
14
14
|
const constants_1 = require("./constants");
|
|
15
15
|
const build_1 = require("./build");
|
|
16
|
+
const create_1 = require("./create");
|
|
16
17
|
function renameExactIfRequired(str, replaces) {
|
|
17
18
|
let renamedString = str;
|
|
18
19
|
let isRenamed = false;
|
|
@@ -71,8 +72,14 @@ const rename = async (_args, ui, _context) => {
|
|
|
71
72
|
return;
|
|
72
73
|
}
|
|
73
74
|
const oldName = await (0, build_1.selectContract)(ui, (0, Runner_1.extractFirstArg)(localArgs));
|
|
74
|
-
const
|
|
75
|
-
(
|
|
75
|
+
const argName = (0, Runner_1.extractSecondArg)(localArgs);
|
|
76
|
+
if (argName !== undefined) {
|
|
77
|
+
const error = (0, utils_1.validateContractName)(argName);
|
|
78
|
+
if (error) {
|
|
79
|
+
throw new Error(error);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const newName = argName ?? (await (0, create_1.requestContractName)('New contract name (PascalCase)', ui));
|
|
76
83
|
const contracts = await (0, utils_1.findContracts)();
|
|
77
84
|
if (contracts.includes(newName)) {
|
|
78
85
|
ui.write(`Contract with name ${newName} already exists.`);
|
package/dist/cli/test.d.ts
CHANGED
package/dist/cli/test.js
CHANGED
|
@@ -4,13 +4,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.test = exports.argSpec = void 0;
|
|
7
|
+
exports.coverage = coverage;
|
|
7
8
|
const child_process_1 = require("child_process");
|
|
8
9
|
const arg_1 = __importDefault(require("arg"));
|
|
9
10
|
const constants_1 = require("./constants");
|
|
10
11
|
exports.argSpec = {
|
|
11
12
|
'--gas-report': Boolean,
|
|
12
13
|
'-g': '--gas-report',
|
|
14
|
+
'--coverage': Boolean,
|
|
13
15
|
};
|
|
16
|
+
async function coverage() {
|
|
17
|
+
(0, child_process_1.execSync)(`npm test -- --reporters @ton/blueprint/dist/jest/CoverageReporter --setupFilesAfterEnv @ton/blueprint/dist/jest/coverageSetup`, {
|
|
18
|
+
stdio: 'inherit',
|
|
19
|
+
});
|
|
20
|
+
}
|
|
14
21
|
const test = async (args, ui) => {
|
|
15
22
|
const localArgs = (0, arg_1.default)({
|
|
16
23
|
...constants_1.helpArgs,
|
|
@@ -20,6 +27,10 @@ const test = async (args, ui) => {
|
|
|
20
27
|
ui.write(constants_1.helpMessages['test']);
|
|
21
28
|
return;
|
|
22
29
|
}
|
|
30
|
+
if (localArgs['--coverage']) {
|
|
31
|
+
await coverage();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
23
34
|
let testArgs = args._.slice(1); // first argument is `test`, need to get rid of it
|
|
24
35
|
if (localArgs['--gas-report']) {
|
|
25
36
|
testArgs = testArgs.slice(1);
|
package/dist/cli/verify.js
CHANGED
|
@@ -151,7 +151,7 @@ const verify = async (_args, ui, context) => {
|
|
|
151
151
|
if (network === 'custom') {
|
|
152
152
|
throw new Error('Cannot use custom network');
|
|
153
153
|
}
|
|
154
|
-
const result = await (0, compile_1.doCompile)(selectedContract);
|
|
154
|
+
const result = await (0, compile_1.doCompile)(selectedContract, { buildLibrary: false });
|
|
155
155
|
const resHash = result.code.hash();
|
|
156
156
|
ui.write(`Compiled code hash hex: ${resHash.toString('hex')}`);
|
|
157
157
|
ui.write('We can look up the address with such code hash in the blockchain automatically');
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Reporter } from '@jest/reporters';
|
|
2
|
+
declare class CoverageReporter implements Reporter {
|
|
3
|
+
private contracts;
|
|
4
|
+
private get coverageDir();
|
|
5
|
+
private get blueprintCoverageDir();
|
|
6
|
+
onRunStart(): Promise<void>;
|
|
7
|
+
onRunComplete(): Promise<void>;
|
|
8
|
+
private printSummary;
|
|
9
|
+
private collectLogs;
|
|
10
|
+
}
|
|
11
|
+
export default CoverageReporter;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
7
|
+
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
8
|
+
const fs_1 = require("fs");
|
|
9
|
+
const core_1 = require("@ton/core");
|
|
10
|
+
// @ts-expect-error blueprint imported inside package
|
|
11
|
+
const blueprint_1 = require("@ton/blueprint");
|
|
12
|
+
const sandbox_1 = require("@ton/sandbox");
|
|
13
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
14
|
+
class CoverageReporter {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.contracts = [];
|
|
17
|
+
}
|
|
18
|
+
get coverageDir() {
|
|
19
|
+
return node_path_1.default.join(process.cwd(), 'coverage');
|
|
20
|
+
}
|
|
21
|
+
get blueprintCoverageDir() {
|
|
22
|
+
return node_path_1.default.join(this.coverageDir, 'blueprint');
|
|
23
|
+
}
|
|
24
|
+
async onRunStart() {
|
|
25
|
+
console.log(`\n๐ ๏ธ Building contracts...`);
|
|
26
|
+
await (0, blueprint_1.buildAll)();
|
|
27
|
+
const buildDir = node_path_1.default.join(process.cwd(), 'build');
|
|
28
|
+
const buildFiles = (await promises_1.default.readdir(buildDir)).filter((f) => f.endsWith('.json'));
|
|
29
|
+
const contents = await Promise.all(buildFiles.map((f) => promises_1.default.readFile(node_path_1.default.join(buildDir, f), 'utf-8')));
|
|
30
|
+
this.contracts = contents.map((json, i) => ({
|
|
31
|
+
name: node_path_1.default.basename(buildFiles[i], '.compiled.json'),
|
|
32
|
+
...JSON.parse(json),
|
|
33
|
+
}));
|
|
34
|
+
console.log(`โ
Built ${this.contracts.length} contracts: ${this.contracts.map((c) => c.name).join(', ')}`);
|
|
35
|
+
if ((0, fs_1.existsSync)(this.blueprintCoverageDir)) {
|
|
36
|
+
console.log(`๐งน Cleaning old coverage at ${this.blueprintCoverageDir}`);
|
|
37
|
+
await promises_1.default.rm(this.blueprintCoverageDir, { recursive: true, force: true });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async onRunComplete() {
|
|
41
|
+
if (!(0, fs_1.existsSync)(this.blueprintCoverageDir)) {
|
|
42
|
+
console.log(`โ ๏ธ No blueprint coverage data found, skipping coverage reports.`);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
console.log(`\n๐ Collecting coverage logs...`);
|
|
46
|
+
const logs = await this.collectLogs();
|
|
47
|
+
console.log(`\n๐ Generating coverage reports...`);
|
|
48
|
+
for (const { name, hex } of this.contracts) {
|
|
49
|
+
const codeCell = core_1.Cell.fromHex(hex);
|
|
50
|
+
const merged = (0, sandbox_1.mergeCoverages)(...logs.map((l) => (0, sandbox_1.collectAsmCoverage)(codeCell, l)));
|
|
51
|
+
const coverage = new sandbox_1.Coverage(merged);
|
|
52
|
+
const report = coverage.report('html');
|
|
53
|
+
const reportPath = node_path_1.default.join(this.coverageDir, `${name}-report.html`);
|
|
54
|
+
await promises_1.default.writeFile(reportPath, report);
|
|
55
|
+
const summary = coverage.summary();
|
|
56
|
+
this.printSummary(name, summary, reportPath);
|
|
57
|
+
}
|
|
58
|
+
console.log(`\nโ
Coverage reports generated in ${this.coverageDir}\n`);
|
|
59
|
+
}
|
|
60
|
+
printSummary(name, summary, reportPath) {
|
|
61
|
+
const pct = summary.coveragePercentage.toFixed(2) + '%';
|
|
62
|
+
const line = chalk_1.default.bold(name.padEnd(20)) +
|
|
63
|
+
chalk_1.default.white(`${summary.coveredLines}/${summary.totalLines} lines`.padEnd(20)) +
|
|
64
|
+
(summary.coveragePercentage >= 80 ? chalk_1.default.green(pct.padEnd(10)) : chalk_1.default.red(pct.padEnd(10))) +
|
|
65
|
+
chalk_1.default.gray(reportPath);
|
|
66
|
+
console.log(' โข ' + line);
|
|
67
|
+
}
|
|
68
|
+
async collectLogs() {
|
|
69
|
+
const files = (await promises_1.default.readdir(this.blueprintCoverageDir, { recursive: true })).filter((f) => f.endsWith('.json'));
|
|
70
|
+
const contents = await Promise.all(files.map((f) => promises_1.default.readFile(node_path_1.default.join(this.blueprintCoverageDir, f), 'utf-8')));
|
|
71
|
+
return contents.flatMap((content) => {
|
|
72
|
+
const { txLogs, getLogs } = JSON.parse(content);
|
|
73
|
+
return [...txLogs, ...getLogs];
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
exports.default = CoverageReporter;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const sandbox_1 = require("@ton/sandbox");
|
|
9
|
+
const txLogs = [];
|
|
10
|
+
const getLogs = [];
|
|
11
|
+
beforeAll(() => {
|
|
12
|
+
const originalCreate = sandbox_1.Blockchain.create.bind(sandbox_1.Blockchain);
|
|
13
|
+
sandbox_1.Blockchain.create = async (...args) => {
|
|
14
|
+
const blockchain = await originalCreate(...args);
|
|
15
|
+
blockchain.enableCoverage();
|
|
16
|
+
const originalVerbosity = { ...blockchain.verbosity };
|
|
17
|
+
originalVerbosity.print = false;
|
|
18
|
+
originalVerbosity.vmLogs = 'vm_logs_verbose';
|
|
19
|
+
Object.defineProperty(blockchain, 'verbosity', {
|
|
20
|
+
get() {
|
|
21
|
+
return originalVerbosity;
|
|
22
|
+
},
|
|
23
|
+
set(_) {
|
|
24
|
+
// prevent changes
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
blockchain.verbosity = originalVerbosity;
|
|
28
|
+
// @ts-expect-error error
|
|
29
|
+
const origRegisterTx = blockchain.registerTxsForCoverage.bind(blockchain);
|
|
30
|
+
// @ts-expect-error error
|
|
31
|
+
const origRegisterGet = blockchain.registerGetMethodForCoverage.bind(blockchain);
|
|
32
|
+
// @ts-expect-error error
|
|
33
|
+
blockchain.registerTxsForCoverage = (txs) => {
|
|
34
|
+
txLogs.push(...txs.map((tx) => tx.vmLogs));
|
|
35
|
+
return origRegisterTx(txs);
|
|
36
|
+
};
|
|
37
|
+
// @ts-expect-error error
|
|
38
|
+
blockchain.registerGetMethodForCoverage = (gets) => {
|
|
39
|
+
getLogs.push(gets.vmLogs);
|
|
40
|
+
return origRegisterGet(gets);
|
|
41
|
+
};
|
|
42
|
+
return blockchain;
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
afterAll(() => {
|
|
46
|
+
const coveragePath = node_path_1.default.join(process.cwd(), 'coverage');
|
|
47
|
+
const blueprintCoveragePath = node_path_1.default.join(coveragePath, 'blueprint');
|
|
48
|
+
const testPath = expect.getState().testPath;
|
|
49
|
+
const testRelative = node_path_1.default.relative(process.cwd(), testPath);
|
|
50
|
+
const logsFilePath = node_path_1.default.join(blueprintCoveragePath, testRelative + '.json');
|
|
51
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(logsFilePath), { recursive: true });
|
|
52
|
+
node_fs_1.default.writeFileSync(logsFilePath, JSON.stringify({ txLogs, getLogs }, null, 2));
|
|
53
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type Explorer = 'tonscan' | 'tonviewer' | 'toncx' | 'dton';
|
|
@@ -3,6 +3,7 @@ import { Address, Cell, Contract, ContractProvider, ContractState, OpenedContrac
|
|
|
3
3
|
import { ContractAdapter } from '@ton-api/ton-adapter';
|
|
4
4
|
import { LiteClient } from 'ton-lite-client';
|
|
5
5
|
import { UIProvider } from '../ui/UIProvider';
|
|
6
|
+
import { Explorer } from './Explorer';
|
|
6
7
|
export type BlueprintTonClient = TonClient4 | TonClient | ContractAdapter | LiteClient;
|
|
7
8
|
type BlockchainConfig = ReturnType<typeof parseFullConfig>;
|
|
8
9
|
export interface SenderWithSendResult extends Sender {
|
|
@@ -17,6 +18,11 @@ export interface NetworkProvider {
|
|
|
17
18
|
* @returns {'mainnet' | 'testnet' | 'custom'} The type of network.
|
|
18
19
|
*/
|
|
19
20
|
network(): 'mainnet' | 'testnet' | 'custom';
|
|
21
|
+
/**
|
|
22
|
+
* Returns the current explorer type.
|
|
23
|
+
* @returns {Explorer} The type of explorer.
|
|
24
|
+
*/
|
|
25
|
+
explorer(): Explorer;
|
|
20
26
|
/**
|
|
21
27
|
* Returns the sender used for transactions.
|
|
22
28
|
* @example
|