From 158178fa6d6fc15c59a0cd8316430be38ff6210b Mon Sep 17 00:00:00 2001 From: Mikey Lombardi Date: Mon, 31 Aug 2026 13:47:30 -0500 Subject: [PATCH 1/5] Add extension methods for docs keywords Prior to this change, retrtieving the `title` and `description` keywords from a schema required using the `get_keyword_as_str` extension method. Setting `title`, `description`, and `markdownDescription` required using the `insert` method on the `Schema` and passing a `serde_json::Value`. This change improves the ergonomics by defining the following extension methods: - `get_title` - retrieve the `title` keyword as a string - `set_title` - override the `title` keyword, returning the previous value if it was defined. - `get_description` - retrieve the `description` keyword as a string - `set_description` - override the `description` keyword, returning the previous value if it was defined. - `set_markdown_description` - override the `markdownDescription` keyword, returning the previous value if it was defined. --- .../src/schema_utility_extensions.rs | 97 +++++++++++++++++++ .../src/vscode/schema_extensions.rs | 17 ++++ 2 files changed, 114 insertions(+) diff --git a/lib/dsc-lib-jsonschema/src/schema_utility_extensions.rs b/lib/dsc-lib-jsonschema/src/schema_utility_extensions.rs index 57fd02040..3e521768b 100644 --- a/lib/dsc-lib-jsonschema/src/schema_utility_extensions.rs +++ b/lib/dsc-lib-jsonschema/src/schema_utility_extensions.rs @@ -1785,6 +1785,88 @@ pub trait SchemaUtilityExtensions { /// assert_eq!(actual, expected); /// ``` fn canonicalize_refs_and_defs_for_bundled_resources(&mut self); + //************************ title keyword functions ***********************// + /// Retrieves the value of the `title` keyword from the schema, if it exists. + /// + /// # Returns + /// + /// An [`Option<&str>`] containing the value of the `title` keyword if it exists, or [`None`] + /// otherwise. + fn get_title(&self) -> Option<&str>; + /// Sets the value of the `title` keyword in the schema. + /// + /// This function sets the value of the `title` keyword in the schema and returns the previous + /// value as a [`String`], if it was already defined. + /// + /// # Arguments + /// + /// - `title` - The value to set for the `title` keyword. + /// + /// # Returns + /// + /// An [`Option`] containing the previous value of the `title` keyword if it was + /// already defined, or [`None`] otherwise. + /// + /// # Example + /// + /// This example shows how you can use this method to define and override the `title` keyword + /// in a schema. + /// + /// ``` + /// use dsc_lib_jsonschema::schema_utility_extensions::SchemaUtilityExtensions; + /// use schemars::json_schema; + /// + /// let ref mut schema = json_schema!({"type": "string"}); + /// assert_eq!(schema.set_title("Example Title"), None); + /// assert_eq!(schema.set_title("New example title"), Some("Example Title".to_string())); + /// ``` + fn set_title(&mut self, title: &str) -> Option; + //********************* description keyword functions ********************// + /// Retrieves the value of the `description` keyword from the schema, if it exists. + /// + /// # Returns + /// + /// An [`Option<&str>`] containing the value of the `description` keyword if it exists, or + /// [`None`] otherwise. + /// + /// # Example + /// + /// This example shows how you can use this method to retrieve the `description` keyword from a + /// schema. + /// + /// ``` + /// use dsc_lib_jsonschema::schema_utility_extensions::SchemaUtilityExtensions; + /// use schemars::json_schema; + /// + /// let schema = json_schema!({"type": "string", "description": "An example description"}); + /// assert_eq!(schema.get_description(), Some("An example description")); + /// ``` + fn get_description(&self) -> Option<&str>; + /// Sets the value of the `description` keyword in the schema. + /// + /// # Arguments + /// + /// - `description` - The value to set for the `description` keyword. + /// + /// # Returns + /// + /// An [`Option`] containing the previous value of the `description` keyword if it was + /// already defined, or [`None`] otherwise. + /// + /// # Example + /// + /// This example shows how you can use this method to define and override the `description` + /// keyword in a schema. + /// + /// ``` + /// use dsc_lib_jsonschema::schema_utility_extensions::SchemaUtilityExtensions; + /// use schemars::json_schema; + /// + /// let ref mut schema = json_schema!({"type": "string"}); + /// assert_eq!(schema.set_description("An example description"), None); + /// assert_eq!(schema.set_description("A new description"), Some("An example description".to_string())); + /// ``` + fn set_description(&mut self, description: &str) -> Option; } impl SchemaUtilityExtensions for Schema { @@ -2251,4 +2333,19 @@ impl SchemaUtilityExtensions for Schema { self.rename_defs_subschema_for_reference(&reference_lookup, bundled_id); } } + fn get_title(&self) -> Option<&str> { + self.get_keyword_as_str("title") + } + fn set_title(&mut self, title: &str) -> Option { + self + .insert("title".to_string(), Value::String(title.to_string())) + .and_then(|v| v.as_str().map(std::string::ToString::to_string)) + } + fn get_description(&self) -> Option<&str> { + self.get_keyword_as_str("description") + } + fn set_description(&mut self, description: &str) -> Option { + self.insert("description".to_string(), Value::String(description.to_string())) + .and_then(|v| v.as_str().map(std::string::ToString::to_string)) + } } diff --git a/lib/dsc-lib-jsonschema/src/vscode/schema_extensions.rs b/lib/dsc-lib-jsonschema/src/vscode/schema_extensions.rs index 73b0fe9b6..90f296d1c 100644 --- a/lib/dsc-lib-jsonschema/src/vscode/schema_extensions.rs +++ b/lib/dsc-lib-jsonschema/src/vscode/schema_extensions.rs @@ -93,6 +93,17 @@ pub trait VSCodeSchemaExtensions { /// If the schema doesn't define the keyword, or defines the keyword with an invalid value, /// this method returns [`None`]. Otherwise, this method returns the description string. fn get_markdown_description(&self) -> Option<&str>; + /// Sets the value for the [`MarkdownDescriptionKeyword`] (`markdownDescription`) in the schema. + /// + /// # Arguments + /// + /// - `description` - The new value for the `markdownDescription` keyword. + /// + /// # Returns + /// + /// Returns the previous value of the `markdownDescription` keyword if it was defined in the + /// schema and otherwise [`None`]. + fn set_markdown_description(&mut self, description: &str) -> Option; /// Retrieves the value for the [`MarkdownEnumDescriptionsKeyword`] (`markdownEnumDescriptions`) /// if it's defined in the schema. /// @@ -156,6 +167,12 @@ impl VSCodeSchemaExtensions for Schema { fn get_markdown_description(&self) -> Option<&str> { self.get_keyword_as_str(MarkdownDescriptionKeyword::KEYWORD_NAME) } + fn set_markdown_description(&mut self, description: &str) -> Option { + self.insert( + MarkdownDescriptionKeyword::KEYWORD_NAME.to_string(), + serde_json::Value::String(description.to_string()) + ).and_then(|v| v.as_str().map(std::string::ToString::to_string)) + } fn get_markdown_enum_descriptions(&self) -> Option> { match self.get_keyword_as_array(MarkdownEnumDescriptionsKeyword::KEYWORD_NAME) { None => None, From 8aa76b7b473156e6bd9200882d27761c2ea2f68f Mon Sep 17 00:00:00 2001 From: Mikey Lombardi Date: Mon, 31 Aug 2026 13:52:15 -0500 Subject: [PATCH 2/5] Add meta schema extension methods Prior to this change, working with the `$schema` field for a schema required using the `get_keyword_as_str` method and parsing into a `Url` or calling the `insert` method with a `serde_json::Value`. This change adds the following extension methods: - `get_meta_schema` - Retrieve the `$schema` keyword as a string slice if defined. - `get_meta_schema_as_url` - Retrieve the `$schema` keyword as a `Url` if defined and valid. - `has_meta_schema_keyword` - Indicates if the schema defines the `$schema` keyword. - `set_meta_schema` - Overrides the `$schema` keyword and returns the previous value if it was already defined. --- .../src/schema_utility_extensions.rs | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/lib/dsc-lib-jsonschema/src/schema_utility_extensions.rs b/lib/dsc-lib-jsonschema/src/schema_utility_extensions.rs index 3e521768b..b193a06d8 100644 --- a/lib/dsc-lib-jsonschema/src/schema_utility_extensions.rs +++ b/lib/dsc-lib-jsonschema/src/schema_utility_extensions.rs @@ -839,6 +839,105 @@ pub trait SchemaUtilityExtensions { /// ``` fn set_id(&mut self, id_uri: &str) -> Option; + //********************** $schema keyword functions ***********************// + /// Retrieves the `$schema` keyword and returns it as a string if it exists. + /// + /// # Examples + /// + /// ```rust + /// use schemars::json_schema; + /// use dsc_lib_jsonschema::schema_utility_extensions::SchemaUtilityExtensions; + /// + /// let ref schema = json_schema!({ + /// "$schema": "https://json-schema.org/draft/2020-12/schema" + /// }); + /// + /// assert_eq!( + /// schema.get_meta_schema(), + /// Some("https://json-schema.org/draft/2020-12/schema") + /// ); + /// ``` + fn get_meta_schema(&self) -> Option<&str>; + /// Retrieves the `$schema` keyword and returns it as a [`Url`] if it exists. + /// + /// # Examples + /// + /// ```rust + /// use schemars::json_schema; + /// use dsc_lib_jsonschema::schema_utility_extensions::SchemaUtilityExtensions; + /// use url::Url; + /// + /// let ref schema = json_schema!({ + /// "$schema": "https://json-schema.org/draft/2020-12/schema", + /// "type": "string" + /// }); + /// + /// assert_eq!( + /// schema.get_meta_schema_as_url(), + /// Some(Url::parse("https://json-schema.org/draft/2020-12/schema").unwrap()) + /// ); + /// ``` + /// + /// ```rust + /// use schemars::json_schema; + /// use dsc_lib_jsonschema::schema_utility_extensions::SchemaUtilityExtensions; + /// + /// let ref schema = json_schema!({ "type": "string" }); + /// + /// assert_eq!( + /// schema.get_meta_schema_as_url(), + /// None) + /// ); + /// ``` + fn get_meta_schema_as_url(&self) -> Option; + /// Checks if the `$schema` keyword is present in the schema. + /// + /// # Examples + /// + /// ```rust + /// use schemars::json_schema; + /// use dsc_lib_jsonschema::schema_utility_extensions::SchemaUtilityExtensions; + /// + /// let ref schema = json_schema!({ + /// "$schema": "https://json-schema.org/draft/2020-12/schema", + /// "type": "string" + /// }); + /// + /// assert_eq!( + /// schema.has_meta_schema_keyword(), + /// true + /// ); + /// ``` + /// + /// ```rust + /// # use schemars::json_schema; + /// # use dsc_lib_jsonschema::schema_utility_extensions::SchemaUtilityExtensions; + /// + /// let ref schema = json_schema!({"type": "string"}); + /// + /// assert_eq!( + /// schema.has_meta_schema_keyword(), + /// false + /// ); + /// ``` + fn has_meta_schema_keyword(&self) -> bool; + /// Sets the `$schema` keyword to the provided URI and returns the previous value if it existed. + /// + /// # Examples + /// + /// ```rust + /// use schemars::json_schema; + /// use dsc_lib_jsonschema::schema_utility_extensions::SchemaUtilityExtensions; + /// + /// let mut schema = json_schema!({ "type": "string" }); + /// let previous = schema.set_meta_schema("https://json-schema.org/draft/2020-12/schema"); + /// assert_eq!(previous, None); + /// assert_eq!( + /// schema.get_meta_schema_as_url(), + /// Some(url::Url::parse("https://json-schema.org/draft/2020-12/schema").unwrap()) + /// ); + /// ``` + fn set_meta_schema(&mut self, meta_schema_uri: &str) -> Option; //*********************** $defs keyword functions ************************// /// Retrieves the `$defs` keyword and returns the object if it exists. /// @@ -2149,6 +2248,19 @@ impl SchemaUtilityExtensions for Schema { self.insert("$id".to_string(), Value::String(id_uri.to_string())) .and(old_id) } + fn get_meta_schema(&self) -> Option<&str> { + self.get_keyword_as_str("$schema") + } + fn get_meta_schema_as_url(&self) -> Option { + self.get_meta_schema().and_then(|s| Url::parse(s).ok()) + } + fn has_meta_schema_keyword(&self) -> bool { + self.get("$schema").is_some() + } + fn set_meta_schema(&mut self, meta_schema_uri: &str) -> Option { + self.insert("$schema".to_string(), Value::String(meta_schema_uri.to_string())) + .and_then(|v| v.as_str().map(std::string::ToString::to_string)) + } fn get_properties(&self) -> Option<&Map> { self.get_keyword_as_object("properties") } From f627726e63a981fb2859dd1073e0d814aa9a4096 Mon Sep 17 00:00:00 2001 From: Mikey Lombardi Date: Mon, 31 Aug 2026 14:04:48 -0500 Subject: [PATCH 3/5] Add transforms for `DscRepoSchema` Prior to this change, defining the `$schema`, `$id`, `title, `description`, and `markdownDescription` keywords to the JSON Schema for a `DscRepoSchema` type required the following type definition pattern: ```rust #[derive(Debug, Clone, JsonSchema, DscRepoSchema)] #[dsc_repo_schema(base_name = "struct", folder_path = "example")] #[schemars( title = schema_i18n!("title"), description = schema_i18n("description"), extend( "$schema" = ExampleStruct::default_export_meta_schema_uri(), "$id" = ExampleStruct::default_export_schema_id_uri(), "markdownDescription" = schema_i18n!("markdownDescription"), ) )] pub struct ExampleStruct { // Elided for brevity } ``` With this change, you can insert the `$id` and `$schema` keywords with the `transform_export_schema_uris` transform method and the localized docs keywords with either the `transform_schema_docs` or `transform_schema_docs_strict` methods. ```rust #[derive(Debug, Clone, JsonSchema, DscRepoSchema)] #[dsc_repo_schema(base_name = "struct", folder_path = "example")] #[schemars( transform = ExampleStruct::transform_export_schema_uris, transform = ExampleStruct::transform_schema_docs, )] pub struct ExampleStruct { // Elided for brevity } ``` This change adds the following transform methods to the `DscRepoSchema` trait with default implementations for each transformer: - `transform_export_schema_uris` - Insert the default export URIs for the `$schema` and `$id` keywords. - `transform_schema_docs` - Insert the `title`, `description`, and `markdownDescription` keywords with localized text. If the translation is missing, silently skip overriding that keyword. - `transform_schema_docs_strict` - As above, but collect missing translations and panic to indicate that the schema is missing docs. --- .../src/dsc_repo/dsc_repo_schema.rs | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/lib/dsc-lib-jsonschema/src/dsc_repo/dsc_repo_schema.rs b/lib/dsc-lib-jsonschema/src/dsc_repo/dsc_repo_schema.rs index fb065fc80..83372c314 100644 --- a/lib/dsc-lib-jsonschema/src/dsc_repo/dsc_repo_schema.rs +++ b/lib/dsc-lib-jsonschema/src/dsc_repo/dsc_repo_schema.rs @@ -357,6 +357,133 @@ pub trait DscRepoSchema : JsonSchema { /// /// Returns a [`DscRepoSchemaMissingTranslationError`] error if the translation key doesn't exist. fn schema_i18n(suffix: &str) -> Result; + + /// Transforms the `$schema` and `$id` fields of the given schema to use the default export URIs. + /// + /// This associated function modifies the given schema in-place to use the default export URIs for the `$schema` + /// and `$id` fields. + /// + /// # Arguments + /// + /// - `schema` - The mutable reference to the schema to be transformed. + /// + /// # Example + /// + /// The first definition shows how you must manually define the `$schema` and `$id` fields + /// without this transformer. + /// + /// ``` + /// # use schemars::JsonSchema; + /// # use dsc_lib_jsonschema::dsc_repo::DscRepoSchema; + /// + /// #[derive(Debug, Clone, JsonSchema, DscRepoSchema)] + /// #[dsc_repo_schema(base_name = "struct", folder_path = "examples")] + /// #[schemars( + /// extend( + /// "$schema" = ExampleStruct::default_export_meta_schema_uri(), + /// "$id" = ExampleStruct::default_export_schema_id_uri(), + /// ) + /// )] + /// struct ExampleStruct { + /// pub field: String, + /// } + /// + /// let schema = schema_for!(ExampleStruct); + /// + /// assert_eq!(schema.get_meta_schema(), Some(ExampleStruct::default_export_meta_schema_uri())); + /// assert_eq!(schema.get_id(), Some(ExampleStruct::default_export_schema_id_uri())); + /// ``` + /// + /// With this transform, the definition is much shorter: + /// + /// ``` + /// # use schemars::JsonSchema; + /// # use dsc_lib_jsonschema::dsc_repo::DscRepoSchema; + /// + /// #[derive(Debug, Clone, JsonSchema, DscRepoSchema)] + /// #[dsc_repo_schema(base_name = "struct", folder_path = "examples")] + /// #[schemars(transform = "ExampleStruct::transform_export_schema_uris")] + /// struct ExampleStruct { + /// pub field: String, + /// } + /// + /// let schema = schema_for!(ExampleStruct); + /// + /// assert_eq!(schema.get_meta_schema(), Some(ExampleStruct::default_export_meta_schema_uri())); + /// assert_eq!(schema.get_id(), Some(ExampleStruct::default_export_schema_id_uri())); + /// ``` + fn transform_export_schema_uris(schema: &mut schemars::Schema) { + schema.set_meta_schema(&Self::default_export_meta_schema_uri()); + schema.set_id(&Self::default_export_schema_id_uri()); + } + + /// Inserts the localized documentation (title, description, and markdown description) into the + /// schema if available. + /// + /// This transform overrides the following keywords in the schema if the matching localized + /// documentation is available: + /// + /// - `title` + /// - `description` + /// - `markdownDescription` + /// + /// To panic on missing translations, use the [`transform_schema_docs_strict`] associated + /// function instead. + /// + /// [`transform_schema_docs_strict`]: Self::transform_schema_docs_strict + fn transform_schema_docs(schema: &mut schemars::Schema) { + use super::super::vscode::VSCodeSchemaExtensions; + + if let Ok(title) = Self::schema_i18n("title") { + schema.set_title(&title); + } + if let Ok(description) = Self::schema_i18n("description") { + schema.set_description(&description); + } + if let Ok(markdown_description) = Self::schema_i18n("markdownDescription") { + schema.set_markdown_description(&markdown_description); + } + } + + /// Inserts the localized documentation (title, description, and markdown description) into the + /// schema and panics if any translations are missing. + /// + /// This transform overrides the following keywords in the schema if the matching localized + /// documentation is available: + /// + /// - `title` + /// - `description` + /// - `markdownDescription` + /// + /// To silently ignore missing translations, use the [`transform_schema_docs`] associated + /// function instead. + /// + /// # Panics + /// + /// This function will panic if any of the localized documentation translations are missing for + /// any of the keywords. + /// + /// [`transform_schema_docs`]: Self::transform_schema_docs + fn transform_schema_docs_strict(schema: &mut schemars::Schema) { + use super::super::vscode::VSCodeSchemaExtensions; + let mut missing_translation_errors: Vec = Vec::new(); + match Self::schema_i18n("title") { + Ok(title) => { schema.set_title(&title); }, + Err(e) => missing_translation_errors.push(e), + } + match Self::schema_i18n("description") { + Ok(description) => { schema.set_description(&description); }, + Err(e) => missing_translation_errors.push(e), + } + match Self::schema_i18n("markdownDescription") { + Ok(markdown_description) => { schema.set_markdown_description(&markdown_description); }, + Err(e) => missing_translation_errors.push(e), + } + + if !missing_translation_errors.is_empty() { + panic!("missing translation errors: {:?}", missing_translation_errors); + } + } } /// Defines the error when a user-defined JSON Schema references an unrecognized schema URI. From 196e31f569e092461af29d8b4038f063e3a7ed22 Mon Sep 17 00:00:00 2001 From: Mikey Lombardi Date: Mon, 31 Aug 2026 14:49:19 -0500 Subject: [PATCH 4/5] Update schemas for `dsc-lib` Prior to this change, the schemas for `DscRepoSchema` types were inconsistent about: - Defining `$schema` and `$id` - some types deriving `JsonSchema` or implementing it manually supplied those keywords, most didn't. Some used `default_schema_id_uri` or `default_export_schema_id_uri`. - Defining the documentation keywords. Most types didn't set them at all. This change ensures every `DscRepoSchema` either defines the keywords directly (for types manually implementing `JsonSchema`) or uses the newly available `transform_*` associated trait functions (for types that derive `JsonSchema`). Most types _don't_ have localized documentation yet, so this PR uses the non-strict transform. Eventually we should always use the strict transforms and panic on missing documentation. --- lib/dsc-lib/src/configure/config_doc.rs | 83 +++++++++++++++++-- lib/dsc-lib/src/configure/config_result.rs | 32 +++++++ .../dscresources/adapted_resource_manifest.rs | 5 ++ lib/dsc-lib/src/dscresources/dscresource.rs | 9 ++ lib/dsc-lib/src/dscresources/invoke_result.rs | 44 ++++++++++ .../src/dscresources/resource_manifest.rs | 79 +++++++++++++++++- lib/dsc-lib/src/extensions/discover.rs | 10 +++ lib/dsc-lib/src/extensions/dscextension.rs | 10 ++- .../src/extensions/extension_manifest.rs | 4 + lib/dsc-lib/src/extensions/import.rs | 5 ++ lib/dsc-lib/src/extensions/secret.rs | 5 ++ lib/dsc-lib/src/functions/mod.rs | 15 ++++ lib/dsc-lib/src/types/date_version.rs | 6 +- lib/dsc-lib/src/types/exit_codes_map.rs | 5 +- .../src/types/fully_qualified_type_name.rs | 7 +- lib/dsc-lib/src/types/resource_version.rs | 7 +- lib/dsc-lib/src/types/resource_version_req.rs | 7 +- lib/dsc-lib/src/types/semantic_version.rs | 4 +- lib/dsc-lib/src/types/semantic_version_req.rs | 4 +- lib/dsc-lib/src/types/tag.rs | 8 +- lib/dsc-lib/src/types/tag_list.rs | 9 +- 21 files changed, 317 insertions(+), 41 deletions(-) diff --git a/lib/dsc-lib/src/configure/config_doc.rs b/lib/dsc-lib/src/configure/config_doc.rs index 25c783b41..1529a6814 100644 --- a/lib/dsc-lib/src/configure/config_doc.rs +++ b/lib/dsc-lib/src/configure/config_doc.rs @@ -18,7 +18,11 @@ use crate::{ #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(rename_all = "camelCase")] -#[schemars(transform = idiomaticize_string_enum)] +#[schemars( + transform = idiomaticize_string_enum, + transform = SecurityContextKind::transform_export_schema_uris, + transform = SecurityContextKind::transform_schema_docs +)] #[dsc_repo_schema(base_name = "securityContext", folder_path = "executionInformation")] pub enum SecurityContextKind { Current, @@ -39,7 +43,11 @@ impl Display for SecurityContextKind { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(rename_all = "camelCase")] -#[schemars(transform = idiomaticize_string_enum)] +#[schemars( + transform = idiomaticize_string_enum, + transform = Operation::transform_export_schema_uris, + transform = Operation::transform_schema_docs +)] #[dsc_repo_schema(base_name = "operation", folder_path = "executionInformation")] pub enum Operation { Get, @@ -62,7 +70,11 @@ impl Display for Operation { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(rename_all = "camelCase")] -#[schemars(transform = idiomaticize_string_enum)] +#[schemars( + transform = idiomaticize_string_enum, + transform = ExecutionKind::transform_export_schema_uris, + transform = ExecutionKind::transform_schema_docs +)] #[dsc_repo_schema(base_name = "executionType", folder_path = "executionInformation")] pub enum ExecutionKind { Actual, @@ -78,7 +90,11 @@ pub struct Process { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(rename_all = "camelCase")] -#[schemars(transform = idiomaticize_externally_tagged_enum)] +#[schemars( + transform = idiomaticize_externally_tagged_enum, + transform = RestartRequired::transform_export_schema_uris, + transform = RestartRequired::transform_schema_docs +)] #[dsc_repo_schema(base_name = "restartRequired", folder_path = "executionInformation")] pub enum RestartRequired { System(String), @@ -88,6 +104,11 @@ pub enum RestartRequired { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(rename_all = "camelCase")] +#[schemars( + transform = idiomaticize_string_enum, + transform = ResourceDiscoveryMode::transform_export_schema_uris, + transform = ResourceDiscoveryMode::transform_schema_docs +)] #[dsc_repo_schema(base_name = "resourceDiscovery", folder_path = "directive")] pub enum ResourceDiscoveryMode { PreDeployment, @@ -158,6 +179,10 @@ impl MicrosoftDscMetadata { #[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(rename_all = "camelCase")] +#[schemars( + transform = ExecutionInformation::transform_export_schema_uris, + transform = ExecutionInformation::transform_schema_docs +)] #[dsc_repo_schema(base_name = "executionInformation", folder_path = "config")] pub struct ExecutionInformation { /// The duration of the configuration operation @@ -219,6 +244,10 @@ impl ExecutionInformation { #[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(rename_all = "camelCase")] +#[schemars( + transform = ConfigDirective::transform_export_schema_uris, + transform = ConfigDirective::transform_schema_docs +)] #[dsc_repo_schema(base_name = "directive", folder_path = "config")] pub struct ConfigDirective { /// Indicates if resources are discovered pre-deployment or during deployment @@ -234,6 +263,10 @@ pub struct ConfigDirective { #[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(rename_all = "camelCase")] +#[schemars( + transform = ResourceDirective::transform_export_schema_uris, + transform = ResourceDirective::transform_schema_docs +)] #[dsc_repo_schema(base_name = "directive", folder_path = "resource")] pub struct ResourceDirective { /// Specify specific adapter type used for implicit operations @@ -245,6 +278,10 @@ pub struct ResourceDirective { } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] +#[schemars( + transform = Metadata::transform_export_schema_uris, + transform = Metadata::transform_schema_docs +)] #[dsc_repo_schema(base_name = "document.metadata", folder_path = "config")] pub struct Metadata { #[serde(rename = "Microsoft.DSC", skip_serializing_if = "Option::is_none")] @@ -254,6 +291,10 @@ pub struct Metadata { } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] +#[schemars( + transform = UserFunction::transform_export_schema_uris, + transform = UserFunction::transform_schema_docs +)] #[dsc_repo_schema(base_name = "document.function", folder_path = "config")] pub struct UserFunction { pub namespace: String, @@ -261,6 +302,10 @@ pub struct UserFunction { } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] +#[schemars( + transform = UserFunctionDefinition::transform_export_schema_uris, + transform = UserFunctionDefinition::transform_schema_docs +)] #[dsc_repo_schema(base_name = "definition", folder_path = "definitions/functions/user")] pub struct UserFunctionDefinition { pub parameters: Option>, @@ -268,6 +313,10 @@ pub struct UserFunctionDefinition { } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] +#[schemars( + transform = UserFunctionParameter::transform_export_schema_uris, + transform = UserFunctionParameter::transform_schema_docs +)] #[dsc_repo_schema(base_name = "parameter", folder_path = "definitions/functions/user")] pub struct UserFunctionParameter { pub name: String, @@ -275,6 +324,10 @@ pub struct UserFunctionParameter { } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] +#[schemars( + transform = UserFunctionOutput::transform_export_schema_uris, + transform = UserFunctionOutput::transform_schema_docs +)] #[dsc_repo_schema(base_name = "output", folder_path = "definitions/functions/user")] pub struct UserFunctionOutput { pub r#type: DataType, @@ -290,6 +343,10 @@ pub enum ValueOrCopy { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields)] +#[schemars( + transform = Output::transform_export_schema_uris, + transform = Output::transform_schema_docs +)] #[dsc_repo_schema(base_name = "document.output", folder_path = "config")] pub struct Output { pub condition: Option, @@ -300,6 +357,10 @@ pub struct Output { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields, rename_all = "camelCase")] +#[schemars( + transform = Configuration::transform_export_schema_uris, + transform = Configuration::transform_schema_docs +)] #[dsc_repo_schema( base_name = "document", folder_path = "config", @@ -334,6 +395,10 @@ pub struct Configuration { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields)] +#[schemars( + transform = Parameter::transform_export_schema_uris, + transform = Parameter::transform_schema_docs +)] #[dsc_repo_schema(base_name = "document.parameter", folder_path = "config")] pub struct Parameter { #[serde(rename = "type")] @@ -357,7 +422,11 @@ pub struct Parameter { } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] -#[schemars(transform = idiomaticize_string_enum)] +#[schemars( + transform = idiomaticize_string_enum, + transform = DataType::transform_export_schema_uris, + transform = DataType::transform_schema_docs +)] #[dsc_repo_schema(base_name = "dataTypes", folder_path = "definitions/parameters")] pub enum DataType { #[serde(rename = "string")] @@ -429,6 +498,10 @@ pub struct Copy { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields, rename_all = "camelCase")] +#[schemars( + transform = Resource::transform_export_schema_uris, + transform = Resource::transform_schema_docs +)] #[dsc_repo_schema(base_name = "document.resource", folder_path = "config")] pub struct Resource { #[serde(skip_serializing_if = "Option::is_none")] diff --git a/lib/dsc-lib/src/configure/config_result.rs b/lib/dsc-lib/src/configure/config_result.rs index 3278e11cb..208a9194a 100644 --- a/lib/dsc-lib/src/configure/config_result.rs +++ b/lib/dsc-lib/src/configure/config_result.rs @@ -22,6 +22,10 @@ pub enum MessageLevel { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields)] #[dsc_repo_schema(base_name = "message", folder_path = "definitions")] +#[schemars( + transform = ResourceMessage::transform_export_schema_uris, + transform = ResourceMessage::transform_schema_docs +)] pub struct ResourceMessage { pub name: String, #[serde(rename="type")] @@ -33,6 +37,10 @@ pub struct ResourceMessage { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields)] #[dsc_repo_schema(base_name = "get.full", folder_path = "outputs/resource")] +#[schemars( + transform = ResourceGetResult::transform_export_schema_uris, + transform = ResourceGetResult::transform_schema_docs +)] pub struct ResourceGetResult { #[serde(rename = "executionInformation", skip_serializing_if = "Option::is_none")] pub execution_information: Option, @@ -59,6 +67,10 @@ impl From for ResourceGetResult { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields, rename_all = "camelCase")] #[dsc_repo_schema(base_name = "get", folder_path = "outputs/config")] +#[schemars( + transform = ConfigurationGetResult::transform_export_schema_uris, + transform = ConfigurationGetResult::transform_schema_docs +)] pub struct ConfigurationGetResult { pub execution_information: Option, pub metadata: Option, @@ -109,6 +121,10 @@ impl From for ConfigurationGetResult { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields)] #[dsc_repo_schema(base_name = "set.full", folder_path = "outputs/resource")] +#[schemars( + transform = ResourceSetResult::transform_export_schema_uris, + transform = ResourceSetResult::transform_schema_docs +)] pub struct ResourceSetResult { #[serde(rename = "executionInformation", skip_serializing_if = "Option::is_none")] pub execution_information: Option, @@ -156,6 +172,10 @@ impl Default for GroupResourceSetResult { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields, rename_all = "camelCase")] #[dsc_repo_schema(base_name = "set", folder_path = "outputs/config")] +#[schemars( + transform = ConfigurationSetResult::transform_export_schema_uris, + transform = ConfigurationSetResult::transform_schema_docs +)] pub struct ConfigurationSetResult { pub execution_information: Option, pub metadata: Option, @@ -189,6 +209,10 @@ impl Default for ConfigurationSetResult { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields)] #[dsc_repo_schema(base_name = "test.full", folder_path = "outputs/resource")] +#[schemars( + transform = ResourceTestResult::transform_export_schema_uris, + transform = ResourceTestResult::transform_schema_docs +)] pub struct ResourceTestResult { #[serde(rename = "executionInformation", skip_serializing_if = "Option::is_none")] pub execution_information: Option, @@ -224,6 +248,10 @@ impl Default for GroupResourceTestResult { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields, rename_all = "camelCase")] #[dsc_repo_schema(base_name = "test", folder_path = "outputs/config")] +#[schemars( + transform = ConfigurationTestResult::transform_export_schema_uris, + transform = ConfigurationTestResult::transform_schema_docs +)] pub struct ConfigurationTestResult { pub execution_information: Option, pub metadata: Option, @@ -257,6 +285,10 @@ impl Default for ConfigurationTestResult { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields, rename_all = "camelCase")] #[dsc_repo_schema(base_name = "export", folder_path = "outputs/config")] +#[schemars( + transform = ConfigurationExportResult::transform_export_schema_uris, + transform = ConfigurationExportResult::transform_schema_docs +)] pub struct ConfigurationExportResult { pub execution_information: Option, pub metadata: Option, diff --git a/lib/dsc-lib/src/dscresources/adapted_resource_manifest.rs b/lib/dsc-lib/src/dscresources/adapted_resource_manifest.rs index 0e2dac392..0cd3d9853 100644 --- a/lib/dsc-lib/src/dscresources/adapted_resource_manifest.rs +++ b/lib/dsc-lib/src/dscresources/adapted_resource_manifest.rs @@ -16,6 +16,7 @@ use std::path::PathBuf; #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] #[serde(rename_all = "camelCase")] +#[schemars(inline)] pub enum AdaptedPathOrContent { Path(PathBuf), Content(Map), @@ -33,6 +34,10 @@ pub enum AdaptedPathOrContent { description = t!("dscresources.resource_manifest.adaptedResourceManifestSchemaDescription"), ) )] +#[schemars( + transform = AdaptedDscResourceManifest::transform_export_schema_uris, + transform = AdaptedDscResourceManifest::transform_schema_docs +)] pub struct AdaptedDscResourceManifest { /// The version of the resource manifest schema. #[serde(rename = "$schema")] diff --git a/lib/dsc-lib/src/dscresources/dscresource.rs b/lib/dsc-lib/src/dscresources/dscresource.rs index d4053e494..91bba2f9a 100644 --- a/lib/dsc-lib/src/dscresources/dscresource.rs +++ b/lib/dsc-lib/src/dscresources/dscresource.rs @@ -29,6 +29,10 @@ use super::{ #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields, rename_all = "camelCase")] #[dsc_repo_schema(base_name = "list", folder_path = "outputs/resource")] +#[schemars( + transform = DscResource::transform_export_schema_uris, + transform = DscResource::transform_schema_docs +)] pub struct DscResource { /// The namespaced name of the resource. #[serde(rename="type")] @@ -69,6 +73,10 @@ pub struct DscResource { #[serde(rename_all = "camelCase")] #[schemars(transform = idiomaticize_string_enum)] #[dsc_repo_schema(base_name = "resourceCapabilities", folder_path = "definitions")] +#[schemars( + transform = Capability::transform_export_schema_uris, + transform = Capability::transform_schema_docs +)] pub enum Capability { /// The resource supports retrieving configuration. Get, @@ -92,6 +100,7 @@ pub enum Capability { #[derive(Clone, Debug, PartialEq, Deserialize, Serialize, JsonSchema)] #[serde(untagged)] +#[schemars(inline)] pub enum ImplementedAs { /// A command line executable Command, diff --git a/lib/dsc-lib/src/dscresources/invoke_result.rs b/lib/dsc-lib/src/dscresources/invoke_result.rs index 9115d2896..578482e91 100644 --- a/lib/dsc-lib/src/dscresources/invoke_result.rs +++ b/lib/dsc-lib/src/dscresources/invoke_result.rs @@ -11,6 +11,10 @@ use crate::schemas::dsc_repo::DscRepoSchema; #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(untagged)] #[dsc_repo_schema(base_name = "get", folder_path = "outputs/resource")] +#[schemars( + transform = GetResult::transform_export_schema_uris, + transform = GetResult::transform_schema_docs +)] pub enum GetResult { Resource(ResourceGetResponse), Group(Vec), @@ -38,6 +42,10 @@ impl From for GetResult { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields)] #[dsc_repo_schema(base_name = "get.simple", folder_path = "outputs/resource")] +#[schemars( + transform = ResourceGetResponse::transform_export_schema_uris, + transform = ResourceGetResponse::transform_schema_docs +)] pub struct ResourceGetResponse { /// The state of the resource as it was returned by the Get method. #[serde(rename = "actualState")] @@ -47,6 +55,10 @@ pub struct ResourceGetResponse { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(untagged)] #[dsc_repo_schema(base_name = "set", folder_path = "outputs/resource")] +#[schemars( + transform = SetResult::transform_export_schema_uris, + transform = SetResult::transform_schema_docs +)] pub enum SetResult { Resource(ResourceSetResponse), Group(Vec), @@ -99,6 +111,10 @@ impl SetResult { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields)] #[dsc_repo_schema(base_name = "set.simple", folder_path = "outputs/resource")] +#[schemars( + transform = ResourceSetResponse::transform_export_schema_uris, + transform = ResourceSetResponse::transform_schema_docs +)] pub struct ResourceSetResponse { /// The state of the resource as it was before the Set method was called. #[serde(rename = "beforeState")] @@ -114,6 +130,10 @@ pub struct ResourceSetResponse { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(untagged)] #[dsc_repo_schema(base_name = "test", folder_path = "outputs/resource")] +#[schemars( + transform = TestResult::transform_export_schema_uris, + transform = TestResult::transform_schema_docs +)] pub enum TestResult { Resource(ResourceTestResponse), Group(Vec), @@ -139,6 +159,10 @@ pub fn get_in_desired_state(test_result: &TestResult) -> bool { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields)] #[dsc_repo_schema(base_name = "test.simple", folder_path = "outputs/resource")] +#[schemars( + transform = ResourceTestResponse::transform_export_schema_uris, + transform = ResourceTestResponse::transform_schema_docs +)] pub struct ResourceTestResponse { /// The state of the resource as it was expected to be. #[serde(rename = "desiredState")] @@ -157,6 +181,10 @@ pub struct ResourceTestResponse { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields)] #[dsc_repo_schema(base_name = "validate", folder_path = "outputs/resource")] +#[schemars( + transform = ValidateResult::transform_export_schema_uris, + transform = ValidateResult::transform_schema_docs +)] pub struct ValidateResult { /// Whether the supplied configuration is valid. pub valid: bool, @@ -167,6 +195,10 @@ pub struct ValidateResult { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields)] #[dsc_repo_schema(base_name = "export", folder_path = "outputs/resource")] +#[schemars( + transform = ExportResult::transform_export_schema_uris, + transform = ExportResult::transform_schema_docs +)] pub struct ExportResult { /// The state of the resource as it was returned by the Export method. #[serde(rename = "actualState")] @@ -176,6 +208,10 @@ pub struct ExportResult { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields)] #[dsc_repo_schema(base_name = "resolve", folder_path = "outputs/resource")] +#[schemars( + transform = ResolveResult::transform_export_schema_uris, + transform = ResolveResult::transform_schema_docs +)] pub struct ResolveResult { /// The resolved configuration. pub configuration: Value, @@ -186,6 +222,10 @@ pub struct ResolveResult { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields)] #[dsc_repo_schema(base_name = "delete", folder_path = "outputs/resource")] +#[schemars( + transform = DeleteResult::transform_export_schema_uris, + transform = DeleteResult::transform_schema_docs +)] pub struct DeleteResult { /// The return from the resource by the Delete method with what-if simulation. #[serde(rename = "_metadata", skip_serializing_if = "Option::is_none")] @@ -194,6 +234,10 @@ pub struct DeleteResult { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[dsc_repo_schema(base_name = "delete.whatIf", folder_path = "outputs/resource")] +#[schemars( + transform = DeleteWhatIfResult::transform_export_schema_uris, + transform = DeleteWhatIfResult::transform_schema_docs +)] #[serde(deny_unknown_fields)] pub struct DeleteWhatIfResult { #[serde(rename = "whatIf", skip_serializing_if = "Option::is_none")] diff --git a/lib/dsc-lib/src/dscresources/resource_manifest.rs b/lib/dsc-lib/src/dscresources/resource_manifest.rs index 786f3e67a..9e94180b4 100644 --- a/lib/dsc-lib/src/dscresources/resource_manifest.rs +++ b/lib/dsc-lib/src/dscresources/resource_manifest.rs @@ -15,7 +15,11 @@ use crate::{ #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(rename_all = "camelCase")] -#[schemars(transform = idiomaticize_string_enum)] +#[schemars( + transform = idiomaticize_string_enum, + transform = Kind::transform_export_schema_uris, + transform = Kind::transform_schema_docs, +)] #[dsc_repo_schema(base_name = "resourceKind", folder_path = "definitions")] pub enum Kind { Adapter, @@ -27,6 +31,10 @@ pub enum Kind { #[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields, rename_all = "camelCase")] +#[schemars( + transform = ResourceManifest::transform_export_schema_uris, + transform = ResourceManifest::transform_schema_docs, +)] #[dsc_repo_schema( base_name = "manifest", folder_path = "resource", @@ -100,6 +108,10 @@ pub struct ResourceManifest { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(untagged)] +#[schemars( + transform = GetArgKind::transform_export_schema_uris, + transform = GetArgKind::transform_schema_docs, +)] #[dsc_repo_schema(base_name = "commandArgs.get", folder_path = "definitions")] pub enum GetArgKind { /// The argument is a string. @@ -138,6 +150,10 @@ pub enum GetArgKind { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(untagged)] +#[schemars( + transform = SetDeleteArgKind::transform_export_schema_uris, + transform = SetDeleteArgKind::transform_schema_docs, +)] #[dsc_repo_schema(base_name = "commandArgs.setDelete", folder_path = "definitions")] pub enum SetDeleteArgKind { /// The argument is a string. @@ -182,6 +198,10 @@ pub enum SetDeleteArgKind { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(untagged)] +#[schemars( + transform = SchemaArgKind::transform_export_schema_uris, + transform = SchemaArgKind::transform_schema_docs, +)] #[dsc_repo_schema(base_name = "commandArgs.schema", folder_path = "definitions")] pub enum SchemaArgKind { /// The argument is a string. @@ -199,7 +219,11 @@ pub enum SchemaArgKind { } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] -#[schemars(transform = idiomaticize_string_enum)] +#[schemars( + transform = idiomaticize_string_enum, + transform = InputKind::transform_schema_docs, + transform = InputKind::transform_export_schema_uris, +)] #[dsc_repo_schema(base_name = "inputKind", folder_path = "definitions")] pub enum InputKind { /// The input is accepted as environmental variables. @@ -211,6 +235,10 @@ pub enum InputKind { } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] +#[schemars( + transform = SchemaKind::transform_export_schema_uris, + transform = SchemaKind::transform_schema_docs, +)] #[dsc_repo_schema(base_name = "manifest.schema", folder_path = "resource")] pub enum SchemaKind { /// The schema is returned by running a command. @@ -224,6 +252,10 @@ pub enum SchemaKind { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[dsc_repo_schema(base_name = "manifest.exportSchema", folder_path = "definitions")] #[serde(rename_all = "camelCase")] +#[schemars( + transform = ExportSchemaKind::transform_export_schema_uris, + transform = ExportSchemaKind::transform_schema_docs, +)] pub enum ExportSchemaKind { /// The export schema is returned by running a command. Command(SchemaCommand), @@ -232,6 +264,7 @@ pub enum ExportSchemaKind { } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)] +#[schemars(inline)] pub struct SchemaCommand { /// The command to run to get the schema. pub executable: String, @@ -240,7 +273,11 @@ pub struct SchemaCommand { } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] -#[schemars(transform = idiomaticize_string_enum)] +#[schemars( + transform = idiomaticize_string_enum, + transform = ReturnKind::transform_schema_docs, + transform = ReturnKind::transform_export_schema_uris, +)] #[dsc_repo_schema(base_name = "returnKind", folder_path = "definitions")] pub enum ReturnKind { /// The return JSON is the state of the resource. @@ -253,6 +290,10 @@ pub enum ReturnKind { #[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[dsc_repo_schema(base_name = "manifest.get", folder_path = "resource")] +#[schemars( + transform = GetMethod::transform_export_schema_uris, + transform = GetMethod::transform_schema_docs, +)] pub struct GetMethod { /// The command to run to get the state of the resource. pub executable: String, @@ -268,6 +309,10 @@ pub struct GetMethod { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[dsc_repo_schema(base_name = "manifest.set", folder_path = "resource")] +#[schemars( + transform = SetMethod::transform_export_schema_uris, + transform = SetMethod::transform_schema_docs, +)] pub struct SetMethod { /// The command to run to set the state of the resource. pub executable: String, @@ -294,6 +339,10 @@ pub struct SetMethod { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[dsc_repo_schema(base_name = "manifest.test", folder_path = "resource")] +#[schemars( + transform = TestMethod::transform_export_schema_uris, + transform = TestMethod::transform_schema_docs, +)] pub struct TestMethod { /// The command to run to test the state of the resource. pub executable: String, @@ -311,6 +360,10 @@ pub struct TestMethod { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[dsc_repo_schema(base_name = "manifest.delete", folder_path = "resource")] +#[schemars( + transform = DeleteMethod::transform_export_schema_uris, + transform = DeleteMethod::transform_schema_docs, +)] pub struct DeleteMethod { /// The command to run to delete the state of the resource. pub executable: String, @@ -325,6 +378,10 @@ pub struct DeleteMethod { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[dsc_repo_schema(base_name = "manifest.validate", folder_path = "resource")] +#[schemars( + transform = ValidateMethod::transform_export_schema_uris, + transform = ValidateMethod::transform_schema_docs, +)] pub struct ValidateMethod { // TODO: enable validation via schema or command /// The command to run to validate the state of the resource. pub executable: String, @@ -336,6 +393,7 @@ pub struct ValidateMethod { // TODO: enable validation via schema or command #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)] #[serde(rename_all = "camelCase")] +#[schemars(inline)] pub enum ExportSchemaOrFiltering { Schema(ExportSchemaKind), SupportsFiltering(bool), @@ -343,6 +401,10 @@ pub enum ExportSchemaOrFiltering { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[dsc_repo_schema(base_name = "manifest.export", folder_path = "resource")] +#[schemars( + transform = ExportMethod::transform_export_schema_uris, + transform = ExportMethod::transform_schema_docs, +)] pub struct ExportMethod { /// The command to run to enumerate instances of the resource. pub executable: String, @@ -359,6 +421,10 @@ pub struct ExportMethod { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[dsc_repo_schema(base_name = "manifest.resolve", folder_path = "resource")] +#[schemars( + transform = ResolveMethod::transform_export_schema_uris, + transform = ResolveMethod::transform_schema_docs, +)] pub struct ResolveMethod { /// The command to run to enumerate instances of the resource. pub executable: String, @@ -370,6 +436,10 @@ pub struct ResolveMethod { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[dsc_repo_schema(base_name = "manifest.adapter", folder_path = "resource")] +#[schemars( + transform = Adapter::transform_export_schema_uris, + transform = Adapter::transform_schema_docs, +)] pub struct Adapter { /// The way to list adapter supported resources. pub list: Option, @@ -379,7 +449,7 @@ pub struct Adapter { } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)] -#[schemars(transform = idiomaticize_string_enum)] +#[schemars(inline, transform = idiomaticize_string_enum)] pub enum AdapterInputKind { /// The adapter accepts full unprocessed configuration. #[serde(rename = "full")] @@ -393,6 +463,7 @@ pub enum AdapterInputKind { } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)] +#[schemars(inline)] pub struct ListMethod { /// The command to run to list resources supported by a group resource. pub executable: String, diff --git a/lib/dsc-lib/src/extensions/discover.rs b/lib/dsc-lib/src/extensions/discover.rs index 50adfd376..668f9657d 100644 --- a/lib/dsc-lib/src/extensions/discover.rs +++ b/lib/dsc-lib/src/extensions/discover.rs @@ -28,6 +28,10 @@ use tracing::{info, trace, warn}; #[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[dsc_repo_schema(base_name = "manifest.discover", folder_path = "extension")] +#[schemars( + transform = DiscoverMethod::transform_export_schema_uris, + transform = DiscoverMethod::transform_schema_docs +)] pub struct DiscoverMethod { /// The command to run to get the state of the resource. pub executable: String, @@ -37,6 +41,7 @@ pub struct DiscoverMethod { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)] #[serde(rename_all = "camelCase")] +#[schemars(inline)] pub enum ManifestKind { /// The path to the resource manifest, must be absolute. ManifestPath(PathBuf), @@ -46,6 +51,10 @@ pub enum ManifestKind { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[dsc_repo_schema(base_name = "discover", folder_path = "extension/stdout")] +#[schemars( + transform = DiscoverResult::transform_export_schema_uris, + transform = DiscoverResult::transform_schema_docs +)] pub struct DiscoverResult { #[serde(flatten)] pub path_or_content: ManifestKind, @@ -53,6 +62,7 @@ pub struct DiscoverResult { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)] #[serde(untagged)] +#[schemars(inline)] pub enum DiscoverArgKind { String(String), Extensions { diff --git a/lib/dsc-lib/src/extensions/dscextension.rs b/lib/dsc-lib/src/extensions/dscextension.rs index 3d30d155c..79d336286 100644 --- a/lib/dsc-lib/src/extensions/dscextension.rs +++ b/lib/dsc-lib/src/extensions/dscextension.rs @@ -13,6 +13,10 @@ use std::path::PathBuf; #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields)] #[dsc_repo_schema(base_name = "list", folder_path = "outputs/extension")] +#[schemars( + transform = DscExtension::transform_export_schema_uris, + transform = DscExtension::transform_schema_docs +)] pub struct DscExtension { /// The namespaced name of the extension. #[serde(rename="type")] @@ -39,7 +43,11 @@ pub struct DscExtension { #[derive(Clone, Debug, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(rename_all = "camelCase")] -#[schemars(transform = idiomaticize_string_enum)] +#[schemars( + transform = idiomaticize_string_enum, + transform = Capability::transform_export_schema_uris, + transform = Capability::transform_schema_docs, +)] #[dsc_repo_schema(base_name = "extensionCapabilities", folder_path = "definitions")] pub enum Capability { /// The extension aids in discovering resources. diff --git a/lib/dsc-lib/src/extensions/extension_manifest.rs b/lib/dsc-lib/src/extensions/extension_manifest.rs index e06a40985..8bd2f7400 100644 --- a/lib/dsc-lib/src/extensions/extension_manifest.rs +++ b/lib/dsc-lib/src/extensions/extension_manifest.rs @@ -14,6 +14,10 @@ use crate::types::{ExitCodesMap, FullyQualifiedTypeName, SemanticVersion, TagLis #[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields, rename_all = "camelCase")] +#[schemars( + transform = ExtensionManifest::transform_export_schema_uris, + transform = ExtensionManifest::transform_schema_docs +)] #[dsc_repo_schema( base_name = "manifest", folder_path = "extension", diff --git a/lib/dsc-lib/src/extensions/import.rs b/lib/dsc-lib/src/extensions/import.rs index 0378f8844..0942cb546 100644 --- a/lib/dsc-lib/src/extensions/import.rs +++ b/lib/dsc-lib/src/extensions/import.rs @@ -21,6 +21,10 @@ use std::path::Path; use tracing::{debug, info, warn}; #[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] +#[schemars( + transform = ImportMethod::transform_export_schema_uris, + transform = ImportMethod::transform_schema_docs +)] #[dsc_repo_schema(base_name = "manifest.import", folder_path = "extension")] pub struct ImportMethod { /// The extensions to import. @@ -36,6 +40,7 @@ pub struct ImportMethod { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)] #[serde(untagged)] +#[schemars(inline)] pub enum ImportArgKind { /// The argument is a string. String(String), diff --git a/lib/dsc-lib/src/extensions/secret.rs b/lib/dsc-lib/src/extensions/secret.rs index b73e09482..6687ca51c 100644 --- a/lib/dsc-lib/src/extensions/secret.rs +++ b/lib/dsc-lib/src/extensions/secret.rs @@ -24,6 +24,7 @@ use tracing::{debug, warn}; #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)] #[serde(untagged)] +#[schemars(inline)] pub enum SecretArgKind { /// The argument is a string. String(String), @@ -42,6 +43,10 @@ pub enum SecretArgKind { } #[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] +#[schemars( + transform = SecretMethod::transform_export_schema_uris, + transform = SecretMethod::transform_schema_docs +)] #[dsc_repo_schema(base_name = "manifest.secret", folder_path = "extension")] pub struct SecretMethod { /// The command to run to get the state of the resource. diff --git a/lib/dsc-lib/src/functions/mod.rs b/lib/dsc-lib/src/functions/mod.rs index d6331a6e8..0afa178ea 100644 --- a/lib/dsc-lib/src/functions/mod.rs +++ b/lib/dsc-lib/src/functions/mod.rs @@ -7,6 +7,7 @@ use crate::DscError; use crate::configure::context::{Context, ProcessMode}; use crate::functions::user_function::invoke_user_function; use crate::schemas::dsc_repo::DscRepoSchema; +use dsc_lib_jsonschema::transforms::idiomaticize_string_enum; use rust_i18n::t; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -103,6 +104,11 @@ pub mod try_which; #[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Serialize, JsonSchema, DscRepoSchema)] #[dsc_repo_schema(base_name = "argKind", folder_path = "definitions/functions/builtin")] #[serde(rename_all = "camelCase")] +#[schemars( + transform = idiomaticize_string_enum, + transform = FunctionArgKind::transform_schema_docs, + transform = FunctionArgKind::transform_export_schema_uris, +)] pub enum FunctionArgKind { Array, Boolean, @@ -374,6 +380,10 @@ impl Default for FunctionDispatcher { #[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields)] #[dsc_repo_schema(base_name = "list", folder_path = "outputs/function")] +#[schemars( + transform = FunctionDefinition::transform_export_schema_uris, + transform = FunctionDefinition::transform_schema_docs, +)] pub struct FunctionDefinition { pub category: Vec, pub name: String, @@ -395,6 +405,11 @@ pub struct FunctionDefinition { #[derive(Clone, Debug, Deserialize, Ord, PartialOrd, Eq, PartialEq, Serialize, JsonSchema, DscRepoSchema)] #[serde(deny_unknown_fields, rename_all = "camelCase")] #[dsc_repo_schema(base_name = "category", folder_path = "definitions/functions/builtin")] +#[schemars( + transform = idiomaticize_string_enum, + transform = FunctionCategory::transform_export_schema_uris, + transform = FunctionCategory::transform_schema_docs, +)] pub enum FunctionCategory { Array, Cidr, diff --git a/lib/dsc-lib/src/types/date_version.rs b/lib/dsc-lib/src/types/date_version.rs index 55a96d1c0..31e032c2e 100644 --- a/lib/dsc-lib/src/types/date_version.rs +++ b/lib/dsc-lib/src/types/date_version.rs @@ -482,12 +482,12 @@ impl DateVersion { impl JsonSchema for DateVersion { fn schema_name() -> std::borrow::Cow<'static, str> { - Self::default_schema_id_uri().into() + Self::default_export_schema_id_uri().into() } fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema { json_schema!({ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": Self::default_schema_id_uri(), + "$schema": Self::default_export_meta_schema_uri(), + "$id": Self::default_export_schema_id_uri(), "title": schema_i18n!("title"), "description": schema_i18n!("description"), "markdownDescription": schema_i18n!("markdownDescription"), diff --git a/lib/dsc-lib/src/types/exit_codes_map.rs b/lib/dsc-lib/src/types/exit_codes_map.rs index 1252eb7d8..789592761 100644 --- a/lib/dsc-lib/src/types/exit_codes_map.rs +++ b/lib/dsc-lib/src/types/exit_codes_map.rs @@ -96,12 +96,13 @@ impl Default for ExitCodesMap { impl JsonSchema for ExitCodesMap { fn schema_name() -> std::borrow::Cow<'static, str> { - Self::default_schema_id_uri().into() + Self::default_export_schema_id_uri().into() } fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema { json_schema!({ - "$schema": "https://json-schema.org/draft/2020-12/schema", + "$schema": Self::default_export_meta_schema_uri(), + "$id": Self::default_export_schema_id_uri(), "title": schema_i18n!("title"), "description": schema_i18n!("description"), "markdownDescription": schema_i18n!("markdownDescription"), diff --git a/lib/dsc-lib/src/types/fully_qualified_type_name.rs b/lib/dsc-lib/src/types/fully_qualified_type_name.rs index 6455d2671..10231266b 100644 --- a/lib/dsc-lib/src/types/fully_qualified_type_name.rs +++ b/lib/dsc-lib/src/types/fully_qualified_type_name.rs @@ -126,12 +126,13 @@ use crate::schemas::dsc_repo::{DscRepoSchema, schema_i18n}; )] #[dsc_repo_schema(base_name = "resourceType", folder_path = "definitions")] #[schemars( - title = schema_i18n!("title"), - description = schema_i18n!("description"), + !try_from, + !into, + transform = FullyQualifiedTypeName::transform_export_schema_uris, + transform = FullyQualifiedTypeName::transform_schema_docs_strict, extend( "pattern" = FullyQualifiedTypeName::VALIDATING_PATTERN, "patternErrorMessage" = schema_i18n!("patternErrorMessage"), - "markdownDescription" = schema_i18n!("markdownDescription"), ) )] #[serde(try_from = "String", into = "String")] diff --git a/lib/dsc-lib/src/types/resource_version.rs b/lib/dsc-lib/src/types/resource_version.rs index 1a8982bd1..825383ccf 100644 --- a/lib/dsc-lib/src/types/resource_version.rs +++ b/lib/dsc-lib/src/types/resource_version.rs @@ -161,11 +161,8 @@ use crate::{ #[serde(untagged, try_from = "String", into = "String")] #[schemars(!try_from, !into)] #[schemars( - title = schema_i18n!("title"), - description = schema_i18n!("description"), - extend( - "markdownDescription" = schema_i18n!("markdownDescription") - ) + transform = ResourceVersion::transform_export_schema_uris, + transform = ResourceVersion::transform_schema_docs_strict, )] pub enum ResourceVersion { /// Defines the resource's version as a semantic version, containing an inner [`SemanticVersion`]. diff --git a/lib/dsc-lib/src/types/resource_version_req.rs b/lib/dsc-lib/src/types/resource_version_req.rs index c3042ec17..4de7de7ed 100644 --- a/lib/dsc-lib/src/types/resource_version_req.rs +++ b/lib/dsc-lib/src/types/resource_version_req.rs @@ -83,11 +83,8 @@ use crate::{ #[serde(untagged, try_from = "String", into = "String")] #[schemars(!try_from, !into)] #[schemars( - title = schema_i18n!("title"), - description = schema_i18n!("description"), - extend( - "markdownDescription" = schema_i18n!("markdownDescription") - ) + transform = ResourceVersionReq::transform_export_schema_uris, + transform = ResourceVersionReq::transform_schema_docs_strict, )] pub enum ResourceVersionReq { /// Defines the version requirement for the resource as a semantic version requirement, diff --git a/lib/dsc-lib/src/types/semantic_version.rs b/lib/dsc-lib/src/types/semantic_version.rs index a098905e0..da7d9813a 100644 --- a/lib/dsc-lib/src/types/semantic_version.rs +++ b/lib/dsc-lib/src/types/semantic_version.rs @@ -455,10 +455,12 @@ impl SemanticVersion { impl JsonSchema for SemanticVersion { fn schema_name() -> std::borrow::Cow<'static, str> { - Self::default_schema_id_uri().into() + Self::default_export_schema_id_uri().into() } fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema { json_schema!({ + "$schema": Self::default_export_meta_schema_uri(), + "$id": Self::default_export_schema_id_uri(), "title": schema_i18n!("title"), "description": schema_i18n!("description"), "markdownDescription": schema_i18n!("markdownDescription"), diff --git a/lib/dsc-lib/src/types/semantic_version_req.rs b/lib/dsc-lib/src/types/semantic_version_req.rs index 576b746d3..27acca20a 100644 --- a/lib/dsc-lib/src/types/semantic_version_req.rs +++ b/lib/dsc-lib/src/types/semantic_version_req.rs @@ -963,10 +963,12 @@ impl SemanticVersionReq { impl JsonSchema for SemanticVersionReq { fn schema_name() -> std::borrow::Cow<'static, str> { - Self::default_schema_id_uri().into() + Self::default_export_schema_id_uri().into() } fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema { json_schema!({ + "$schema": Self::default_export_meta_schema_uri(), + "$id": Self::default_export_schema_id_uri(), "title": schema_i18n!("title"), "description": schema_i18n!("description"), "markdownDescription": schema_i18n!("markdownDescription"), diff --git a/lib/dsc-lib/src/types/tag.rs b/lib/dsc-lib/src/types/tag.rs index dba3fe085..332adc03f 100644 --- a/lib/dsc-lib/src/types/tag.rs +++ b/lib/dsc-lib/src/types/tag.rs @@ -39,14 +39,12 @@ use crate::{dscerror::DscError, schemas::dsc_repo::{DscRepoSchema, schema_i18n}} #[dsc_repo_schema(base_name = "tag", folder_path = "definitions")] #[serde(try_from = "String")] #[schemars( - title = schema_i18n!("title"), - description = schema_i18n!("description"), + transform = Tag::transform_export_schema_uris, + transform = Tag::transform_schema_docs_strict, extend( "pattern" = Tag::VALIDATING_PATTERN, "patternErrorMessage" = schema_i18n!("patternErrorMessage"), - "markdownDescription" = schema_i18n!("markdownDescription"), - ), - inline + ) )] pub struct Tag(String); diff --git a/lib/dsc-lib/src/types/tag_list.rs b/lib/dsc-lib/src/types/tag_list.rs index 629c263fd..46e5394ed 100644 --- a/lib/dsc-lib/src/types/tag_list.rs +++ b/lib/dsc-lib/src/types/tag_list.rs @@ -6,7 +6,7 @@ use std::{borrow::Borrow, collections::HashSet, ops::{Deref, DerefMut}}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use crate::{schemas::dsc_repo::{DscRepoSchema, schema_i18n}, types::Tag}; +use crate::{schemas::dsc_repo::DscRepoSchema, types::Tag}; /// Wraps a [`HashSet`] of [`Tag`] instances to enable defining a reusable canonical JSON Schema for /// manifests, resources, and extensions. @@ -17,11 +17,8 @@ use crate::{schemas::dsc_repo::{DscRepoSchema, schema_i18n}, types::Tag}; #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, DscRepoSchema)] #[dsc_repo_schema(base_name = "tags", folder_path = "definitions")] #[schemars( - title = schema_i18n!("title"), - description = schema_i18n!("description"), - extend( - "markdownDescription" = schema_i18n!("markdownDescription"), - ) + transform = TagList::transform_export_schema_uris, + transform = TagList::transform_schema_docs_strict )] #[serde(into = "Vec")] pub struct TagList(HashSet); From 56768ed9eaf321c1ee7817f70477ee6d028cc734 Mon Sep 17 00:00:00 2001 From: Mikey Lombardi Date: Mon, 31 Aug 2026 15:50:46 -0500 Subject: [PATCH 5/5] Fix clippy violation --- lib/dsc-lib-jsonschema/src/dsc_repo/dsc_repo_schema.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/dsc-lib-jsonschema/src/dsc_repo/dsc_repo_schema.rs b/lib/dsc-lib-jsonschema/src/dsc_repo/dsc_repo_schema.rs index 83372c314..c5a96fce2 100644 --- a/lib/dsc-lib-jsonschema/src/dsc_repo/dsc_repo_schema.rs +++ b/lib/dsc-lib-jsonschema/src/dsc_repo/dsc_repo_schema.rs @@ -480,9 +480,10 @@ pub trait DscRepoSchema : JsonSchema { Err(e) => missing_translation_errors.push(e), } - if !missing_translation_errors.is_empty() { - panic!("missing translation errors: {:?}", missing_translation_errors); - } + assert!( + missing_translation_errors.is_empty(), + "missing translation errors: {missing_translation_errors:?}" + ); } }