diff --git a/Cargo.lock b/Cargo.lock index e1d6f8f3..116275b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -164,7 +164,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.32", + "syn 2.0.33", "which", ] @@ -362,7 +362,7 @@ dependencies = [ [[package]] name = "cargo-playdate" -version = "0.1.3" +version = "0.2.0" dependencies = [ "anyhow", "byteorder", @@ -500,7 +500,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -2498,7 +2498,7 @@ dependencies = [ "proc-macro2", "quote", "semver", - "syn 2.0.32", + "syn 2.0.33", "which", ] @@ -2647,7 +2647,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -2661,9 +2661,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" dependencies = [ "unicode-ident", ] @@ -2958,7 +2958,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -2972,9 +2972,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc66a619ed80bf7a0f6b17dd063a84b88f6dea1813737cf469aef1d081142c2" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" dependencies = [ "itoa", "ryu", @@ -3188,9 +3188,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.32" +version = "2.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" +checksum = "9caece70c63bfba29ec2fed841a09851b14a235c60010fa4de58089b6c025668" dependencies = [ "proc-macro2", "quote", @@ -3273,7 +3273,7 @@ checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", ] [[package]] @@ -3531,7 +3531,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", "wasm-bindgen-shared", ] @@ -3553,7 +3553,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.33", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/api/ctrl/Cargo.toml b/api/ctrl/Cargo.toml index 56f058d5..7ab5a772 100644 --- a/api/ctrl/Cargo.toml +++ b/api/ctrl/Cargo.toml @@ -1,5 +1,3 @@ -#:schema ../../cargo-playdate.json - [package] name = "playdate-controls" version = "0.1.1" diff --git a/cargo/Cargo.toml b/cargo/Cargo.toml index c1bde2a7..6f0d6eef 100644 --- a/cargo/Cargo.toml +++ b/cargo/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cargo-playdate" -version = "0.1.3" +version = "0.2.0" edition = "2021" readme = "README.md" diff --git a/cargo/cargo-playdate.json b/cargo/cargo-playdate.json deleted file mode 100644 index 5cb9e19a..00000000 --- a/cargo/cargo-playdate.json +++ /dev/null @@ -1,288 +0,0 @@ -{ - "$id": "https://json.schemastore.org/cargo-playdate.json", - "$schema": "http://json-schema.org/draft-07/schema#", - "$comment": "https://github.com/boozook/playdate", - "allOf": [ - { - "$ref": "https://json.schemastore.org/cargo.json" - } - ], - "definitions": { - "Package": { - "allOf": [ - { - "$ref": "https://json.schemastore.org/cargo.json#/definitions/Package" - } - ], - "type": "object", - "required": [ - "metadata" - ], - "additionalProperties": true, - "properties": { - "metadata": { - "allOf": [ - { - "$ref": "https://json.schemastore.org/cargo.json#/definitions/Package/properties/metadata" - } - ], - "type": "object", - "properties": { - "playdate": { - "$ref": "#/definitions/PlaydateMetadata" - } - }, - "required": [ - "playdate" - ], - "additionalProperties": true, - "x-taplo": { - "links": { - "key": "https://doc.rust-lang.org/cargo/reference/manifest.html#the-metadata-table" - } - } - } - }, - "x-taplo": { - "links": { - "key": "https://doc.rust-lang.org/cargo/reference/manifest.html#the-package-section" - } - } - }, - "PlaydateMetadata": { - "title": "Playdate Package Metadata", - "description": "Metadata and build configuration.", - "type": "object", - "required": [ - "bundle-id" - ], - "properties": { - "bundle-id": { - "type": "string", - "description": "A unique identifier for your game, in reverse DNS notation.", - "x-taplo": { - "links": { - "key": "https://sdk.play.date/#pdxinfo" - } - } - }, - "name": { - "type": "string", - "description": "A game version number, formatted any way you wish, that is displayed to players. It is not used to compute when updates should occur.", - "x-taplo": { - "links": { - "key": "https://sdk.play.date/#pdxinfo" - } - } - }, - "author": { - "type": "string", - "x-taplo": { - "links": { - "key": "https://sdk.play.date/#pdxinfo" - } - } - }, - "description": { - "type": "string", - "x-taplo": { - "links": { - "key": "https://sdk.play.date/#pdxinfo" - } - } - }, - "version": { - "type": "string", - "x-taplo": { - "links": { - "key": "https://sdk.play.date/#pdxinfo" - } - } - }, - "build-number": { - "type": "integer", - "exclusiveMinimum": 0, - "x-taplo": { - "links": { - "key": "https://sdk.play.date/#pdxinfo" - } - }, - "description": "A monotonically-increasing integer value used to indicate a unique version of your game. This can be set using an automated build process like Continuous Integration to avoid having to set the value by hand.\n\nFor sideloaded games, buildNumber is required and is used to determine when a newer version is available to download." - }, - "image-path": { - "type": "string", - "x-taplo": { - "links": { - "key": "https://sdk.play.date/#pdxinfo" - } - }, - "description": "A directory of images that will be used by the launcher.\n\nMore in [official documentation](https://sdk.play.date/#pdxinfo)." - }, - "launch-sound-path": { - "type": "string", - "x-taplo": { - "links": { - "key": "https://sdk.play.date/#pdxinfo" - } - }, - "description": "Should point to the path of a short audio file to be played as the game launch animation is taking place.\n\nMore in [official documentation](https://sdk.play.date/#pdxinfo)." - }, - "content-warning": { - "type": "string", - "x-taplo": { - "links": { - "key": "https://sdk.play.date/#pdxinfo" - } - }, - "description": "Optional. A content warning that displays when the user launches your game for the first time. The user will have the option of backing out and not launching your game if they choose." - }, - "content-warning2": { - "type": "string", - "x-taplo": { - "links": { - "key": "https://sdk.play.date/#pdxinfo" - } - }, - "description": "Optional. A second content warning that displays on a second screen when the user launches your game for the first time. The user will have the option of backing out and not launching your game if they choose.\n\nNote: `content-warning2` will only display if a `content-warning` attribute is also specified.\n\nThe string displayed on the content warning screen can only be so long before it will be truncated with an \"…\" character. Be sure to keep this in mind when designing your `content-warning` and `content-warning2` text." - }, - "assets": { - "anyOf": [ - { - "$ref": "#/definitions/PlaydateMetadataAssetsMap" - }, - { - "$ref": "#/definitions/PlaydateMetadataAssetsArray" - } - ] - }, - "options": { - "$ref": "#/definitions/PlaydateMetadataOptions" - }, - "support": { - "type": "object", - "properties": {}, - "additionalProperties": true - } - }, - "additionalProperties": false, - "x-taplo": { - "initKeys": [ - "bundle-id", - "name", - "description", - "author", - "image-path", - "launch-sound-path" - ], - "links": { - "key": "https://sdk.play.date/#pdxinfo" - } - } - }, - "PlaydateMetadataAssetsArray": { - "type": "array", - "title": "Assets list", - "description": "List of paths to include.", - "uniqueItems": true, - "items": { - "title": "Path", - "description": "Path to include.", - "type": "string" - }, - "x-taplo": { - "links": { - "key": "https://github.com/boozook/playdate/blob/main/support/build/README.md#assets-list" - } - } - }, - "PlaydateMetadataAssetsMap": { - "type": "object", - "title": "Assets rules", - "description": "Rules used to resolve paths to include.", - "properties": { - "options": { - "$ref": "#/definitions/PlaydateMetadataAssetsOptions" - } - }, - "additionalProperties": { - "anyOf": [ - { - "type": "string", - "title": "Path", - "description": "Path of files to include. Can be absolute, relative to the crate root, or/and glob.\n\nLeft hand is where to put files, path in the resulting package.\n\nRight hand is a path or pattern to match files to include." - }, - { - "type": "boolean", - "title": "Include", - "description": "Include or exclude the file or glob-pattern." - } - ] - }, - "x-taplo": { - "links": { - "key": "https://github.com/boozook/playdate/blob/main/support/build/README.md#assets-table" - } - } - }, - "PlaydateMetadataAssetsOptions": { - "type": "object", - "title": "Assets Configuration", - "description": "Options for assets paths resolution and how to build assets collection", - "additionalProperties": false, - "properties": { - "overwrite": { - "type": "boolean", - "description": "Allow overwriting existing files." - }, - "follow-symlinks": { - "type": "boolean" - }, - "method": { - "type": "string", - "enum": [ - "copy", - "link" - ] - }, - "dependencies": { - "type": "boolean", - "description": "Allow build assets for dependencies." - } - }, - "x-taplo": { - "links": { - "key": "https://github.com/boozook/playdate/blob/main/support/build/README.md#assets-options" - } - } - }, - "PlaydateMetadataOptions": { - "type": "object", - "title": "Configuration", - "description": "Package build options.", - "additionalProperties": true, - "properties": { - "assets": { - "$ref": "#/definitions/PlaydateMetadataAssetsOptions" - } - }, - "x-taplo": { - "links": { - "key": "https://github.com/boozook/playdate/blob/main/support/build/README.md#options" - } - } - } - }, - "properties": { - "package": { - "$ref": "#/definitions/Package" - } - }, - "x-taplo-info": { - "authors": [ - "Alex Koz. (https://github.com/boozook)" - ], - "patterns": [ - "^(.*(/|\\\\)Cargo\\.toml|Cargo\\.toml)$" - ] - } - } diff --git a/cargo/src/cli/deps.rs b/cargo/src/cli/deps.rs index 417a0744..8a540de3 100644 --- a/cargo/src/cli/deps.rs +++ b/cargo/src/cli/deps.rs @@ -14,13 +14,20 @@ pub struct Dependency<'t> { impl Dependency<'_> { pub const fn git(&self) -> Option<&'static str> { + const GIT: &'static str = env!("CARGO_PKG_REPOSITORY"); match self.source { DependencySource::CratesIo => None, DependencySource::Git => { match self.name { - DependencyName::Sys => Some("https://github.com/boozook/playdate.git"), - DependencyName::Playdate => Some("https://github.com/boozook/playdate.git"), - DependencyName::Controls => Some("https://github.com/boozook/playdate.git"), + DependencyName::Sys => Some(GIT), + DependencyName::System => Some(GIT), + DependencyName::Menu => Some(GIT), + DependencyName::Controls => Some(GIT), + DependencyName::Fs => Some(GIT), + DependencyName::Sound => Some(GIT), + DependencyName::Graphics => Some(GIT), + DependencyName::Color => Some(GIT), + DependencyName::Playdate => Some(GIT), DependencyName::Other(_) => None, } }, @@ -33,22 +40,48 @@ impl ValueEnum for Dependency<'_> { use DependencyName as Name; use DependencySource as Src; - &[ - Self { name: Name::Playdate, - source: Src::CratesIo, }, - Self { name: Name::Playdate, - source: Src::Git, }, - Self { name: Name::Sys, - source: Src::CratesIo, }, - Self { name: Name::Sys, - source: Src::Git, }, - Self { name: Name::Controls, - source: Src::CratesIo, }, - Self { name: Name::Controls, - source: Src::Git, }, - Self { name: Name::Other(Cow::Borrowed("any-other")), - source: Src::CratesIo, }, - ] + #[rustfmt::skip] + let res = &[ + Self { name: Name::Playdate, source: Src::CratesIo, }, + Self { name: Name::Playdate, source: Src::Git, }, + + Self { name: Name::Sys, source: Src::CratesIo, }, + Self { name: Name::Sys, source: Src::Git, }, + + Self { name: Name::System, source: Src::CratesIo, }, + Self { name: Name::System, source: Src::Git, }, + + Self { name: Name::Controls, source: Src::CratesIo, }, + Self { name: Name::Controls, source: Src::Git, }, + + Self { name: Name::Menu, source: Src::CratesIo, }, + Self { name: Name::Menu, source: Src::Git, }, + + Self { name: Name::Fs, source: Src::CratesIo, }, + Self { name: Name::Fs, source: Src::Git, }, + + Self { name: Name::Sound, source: Src::CratesIo, }, + Self { name: Name::Sound, source: Src::Git, }, + + Self { name: Name::Graphics, source: Src::CratesIo, }, + Self { name: Name::Graphics, source: Src::Git, }, + + Self { name: Name::Color, source: Src::CratesIo, }, + Self { name: Name::Color, source: Src::Git, }, + + Self { name: Name::Other(Cow::Borrowed("any-other")), source: Src::CratesIo, }, + ]; + + #[cfg(debug_assertions)] + { + let missed: Vec<_> = + DependencyName::value_variants().into_iter() + .filter(|name| res.iter().find(|dep| dep.name == **name).is_none()) + .collect(); + debug_assert_eq!(0, missed.len(), "Missing dependencies: {:?}", missed); + } + + res } fn to_possible_value<'a>(&self) -> Option { @@ -56,36 +89,23 @@ impl ValueEnum for Dependency<'_> { use DependencySource as Src; match (&self.name, &self.source) { - (Name::Sys, Src::CratesIo) => { - PossibleValue::new("playdate-sys").alias("sys") - .help("Low-level Playdate API") - .into() - }, - (Name::Sys, Src::Git) => { - PossibleValue::new("playdate-sys:git").alias("sys:git") - .help("Low-level Playdate API (git)") - .into() - }, - (Name::Playdate, Src::CratesIo) => PossibleValue::new("playdate").help("Playdate API").into(), - (Name::Playdate, Src::Git) => { - PossibleValue::new("playdate:git").help("Playdate API (git)") - .into() - }, - (Name::Controls, Src::CratesIo) => { - PossibleValue::new("playdate-controls").alias("controls") - .help("Playdate Controls API") - .into() - }, - (Name::Controls, Src::Git) => { - PossibleValue::new("playdate-controls:git").alias("controls:git") - .help("Playdate Controls API (git)") - .into() - }, (Name::Other(s), Src::CratesIo) => { PossibleValue::new(s.as_ref().to_owned()).help("Any other package (crates.io only)") .into() }, (Name::Other(_), _) => None, + + (name, Src::CratesIo) => { + PossibleValue::new(name.to_string()).aliases(name.aliases()) + .help(name.description().to_string()) + .into() + }, + (name, Src::Git) => { + let help = format!("{} (git)", name.description()); + PossibleValue::new(name.to_string()).aliases(name.aliases()) + .help(help) + .into() + }, } } } @@ -119,20 +139,68 @@ impl std::fmt::Display for Dependency<'_> { #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum DependencyName<'t> { Sys, - Playdate, + System, Controls, - // Other(String), + Menu, + Fs, + Sound, + Graphics, + Color, + Playdate, Other(Cow<'t, str>), } +impl<'t> DependencyName<'t> { + pub fn as_str(&self) -> Cow<'t, str> { + match self { + DependencyName::Sys => "playdate-sys".into(), + DependencyName::System => "playdate-system".into(), + DependencyName::Controls => "playdate-controls".into(), + DependencyName::Menu => "playdate-menu".into(), + DependencyName::Fs => "playdate-fs".into(), + DependencyName::Sound => "playdate-sound".into(), + DependencyName::Graphics => "playdate-graphics".into(), + DependencyName::Color => "playdate-color".into(), + DependencyName::Playdate => "playdate".into(), + DependencyName::Other(s) => s.clone(), + } + } + + pub fn description(&self) -> Cow<'t, str> { + match self { + DependencyName::Sys => "Low-level Playdate API".into(), + DependencyName::System => "Playdate system API".into(), + DependencyName::Controls => "Playdate controls API".into(), + DependencyName::Menu => "Playdate menu API".into(), + DependencyName::Fs => "Playdate file-system API".into(), + DependencyName::Sound => "Playdate sound API".into(), + DependencyName::Graphics => "Playdate graphics API".into(), + DependencyName::Color => "Playdate color API".into(), + DependencyName::Playdate => "High-level Playdate API".into(), + DependencyName::Other(s) => s.clone(), + } + } + + pub fn aliases(&self) -> impl Iterator { + match self { + DependencyName::Sys => &["sys"][..], + DependencyName::System => &["system"][..], + DependencyName::Controls => &["controls", "ctrl"][..], + DependencyName::Menu => &["menu"], + DependencyName::Fs => &["fs"], + DependencyName::Sound => &["sound"], + DependencyName::Graphics => &["graphics"], + DependencyName::Color => &["color"], + DependencyName::Playdate => &["pd"], + DependencyName::Other(_) => &[], + }.into_iter() + .map(|s| *s) + } +} + impl std::fmt::Display for DependencyName<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let s = match self { - DependencyName::Sys => "playdate-sys", - DependencyName::Playdate => "playdate", - DependencyName::Controls => "playdate-controls", - DependencyName::Other(s) => s, - }; + let s = self.as_str(); write!(f, "{s}") } } @@ -141,11 +209,20 @@ impl FromStr for DependencyName<'_> { type Err = Infallible; fn from_str(s: &str) -> Result { + use DependencyName::*; + let this = match s.trim().to_lowercase().as_str() { - "playdate" => DependencyName::Playdate, - "playdate-sys" | "sys" | "" => DependencyName::Sys, - "playdate-controls" | "controls" => DependencyName::Controls, - other => DependencyName::Other(other.to_owned().into()), + "" => Sys, // default empty case + n if n == Sys.as_str() || Sys.aliases().find(|a| *a == n).is_some() => Sys, + n if n == System.as_str() || System.aliases().find(|a| *a == n).is_some() => System, + n if n == Controls.as_str() || Controls.aliases().find(|a| *a == n).is_some() => Controls, + n if n == Menu.as_str() || Menu.aliases().find(|a| *a == n).is_some() => Menu, + n if n == Fs.as_str() || Fs.aliases().find(|a| *a == n).is_some() => Fs, + n if n == Sound.as_str() || Sound.aliases().find(|a| *a == n).is_some() => Sound, + n if n == Graphics.as_str() || Graphics.aliases().find(|a| *a == n).is_some() => Graphics, + n if n == Color.as_str() || Color.aliases().find(|a| *a == n).is_some() => Color, + n if n == Playdate.as_str() || Playdate.aliases().find(|a| *a == n).is_some() => Playdate, + other => Other(other.to_owned().into()), }; Ok(this) } @@ -191,8 +268,14 @@ impl DependencyName<'_> { use DependencyName as Name; static ALL: &[Name] = &[ Name::Sys, - Name::Playdate, + Name::System, Name::Controls, + Name::Menu, + Name::Fs, + Name::Sound, + Name::Graphics, + Name::Color, + Name::Playdate, Name::Other(Cow::Borrowed("any-other")), ]; ALL @@ -200,19 +283,15 @@ impl DependencyName<'_> { pub fn to_possible_value(&self) -> Option { match self { - Self::Sys => { - PossibleValue::new("playdate-sys").help("Low-level Playdate API") - .into() - }, - Self::Playdate => PossibleValue::new("playdate").help("Playdate API").into(), - Self::Controls => { - PossibleValue::new("playdate-controls").help("Playdate Controls API") - .into() - }, Self::Other(s) => { PossibleValue::new(s.as_ref().to_owned()).help("Any other package") .into() }, + name => { + PossibleValue::new(name.to_string()).aliases(name.aliases()) + .help(name.description().to_string()) + .into() + }, } } } diff --git a/cargo/src/cli/opts.rs b/cargo/src/cli/opts.rs index a86aedf8..804beb14 100644 --- a/cargo/src/cli/opts.rs +++ b/cargo/src/cli/opts.rs @@ -370,10 +370,10 @@ pub fn main(aliases: Option<&HashMap + Clone, impl AsRef>>) .subcommand(set_aliases(build(), aliases)) .subcommand(run()) .subcommand(assets()) - .subcommand(new_crate().hide(true)) - .subcommand(init_crate().hide(true)) + .subcommand(new_crate()) + .subcommand(init_crate()) + .subcommand(package()) .subcommand(migrate().hide(true)) - .subcommand(package().hide(true)) .subcommand(publish().hide(true)) } diff --git a/cargo/src/init/mod.rs b/cargo/src/init/mod.rs index 076aaecb..cfbef746 100644 --- a/cargo/src/init/mod.rs +++ b/cargo/src/init/mod.rs @@ -77,11 +77,8 @@ pub fn new_or_init<'cfg>(config: &'cfg Config<'cfg>) -> CargoResult<()> { } - // export schema: - let schema_bang = manifest_schema(config, path)?.unwrap_or_default(); - // export manifest: - let manifest = format!("{schema_bang}\n{}", manifest.to_string()); + let manifest = manifest.to_string(); std::fs::write(manifest_path, manifest.trim_start())?; @@ -359,39 +356,6 @@ fn cargo_config>(config: &Config, path: P) -> CargoResult<()> { } -/// Returns schema-bang for toml cargo package manifest. -/// -/// There can be three options: -/// 1. URI pointing to schemastore.org -/// 1. local path to .cargo/{file} if it requested or * -/// 1. `None` if requested "no-schema" -/// -/// \* Local schema currently is default option -/// because schema is not published on schemastore.org yet. -fn manifest_schema>(config: &Config, dir: P) -> CargoResult> { - let bytes = include_bytes!("../../cargo-playdate.json"); - let schema = if config.create_local_schema { - let path = dir.as_ref().join(".cargo").join("cargo-playdate.json"); - - if let Some(parent) = path.parent() { - if !parent.try_exists()? { - std::fs::create_dir_all(parent)?; - } - } - std::fs::write(path, bytes)?; - - Some(format!("#:schema .cargo/cargo-playdate.json\n")) - } else { - const MANIFEST_SCHEMA_DEFAULT: &str = "https://json.schemastore.org/cargo-playdate.json"; - let json: serde_json::Value = serde_json::from_slice(bytes)?; - let uri = json["$id"].as_str().unwrap_or(MANIFEST_SCHEMA_DEFAULT); - Some(format!("#:schema {uri}\n")) - }; - - Ok(schema) -} - - fn lib(_config: &Config, root: &Path, manifest: &mut toml_edit::Document) -> CargoResult<()> { use toml_edit::Document; diff --git a/cargo/tests/crates/metadata/Cargo.toml b/cargo/tests/crates/metadata/Cargo.toml index 9ca06024..91eb8a10 100644 --- a/cargo/tests/crates/metadata/Cargo.toml +++ b/cargo/tests/crates/metadata/Cargo.toml @@ -1,5 +1,3 @@ -#:schema ../../../../cargo-playdate.json - [workspace] resolver = "2" members = ["sub"]