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:
parent
0683136ca0
commit
608506cb57
6 changed files with 62 additions and 26 deletions
|
|
@ -159,7 +159,7 @@ impl TreeSitterJSON {
|
|||
pub struct Grammar {
|
||||
pub name: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub upper_camel_name: Option<String>,
|
||||
pub camelcase: Option<String>,
|
||||
pub scope: String,
|
||||
pub path: PathBuf,
|
||||
#[serde(default, skip_serializing_if = "PathsJSON::is_empty")]
|
||||
|
|
@ -192,7 +192,8 @@ pub struct Metadata {
|
|||
pub authors: Option<Vec<Author>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub links: Option<Links>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
// #[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(skip)]
|
||||
pub namespace: Option<String>,
|
||||
}
|
||||
|
||||
|
|
@ -217,7 +218,9 @@ pub struct Links {
|
|||
pub struct Bindings {
|
||||
pub c: bool,
|
||||
pub go: bool,
|
||||
#[serde(skip)]
|
||||
pub java: bool,
|
||||
#[serde(skip)]
|
||||
pub kotlin: bool,
|
||||
pub node: bool,
|
||||
pub python: bool,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)?,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@
|
|||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"$schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"grammars": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
|
@ -132,6 +135,7 @@
|
|||
"description": "A regex pattern that will be tested against the contents of the file in order to break ties in cases where multiple grammars matched the file."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"name",
|
||||
"scope"
|
||||
|
|
@ -174,6 +178,7 @@
|
|||
"description": "The project's homepage."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"repository"
|
||||
]
|
||||
|
|
@ -196,6 +201,7 @@
|
|||
"format": "uri"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"name"
|
||||
]
|
||||
|
|
@ -209,6 +215,7 @@
|
|||
"$comment": "Used as is in the Maven/Gradle group name and transformed accordingly for the package names and directories (e.g. io.github.treesitter.jtreesitter.html - src/main/java/io/github/treesitter/jtreesitter/html)."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"version",
|
||||
"links"
|
||||
|
|
@ -230,11 +237,11 @@
|
|||
},
|
||||
"java": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
"default": false
|
||||
},
|
||||
"kotlin": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
"default": false
|
||||
},
|
||||
"node": {
|
||||
"type": "boolean",
|
||||
|
|
@ -256,9 +263,11 @@
|
|||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"grammars",
|
||||
"metadata"
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@
|
|||
"additionalProperties": false,
|
||||
|
||||
"properties": {
|
||||
"$schema": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
"name": {
|
||||
"description": "The name of the grammar",
|
||||
"type": "string",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue