Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,15 @@ Cached: 0 cached, 2 total
Time: 7.178s
```

**Note:** Speed up the development process by skipping the prover and verifier key file generation:
Speed up the development process by targeting a single directory
and skipping the prover and verifier key file generation:

```bash
turbo compact -- --skip-zk
# Individual module compilation (recommended for development)
turbo compact:token --filter=@openzeppelin-compact/contracts -- --skip-zk

# Full compilation with skip-zk (use environment variable)
SKIP_ZK=true turbo compact
```

### Run tests
Expand Down
45 changes: 38 additions & 7 deletions compact/src/Compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ const COMPACTC_PATH: string = join(COMPACT_HOME, 'compactc');
* compiler.compile().catch(err => console.error(err));
* ```
*
* @example Compile specific directory
* ```typescript
* const compiler = new CompactCompiler('--skip-zk', 'security');
* compiler.compile().catch(err => console.error(err));
* ```
*
* @example Successful Compilation Output
* ```
* ℹ [COMPILE] Found 2 .compact file(s) to compile
Expand All @@ -48,19 +54,26 @@ const COMPACTC_PATH: string = join(COMPACT_HOME, 'compactc');
export class CompactCompiler {
/** Stores the compiler flags passed via command-line arguments */
private readonly flags: string;
/** Optional target directory to limit compilation scope */
private readonly targetDir?: string;

/**
* Constructs a new CompactCompiler instance, validating the `compactc` binary path.
*
* @param flags - Space-separated string of `compactc` flags (e.g., "--skip-zk --no-communications-commitment")
* @param targetDir - Optional subdirectory within src/ to limit compilation (e.g., "security", "utils")
* @throws {Error} If the `compactc` binary is not found at the resolved path
*/
constructor(flags: string) {
constructor(flags: string, targetDir?: string) {
this.flags = flags.trim();
this.targetDir = targetDir;
const spinner = ora();

spinner.info(chalk.blue(`[COMPILE] COMPACT_HOME: ${COMPACT_HOME}`));
spinner.info(chalk.blue(`[COMPILE] COMPACTC_PATH: ${COMPACTC_PATH}`));
if (this.targetDir) {
spinner.info(chalk.blue(`[COMPILE] TARGET_DIR: ${this.targetDir}`));
}

if (!existsSync(COMPACTC_PATH)) {
spinner.fail(
Expand All @@ -73,25 +86,42 @@ export class CompactCompiler {
}

/**
* Compiles all `.compact` files in the source directory and its subdirectories (e.g., `src/test/mock/`).
* Scans the `src` directory recursively for `.compact` files, compiles each one using `compactc`,
* and displays progress with a spinner and colored output.
* Compiles all `.compact` files in the source directory (or target subdirectory) and its subdirectories.
* Scans the `src` directory (or `src/{targetDir}`) recursively for `.compact` files,
* compiles each one using `compactc`, and displays progress with a spinner and colored output.
*
* @returns A promise that resolves when all files are compiled successfully
* @throws {Error} If compilation fails for any file
*/
public async compile(): Promise<void> {
const compactFiles: string[] = await this.getCompactFiles(SRC_DIR);
const searchDir = this.targetDir ? join(SRC_DIR, this.targetDir) : SRC_DIR;

// Validate target directory exists
if (this.targetDir && !existsSync(searchDir)) {
const spinner = ora();
spinner.fail(
chalk.red(
`[COMPILE] Error: Target directory ${searchDir} does not exist.`,
),
);
throw new Error(`Target directory ${searchDir} does not exist`);
}

const compactFiles: string[] = await this.getCompactFiles(searchDir);

const spinner = ora();
if (compactFiles.length === 0) {
spinner.warn(chalk.yellow('[COMPILE] No .compact files found.'));
const searchLocation = this.targetDir ? `${this.targetDir}/` : '';
spinner.warn(
chalk.yellow(`[COMPILE] No .compact files found in ${searchLocation}.`),
);
return;
}

const searchLocation = this.targetDir ? ` in ${this.targetDir}/` : '';
spinner.info(
chalk.blue(
`[COMPILE] Found ${compactFiles.length} .compact file(s) to compile`,
`[COMPILE] Found ${compactFiles.length} .compact file(s) to compile${searchLocation}`,
),
);

Expand Down Expand Up @@ -123,6 +153,7 @@ export class CompactCompiler {
}

if (entry.isFile() && fullPath.endsWith('.compact')) {
// Always return relative path from SRC_DIR, regardless of search directory
return [relative(SRC_DIR, fullPath)];
}
return [];
Expand Down
79 changes: 74 additions & 5 deletions compact/src/runCompiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,95 @@ import { CompactCompiler } from './Compiler.js';
* Executes the Compact compiler CLI.
* Compiles `.compact` files using the `CompactCompiler` class with provided flags.
*
* @example
* For individual module compilation, CLI flags work directly.
* For full compilation with dependencies, use environment variables due to Turbo task orchestration.
*
* @example Individual module compilation (CLI flags work directly)
* ```bash
* npx compact-compiler --dir security --skip-zk
* turbo compact:access -- --skip-zk
* turbo compact:security -- --skip-zk --other-flag
* ```
*
* @example Full compilation (environment variables required)
* ```bash
* # Use environment variables for full builds due to task dependencies
* SKIP_ZK=true turbo compact
*
* # Normal full build
* turbo compact
* ```
*
* @example Direct CLI usage
* ```bash
* npx compact-compiler --skip-zk
* npx compact-compiler --dir security --skip-zk
* ```
*
* Environment Variables (only needed for full builds):
* - `SKIP_ZK=true`: Adds --skip-zk flag when running full compilation via `turbo compact`
*
* Expected output:
* ```
* ℹ [COMPILE] Compact compiler started
* ℹ [COMPILE] COMPACT_HOME: /path/to/compactc
* ℹ [COMPILE] COMPACTC_PATH: /path/to/compactc/compactc
* ℹ [COMPILE] Found 1 .compact file(s) to compile
* ✔ [COMPILE] [1/1] Compiled Foo.compact
* ℹ [COMPILE] TARGET_DIR: access:compact:access:
* ℹ [COMPILE] Found 4 .compact file(s) to compile in access/
* ✔ [COMPILE] [1/4] Compiled access/AccessControl.compact
* ✔ [COMPILE] [2/4] Compiled access/Ownable.compact
* ✔ [COMPILE] [3/4] Compiled access/test/mocks/MockAccessControl.compact
* ✔ [COMPILE] [4/4] Compiled access/test/mocks/MockOwnable.compact
* Compactc version: 0.24.0
* ```
*/
async function runCompiler(): Promise<void> {
const spinner = ora(chalk.blue('[COMPILE] Compact Compiler started')).info();

try {
const compilerFlags = process.argv.slice(2).join(' ');
const compiler = new CompactCompiler(compilerFlags);
const args = process.argv.slice(2);

// Parse arguments more robustly
let targetDir: string | undefined;
const compilerFlags: string[] = [];

// Handle common development flags via environment variables
// This is especially useful when using with Turbo monorepo tasks
if (process.env.SKIP_ZK === 'true') {
compilerFlags.push('--skip-zk');
}

for (let i = 0; i < args.length; i++) {
if (args[i] === '--dir') {
const dirNameExists =
i + 1 < args.length && !args[i + 1].startsWith('--');
if (dirNameExists) {
targetDir = args[i + 1];
i++; // Skip the next argument (directory name)
} else {
spinner.fail(
chalk.red('[COMPILE] Error: --dir flag requires a directory name'),
);
console.log(
chalk.yellow(
'Usage: compact-compiler --dir <directory> [other-flags]',
),
);
console.log(
chalk.yellow('Example: compact-compiler --dir access --skip-zk'),
);
console.log(
chalk.yellow('Example: SKIP_ZK=true compact-compiler --dir access'),
);
process.exit(1);
}
} else {
// All other arguments are compiler flags
compilerFlags.push(args[i]);
}
}

const compiler = new CompactCompiler(compilerFlags.join(' '), targetDir);
await compiler.compile();
} catch (err) {
spinner.fail(
Expand Down
7 changes: 6 additions & 1 deletion contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@
},
"scripts": {
"compact": "compact-compiler",
"compact:access": "compact-compiler --dir access",
"compact:archive": "compact-compiler --dir archive",
"compact:security": "compact-compiler --dir security",
"compact:token": "compact-compiler --dir token",
"compact:utils": "compact-compiler --dir utils",
"build": "compact-builder && tsc",
"test": "vitest run",
"test": "compact-compiler --skip-zk && vitest run",
"types": "tsc -p tsconfig.json --noEmit",
"clean": "git clean -fXd"
},
Expand Down
58 changes: 53 additions & 5 deletions turbo.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,65 @@
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"compact": {
"compact:security": {
"dependsOn": ["^build"],
"env": ["COMPACT_HOME"],
"inputs": ["contracts/src/**/*.compact"],
"env": ["COMPACT_HOME", "SKIP_ZK"],
"inputs": ["src/security/**/*.compact"],
"outputLogs": "new-only",
"outputs": ["artifacts/**/"]
},
"compact:utils": {
"dependsOn": ["^build"],
"env": ["COMPACT_HOME", "SKIP_ZK"],
"inputs": ["src/utils/**/*.compact"],
"outputLogs": "new-only",
"outputs": ["artifacts/**/"]
},
"compact:access": {
"dependsOn": ["^build", "compact:security", "compact:utils"],
"env": ["COMPACT_HOME", "SKIP_ZK"],
"inputs": ["src/access/**/*.compact"],
"outputLogs": "new-only",
"outputs": ["artifacts/**/"]
},
"compact:archive": {
"dependsOn": ["^build", "compact:utils"],
"env": ["COMPACT_HOME", "SKIP_ZK"],
"inputs": ["src/archive/**/*.compact"],
"outputLogs": "new-only",
"outputs": ["artifacts/**/"]
},
"compact:token": {
"dependsOn": ["^build", "compact:security", "compact:utils"],
"env": ["COMPACT_HOME", "SKIP_ZK"],
"inputs": ["src/token/**/*.compact"],
"outputLogs": "new-only",
"outputs": ["artifacts/**/"]
},
"compact": {
"dependsOn": [
"compact:security",
"compact:utils",
"compact:access",
"compact:archive",
"compact:token"
],
"env": ["COMPACT_HOME", "SKIP_ZK"],
"inputs": ["src/**/*.compact", "test/**/*.compact"],
"outputLogs": "new-only",
"outputs": ["artifacts/**"]
},
"test": {
"dependsOn": ["^build", "compact"],
"dependsOn": ["^build"],
"env": ["COMPACT_HOME"],
"inputs": [
"src/**/*.ts",
"src/**/*.compact",
"vitest.config.ts",
"package.json"
],
"outputs": [],
"cache": false
"cache": true
},
"build": {
"dependsOn": ["^build"],
Expand Down
Loading