Skip to content

Commit

Permalink
fix: preserve line comments on creating/ modifying rust code (#382)
Browse files Browse the repository at this point in the history
* Refactor un_parse_pretty function

* Move important scaffold functions to the top of the module for easy accesss

* fix improper use of bool.then_some

* ensure line comments are preserved

* derive a convert rust line comments to doc comments util function and apply to map_rust_files function

* ensure initially generated comments are correctly formatted

* remove unnecessary inline attribute on unparse_pretty

* Replace once_cell::Lazy with standard lib LazyLock
  • Loading branch information
c12i authored Oct 4, 2024
1 parent 5c69d96 commit 5bf7183
Show file tree
Hide file tree
Showing 16 changed files with 931 additions and 832 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,3 @@ colored = "2.1.0"
dprint-plugin-typescript = "0.91.1"
markup_fmt = "0.10.0"
git2 = { version = "0.19.0", default-features = false, features = ["https", "ssh_key_from_memory", "vendored-libgit2", "vendored-openssl"] }
once_cell = "1.19.0"
41 changes: 39 additions & 2 deletions src/file_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use anyhow::Context;
use build_fs_tree::{dir, file, Build, FileSystemTree, MergeableFileSystemTree};
use ignore::WalkBuilder;
use include_dir::Dir;
use regex::Regex;
use std::collections::BTreeMap;
use std::ffi::OsString;
use std::fs;
Expand Down Expand Up @@ -81,6 +82,8 @@ pub fn insert_file(
let mut folder_path = file_path.to_path_buf();
folder_path.pop();

let content = convert_rust_line_to_doc_comments(file_path, content);

insert_file_tree_in_dir(
file_tree,
&folder_path,
Expand Down Expand Up @@ -191,8 +194,11 @@ pub fn map_rust_files<F: Fn(PathBuf, syn::File) -> ScaffoldResult<syn::File> + C
map_all_files(file_tree, |file_path, contents| {
if let Some(extension) = file_path.extension() {
if extension == "rs" {
let original_file: syn::File = syn::parse_str(&contents)
.map_err(|e| ScaffoldError::MalformedFile(file_path.clone(), e.to_string()))?;
let original_file: syn::File =
syn::parse_str(&convert_rust_line_to_doc_comments(&file_path, &contents))
.map_err(|e| {
ScaffoldError::MalformedFile(file_path.clone(), e.to_string())
})?;
let new_file = map_fn(file_path, original_file.clone())?;
// Only reformat the file via unparse_pretty if the contents of the newly modified
// file are different from the original
Expand All @@ -205,6 +211,37 @@ pub fn map_rust_files<F: Fn(PathBuf, syn::File) -> ScaffoldResult<syn::File> + C
})
}

/// Converts line comments to doc comments in Rust files
///
/// This function is a workaround for a limitation in the `prettyplease::unparse` function,
/// which is used to pretty-print Rust syntax trees. The `unparse` function discards line
/// comments but preserves doc comments. To maintain all comments in the code, this function
/// converts line comments to doc comments before parsing, allowing them to be preserved
/// during the pretty-printing process.
///
/// After pretty-printing, these doc comments can be converted back to line comments if needed.
///
/// # Arguments
///
/// * `file_path` - A reference to the Path of the file being processed
/// * `content` - A string slice containing the content of the file
///
/// # Returns
///
/// A String with line comments converted to doc comments if the file is a Rust file,
/// otherwise returns the original content unchanged.
fn convert_rust_line_to_doc_comments(file_path: &Path, content: &str) -> String {
if file_path.extension().and_then(|ext| ext.to_str()) == Some("rs") {
let re = Regex::new(r"^\/\/[^\/]|[^\/]\/\/[^\/]").expect("Failed to create regex");
content
.lines()
.map(|line| re.replace_all(line, "/// ").into_owned() + "\n")
.collect()
} else {
content.to_string()
}
}

pub fn flatten_file_tree(file_tree: &FileTree) -> BTreeMap<PathBuf, Option<String>> {
walk_file_tree_rec(file_tree, &PathBuf::new())
}
Expand Down
200 changes: 100 additions & 100 deletions src/scaffold/collection/coordinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,106 @@ use crate::{

use super::CollectionType;

pub fn add_collection_to_coordinators(
integrity_zome_file_tree: ZomeFileTree,
collection_name: &str,
link_type_name: &str,
collection_type: &CollectionType,
entry_type: &EntryTypeReference,
) -> ScaffoldResult<(DnaFileTree, ZomeManifest, bool)> {
let integrity_zome_name = integrity_zome_file_tree.zome_manifest.name.0.to_string();
let dna_manifest_path = integrity_zome_file_tree
.dna_file_tree
.dna_manifest_path
.clone();

let coordinator_zomes_for_integrity = get_coordinator_zomes_for_integrity(
&integrity_zome_file_tree.dna_file_tree.dna_manifest,
&integrity_zome_name,
);

let coordinator_zome = match coordinator_zomes_for_integrity.len() {
0 => Err(ScaffoldError::NoCoordinatorZomesFoundForIntegrityZome(
integrity_zome_file_tree.dna_file_tree.dna_manifest.name(),
integrity_zome_file_tree.zome_manifest.name.0.to_string(),
)),
1 => Ok(coordinator_zomes_for_integrity[0].clone()),
_ => {
let names: Vec<String> = coordinator_zomes_for_integrity
.iter()
.map(|z| z.name.0.to_string())
.collect();
let selection = Select::with_theme(&ColorfulTheme::default())
.with_prompt(
"Which coordinator zome should the collection getter functions be scaffolded in?",
)
.default(0)
.items(&names[..])
.interact()?;

Ok(coordinator_zomes_for_integrity[selection].clone())
}
}?;

// 1. Create an INDEX_NAME.rs in "src/", with the appropriate zome functions
let zome_file_tree = ZomeFileTree::from_zome_manifest(
integrity_zome_file_tree.dna_file_tree,
coordinator_zome.clone(),
)?;

let snake_link_type_name = collection_name.to_case(Case::Snake);

let getter = match collection_type {
CollectionType::Global => {
global_collection_getter(&integrity_zome_name, collection_name, link_type_name)
}
CollectionType::ByAuthor => {
by_author_collection_getter(&integrity_zome_name, collection_name, link_type_name)
}
};

let mut file_tree = zome_file_tree.dna_file_tree.file_tree();

let crate_src_path = zome_file_tree.zome_crate_path.join("src");
let collection_path = crate_src_path.join(format!("{}.rs", snake_link_type_name.clone()));

let file = unparse_pretty(&syn::parse_quote! { #getter });

insert_file(&mut file_tree, &collection_path, &file)?;

// 2. Add this file as a module in the entry point for the crate
let lib_rs_path = crate_src_path.join("lib.rs");

map_file(&mut file_tree, &lib_rs_path, |contents| {
Ok(format!(
r#"pub mod {snake_link_type_name};
{contents}"#,
))
})?;

let mut dna_file_tree = DnaFileTree::from_dna_manifest_path(file_tree, &dna_manifest_path)?;

dna_file_tree = add_create_link_in_create_function(
dna_file_tree,
&coordinator_zomes_for_integrity,
collection_name,
link_type_name,
collection_type,
entry_type,
)?;

let (dna_file_tree, deletable) = add_delete_link_in_delete_function(
dna_file_tree,
&coordinator_zomes_for_integrity,
collection_name,
link_type_name,
collection_type,
entry_type,
)?;

Ok((dna_file_tree, coordinator_zome, deletable))
}

fn global_collection_getter(
integrity_zome_name: &str,
collection_name: &str,
Expand Down Expand Up @@ -328,103 +428,3 @@ fn add_delete_link_in_delete_function(

Ok((dna_file_tree, true))
}

pub fn add_collection_to_coordinators(
integrity_zome_file_tree: ZomeFileTree,
collection_name: &str,
link_type_name: &str,
collection_type: &CollectionType,
entry_type: &EntryTypeReference,
) -> ScaffoldResult<(DnaFileTree, ZomeManifest, bool)> {
let integrity_zome_name = integrity_zome_file_tree.zome_manifest.name.0.to_string();
let dna_manifest_path = integrity_zome_file_tree
.dna_file_tree
.dna_manifest_path
.clone();

let coordinator_zomes_for_integrity = get_coordinator_zomes_for_integrity(
&integrity_zome_file_tree.dna_file_tree.dna_manifest,
&integrity_zome_name,
);

let coordinator_zome = match coordinator_zomes_for_integrity.len() {
0 => Err(ScaffoldError::NoCoordinatorZomesFoundForIntegrityZome(
integrity_zome_file_tree.dna_file_tree.dna_manifest.name(),
integrity_zome_file_tree.zome_manifest.name.0.to_string(),
)),
1 => Ok(coordinator_zomes_for_integrity[0].clone()),
_ => {
let names: Vec<String> = coordinator_zomes_for_integrity
.iter()
.map(|z| z.name.0.to_string())
.collect();
let selection = Select::with_theme(&ColorfulTheme::default())
.with_prompt(
"Which coordinator zome should the collection getter functions be scaffolded in?",
)
.default(0)
.items(&names[..])
.interact()?;

Ok(coordinator_zomes_for_integrity[selection].clone())
}
}?;

// 1. Create an INDEX_NAME.rs in "src/", with the appropriate zome functions
let zome_file_tree = ZomeFileTree::from_zome_manifest(
integrity_zome_file_tree.dna_file_tree,
coordinator_zome.clone(),
)?;

let snake_link_type_name = collection_name.to_case(Case::Snake);

let getter = match collection_type {
CollectionType::Global => {
global_collection_getter(&integrity_zome_name, collection_name, link_type_name)
}
CollectionType::ByAuthor => {
by_author_collection_getter(&integrity_zome_name, collection_name, link_type_name)
}
};

let mut file_tree = zome_file_tree.dna_file_tree.file_tree();

let crate_src_path = zome_file_tree.zome_crate_path.join("src");
let collection_path = crate_src_path.join(format!("{}.rs", snake_link_type_name.clone()));

let file = unparse_pretty(&syn::parse_quote! { #getter });

insert_file(&mut file_tree, &collection_path, &file)?;

// 2. Add this file as a module in the entry point for the crate
let lib_rs_path = crate_src_path.join("lib.rs");

map_file(&mut file_tree, &lib_rs_path, |contents| {
Ok(format!(
r#"pub mod {snake_link_type_name};
{contents}"#,
))
})?;

let mut dna_file_tree = DnaFileTree::from_dna_manifest_path(file_tree, &dna_manifest_path)?;

dna_file_tree = add_create_link_in_create_function(
dna_file_tree,
&coordinator_zomes_for_integrity,
collection_name,
link_type_name,
collection_type,
entry_type,
)?;

let (dna_file_tree, deletable) = add_delete_link_in_delete_function(
dna_file_tree,
&coordinator_zomes_for_integrity,
collection_name,
link_type_name,
collection_type,
entry_type,
)?;

Ok((dna_file_tree, coordinator_zome, deletable))
}
46 changes: 23 additions & 23 deletions src/scaffold/dna/coordinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,6 @@ use crate::{

use super::{manifest::check_zome_doesnt_exist, zome_wasm_location, DnaFileTree};

pub fn new_coordinator_zome_manifest(
dna_file_tree: &DnaFileTree,
name: &str,
maybe_dependencies: Option<&Vec<String>>,
) -> ScaffoldResult<ZomeManifest> {
let location = zome_wasm_location(dna_file_tree, name);
let zome_manifest = ZomeManifest {
name: name.into(),
hash: None,
location,
dependencies: maybe_dependencies.map(|dz| {
dz.iter()
.map(|d| ZomeDependency {
name: d.to_owned().into(),
})
.collect()
}),
dylib: None,
};

Ok(zome_manifest)
}

pub fn add_coordinator_zome_to_manifest(
mut dna_file_tree: DnaFileTree,
zome_manifest: ZomeManifest,
Expand Down Expand Up @@ -74,3 +51,26 @@ pub fn add_coordinator_zome_to_manifest(

Ok(dna_file_tree)
}

pub fn new_coordinator_zome_manifest(
dna_file_tree: &DnaFileTree,
name: &str,
maybe_dependencies: Option<&Vec<String>>,
) -> ScaffoldResult<ZomeManifest> {
let location = zome_wasm_location(dna_file_tree, name);
let zome_manifest = ZomeManifest {
name: name.into(),
hash: None,
location,
dependencies: maybe_dependencies.map(|dz| {
dz.iter()
.map(|d| ZomeDependency {
name: d.to_owned().into(),
})
.collect()
}),
dylib: None,
};

Ok(zome_manifest)
}
32 changes: 16 additions & 16 deletions src/scaffold/dna/integrity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,6 @@ use crate::{error::ScaffoldResult, file_tree::insert_file};

use super::{manifest::check_zome_doesnt_exist, zome_wasm_location, DnaFileTree};

pub fn new_integrity_zome_manifest(
dna_file_tree: &DnaFileTree,
name: &str,
) -> ScaffoldResult<ZomeManifest> {
let location = zome_wasm_location(dna_file_tree, name);
let zome_manifest = ZomeManifest {
name: name.into(),
hash: None,
location,
dependencies: None,
dylib: None,
};

Ok(zome_manifest)
}

pub fn add_integrity_zome_to_manifest(
dna_file_tree: DnaFileTree,
zome_manifest: ZomeManifest,
Expand Down Expand Up @@ -53,3 +37,19 @@ pub fn add_integrity_zome_to_manifest(

Ok(dna_file_tree)
}

pub fn new_integrity_zome_manifest(
dna_file_tree: &DnaFileTree,
name: &str,
) -> ScaffoldResult<ZomeManifest> {
let location = zome_wasm_location(dna_file_tree, name);
let zome_manifest = ZomeManifest {
name: name.into(),
hash: None,
location,
dependencies: None,
dylib: None,
};

Ok(zome_manifest)
}
Loading

0 comments on commit 5bf7183

Please sign in to comment.