From 6dbcfdf2826bdb80b53acb6301c0ca28b2b181ed Mon Sep 17 00:00:00 2001 From: Amaan Qureshi Date: Thu, 23 Jan 2025 01:07:09 -0500 Subject: [PATCH] feat(init): add an optional `funding` field --- cli/loader/src/lib.rs | 2 ++ cli/src/init.rs | 31 ++++++++++++++++++++++ cli/src/main.rs | 20 ++++++++++++++ cli/src/templates/package.json | 1 + cli/src/templates/pyproject.toml | 1 + docs/src/assets/schemas/config.schema.json | 5 ++++ 6 files changed, 60 insertions(+) diff --git a/cli/loader/src/lib.rs b/cli/loader/src/lib.rs index 7d99a62a..d4a5b1ac 100644 --- a/cli/loader/src/lib.rs +++ b/cli/loader/src/lib.rs @@ -217,6 +217,8 @@ pub struct Author { pub struct Links { pub repository: Url, #[serde(skip_serializing_if = "Option::is_none")] + pub funding: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub homepage: Option, } diff --git a/cli/src/init.rs b/cli/src/init.rs index 8f1d0f2d..bbae3e3d 100644 --- a/cli/src/init.rs +++ b/cli/src/init.rs @@ -52,6 +52,8 @@ const AUTHOR_BLOCK_GRAMMAR: &str = "\n * @author "; const AUTHOR_NAME_PLACEHOLDER_GRAMMAR: &str = "PARSER_AUTHOR_NAME"; const AUTHOR_EMAIL_PLACEHOLDER_GRAMMAR: &str = " PARSER_AUTHOR_EMAIL"; +const FUNDING_URL_PLACEHOLDER: &str = "FUNDING_URL"; + const GRAMMAR_JS_TEMPLATE: &str = include_str!("./templates/grammar.js"); const PACKAGE_JSON_TEMPLATE: &str = include_str!("./templates/package.json"); const GITIGNORE_TEMPLATE: &str = include_str!("./templates/gitignore"); @@ -118,6 +120,8 @@ pub struct JsonConfigOpts { pub description: String, #[serde(skip_serializing_if = "Option::is_none")] pub repository: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub funding: Option, pub scope: String, pub file_types: Vec, pub version: Version, @@ -166,6 +170,7 @@ impl JsonConfigOpts { )) .expect("Failed to parse default repository URL") }), + funding: self.funding, homepage: None, }), namespace: None, @@ -182,6 +187,7 @@ impl Default for JsonConfigOpts { camelcase: String::new(), description: String::new(), repository: None, + funding: None, scope: String::new(), file_types: vec![], version: Version::from_str("0.1.0").unwrap(), @@ -200,6 +206,7 @@ struct GenerateOpts<'a> { license: Option<&'a str>, description: Option<&'a str>, repository: Option<&'a str>, + funding: Option<&'a str>, version: &'a Version, camel_parser_name: &'a str, } @@ -261,6 +268,11 @@ pub fn generate_grammar_files( .links .as_ref() .map(|l| l.repository.as_str()), + funding: tree_sitter_config + .metadata + .links + .as_ref() + .and_then(|l| l.funding.as_ref().map(|f| f.as_str())), version: &tree_sitter_config.metadata.version, camel_parser_name: &camel_name, }; @@ -848,6 +860,25 @@ fn generate_file( } } + if let Some(funding_url) = generate_opts.funding { + match filename { + "pyproject.toml" | "package.json" => { + replacement = replacement.replace(FUNDING_URL_PLACEHOLDER, funding_url); + } + _ => {} + } + } else { + match filename { + "package.json" => { + replacement = replacement.replace(" \"funding\": \"FUNDING_URL\",\n", ""); + } + "pyproject.toml" => { + replacement = replacement.replace("Funding = \"FUNDING_URL\"\n", ""); + } + _ => {} + } + } + write_file(path, replacement)?; Ok(()) } diff --git a/cli/src/main.rs b/cli/src/main.rs index cb313fdc..83c0fcdb 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -560,6 +560,24 @@ impl Init { .interact_text() }; + let funding = || { + Input::::with_theme(&ColorfulTheme::default()) + .with_prompt("Funding URL") + .allow_empty(true) + .validate_with(|input: &String| { + if input.trim().is_empty() + || Url::parse(input) + .is_ok_and(|u| u.scheme() == "http" || u.scheme() == "https") + { + Ok(()) + } else { + Err("The URL must start with 'http://' or 'https://'") + } + }) + .interact_text() + .map(|e| (!e.trim().is_empty()).then(|| Url::parse(&e).unwrap())) + }; + let scope = |name: &str| { Input::::with_theme(&ColorfulTheme::default()) .with_prompt("TextMate scope") @@ -640,6 +658,7 @@ impl Init { "camelcase", "description", "repository", + "funding", "scope", "file_types", "version", @@ -657,6 +676,7 @@ impl Init { "camelcase" => opts.camelcase = camelcase_name(&opts.name)?, "description" => opts.description = description(&opts.name)?, "repository" => opts.repository = Some(repository(&opts.name)?), + "funding" => opts.funding = funding()?, "scope" => opts.scope = scope(&opts.name)?, "file_types" => opts.file_types = file_types(&opts.name)?, "version" => opts.version = initial_version()?, diff --git a/cli/src/templates/package.json b/cli/src/templates/package.json index 1db11b2d..ba86aef7 100644 --- a/cli/src/templates/package.json +++ b/cli/src/templates/package.json @@ -3,6 +3,7 @@ "version": "PARSER_VERSION", "description": "PARSER_DESCRIPTION", "repository": "PARSER_URL", + "funding": "FUNDING_URL", "license": "PARSER_LICENSE", "author": { "name": "PARSER_AUTHOR_NAME", diff --git a/cli/src/templates/pyproject.toml b/cli/src/templates/pyproject.toml index e4cca2d4..0e0c4d24 100644 --- a/cli/src/templates/pyproject.toml +++ b/cli/src/templates/pyproject.toml @@ -20,6 +20,7 @@ readme = "README.md" [project.urls] Homepage = "PARSER_URL" +Funding = "FUNDING_URL" [project.optional-dependencies] core = ["tree-sitter~=0.24"] diff --git a/docs/src/assets/schemas/config.schema.json b/docs/src/assets/schemas/config.schema.json index f07a8041..c14a9e64 100644 --- a/docs/src/assets/schemas/config.schema.json +++ b/docs/src/assets/schemas/config.schema.json @@ -172,6 +172,11 @@ "format": "uri", "description": "The project's repository." }, + "funding": { + "type": "string", + "format": "uri", + "description": "The project's funding link." + }, "homepage": { "type": "string", "format": "uri",