Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved CLI #287

Merged
merged 39 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
b031539
chore: add meow, clean up the tact entry point
vitorpy Apr 27, 2024
46bea40
chore: remove tabs from tact script
vitorpy Apr 27, 2024
3c39774
feat: add --func and --check
vitorpy Apr 27, 2024
650d3cb
fix: remove extra packageManager entry from package.json
vitorpy Apr 27, 2024
ce957f6
fix: reintroduce --config and move bin/tact to bin/tact.mjs
vitorpy Apr 28, 2024
ce2a40c
fix: remove extra packageManager entry from package.json and tsconfig…
vitorpy Apr 28, 2024
f13ce1e
fix: rename references to bin/tact in the GitHub workflow
vitorpy Apr 28, 2024
08ba95e
chore: update CHANGELOG.md
vitorpy Apr 28, 2024
94f4dcd
chore: merge upstream/main
vitorpy Apr 28, 2024
5b76f06
Update bin/tact.mjs
vitorpy Apr 28, 2024
df99e2a
Update bin/tact.mjs
vitorpy Apr 28, 2024
b061500
Update bin/tact.mjs
vitorpy Apr 28, 2024
efe0501
Update bin/tact.mjs
vitorpy Apr 28, 2024
cb0455b
Update CHANGELOG.md
vitorpy Apr 28, 2024
d757a47
feat: compile single file
vitorpy Apr 28, 2024
f0ed93a
fix: refactor cli args into the config object
vitorpy Apr 29, 2024
6fe29ea
chore: run prettier
vitorpy Apr 29, 2024
d91ff38
feat: add tests.
vitorpy Apr 29, 2024
3a139b2
chore: run prettier
vitorpy Apr 29, 2024
1531725
fix: bin/tact for Blueprint compatibility
vitorpy Apr 29, 2024
df6813e
fix: handle symlinks in the bin/tact wrapper script
vitorpy Apr 29, 2024
ae2c5f6
fix: handle symlinks in macos, avoid negations on the windows flow
vitorpy Apr 29, 2024
7a02591
fix: rename bin tact.mjs to tact to avoid issues on windows
vitorpy Apr 29, 2024
996b70a
Merge branch 'main' into new-cli
vitorpy Apr 29, 2024
dffe193
fix/feat: debugged and enhanced the CLI
novusnota Apr 30, 2024
8c083cb
fix: debugged issues and simplified configurations
novusnota Apr 30, 2024
2917688
feat: extended JSON Schema for tact.config.json
novusnota Apr 30, 2024
d340daf
fix: moved catching of empty config after `--config` flag onto the bu…
novusnota Apr 30, 2024
4d2ea34
chore: better wording
novusnota Apr 30, 2024
3ccfb6f
chore: updated CHANGELOG
novusnota Apr 30, 2024
81c099e
chore: remove redundant line from CHANGELOG
novusnota May 1, 2024
c38b42c
feat: Introduce an enum for the compilation mode over disjoint boolea…
novusnota May 1, 2024
7dbb345
chore: Visible default values (only as a schema completion hints)
novusnota May 1, 2024
93c7fe0
chore: misc. things
novusnota May 1, 2024
0b18c8c
feat: Enum of strings for compilation `mode` over many disjoint boole…
novusnota May 1, 2024
a0257f8
fix: Bug with single and non-single file usage
novusnota May 1, 2024
b6f9644
chore: Update workflows
novusnota May 1, 2024
dcb8346
Apply suggestions from code review
novusnota May 1, 2024
d21d038
fix: corrected precedence -- local flags override ones in config
novusnota May 2, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions .github/workflows/tact.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ jobs:
cache: "yarn"

- name: Install dependencies
run: yarn install

run: |
corepack enable
yarn install

- name: Build and Test Tact compiler
run: |
Expand All @@ -54,17 +57,32 @@ jobs:
run: |
type examples\output\echo_Echo.pkg

- name: Install the package locally
run: |
npm install -g ./

- name: Compare Tact version from CLI flag `--version` against package.json
novusnota marked this conversation as resolved.
Show resolved Hide resolved
if: runner.os != 'Windows'
run: |
if [ "$(./bin/tact --version)" != "$(jq -r '.version' < package.json)" ];
if [ "$(tact --version)" != "$(jq -r '.version' < package.json)" ];
then false
fi

- name: Check command line options
anton-trunov marked this conversation as resolved.
Show resolved Hide resolved
novusnota marked this conversation as resolved.
Show resolved Hide resolved
run: |
tact --check test/tact-cli/success.tact
tact --func test/tact-cli/success.tact
tact test/tact-cli/success.tact

