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

feat: Create links from/to ExternalHash #380

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
363a9ad
add ExternalHash field types and option to target this type when scaf…
c12i Sep 17, 2024
54c64d0
ensure external hash is imported in type declarations
c12i Sep 17, 2024
12b656d
Merge remote-tracking branch 'holochain/develop' into feat/add-option…
c12i Sep 24, 2024
06bb80a
feat: create links from/to AnyLinkableHash
c12i Sep 24, 2024
217530c
Add AnyLinkablehHash field type templates and add to reserved words
c12i Sep 25, 2024
37dc25a
fix failed to resolve errors
c12i Sep 30, 2024
1133ba2
improve checking for reserved keywords
c12i Sep 30, 2024
5d11459
fix invalid link-type delete method in test template
c12i Sep 30, 2024
7c54f5d
simplify reserved_words hashsets
c12i Oct 1, 2024
3f1300a
update cli
c12i Oct 1, 2024
9cfd9a5
Extend reserved keywords to check for javascript keywords
c12i Oct 4, 2024
442660e
Update AnyLinkableHash sample value
c12i Oct 4, 2024
277cf4b
Extend reserved words check tests
c12i Oct 4, 2024
fb6a723
Merge remote-tracking branch 'holochain/develop' into feat/add-option…
c12i Oct 7, 2024
56cc16a
fix AnyLinkableHash link-type tests
c12i Oct 7, 2024
9b0cda2
Fix AnyLinkableHash link-type tests and remove redundant AND/OR hbs
c12i Oct 7, 2024
52a3ec8
update inner_choose_referenceable
c12i Oct 7, 2024
d239ea7
/AnyLinkableHash/ExternalHash
c12i Oct 14, 2024
6f791f6
Update invalid serserved word error message
c12i Oct 14, 2024
ec56ad9
Refactor entry/link type utils
c12i Oct 15, 2024
b534735
Add some context to the [None] option when scaffolding a link-type
c12i Oct 15, 2024
19bfe2d
Merge remote-tracking branch 'holochain/develop' into feat/add-option…
c12i Oct 15, 2024
06070f0
/AnyLinkableHash/ExternalHash in link-type template
c12i Oct 15, 2024
4212ae7
Merge remote-tracking branch 'holochain/develop' into feat/add-option…
c12i Oct 15, 2024
0e12926
Fix option placement
c12i Oct 15, 2024
a7396ae
Prevent UI from getting generated where the base type of a link is an
c12i Oct 15, 2024
79f118c
ExternalHash links can be bidirectional
c12i Oct 15, 2024
e188a78
Only skip ui if to_referenceable is some and the field_type is of
c12i Oct 15, 2024
26c61f9
Remove unnecessary into call in delete link function
c12i Oct 15, 2024
d3973ed
Fix rustfmt ci failure
c12i Oct 16, 2024
219a7dd
Fix missing conversion
c12i Oct 16, 2024
566c6ea
Fix react link-type template
c12i Oct 16, 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
18 changes: 8 additions & 10 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,15 @@ impl HcScaffold {
let template_type = self.get_template_type(&current_dir, scaffold_config.as_ref())?;

match self.command {
HcScaffoldCommand::WebApp(web_app) => web_app.run(&template_type).await?,
HcScaffoldCommand::Template(template) => template.run(&template_type)?,
HcScaffoldCommand::Dna(dna) => dna.run(&template_type)?,
HcScaffoldCommand::Zome(zome) => zome.run(&template_type)?,
HcScaffoldCommand::EntryType(entry_type) => entry_type.run(&template_type)?,
HcScaffoldCommand::LinkType(link_type) => link_type.run(&template_type)?,
HcScaffoldCommand::Collection(collection) => collection.run(&template_type)?,
HcScaffoldCommand::Example(example) => example.run(&template_type).await?,
HcScaffoldCommand::WebApp(web_app) => web_app.run(&template_type).await,
HcScaffoldCommand::Template(template) => template.run(&template_type),
HcScaffoldCommand::Dna(dna) => dna.run(&template_type),
HcScaffoldCommand::Zome(zome) => zome.run(&template_type),
HcScaffoldCommand::EntryType(entry_type) => entry_type.run(&template_type),
HcScaffoldCommand::LinkType(link_type) => link_type.run(&template_type),
HcScaffoldCommand::Collection(collection) => collection.run(&template_type),
HcScaffoldCommand::Example(example) => example.run(&template_type).await,
}

Ok(())
}

