@ton/blueprint 0.31.1 → 0.32.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 CHANGED
@@ -5,6 +5,22 @@ 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.32.0] - 2025-05-02
9
+
10
+ ### Added
11
+
12
+ - Compiler version is now shown during contract build
13
+ - Added 'All Contracts' option to build wizard
14
+ - Added function to build all tact contracts, required for rebuilding before tests
15
+
16
+ ### Changed
17
+
18
+ - Made error of non-PascalCase contract names nicer
19
+
20
+ ### Fixed
21
+
22
+ - `blueprint build --all` now exits with a non-zero exit code on failure
23
+
8
24
  ## [0.31.1] - 2025-04-24
9
25
 
10
26
  ### Fixed
package/README.md CHANGED
@@ -122,6 +122,10 @@ export async function run(provider: NetworkProvider) {
122
122
 
123
123
  FunC version can be updated using `npx/yarn blueprint set func` command
124
124
 
125
+ ### Updating Tact version
126
+
127
+ Tact version can be updated to the latest using `npm update/yarn upgrade @tact-lang/compiler` command
128
+
125
129
  ### Help and additional commands
126
130
 
127
131
  Run in terminal:   `npx blueprint help`   or   `yarn blueprint help`
package/dist/build.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  import { UIProvider } from './ui/UIProvider';
2
2
  export declare function buildOne(contract: string, ui?: UIProvider): Promise<void>;
3
3
  export declare function buildAll(ui?: UIProvider): Promise<void>;
4
+ export declare function buildAllTact(ui?: UIProvider): Promise<void>;
package/dist/build.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.buildAll = exports.buildOne = void 0;
6
+ exports.buildAllTact = exports.buildAll = exports.buildOne = void 0;
7
7
  const path_1 = __importDefault(require("path"));
8
8
  const promises_1 = __importDefault(require("fs/promises"));
9
9
  const compile_1 = require("./compile/compile");
@@ -18,6 +18,9 @@ async function buildOne(contract, ui) {
18
18
  catch (e) { }
19
19
  ui?.setActionPrompt('⏳ Compiling...');
20
20
  try {
21
+ const config = await (0, compile_1.getCompilerConfigForContract)(contract);
22
+ const compilerOptions = await (0, compile_1.getCompilerOptions)(config);
23
+ ui?.write(`🔧 Using ${compilerOptions.lang} version ${compilerOptions.version}...`);
21
24
  const result = await (0, compile_1.doCompile)(contract);
22
25
  if (result.lang === 'tact') {
23
26
  for (const [k, v] of result.fs) {
@@ -71,3 +74,13 @@ async function buildAll(ui) {
71
74
  }
72
75
  }
73
76
  exports.buildAll = buildAll;
77
+ async function buildAllTact(ui) {
78
+ // TODO: when tact config introduced rewrite to use it
79
+ for (const file of await (0, utils_1.findCompiles)()) {
80
+ const config = await (0, compile_1.extractCompileConfig)(file.path);
81
+ if (config.lang === 'tact') {
82
+ await buildOne(file.name, ui);
83
+ }
84
+ }
85
+ }
86
+ exports.buildAllTact = buildAllTact;
@@ -3,6 +3,7 @@ import { UIProvider } from '../ui/UIProvider';
3
3
  import { Config } from '../config/Config';
4
4
  export declare const argSpec: {};
5
5
  export type Args = arg.Result<typeof argSpec>;
6
+ export declare function extractFirstArg(args: Args): string | undefined;
6
7
  export type RunnerContext = {
7
8
  config?: Config;
8
9
  };
@@ -1,4 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.argSpec = void 0;
3
+ exports.extractFirstArg = exports.argSpec = void 0;
4
4
  exports.argSpec = {};
5
+ function extractFirstArg(args) {
6
+ return args._.length > 1 && args._[1].trim().length > 0 ? args._[1].trim() : undefined;
7
+ }
8
+ exports.extractFirstArg = extractFirstArg;
@@ -1,8 +1,6 @@
1
1
  import { Args, Runner } from './Runner';
2
2
  import { UIProvider } from '../ui/UIProvider';
3
- export declare function selectCompile(ui: UIProvider, args: Args): Promise<{
4
- module: any;
5
- name: string;
6
- path: string;
7
- }>;
3
+ export declare function extractBuildFile(args: Args): string | undefined;
4
+ export declare function selectContract(ui: UIProvider, hint?: string): Promise<string>;
5
+ export declare function selectContract(ui: UIProvider, hint?: string, withAllOption?: boolean): Promise<string | string[]>;
8
6
  export declare const build: Runner;
package/dist/cli/build.js CHANGED
@@ -3,19 +3,38 @@ 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.build = exports.selectCompile = void 0;
6
+ exports.build = exports.selectContract = exports.extractBuildFile = void 0;
7
7
  const utils_1 = require("../utils");
8
8
  const arg_1 = __importDefault(require("arg"));
9
9
  const build_1 = require("../build");
10
10
  const constants_1 = require("./constants");
11
- async function selectCompile(ui, args) {
12
- return await (0, utils_1.selectFile)(await (0, utils_1.findCompiles)(), {
11
+ function extractBuildFile(args) {
12
+ return args._.length > 1 && args._[1].length > 0 ? args._[1] : undefined;
13
+ }
14
+ exports.extractBuildFile = extractBuildFile;
15
+ async function selectContract(ui, hint, withAllOption = false) {
16
+ const compiles = await (0, utils_1.findCompiles)();
17
+ const contracts = compiles.map(compile => compile.name);
18
+ const options = contracts.map((contract) => ({ name: contract, value: contract }));
19
+ const allContractsValue = 'all_contracts';
20
+ if (withAllOption) {
21
+ const allContractsOption = {
22
+ name: 'All Contracts',
23
+ value: allContractsValue,
24
+ };
25
+ options.push(allContractsOption);
26
+ }
27
+ const selectedOption = await (0, utils_1.selectOption)(options, {
28
+ msg: 'Select contract to use',
13
29
  ui,
14
- hint: args._.length > 1 && args._[1].length > 0 ? args._[1] : undefined,
15
- import: false,
30
+ hint,
16
31
  });
32
+ if (selectedOption.value === allContractsValue) {
33
+ return contracts;
34
+ }
35
+ return selectedOption.value;
17
36
  }
18
- exports.selectCompile = selectCompile;
37
+ exports.selectContract = selectContract;
19
38
  const build = async (args, ui) => {
20
39
  const localArgs = (0, arg_1.default)({
21
40
  '--all': Boolean,
@@ -26,11 +45,16 @@ const build = async (args, ui) => {
26
45
  return;
27
46
  }
28
47
  if (localArgs['--all']) {
29
- await (0, build_1.buildAll)();
48
+ await (0, build_1.buildAll)(ui);
30
49
  }
31
50
  else {
32
- const sel = await selectCompile(ui, localArgs);
33
- await (0, build_1.buildOne)(sel.name, ui);
51
+ const selected = await selectContract(ui, extractBuildFile(args), true);
52
+ if (typeof selected === 'string') {
53
+ await (0, build_1.buildOne)(selected, ui);
54
+ }
55
+ else {
56
+ await (0, build_1.buildAll)(ui);
57
+ }
34
58
  }
35
59
  };
36
60
  exports.build = build;
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.create = void 0;
7
+ const Runner_1 = require("./Runner");
7
8
  const promises_1 = require("fs/promises");
8
9
  const path_1 = __importDefault(require("path"));
9
10
  const template_1 = require("../template");
@@ -56,13 +57,16 @@ const create = async (args, ui) => {
56
57
  ui.write(constants_1.helpMessages['create']);
57
58
  return;
58
59
  }
59
- const name = localArgs._.length > 1 && localArgs._[1].trim().length > 0
60
- ? localArgs._[1].trim()
61
- : await ui.input('Contract name (PascalCase)');
60
+ const name = (0, Runner_1.extractFirstArg)(localArgs)
61
+ ?? await ui.input('Contract name (PascalCase)');
62
62
  if (name.length === 0)
63
63
  throw new Error(`Cannot create a contract with an empty name`);
64
- if (name.toLowerCase() === 'contract' || !/^[A-Z][a-zA-Z0-9]*$/.test(name))
65
- throw new Error(`Cannot create a contract with the name '${name}'`);
64
+ if (name.toLowerCase() === 'contract') {
65
+ throw new Error(`Cannot create a contract with the reserved name 'contract'. Please choose a different name.`);
66
+ }
67
+ if (!(0, utils_1.isPascalCase)(name)) {
68
+ throw new Error(`Contract name '${name}' is not in PascalCase. Please try ${(0, utils_1.toPascalCase)(name)}.`);
69
+ }
66
70
  const which = (await (0, utils_1.selectOption)(constants_1.templateTypes, {
67
71
  ui,
68
72
  msg: 'What type of contract do you want to create?',
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.verify = void 0;
7
7
  const core_1 = require("@ton/core");
8
8
  const compile_1 = require("../compile/compile");
9
+ const Runner_1 = require("./Runner");
9
10
  const path_1 = __importDefault(require("path"));
10
11
  const createNetworkProvider_1 = require("../network/createNetworkProvider");
11
12
  const build_1 = require("./build");
@@ -126,7 +127,7 @@ const verify = async (args, ui, context) => {
126
127
  ui.write(constants_1.helpMessages['verify']);
127
128
  return;
128
129
  }
129
- const sel = await (0, build_1.selectCompile)(ui, localArgs);
130
+ const selectedContract = await (0, build_1.selectContract)(ui, (0, Runner_1.extractFirstArg)(localArgs));
130
131
  const networkProvider = await (0, createNetworkProvider_1.createNetworkProvider)(ui, localArgs, context.config, false);
131
132
  const sender = networkProvider.sender();
132
133
  const senderAddress = sender.address;
@@ -137,7 +138,7 @@ const verify = async (args, ui, context) => {
137
138
  if (network === 'custom') {
138
139
  throw new Error('Cannot use custom network');
139
140
  }
140
- const result = await (0, compile_1.doCompile)(sel.name);
141
+ const result = await (0, compile_1.doCompile)(selectedContract);
141
142
  const resHash = result.code.hash();
142
143
  ui.write(`Compiled code hash hex: ${resHash.toString('hex')}`);
143
144
  ui.write('We can look up the address with such code hash in the blockchain automatically');
@@ -1,8 +1,10 @@
1
1
  /// <reference types="node" />
2
2
  import { Cell } from '@ton/core';
3
- import { TactCompilerConfig } from './CompilerConfig';
3
+ import { CompilerConfig, TactCompilerConfig } from './CompilerConfig';
4
4
  export declare function getCompilablesDirectory(): Promise<string>;
5
5
  export declare const COMPILE_END = ".compile.ts";
6
+ export declare function extractCompileConfig(path: string): Promise<CompilerConfig>;
7
+ export declare function getCompilerConfigForContract(name: string): Promise<CompilerConfig>;
6
8
  export type SourceSnapshot = {
7
9
  filename: string;
8
10
  content: string;
@@ -28,8 +30,14 @@ export type TactCompileResult = {
28
30
  fs: Map<string, Buffer>;
29
31
  code: Cell;
30
32
  options?: TactCompilerConfig['options'];
33
+ version: string;
31
34
  };
35
+ export declare function getTactVersion(): Promise<any>;
32
36
  export type CompileResult = TactCompileResult | FuncCompileResult | TolkCompileResult;
37
+ export declare function getCompilerOptions(config: CompilerConfig): Promise<{
38
+ lang: 'tact' | 'tolk' | 'func';
39
+ version: string;
40
+ }>;
33
41
  export declare function doCompile(name: string, opts?: CompileOpts): Promise<CompileResult>;
34
42
  /**
35
43
  * Optional compilation settings, including user data passed to hooks
@@ -25,8 +25,9 @@ var __importStar = (this && this.__importStar) || function (mod) {
25
25
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
27
  };
28
+ var _a, _b;
28
29
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.compile = exports.doCompile = exports.COMPILE_END = exports.getCompilablesDirectory = void 0;
30
+ exports.compile = exports.doCompile = exports.getCompilerOptions = exports.getTactVersion = exports.getCompilerConfigForContract = exports.extractCompileConfig = exports.COMPILE_END = exports.getCompilablesDirectory = void 0;
30
31
  const func_js_1 = require("@ton-community/func-js");
31
32
  const fs_1 = require("fs");
32
33
  const path_1 = __importDefault(require("path"));
@@ -45,15 +46,19 @@ async function getCompilablesDirectory() {
45
46
  }
46
47
  exports.getCompilablesDirectory = getCompilablesDirectory;
47
48
  exports.COMPILE_END = '.compile.ts';
48
- async function getCompilerConfigForContract(name) {
49
- var _a;
50
- const compilablesDirectory = await getCompilablesDirectory();
51
- const mod = await (_a = path_1.default.join(compilablesDirectory, name + exports.COMPILE_END), Promise.resolve().then(() => __importStar(require(_a))));
49
+ async function extractCompileConfig(path) {
50
+ const mod = await (_a = path, Promise.resolve().then(() => __importStar(require(_a))));
52
51
  if (typeof mod.compile !== 'object') {
53
52
  throw new Error(`Object 'compile' is missing`);
54
53
  }
55
54
  return mod.compile;
56
55
  }
56
+ exports.extractCompileConfig = extractCompileConfig;
57
+ async function getCompilerConfigForContract(name) {
58
+ const compilablesDirectory = await getCompilablesDirectory();
59
+ return extractCompileConfig(path_1.default.join(compilablesDirectory, name + exports.COMPILE_END));
60
+ }
61
+ exports.getCompilerConfigForContract = getCompilerConfigForContract;
57
62
  async function doCompileTolk(config) {
58
63
  const res = await (0, tolk_js_1.runTolkCompiler)(config);
59
64
  if (res.status === 'error') {
@@ -116,6 +121,12 @@ function getRootTactConfigOptionsForContract(name) {
116
121
  }
117
122
  return undefined;
118
123
  }
124
+ async function getTactVersion() {
125
+ const packageJsonPath = require.resolve('@tact-lang/compiler/package.json');
126
+ const { version } = await (_b = packageJsonPath, Promise.resolve().then(() => __importStar(require(_b))));
127
+ return version;
128
+ }
129
+ exports.getTactVersion = getTactVersion;
119
130
  async function doCompileTact(config, name) {
120
131
  const rootConfigOptions = getRootTactConfigOptionsForContract(name);
121
132
  const fs = new OverwritableVirtualFileSystem_1.OverwritableVirtualFileSystem(process.cwd());
@@ -139,6 +150,7 @@ async function doCompileTact(config, name) {
139
150
  fs: fs.overwrites,
140
151
  code,
141
152
  options: buildConfig.config.options,
153
+ version: await getTactVersion(),
142
154
  };
143
155
  }
144
156
  async function doCompileInner(name, config) {
@@ -160,6 +172,25 @@ async function doCompileInner(name, config) {
160
172
  optLevel: config.optLevel,
161
173
  });
162
174
  }
175
+ function getCompilerName(config) {
176
+ return config.lang ?? 'func';
177
+ }
178
+ async function getCompilerVersion(config) {
179
+ if (config.lang === 'tact') {
180
+ return getTactVersion();
181
+ }
182
+ if (config.lang === 'tolk') {
183
+ return (0, tolk_js_1.getTolkCompilerVersion)();
184
+ }
185
+ return (await (0, func_js_1.compilerVersion)()).funcVersion;
186
+ }
187
+ async function getCompilerOptions(config) {
188
+ return {
189
+ lang: getCompilerName(config),
190
+ version: await getCompilerVersion(config),
191
+ };
192
+ }
193
+ exports.getCompilerOptions = getCompilerOptions;
163
194
  async function doCompile(name, opts) {
164
195
  const config = await getCompilerConfigForContract(name);
165
196
  if (config.preCompileHook !== undefined) {
package/dist/index.d.ts CHANGED
@@ -8,4 +8,4 @@ export { Config } from './config/Config';
8
8
  export { Args, Runner, RunnerContext } from './cli/Runner';
9
9
  export { PluginRunner, Plugin } from './config/Plugin';
10
10
  export { CustomNetwork } from './config/CustomNetwork';
11
- export { buildOne, buildAll } from './build';
11
+ export { buildOne, buildAll, buildAllTact } from './build';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.buildAll = exports.buildOne = exports.compile = exports.createNetworkProvider = exports.sleep = exports.tonDeepLink = void 0;
3
+ exports.buildAllTact = exports.buildAll = exports.buildOne = exports.compile = exports.createNetworkProvider = exports.sleep = exports.tonDeepLink = void 0;
4
4
  var utils_1 = require("./utils");
5
5
  Object.defineProperty(exports, "tonDeepLink", { enumerable: true, get: function () { return utils_1.tonDeepLink; } });
6
6
  Object.defineProperty(exports, "sleep", { enumerable: true, get: function () { return utils_1.sleep; } });
@@ -11,3 +11,4 @@ Object.defineProperty(exports, "compile", { enumerable: true, get: function () {
11
11
  var build_1 = require("./build");
12
12
  Object.defineProperty(exports, "buildOne", { enumerable: true, get: function () { return build_1.buildOne; } });
13
13
  Object.defineProperty(exports, "buildAll", { enumerable: true, get: function () { return build_1.buildAll; } });
14
+ Object.defineProperty(exports, "buildAllTact", { enumerable: true, get: function () { return build_1.buildAllTact; } });
@@ -2,3 +2,4 @@ export * from './object.utils';
2
2
  export * from './timer.utils';
3
3
  export * from './ton.utils';
4
4
  export * from './selection.utils';
5
+ export * from './string.utils';
@@ -18,3 +18,4 @@ __exportStar(require("./object.utils"), exports);
18
18
  __exportStar(require("./timer.utils"), exports);
19
19
  __exportStar(require("./ton.utils"), exports);
20
20
  __exportStar(require("./selection.utils"), exports);
21
+ __exportStar(require("./string.utils"), exports);
@@ -0,0 +1,2 @@
1
+ export declare function isPascalCase(str: string): boolean;
2
+ export declare function toPascalCase(str: string): string;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toPascalCase = exports.isPascalCase = void 0;
4
+ function isPascalCase(str) {
5
+ return /^[A-Z][a-zA-Z0-9]*$/.test(str);
6
+ }
7
+ exports.isPascalCase = isPascalCase;
8
+ function toPascalCase(str) {
9
+ return str
10
+ .replace(/([a-z])([A-Z])/g, '$1 $2') // Splits camelCase words into separate words
11
+ .replace(/[^a-zA-Z0-9]+/g, ' ') // Replaces all characters that are not allowed with spaces
12
+ .toLowerCase() // Converts the entire string to lowercase
13
+ .replace(/(?:^|\s)(\p{L})/gu, (_, letter) => letter.toUpperCase()) // Capitalizes the first letter of each word
14
+ .replace(/\s+/g, ''); // Removes all spaces
15
+ }
16
+ exports.toPascalCase = toPascalCase;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ton/blueprint",
3
- "version": "0.31.1",
3
+ "version": "0.32.0",
4
4
  "description": "Framework for development of TON smart contracts",
5
5
  "main": "dist/index.js",
6
6
  "bin": "./dist/cli/cli.js",