fix(init): fix some schema issues

- Validate CamelCase name, TextMate scope
- Skip serialization of unused properties
- Disallow additional properties in schema
This commit is contained in:
ObserverOfTime 2024-10-01 11:02:41 +03:00 committed by Amaan Qureshi
parent 0683136ca0
commit 608506cb57
6 changed files with 62 additions and 26 deletions

View file

@ -131,7 +131,7 @@ fn insert_after(
#[derive(Serialize, Deserialize, Clone)]
pub struct JsonConfigOpts {
pub name: String,
pub upper_camel_name: String,
pub camelcase: String,
pub description: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub repository: Option<Url>,
@ -151,7 +151,7 @@ impl JsonConfigOpts {
TreeSitterJSON {
grammars: vec![Grammar {
name: self.name.clone(),
upper_camel_name: Some(self.upper_camel_name),
camelcase: Some(self.camelcase),
scope: self.scope,
path: PathBuf::from("."),
external_files: PathsJSON::Empty,
@ -194,7 +194,7 @@ impl Default for JsonConfigOpts {
fn default() -> Self {
Self {
name: String::new(),
upper_camel_name: String::new(),
camelcase: String::new(),
description: String::new(),
repository: None,
scope: String::new(),
@ -245,7 +245,7 @@ pub fn migrate_package_json(repo_path: &Path) -> Result<bool> {
.into_iter()
.map(|l| Grammar {
name: name.clone(),
upper_camel_name: Some(name.to_upper_camel_case()),
camelcase: Some(name.to_upper_camel_case()),
scope: l.scope.unwrap_or_else(|| format!("source.{name}")),
path: l.path,
external_files: l.external_files,

View file

@ -469,10 +469,20 @@ impl Init {
.interact_text()
};
let upper_camel_name = |name: &str| {
let camelcase_name = |name: &str| {
Input::<String>::with_theme(&ColorfulTheme::default())
.with_prompt("UpperCamelCase name")
.with_prompt("CamelCase name")
.default(name.to_upper_camel_case())
.validate_with(|input: &String| {
if input
.chars()
.all(|c| c.is_ascii_alphabetic() || c.is_ascii_digit() || c == '_')
{
Ok(())
} else {
Err("The name must contain only letters, digits, and underscores")
}
})
.interact_text()
};
@ -506,6 +516,13 @@ impl Init {
Input::<String>::with_theme(&ColorfulTheme::default())
.with_prompt("TextMate scope")
.default(format!("source.{name}"))
.validate_with(|input: &String| {
if input.starts_with("source.") || input.starts_with("text.") {
Ok(())
} else {
Err("The scope must start with 'source.' or 'text.'")
}
})
.interact_text()
};
@ -549,20 +566,21 @@ impl Init {
let email = || {
Input::with_theme(&ColorfulTheme::default())
.with_prompt("Author email")
.validate_with({
let mut force = None;
move |input: &String| -> Result<(), &str> {
if input.contains('@') || input.trim().is_empty() || force.as_ref().map_or(false, |old| old == input) {
Ok(())
} else {
force = Some(input.clone());
Err("This is not an email address; type the same value again to force use")
.with_prompt("Author email")
.validate_with({
move |input: &String| -> Result<(), &str> {
if (input.contains('@') && input.contains('.'))
|| input.trim().is_empty()
{
Ok(())
} else {
Err("This is not a valid email address")
}
}
}
})
.allow_empty(true)
.interact_text().map(|e| (!e.trim().is_empty()).then_some(e))
})
.allow_empty(true)
.interact_text()
.map(|e| (!e.trim().is_empty()).then_some(e))
};
let url = || {
@ -582,7 +600,7 @@ impl Init {
let choices = [
"name",
"upper_camel_name",
"camelcase",
"description",
"repository",
"scope",
@ -599,7 +617,7 @@ impl Init {
($choice:expr) => {
match $choice {
"name" => opts.name = name()?,
"upper_camel_name" => opts.upper_camel_name = upper_camel_name(&opts.name)?,
"camelcase" => opts.camelcase = camelcase_name(&opts.name)?,
"description" => opts.description = description(&opts.name)?,
"repository" => opts.repository = Some(repository(&opts.name)?),
"scope" => opts.scope = scope(&opts.name)?,

View file

@ -8,4 +8,6 @@ bindings/** linguist-generated
binding.gyp linguist-generated
setup.py linguist-generated
Makefile linguist-generated
CMakeLists.txt linguist-generated
Package.swift linguist-generated
go.mod linguist-generated