diff --git a/README.md b/README.md index 0e730124..6b688a27 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/compact/src/Compiler.ts b/compact/src/Compiler.ts index 53b292ae..af426286 100755 --- a/compact/src/Compiler.ts +++ b/compact/src/Compiler.ts @@ -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 @@ -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( @@ -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 { - 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}`, ), ); @@ -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 []; diff --git a/compact/src/runCompiler.ts b/compact/src/runCompiler.ts index b7a84f24..8d5b98aa 100644 --- a/compact/src/runCompiler.ts +++ b/compact/src/runCompiler.ts @@ -8,17 +8,45 @@ 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 * ``` */ @@ -26,8 +54,49 @@ async function runCompiler(): Promise { 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 [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( diff --git a/contracts/package.json b/contracts/package.json index 493433f8..acd41414 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -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" }, diff --git a/turbo.json b/turbo.json index 8dc18388..f6041193 100644 --- a/turbo.json +++ b/turbo.json @@ -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"],