fn get_template_type(
Expand Down
4 changes: 2 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ pub enum ScaffoldError {
#[error("Folder already exists: {0}")]
FolderAlreadyExists(PathBuf),

#[error("Invalid reserved word: {0}")]
InvalidReservedWord(String),
#[error("Invalid use of reserved {context} keyword '{word}' in this context.")]
InvalidReservedWord { context: String, word: String },

#[error("Invalid path {0}: {1}")]
InvalidPath(PathBuf, String),
Expand Down
144 changes: 110 additions & 34 deletions src/reserved_words.rs
Original file line number Diff line number Diff line change
@@ -1,44 +1,120 @@
use std::collections::HashSet;

use crate::error::{ScaffoldError, ScaffoldResult};

const RESERVED_WORDS: [&str; 27] = [
"type",
/// Returns an error if the given string is invalid due to it being a reserved word
pub fn check_for_reserved_keywords(string_to_check: &str) -> ScaffoldResult<()> {
let reserved_holochain_words_set = HashSet::from(HOLOCHAIN_RESERVED_KEYWORDS);
let reserved_rust_words_set = HashSet::from(RUST_RESERVED_KEYWORDS);
let reserved_javascript_words_set = HashSet::from(JAVASCRIPT_RESERVED_KEYWORDS);

if reserved_holochain_words_set.contains(string_to_check.to_ascii_lowercase().as_str()) {
return Err(ScaffoldError::InvalidReservedWord {
context: "holochain".to_string(),
word: string_to_check.to_string(),
});
}

if reserved_rust_words_set.contains(string_to_check.to_ascii_lowercase().as_str()) {
return Err(ScaffoldError::InvalidReservedWord {
context: "rust".to_string(),
word: string_to_check.to_string(),
});
}

if reserved_javascript_words_set.contains(string_to_check.to_ascii_lowercase().as_str()) {
return Err(ScaffoldError::InvalidReservedWord {
context: "javascript".to_string(),
word: string_to_check.to_string(),
});
}

Ok(())
}

const HOLOCHAIN_RESERVED_KEYWORDS: [&str; 16] = [
"role",
"enum",
"pub",
"fn",
"mod",
"struct",
"const",
"Option",
"Result",
"crate",
"hdi",
"hdk",
"return",
"if",
"action",
"entry",
"record",
"zome",
"dna",
"entrytype",
"entryhash",
"actionhash",
"agentpubkey",
"anylinkablehash",
"holohash",
"externalhash",
"call",
];

// <https://doc.rust-lang.org/reference/keywords.html>
const RUST_RESERVED_KEYWORDS: [&str; 50] = [
"as", "break", "const", "continue", "crate", "else", "enum", "extern", "false", "fn", "for",
"if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref", "return",
"self", "Self", "static", "struct", "super", "trait", "true", "type", "unsafe", "use", "where",
"while", "abstract", "async", "await", "become", "box", "do", "final", "macro", "override",
"priv", "try", "typeof", "unsized", "virtual", "yield",
];

// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#reserved_words>
const JAVASCRIPT_RESERVED_KEYWORDS: [&str; 35] = [
"break",
"case",
"catch",
"class",
"const",
"continue",
"debugger",
"default",
"delete",
"do",
"else",
"match",
"Action",
"Entry",
"Record",
"Zome",
"Dna",
"EntryType",
"EntryHash",
"ActionHash",
"AgentPubKey",
"Call",
"export",
"extends",
"false",
"finally",
"for",
"function",
"if",
"import",
"in",
"instanceof",
"new",
"null",
"return",
"super",
"switch",
"this",
"throw",
"true",
"try",
"typeof",
"var",
"void",
"while",
"with",
];

/// Returns an error if the given string is invalid due to it being a reserved word
pub fn check_for_reserved_words(string_to_check: &str) -> ScaffoldResult<()> {
if RESERVED_WORDS
.iter()
.any(|w| string_to_check.eq_ignore_ascii_case(w))
{
return Err(ScaffoldError::InvalidReservedWord(
string_to_check.to_string(),
));
#[cfg(test)]
mod tests {
use super::*;

#[test]
fn check_for_reserved_keywords_works() {
let valid = check_for_reserved_keywords("Value");
assert!(valid.is_ok());

let invalid = check_for_reserved_keywords("static");
assert!(invalid.is_err());

let invalid = check_for_reserved_keywords("EntryType");
assert!(invalid.is_err());

let invalid = check_for_reserved_keywords("new");
assert!(invalid.is_err());
}
Ok(())
}
4 changes: 2 additions & 2 deletions src/scaffold/collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use serde::Serialize;
use crate::{
error::{ScaffoldError, ScaffoldResult},
file_tree::FileTree,
reserved_words::check_for_reserved_words,
reserved_words::check_for_reserved_keywords,
templates::{collection::scaffold_collection_templates, ScaffoldedTemplate},
};

Expand Down Expand Up @@ -74,7 +74,7 @@ pub fn scaffold_collection(
no_ui: bool,
no_spec: bool,
) -> ScaffoldResult<ScaffoldedTemplate> {
check_for_reserved_words(collection_name)?;
check_for_reserved_keywords(collection_name)?;

let all_entries = get_all_entry_types(&integrity_zome_file_tree)?.ok_or(
ScaffoldError::NoEntryTypesDefFoundForIntegrityZome(
Expand Down
4 changes: 2 additions & 2 deletions src/scaffold/dna.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
dir_exists, file_content, find_files_by_name, insert_file, insert_file_tree_in_dir,
FileTree,
},
reserved_words::check_for_reserved_words,
reserved_words::check_for_reserved_keywords,
templates::{dna::scaffold_dna_templates, ScaffoldedTemplate},
utils::choose_directory_path,
};
Expand Down Expand Up @@ -168,7 +168,7 @@ pub fn scaffold_dna(
template_file_tree: &FileTree,
dna_name: &str,
) -> ScaffoldResult<ScaffoldedTemplate> {
check_for_reserved_words(dna_name)?;
check_for_reserved_keywords(dna_name)?;

let new_dna_file_tree: FileTree = dir! {
"zomes" => dir! {
Expand Down
10 changes: 5 additions & 5 deletions src/scaffold/entry_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{ffi::OsString, path::PathBuf};

use crate::{
file_tree::FileTree,
reserved_words::check_for_reserved_words,
reserved_words::check_for_reserved_keywords,
templates::{entry_type::scaffold_entry_type_templates, ScaffoldedTemplate},
};

Expand Down Expand Up @@ -47,7 +47,7 @@ pub fn scaffold_entry_type(
no_ui: bool,
no_spec: bool,
) -> ScaffoldResult<ScaffoldedTemplate> {
check_for_reserved_words(name)?;
check_for_reserved_keywords(name)?;

if no_ui {
let warning_text = r#"
Expand Down Expand Up @@ -139,13 +139,13 @@ inadvertently reference or expect elements from the skipped entry type."#
let coordinator_zome = match coordinator_zomes_for_integrity.len() {
0 => Err(ScaffoldError::NoCoordinatorZomesFoundForIntegrityZome(
zome_file_tree.dna_file_tree.dna_manifest.name(),
zome_file_tree.zome_manifest.name.0.to_string(),
zome_file_tree.zome_manifest.name.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())
.map(|z| z.name.to_string())
.collect();
let selection = Select::with_theme(&ColorfulTheme::default())
.with_prompt("Which coordinator zome should the CRUD functions be scaffolded in?")
Expand Down Expand Up @@ -217,7 +217,7 @@ fn check_field_definitions(
.iter()
.filter_map(|f| f.linked_from.clone())
.filter_map(|t| match t {
Referenceable::Agent { .. } => None,
Referenceable::Agent { .. } | Referenceable::ExternalHash { .. } => None,
Referenceable::EntryType(et) => Some(et),
})
.collect();
Expand Down
4 changes: 2 additions & 2 deletions src/scaffold/entry_type/coordinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,10 @@ pub fn add_crud_functions_to_coordinator(
}

fn no_update_read_handler(entry_def: &EntryDefinition) -> TokenStream {
let hash_type = entry_def.referenceable().hash_type().to_string();
let hash_type = entry_def.referenceable().field_type().to_string();
let snake_entry_def_name = entry_def.name.to_case(Case::Snake);

match entry_def.referenceable().hash_type() {
match entry_def.referenceable().field_type() {
FieldType::ActionHash => {
let get_entry_def_function_name = format_ident!("get_{snake_entry_def_name}");
let entry_hash_param = format_ident!("{snake_entry_def_name}_hash");
Expand Down
Loading