diff --git a/CHANGELOG.md b/CHANGELOG.md index bfd3a9ed6f..4c23c47043 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ The minor version will be incremented upon a breaking change and the patch versi - spl: Add pausable mint extension support ([#4092](https://github.com/solana-foundation/anchor/pull/4092)). - cli: Resolve the target directory via `cargo metadata` to support target directory overrides ([#3817](https://github.com/solana-foundation/anchor/pull/3817)). - spl: Added `token_metadata_remove_key` to support removing keys from token metadata extension ([#3717](https://github.com/solana-foundation/anchor/pull/3717)). +- cli: Allow configuring IDL JSON location in workspace config ([#4483](https://github.com/solana-foundation/anchor/pull/4483)). - lang: Derive `Clone`, `Debug`, `Copy`, and `Default` on generated client / CPI account structs and instruction args where the field types allow it ([#4085](https://github.com/solana-foundation/anchor/pull/4085)). - lang: Add `AccountLoader::new_unchecked` for constructing an `AccountLoader` without performing owner or discriminator checks ([#4162](https://github.com/solana-foundation/anchor/pull/4162)). diff --git a/cli/src/config.rs b/cli/src/config.rs index f8582fc7b1..1275b4c39f 100644 --- a/cli/src/config.rs +++ b/cli/src/config.rs @@ -608,6 +608,8 @@ pub struct WorkspaceConfig { #[serde(default, skip_serializing_if = "Vec::is_empty")] pub exclude: Vec, #[serde(default, skip_serializing_if = "String::is_empty")] + pub idls: String, + #[serde(default, skip_serializing_if = "String::is_empty")] pub types: String, } diff --git a/cli/src/lib.rs b/cli/src/lib.rs index f0ea92f335..8741dbd1ec 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -2132,6 +2132,9 @@ pub fn build( }; fs::create_dir_all(idl_ts_out.as_ref().unwrap())?; + if !cfg.workspace.idls.is_empty() { + fs::create_dir_all(cfg_parent.join(&cfg.workspace.idls))?; + }; if !cfg.workspace.types.is_empty() { fs::create_dir_all(cfg_parent.join(&cfg.workspace.types))?; }; @@ -2450,6 +2453,9 @@ fn build_cwd_verifiable( fs::create_dir_all(target_dir.join("verifiable"))?; fs::create_dir_all(target_dir.join("idl"))?; fs::create_dir_all(target_dir.join("types"))?; + if !&cfg.workspace.idls.is_empty() { + fs::create_dir_all(workspace_dir.join(&cfg.workspace.idls))?; + } if !&cfg.workspace.types.is_empty() { fs::create_dir_all(workspace_dir.join(&cfg.workspace.types))?; } @@ -2485,6 +2491,18 @@ fn build_cwd_verifiable( .with_extension("json"); write_idl(&idl, OutFile::File(out_file.clone()))?; + if !&cfg.workspace.idls.is_empty() { + write_idl( + &idl, + OutFile::File( + workspace_dir + .join(&cfg.workspace.idls) + .join(&idl.metadata.name) + .with_extension("json"), + ), + )?; + } + // Write out the TypeScript type. println!("Writing the .ts file"); let ts_file = target_dir @@ -2772,6 +2790,7 @@ fn _build_rust_cwd( // Generate IDL if !no_idl { let idl = generate_idl(cfg, skip_lint, no_docs, &cargo_args)?; + let cfg_parent = cfg.path().parent().expect("Invalid Anchor.toml"); // JSON out path. let out = match idl_out { @@ -2790,11 +2809,21 @@ fn _build_rust_cwd( // Write out the JSON file. write_idl(&idl, OutFile::File(out.clone()))?; + if !&cfg.workspace.idls.is_empty() { + write_idl( + &idl, + OutFile::File( + cfg_parent + .join(&cfg.workspace.idls) + .join(&idl.metadata.name) + .with_extension("json"), + ), + )?; + } // Write out the TypeScript type. fs::write(&ts_out, idl_ts(&idl)?)?; // Copy out the TypeScript type. - let cfg_parent = cfg.path().parent().expect("Invalid Anchor.toml"); if !&cfg.workspace.types.is_empty() { fs::copy( &ts_out, diff --git a/docs/content/docs/references/anchor-toml.mdx b/docs/content/docs/references/anchor-toml.mdx index 6a04bb95d5..f459ad64df 100644 --- a/docs/content/docs/references/anchor-toml.mdx +++ b/docs/content/docs/references/anchor-toml.mdx @@ -54,10 +54,24 @@ resolution = true ## workspace +### idls + +Adds a directory where you want the `.json` file to be copied when running +`anchor build`. This is helpful when you want the generated IDL JSON outside the +workspace `target` directory, such as for versioning or consumption by another +tool. + +Example: + +```toml +[workspace] +idls = "app/src/idls/" +``` + ### types -Adds a directory where you want the `.ts` file to be copied when running -`anchor build`. This is helpful when you want to keep this file in version +Adds a directory where you want the `.ts` file to be copied when running +`anchor build`. This is helpful when you want to keep IDL type definitions in version control, like when using it on the frontend, which will probably not have access to the `target` directory generated by anchor. @@ -65,7 +79,7 @@ Example: ```toml [workspace] -types = "app/src/idl/" +types = "app/src/idls/" ``` ### members diff --git a/tests/idl/.gitignore b/tests/idl/.gitignore new file mode 100644 index 0000000000..570d0cdcfd --- /dev/null +++ b/tests/idl/.gitignore @@ -0,0 +1,2 @@ +workspace-idls +workspace-types diff --git a/tests/idl/Anchor.toml b/tests/idl/Anchor.toml index fa49ee54de..5cf4526d95 100644 --- a/tests/idl/Anchor.toml +++ b/tests/idl/Anchor.toml @@ -14,5 +14,9 @@ numbers_123 = { address = "Numbers111111111111111111111111111111111111", idl = " cluster = "localnet" wallet = "~/.config/solana/id.json" +[workspace] +idls = "workspace-idls" +types = "workspace-types" + [scripts] test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" diff --git a/tests/idl/test.sh b/tests/idl/test.sh index dddb877b62..257792dcef 100755 --- a/tests/idl/test.sh +++ b/tests/idl/test.sh @@ -17,6 +17,18 @@ popd # Run anchor test anchor test --skip-lint +# Verify workspace.idl copies the generated JSON files out of `target/idl`. +for idl in target/idl/*.json; do + filename=$(basename "$idl") + diff -u "$idl" "workspace-idls/$filename" +done + +# Verify workspace.types copies the generated TypeScript files out of `target/types`. +for types in target/types/*.ts; do + filename=$(basename "$types") + diff -u "$types" "workspace-types/$filename" +done + # Generate IDLs ./generate.sh $tmp_dir