- name: Check command line arguments parsing
novusnota marked this conversation as resolved.
Show resolved Hide resolved
if: runner.os != 'Windows'
run: |
! tact --nonexistentoption test/tact-cli/success.config.json

- name: Tact CLI non-zero exit code
novusnota marked this conversation as resolved.
Show resolved Hide resolved
if: runner.os != 'Windows'
run: |
! ./bin/tact --config test/tact-cli/tact.config.json
! tact --config test/tact-cli/fail.config.json

- name: Link Tact compiler
run: |
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- The `pow2` power function with base 2: PR [#267](https://github.com/tact-lang/tact/pull/267)
- The `try` and `try-catch` statements: PR [#212](https://github.com/tact-lang/tact/pull/212)
- The `del` method for the `Map` type: PR [#95](https://github.com/tact-lang/tact/pull/95)
- The `-h`/`--help`, `-v` (short for `--version`), `-p` (short for `--project`), `--func` (for only outputting FunC code) and `--check` (for only doing the syntax and type checking) command-line flags: PR [#287](https://github.com/tact-lang/tact/pull/287)
- The `mode` enum in project properties of `tact.config.json` for specifying compilation mode: `full` (default), `funcOnly` (only outputs FunC code and exits), or `checkOnly` (only does the syntax and type checking, then exits): PR [#287](https://github.com/tact-lang/tact/pull/287)

### Changed

Expand All @@ -34,6 +36,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Use `|` instead of `+` for send mode flags because the bitwise OR operation is idempotent and hence safer: PR [#274](https://github.com/tact-lang/tact/pull/274)
- Bumped the versions of `@ton/core` and `ohm-js` to the most recent ones: PR [#276](https://github.com/tact-lang/tact/pull/276)
- Generated `.pkg`-files always use POSIX file paths (even on Windows): PR [# 300](https://github.com/tact-lang/tact/pull/300)
- The `-p`/`--project` flags now allow specifying more than one project name. Additionally, they also require a `--config` flag to be specified: PR [#287](https://github.com/tact-lang/tact/pull/287)
- Command-line interface now allows compiling a single Tact file directly, without specifying a config: PR [#287](https://github.com/tact-lang/tact/pull/287)

### Fixed

Expand Down
174 changes: 138 additions & 36 deletions bin/tact
Original file line number Diff line number Diff line change
@@ -1,38 +1,140 @@
#!/usr/bin/env node
const main = require("../dist/node");
const arg = require("arg");

// Resolve arguments
const args = arg({
"--config": String,
"--project": String,
"--version": Boolean,
});

if (args["--version"]) {
console.log("1.2.0");
return;
}

if (!args["--config"]) {
console.log("USAGE: tact --config <config_path> [--project <project_name]");
return;
}

// Perform compilation
(async () => {
try {
const success = await main.run({
configPath: args["--config"],
projectNames: args["--project"] ? args["--project"] : [],
});
// https://nodejs.org/docs/v20.12.1/api/process.html#exit-codes
if (!success) process.exit(30);
} catch (e) {
console.warn(
"Internal compiler error. Please, report it to https://github.com/tact-lang/tact/issues.",

// @ts-nocheck
const pkg = require("../package.json");
const main = require("../dist/node.js");
const meowModule = import("meow");

meowModule.then(
/** @param meow {import('meow/build/index')} */
(meow) => {
const cli = meow.default(
`
Usage
$ tact [...flags] (--config CONFIG | FILE)

Flags
-c, --config CONFIG Specify path to config file (tact.config.json)
-p, --project ...names Build only the specified project name(s) from the config file
--func Output intermediate FunC code and exit
--check Perform syntax and type checking, then exit
-v, --version Print Tact compiler version and exit
-h, --help Display this text and exit

Examples
$ tact --version
${pkg.version}

Learn more about Tact: https://docs.tact-lang.org
Join Telegram group: https://t.me/tactlang
Follow X/Twitter account: https://twitter.com/tact_language`,
{
importMeta: {
url: new URL("file://" + __dirname + __filename).toString(),
},
description: `Command-line utility for the Tact compiler:\n${pkg.description}`,
flags: {
config: {
shortFlag: "c",
type: "string",
isRequired: (flags, _) => {
// Require a config when the projects are specified AND version/help are not specified
if (
flags.projects.length !== 0 &&
!flags.version &&
!flags.help
) {
return true;
}
// Don't require it otherwise
return false;
},
},
projects: { shortFlag: "p", type: "string", isMultiple: true },
func: { type: "boolean", default: false },
check: { type: "boolean", default: false },
version: { shortFlag: "v", type: "boolean" },
help: { shortFlag: "h", type: "boolean" },
},
allowUnknownFlags: false,
},
);
console.log(e);
process.exit(30);
}
})();

// Helper function to write less in following checks
const isEmptyConfigAndInput = () => {
if (cli.flags.config === undefined && cli.input.length === 0) {
return true;
}
return false;
};

// Show help regardless of other flags
if (cli.flags.help) {
cli.showHelp(0);
}

// Show version regardless of other flags
if (cli.flags.version) {
cli.showVersion();
}

// Disallow specifying both config or Tact source file at the same time
if (cli.flags.config !== undefined && cli.input.length > 0) {
console.log(
"Error: Both config and Tact file can't be simultaneously specified, pick one!",
);
cli.showHelp();
}

// Disallow specifying both --func and --check flags at the same time
if (cli.flags.check && cli.flags.func) {
console.log("Error: Flags --func and --check are mutually exclusive!");
cli.showHelp();
}

// Disallow running --func and --check flags without a config or a file specified
if (isEmptyConfigAndInput() && (cli.flags.check || cli.flags.func)) {
console.log("Error: Either config or Tact file have to be specified!");
cli.showHelp();
}

// Disallow specifying more than one Tact file
if (cli.input.length > 1) {
console.log(
"Error: Only one Tact file can be specified at a time. If you want more, provide a config!",
);
cli.showHelp();
}

// Show help when all flags and inputs are empty
// Note, that version/help flags are already processed above and don't need to be mentioned here
if (
isEmptyConfigAndInput() &&
!cli.flags.check &&
!cli.flags.func &&
cli.flags.projects.length === 0
) {
cli.showHelp(0);
}

// Compilation mode
const mode = cli.flags.check
? "checkOnly"
: cli.flags.func
? "funcOnly"
: undefined;

// Main command
main
.run({
fileName: cli.input.at(0),
configPath: cli.flags.config,
projectNames: cli.flags.projects ?? [],
singleFileOptions: { mode },
})
.then((success) => {
// https://nodejs.org/docs/v20.12.1/api/process.html#exit-codes
process.exit(success ? 0 : 30);
});
},
);
11 changes: 11 additions & 0 deletions grammar/configSchema.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,17 @@
"properties": {
"debug": {
"type": "boolean",
"default": false,
"description": "False by default. If set to true, enables debug output of a contract and allows usage of `dump()` function, which is useful for debugging purposes. With this option enabled, the contract will report that it was compiled in debug mode using the supported_interfaces method.\n\nRead more on debugging Tact code: https://docs.tact-lang.org/book/debug."
},
"masterchain": {
"type": "boolean",
"default": false,
"description": "False by default. If set to true, enables masterchain support.\n\nRead more about masterchain: https://docs.tact-lang.org/book/masterchain."
},
"external": {
"type": "boolean",
"default": false,
"description": "False by default. If set to true, enables support of external message receivers.\n\nRead more about external message receivers: https://docs.tact-lang.org/book/external."
},
"experimental": {
Expand All @@ -47,11 +50,19 @@
"properties": {
"inline": {
"type": "boolean",
"default": false,
"description": "False by default. If set to true, enables inlining of all functions in contracts. This can reduce gas usage at the cost of bigger contracts."
}
}
}
}
},
"mode": {
"type": "string",
"default": "full",
"enum": ["full", "checkOnly", "funcOnly"],
"title": "Compilation mode of the project.",
"description": "Set to `full` by default, which runs the whole pipeline of the compilation and emits FunC code, BoC and various utility files, including wrappers for TypeScript.\nIf set to `checkOnly`, only performs syntax and type checking, preventing further compilation.\nIf set to `funcOnly`, only outputs intermediate FunC code, preventing further compilation."
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@
"@tact-lang/opcode": "^0.0.14",
"@ton/core": "0.56.3",
"@ton/crypto": "^3.2.0",
"arg": "^5.0.2",
"blockstore-core": "1.0.5",
"change-case": "^4.1.2",
"ipfs-unixfs-importer": "9.0.10",
"meow": "^13.2.0",
"mkdirp": "^2.1.3",
"multiformats": "^13.1.0",
"ohm-js": "^17.1.0",
Expand Down
1 change: 1 addition & 0 deletions src/config/parseConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const projectSchema = z
path: z.string(),
output: z.string(),
options: optionsSchema.optional(),
mode: z.enum(["full", "checkOnly", "funcOnly"]).optional(),
})
.strict();

Expand Down
Loading
Loading