From 78e8561583e361c3080447647a9a09b4487c6174 Mon Sep 17 00:00:00 2001 From: Mikey Lombardi Date: Fri, 10 Apr 2026 11:02:58 -0500 Subject: [PATCH 1/5] (GH-538) Add helper for schema i18n Prior to this change, defining the documentation keywords for schemas in `dsc-lib` and other crates required passing long lookup keys for i18n, like: ```rust t!("schemas.definitions.resourceVersionReq.semanticVariant.description") ``` This change: 1. Adds the new `schema_i18n()` helper method to the `DscRepoSchema` trait, which concatenates the input value to the root key defined in the new `SCHEMA_I18N_ROOT_KEY` associated constant. This method retrieves the translation and returns an _error_ if the translation isn't defined. This is different from the behavior for calling `t!()` directly, which emits the lookup key as the output string when that key isn't defined. Returning an error allows us to call `unwrap()` on the lookup, raising a panic on missing values and stopping the tests. 1. Defines the `schema_i18n!()` macro, which simplifies invoking the new method for more readable type and schema definitions. 1. Updates the derive macro for `DscRepoSchema` to automatically define the value of `SCHEMA_I18N_ROOT_KEY` as the joining of the `SCHEMA_FOLDER_PATH` and `SCHEMA_FILE_BASE_NAME` associated constants. The path separators are replaced with periods (`.`) and the two values are joined with a period. This change is also a necessary precursor to programmatically munging the documentation for these fields to insert links to the online documentation, ensure line breaks where needed, and so on. --- .../src/derive/dsc_repo_schema.rs | 41 +- .../src/dsc_repo/dsc_repo_schema.rs | 30 ++ lib/dsc-lib-jsonschema/src/dsc_repo/macros.rs | 6 + lib/dsc-lib-jsonschema/src/dsc_repo/mod.rs | 5 + lib/dsc-lib-jsonschema/src/tests/dsc_repo.rs | 27 +- .../dsc_repo/derive_dsc_repo_schema.rs | 417 +++++++++++++++++- .../tests/integration/main.rs | 5 + .../tests/locales/schemas.yaml | 69 +++ 8 files changed, 571 insertions(+), 29 deletions(-) create mode 100644 lib/dsc-lib-jsonschema/src/dsc_repo/macros.rs create mode 100644 lib/dsc-lib-jsonschema/tests/locales/schemas.yaml diff --git a/lib/dsc-lib-jsonschema-macros/src/derive/dsc_repo_schema.rs b/lib/dsc-lib-jsonschema-macros/src/derive/dsc_repo_schema.rs index c46fb6f31..b25589553 100644 --- a/lib/dsc-lib-jsonschema-macros/src/derive/dsc_repo_schema.rs +++ b/lib/dsc-lib-jsonschema-macros/src/derive/dsc_repo_schema.rs @@ -21,6 +21,10 @@ struct DscRepoSchemaReceiver { /// other schemas may not be. #[darling(default)] pub should_bundle: bool, + /// Defines the root dotpath for the JSON Schema keyword value translations used by `rust_i18n` + /// crate. Must be a literal string like `"schemas.definitions.tag"`. + #[darling(default)] + pub i18n_root_key: Option, /// Defines the field for the struct that is used as the `$schema` property. Typically only /// defined for root schemas. #[darling(default)] @@ -62,6 +66,12 @@ pub(crate) fn dsc_repo_schema_impl(input: TokenStream) -> TokenStream { } }; + let i18n_root_key = args.i18n_root_key.unwrap_or(format!( + "schemas.{}.{}", + args.folder_path.replace('/', "."), + args.base_name + )); + let mut output = quote!(); if let Some(schema_field) = args.schema_field { @@ -70,6 +80,7 @@ pub(crate) fn dsc_repo_schema_impl(input: TokenStream) -> TokenStream { args.base_name, args.folder_path, args.should_bundle, + i18n_root_key, schema_field )); } else { @@ -77,7 +88,8 @@ pub(crate) fn dsc_repo_schema_impl(input: TokenStream) -> TokenStream { ident, args.base_name, args.folder_path, - args.should_bundle + args.should_bundle, + i18n_root_key )); } @@ -91,14 +103,19 @@ fn generate_without_schema_field( ident: Ident, base_name: String, folder_path: String, - should_bundle: bool + should_bundle: bool, + i18n_root_key: String, ) -> proc_macro2::TokenStream { + let translation_fn = generate_schema_i18n_fn(); quote!( #[automatically_derived] impl DscRepoSchema for #ident { const SCHEMA_FILE_BASE_NAME: &'static str = #base_name; const SCHEMA_FOLDER_PATH: &'static str = #folder_path; const SCHEMA_SHOULD_BUNDLE: bool = #should_bundle; + const SCHEMA_I18N_ROOT_KEY: &'static str = #i18n_root_key; + + #translation_fn fn schema_property_metadata() -> schemars::Schema { schemars::json_schema!({}) @@ -118,9 +135,11 @@ fn generate_with_schema_field( base_name: String, folder_path: String, should_bundle: bool, + i18n_root_key: String, schema_field: DscRepoSchemaField ) -> proc_macro2::TokenStream { let schema_property_metadata = generate_schema_property_metadata_fn(&schema_field); + let translation_fn = generate_schema_i18n_fn(); let field = schema_field.name; quote!( #[automatically_derived] @@ -128,6 +147,9 @@ fn generate_with_schema_field( const SCHEMA_FILE_BASE_NAME: &'static str = #base_name; const SCHEMA_FOLDER_PATH: &'static str = #folder_path; const SCHEMA_SHOULD_BUNDLE: bool = #should_bundle; + const SCHEMA_I18N_ROOT_KEY: &'static str = #i18n_root_key; + + #translation_fn #schema_property_metadata @@ -169,3 +191,18 @@ fn generate_schema_property_metadata_fn(schema_field: &DscRepoSchemaField) -> pr } } } + +/// Generates a crate-local implementation for the `lookup_translation()` trait function. This is +/// required to ensure that the translations use the correct locale definitions. +fn generate_schema_i18n_fn() -> proc_macro2::TokenStream { + quote! { + fn schema_i18n(suffix: &str) -> Result { + let i18n_key = format!("{}.{}", Self::SCHEMA_I18N_ROOT_KEY, suffix); + if let Some(translated) = crate::_rust_i18n_try_translate(&rust_i18n::locale(), &i18n_key) { + Ok(translated.into()) + } else { + Err(dsc_lib_jsonschema::dsc_repo::DscRepoSchemaMissingTranslation { i18n_key }) + } + } + } +} 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 eb18a111c..04f1b8a78 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 @@ -46,6 +46,11 @@ pub trait DscRepoSchema : JsonSchema { /// aren't published with the VS Code form. const SCHEMA_SHOULD_BUNDLE: bool; + /// Defines the translation root key to use when resolving translations for JSON Schema keywords. + /// + /// All bundled schemas must include documentation keywords like `title` and `description`. + const SCHEMA_I18N_ROOT_KEY: &'static str; + /// Defines the metadata for the `$schema` property of a struct that takes multiple schema /// versions. /// @@ -341,6 +346,22 @@ pub trait DscRepoSchema : JsonSchema { vec![SchemaForm::Canonical] } } + + /// Retrieves a translation string using a dot-path relative to the [`SCHEMA_I18N_ROOT_KEY`]. + /// + /// # Arguments + /// + /// - `suffix` - The string to append to the root key, like `items.description`. + /// + /// # Errors + /// + /// Returns a [`DscRepoSchemaMissingTranslation`] error if the translation key doesn't exist. + /// + /// # Example + /// + /// ```ignore + /// ``` + fn schema_i18n(suffix: &str) -> Result; } /// Defines the error when a user-defined JSON Schema references an unrecognized schema URI. @@ -351,3 +372,12 @@ pub trait DscRepoSchema : JsonSchema { t2 = t!("dsc_repo.dsc_repo_schema.validSchemaUrisAre") )] pub struct UnrecognizedSchemaUri(pub String, pub Vec); + +#[derive(Error, Debug, Clone, PartialEq)] +#[error("{t}", t = t!( + "dsc_repo.dsc_repo_schema.missingTranslation", + "key" => i18n_key +))] +pub struct DscRepoSchemaMissingTranslation { + pub i18n_key: String +} diff --git a/lib/dsc-lib-jsonschema/src/dsc_repo/macros.rs b/lib/dsc-lib-jsonschema/src/dsc_repo/macros.rs new file mode 100644 index 000000000..88a3c9458 --- /dev/null +++ b/lib/dsc-lib-jsonschema/src/dsc_repo/macros.rs @@ -0,0 +1,6 @@ +#[macro_export] +macro_rules! schema_i18n { + ($dotPath: literal) => { + Self::schema_i18n($dotPath).unwrap() + }; +} diff --git a/lib/dsc-lib-jsonschema/src/dsc_repo/mod.rs b/lib/dsc-lib-jsonschema/src/dsc_repo/mod.rs index eb12d1e30..40a99f2e0 100644 --- a/lib/dsc-lib-jsonschema/src/dsc_repo/mod.rs +++ b/lib/dsc-lib-jsonschema/src/dsc_repo/mod.rs @@ -6,6 +6,11 @@ use schemars::{Schema, json_schema}; mod dsc_repo_schema; pub use dsc_repo_schema::DscRepoSchema; pub use dsc_repo_schema::UnrecognizedSchemaUri; +pub use dsc_repo_schema::DscRepoSchemaMissingTranslation; + +#[macro_use] +mod macros; +pub use crate::schema_i18n; mod recognized_schema_version; pub use recognized_schema_version::RecognizedSchemaVersion; diff --git a/lib/dsc-lib-jsonschema/src/tests/dsc_repo.rs b/lib/dsc-lib-jsonschema/src/tests/dsc_repo.rs index 943db2935..bbb85ca33 100644 --- a/lib/dsc-lib-jsonschema/src/tests/dsc_repo.rs +++ b/lib/dsc-lib-jsonschema/src/tests/dsc_repo.rs @@ -5,12 +5,7 @@ use schemars::{JsonSchema, Schema, json_schema}; use serde::{Deserialize, Serialize}; use crate::dsc_repo::{ - DscRepoSchema, - RecognizedSchemaVersion, - SchemaForm, - SchemaUriPrefix, - get_default_schema_uri, - get_recognized_schema_uri + DscRepoSchema, DscRepoSchemaMissingTranslation, RecognizedSchemaVersion, SchemaForm, SchemaUriPrefix, get_default_schema_uri, get_recognized_schema_uri }; #[test] @@ -55,6 +50,16 @@ fn test_dsc_repo_schema_bundled() { const SCHEMA_FILE_BASE_NAME: &'static str = "schema"; const SCHEMA_FOLDER_PATH: &'static str = "example"; const SCHEMA_SHOULD_BUNDLE: bool = true; + const SCHEMA_I18N_ROOT_KEY: &'static str = "example.schema"; + + fn schema_i18n(suffix: &str) -> Result { + let i18n_key = format!("{}.{}", Self::SCHEMA_I18N_ROOT_KEY, suffix); + if let Some(translated) = crate::_rust_i18n_try_translate(&rust_i18n::locale(), &i18n_key) { + Ok(translated.into()) + } else { + Err(DscRepoSchemaMissingTranslation { i18n_key }) + } + } fn schema_property_metadata() -> Schema { json_schema!({ @@ -100,6 +105,16 @@ fn test_dsc_repo_schema_not_bundled() { const SCHEMA_FILE_BASE_NAME: &'static str = "schema"; const SCHEMA_FOLDER_PATH: &'static str = "example"; const SCHEMA_SHOULD_BUNDLE: bool = false; + const SCHEMA_I18N_ROOT_KEY: &'static str = "example.schema"; + + fn schema_i18n(suffix: &str) -> Result { + let i18n_key = format!("{}.{}", Self::SCHEMA_I18N_ROOT_KEY, suffix); + if let Some(translated) = crate::_rust_i18n_try_translate(&rust_i18n::locale(), &i18n_key) { + Ok(translated.into()) + } else { + Err(DscRepoSchemaMissingTranslation { i18n_key }) + } + } fn schema_property_metadata() -> Schema { json_schema!({ diff --git a/lib/dsc-lib-jsonschema/tests/integration/dsc_repo/derive_dsc_repo_schema.rs b/lib/dsc-lib-jsonschema/tests/integration/dsc_repo/derive_dsc_repo_schema.rs index d98b0b993..34d50923a 100644 --- a/lib/dsc-lib-jsonschema/tests/integration/dsc_repo/derive_dsc_repo_schema.rs +++ b/lib/dsc-lib-jsonschema/tests/integration/dsc_repo/derive_dsc_repo_schema.rs @@ -11,29 +11,54 @@ macro_rules! testing_title { #[cfg(test)] mod for_enum { #[cfg(test)] mod without_bundling { + use std::ops::Index; + use pretty_assertions::assert_eq; - use schemars::JsonSchema; - use dsc_lib_jsonschema::dsc_repo::{DscRepoSchema, RecognizedSchemaVersion}; + use schemars::{JsonSchema, Schema, schema_for}; + use dsc_lib_jsonschema::{ + dsc_repo::{DscRepoSchema, RecognizedSchemaVersion, schema_i18n}, schema_utility_extensions::SchemaUtilityExtensions}; #[allow(dead_code)] #[derive(Clone, Debug, JsonSchema, DscRepoSchema)] - #[dsc_repo_schema(base_name = "valid", folder_path = "example")] + #[dsc_repo_schema(base_name = "valid.enum", folder_path = "example")] + #[schemars( + title = schema_i18n!("title"), + description = schema_i18n!("description"), + extend( + "markdownDescription" = schema_i18n!("markdownDescription"), + ) + )] enum Example { + #[schemars( + title = schema_i18n!("stringVariant.title"), + description = schema_i18n!("stringVariant.description"), + extend( + "markdownDescription" = schema_i18n!("stringVariant.markdownDescription") + ) + )] String(String), + + #[schemars( + title = schema_i18n!("booleanVariant.title"), + description = schema_i18n!("booleanVariant.description"), + extend( + "markdownDescription" = schema_i18n!("booleanVariant.markdownDescription") + ) + )] Boolean(bool) } #[test] fn test_default_schema_id_uri() { assert_eq!( Example::default_schema_id_uri(), - "https://aka.ms/dsc/schemas/v3/example/valid.json".to_string() + "https://aka.ms/dsc/schemas/v3/example/valid.enum.json".to_string() ) } #[test] fn test_get_canonical_schema_id_uri() { assert_eq!( Example::get_canonical_schema_id_uri(RecognizedSchemaVersion::V3), - "https://aka.ms/dsc/schemas/v3/example/valid.json".to_string() + "https://aka.ms/dsc/schemas/v3/example/valid.enum.json".to_string() ) } @@ -49,6 +74,64 @@ macro_rules! testing_title { None ) } + + #[test] fn test_schema_docs() { + let schema = &schema_for!(Example); + assert_eq!( + schema.get_keyword_as_str("title"), + Some("Example valid enum") + ); + assert_eq!( + schema.get_keyword_as_str("description"), + Some("Defines an enum with the DscRepoSchema trait.") + ); + assert_eq!( + schema.get_keyword_as_str("markdownDescription"), + Some("Defines an enum with the `DscRepoSchema` trait.") + ); + + let ref string_variant: Schema = schema.get_keyword_as_array("oneOf") + .unwrap() + .index(0) + .as_object() + .unwrap() + .clone() + .into(); + + assert_eq!( + string_variant.get_keyword_as_str("title"), + Some("Example string variant") + ); + assert_eq!( + string_variant.get_keyword_as_str("description"), + Some("Defines a string variant for the enum.") + ); + assert_eq!( + string_variant.get_keyword_as_str("markdownDescription"), + Some("Defines a `string` variant for the enum.") + ); + + let ref boolean_variant: Schema = schema.get_keyword_as_array("oneOf") + .unwrap() + .index(1) + .as_object() + .unwrap() + .clone() + .into(); + + assert_eq!( + boolean_variant.get_keyword_as_str("title"), + Some("Example boolean variant") + ); + assert_eq!( + boolean_variant.get_keyword_as_str("description"), + Some("Defines a boolean variant for the enum.") + ); + assert_eq!( + boolean_variant.get_keyword_as_str("markdownDescription"), + Some("Defines a `boolean` variant for the enum.") + ); + } } } @@ -56,29 +139,66 @@ macro_rules! testing_title { #[cfg(test)] mod without_bundling { #[cfg(test)] mod without_schema_field { use pretty_assertions::assert_eq; - use schemars::JsonSchema; - use dsc_lib_jsonschema::dsc_repo::{DscRepoSchema, RecognizedSchemaVersion}; + use schemars::{JsonSchema, schema_for}; + use dsc_lib_jsonschema::{ + dsc_repo::{ + DscRepoSchema, + RecognizedSchemaVersion, + schema_i18n + }, + schema_utility_extensions::SchemaUtilityExtensions + }; #[allow(dead_code)] #[derive(Clone, Debug, JsonSchema, DscRepoSchema)] - #[dsc_repo_schema(base_name = "valid", folder_path = "example")] + #[dsc_repo_schema(base_name = "valid.struct", folder_path = "example")] + #[schemars( + title = schema_i18n!("title"), + description = schema_i18n!("description"), + extend( + "markdownDescription" = schema_i18n!("markdownDescription"), + ) + )] struct Example { + #[schemars( + title = schema_i18n!("foo.title"), + description = schema_i18n!("foo.description"), + extend( + "markdownDescription" = schema_i18n!("foo.markdownDescription"), + ) + )] pub foo: String, + + #[schemars( + title = schema_i18n!("bar.title"), + description = schema_i18n!("bar.description"), + extend( + "markdownDescription" = schema_i18n!("bar.markdownDescription"), + ) + )] pub bar: i32, + + #[schemars( + title = schema_i18n!("baz.title"), + description = schema_i18n!("baz.description"), + extend( + "markdownDescription" = schema_i18n!("baz.markdownDescription"), + ) + )] pub baz: bool, } #[test] fn test_default_schema_id_uri() { assert_eq!( Example::default_schema_id_uri(), - "https://aka.ms/dsc/schemas/v3/example/valid.json".to_string() + "https://aka.ms/dsc/schemas/v3/example/valid.struct.json".to_string() ) } #[test] fn test_get_canonical_schema_id_uri() { assert_eq!( Example::get_canonical_schema_id_uri(RecognizedSchemaVersion::V3), - "https://aka.ms/dsc/schemas/v3/example/valid.json".to_string() + "https://aka.ms/dsc/schemas/v3/example/valid.struct.json".to_string() ) } @@ -94,27 +214,101 @@ macro_rules! testing_title { None ) } + + #[test] fn test_schema_docs() { + let schema = &schema_for!(Example); + assert_eq!( + schema.get_keyword_as_str("title"), + Some("Example valid struct") + ); + assert_eq!( + schema.get_keyword_as_str("description"), + Some("Defines a struct with the DscRepoSchema trait.") + ); + assert_eq!( + schema.get_keyword_as_str("markdownDescription"), + Some("Defines a struct with the `DscRepoSchema` trait.") + ); + + for property_name in vec!["foo", "bar", "baz"] { + let property_schema = schema.get_property_subschema(property_name).unwrap(); + + assert_eq!( + property_schema.get_keyword_as_string("title"), + Some(format!("{property_name} field")) + ); + assert_eq!( + property_schema.get_keyword_as_string("description"), + Some(format!("Defines the {property_name} field.")) + ); + assert_eq!( + property_schema.get_keyword_as_string("markdownDescription"), + Some(format!("Defines the `{property_name}` field.")) + ); + } + } } + #[cfg(test)] mod with_schema_field { use pretty_assertions::assert_eq; - use schemars::JsonSchema; - use dsc_lib_jsonschema::{dsc_repo::{DscRepoSchema, RecognizedSchemaVersion, UnrecognizedSchemaUri}, schema_utility_extensions::SchemaUtilityExtensions}; + use schemars::{JsonSchema, schema_for}; + use dsc_lib_jsonschema::{ + dsc_repo::{ + DscRepoSchema, + RecognizedSchemaVersion, + UnrecognizedSchemaUri, + schema_i18n + }, + schema_utility_extensions::SchemaUtilityExtensions + }; #[allow(dead_code)] #[derive(Clone, Debug, JsonSchema, DscRepoSchema)] #[dsc_repo_schema( base_name = "valid", folder_path = "example", + i18n_root_key = "schemas.example.valid.struct", schema_field( name = schema_version, title = testing_title!(), description = "An example struct with a schema field.", ) )] + #[schemars( + title = schema_i18n!("title"), + description = schema_i18n!("description"), + extend( + "markdownDescription" = schema_i18n!("markdownDescription"), + ) + )] struct Example { pub schema_version: String, + + #[schemars( + title = schema_i18n!("foo.title"), + description = schema_i18n!("foo.description"), + extend( + "markdownDescription" = schema_i18n!("foo.markdownDescription"), + ) + )] pub foo: String, + + #[schemars( + title = schema_i18n!("bar.title"), + description = schema_i18n!("bar.description"), + extend( + "markdownDescription" = schema_i18n!("bar.markdownDescription"), + ) + )] pub bar: i32, + + #[schemars( + title = schema_i18n!("baz.title"), + description = schema_i18n!("baz.description"), + extend( + "markdownDescription" = schema_i18n!("baz.markdownDescription"), + ) + )] pub baz: bool, } @@ -220,56 +414,172 @@ macro_rules! testing_title { Err(UnrecognizedSchemaUri(invalid_uri, Example::recognized_schema_uris())) ) } + + #[test] fn test_schema_docs() { + let schema = &schema_for!(Example); + assert_eq!( + schema.get_keyword_as_str("title"), + Some("Example valid struct") + ); + assert_eq!( + schema.get_keyword_as_str("description"), + Some("Defines a struct with the DscRepoSchema trait.") + ); + assert_eq!( + schema.get_keyword_as_str("markdownDescription"), + Some("Defines a struct with the `DscRepoSchema` trait.") + ); + + for property_name in vec!["foo", "bar", "baz"] { + let property_schema = schema.get_property_subschema(property_name).unwrap(); + + assert_eq!( + property_schema.get_keyword_as_string("title"), + Some(format!("{property_name} field")) + ); + assert_eq!( + property_schema.get_keyword_as_string("description"), + Some(format!("Defines the {property_name} field.")) + ); + assert_eq!( + property_schema.get_keyword_as_string("markdownDescription"), + Some(format!("Defines the `{property_name}` field.")) + ); + } + } } } #[cfg(test)] mod with_bundling { #[cfg(test)] mod without_schema_field { use pretty_assertions::assert_eq; - use schemars::JsonSchema; - use dsc_lib_jsonschema::dsc_repo::{DscRepoSchema, RecognizedSchemaVersion}; + use schemars::{JsonSchema, schema_for}; + use dsc_lib_jsonschema::{ + dsc_repo::{ + DscRepoSchema, + RecognizedSchemaVersion, + schema_i18n + }, + schema_utility_extensions::SchemaUtilityExtensions + }; #[allow(dead_code)] #[derive(Clone, Debug, JsonSchema, DscRepoSchema)] - #[dsc_repo_schema(base_name = "valid", folder_path = "example", should_bundle = true)] + #[dsc_repo_schema( + base_name = "valid.struct", + folder_path = "example", + should_bundle = true, + i18n_root_key = "schemas.example.valid.struct" + )] + #[schemars( + title = schema_i18n!("title"), + description = schema_i18n!("description"), + extend( + "markdownDescription" = schema_i18n!("markdownDescription"), + ) + )] struct Example { + #[schemars( + title = schema_i18n!("foo.title"), + description = schema_i18n!("foo.description"), + extend( + "markdownDescription" = schema_i18n!("foo.markdownDescription"), + ) + )] pub foo: String, + + #[schemars( + title = schema_i18n!("bar.title"), + description = schema_i18n!("bar.description"), + extend( + "markdownDescription" = schema_i18n!("bar.markdownDescription"), + ) + )] pub bar: i32, + + #[schemars( + title = schema_i18n!("baz.title"), + description = schema_i18n!("baz.description"), + extend( + "markdownDescription" = schema_i18n!("baz.markdownDescription"), + ) + )] pub baz: bool, } #[test] fn test_default_schema_id_uri() { assert_eq!( Example::default_schema_id_uri(), - "https://aka.ms/dsc/schemas/v3/bundled/example/valid.json".to_string() + "https://aka.ms/dsc/schemas/v3/bundled/example/valid.struct.json".to_string() ) } #[test] fn test_get_canonical_schema_id_uri() { assert_eq!( Example::get_canonical_schema_id_uri(RecognizedSchemaVersion::V3), - "https://aka.ms/dsc/schemas/v3/example/valid.json".to_string() + "https://aka.ms/dsc/schemas/v3/example/valid.struct.json".to_string() ) } #[test] fn test_get_bundled_schema_id_uri() { assert_eq!( Example::get_bundled_schema_id_uri(RecognizedSchemaVersion::V3), - Some("https://aka.ms/dsc/schemas/v3/bundled/example/valid.json".to_string()) + Some("https://aka.ms/dsc/schemas/v3/bundled/example/valid.struct.json".to_string()) ) } #[test] fn test_get_enhanced_schema_id_uri() { assert_eq!( Example::get_enhanced_schema_id_uri(RecognizedSchemaVersion::V3), - Some("https://aka.ms/dsc/schemas/v3/bundled/example/valid.vscode.json".to_string()) + Some("https://aka.ms/dsc/schemas/v3/bundled/example/valid.struct.vscode.json".to_string()) ) } + + #[test] fn test_schema_docs() { + let schema = &schema_for!(Example); + assert_eq!( + schema.get_keyword_as_str("title"), + Some("Example valid struct") + ); + assert_eq!( + schema.get_keyword_as_str("description"), + Some("Defines a struct with the DscRepoSchema trait.") + ); + assert_eq!( + schema.get_keyword_as_str("markdownDescription"), + Some("Defines a struct with the `DscRepoSchema` trait.") + ); + + for property_name in vec!["foo", "bar", "baz"] { + let property_schema = schema.get_property_subschema(property_name).unwrap(); + + assert_eq!( + property_schema.get_keyword_as_string("title"), + Some(format!("{property_name} field")) + ); + assert_eq!( + property_schema.get_keyword_as_string("description"), + Some(format!("Defines the {property_name} field.")) + ); + assert_eq!( + property_schema.get_keyword_as_string("markdownDescription"), + Some(format!("Defines the `{property_name}` field.")) + ); + } + } } #[cfg(test)] mod with_schema_field { use pretty_assertions::assert_eq; - use schemars::JsonSchema; - use dsc_lib_jsonschema::{dsc_repo::{DscRepoSchema, RecognizedSchemaVersion, UnrecognizedSchemaUri}, schema_utility_extensions::SchemaUtilityExtensions}; + use schemars::{JsonSchema, schema_for}; + use dsc_lib_jsonschema::{ + dsc_repo::{ + DscRepoSchema, + RecognizedSchemaVersion, + UnrecognizedSchemaUri, + schema_i18n + }, + schema_utility_extensions::SchemaUtilityExtensions + }; #[allow(dead_code)] #[derive(Clone, Debug, JsonSchema, DscRepoSchema)] @@ -277,16 +587,48 @@ macro_rules! testing_title { base_name = "valid", folder_path = "example", should_bundle = true, + i18n_root_key = "schemas.example.valid.struct", schema_field( name = schema_version, title = testing_title!(), description = "An example struct with a schema field.", ) )] + #[schemars( + title = schema_i18n!("title"), + description = schema_i18n!("description"), + extend( + "markdownDescription" = schema_i18n!("markdownDescription"), + ) + )] struct Example { pub schema_version: String, + + #[schemars( + title = schema_i18n!("foo.title"), + description = schema_i18n!("foo.description"), + extend( + "markdownDescription" = schema_i18n!("foo.markdownDescription"), + ) + )] pub foo: String, + + #[schemars( + title = schema_i18n!("bar.title"), + description = schema_i18n!("bar.description"), + extend( + "markdownDescription" = schema_i18n!("bar.markdownDescription"), + ) + )] pub bar: i32, + + #[schemars( + title = schema_i18n!("baz.title"), + description = schema_i18n!("baz.description"), + extend( + "markdownDescription" = schema_i18n!("baz.markdownDescription"), + ) + )] pub baz: bool, } @@ -392,6 +734,39 @@ macro_rules! testing_title { Err(UnrecognizedSchemaUri(invalid_uri, Example::recognized_schema_uris())) ) } + + #[test] fn test_schema_docs() { + let schema = &schema_for!(Example); + assert_eq!( + schema.get_keyword_as_str("title"), + Some("Example valid struct") + ); + assert_eq!( + schema.get_keyword_as_str("description"), + Some("Defines a struct with the DscRepoSchema trait.") + ); + assert_eq!( + schema.get_keyword_as_str("markdownDescription"), + Some("Defines a struct with the `DscRepoSchema` trait.") + ); + + for property_name in vec!["foo", "bar", "baz"] { + let property_schema = schema.get_property_subschema(property_name).unwrap(); + + assert_eq!( + property_schema.get_keyword_as_string("title"), + Some(format!("{property_name} field")) + ); + assert_eq!( + property_schema.get_keyword_as_string("description"), + Some(format!("Defines the {property_name} field.")) + ); + assert_eq!( + property_schema.get_keyword_as_string("markdownDescription"), + Some(format!("Defines the `{property_name}` field.")) + ); + } + } } } } diff --git a/lib/dsc-lib-jsonschema/tests/integration/main.rs b/lib/dsc-lib-jsonschema/tests/integration/main.rs index d15748633..fc2b4e9e2 100644 --- a/lib/dsc-lib-jsonschema/tests/integration/main.rs +++ b/lib/dsc-lib-jsonschema/tests/integration/main.rs @@ -15,5 +15,10 @@ //! higher in the `tests` folder, Rust would generate numerous binaries to //! execute our tests. +use rust_i18n::i18n; + #[cfg(test)] mod transforms; #[cfg(test)] mod dsc_repo; + +// Enable localization for emitted strings, needed for testing DscRepoSchema +i18n!("./tests/locales", fallback = "en-US"); diff --git a/lib/dsc-lib-jsonschema/tests/locales/schemas.yaml b/lib/dsc-lib-jsonschema/tests/locales/schemas.yaml new file mode 100644 index 000000000..1dcc16d6c --- /dev/null +++ b/lib/dsc-lib-jsonschema/tests/locales/schemas.yaml @@ -0,0 +1,69 @@ +_version: 2 + +schemas: + example: + valid: + enum: + title: + en-US: Example valid enum + description: + en-US: >- + Defines an enum with the DscRepoSchema trait. + markdownDescription: + en-US: |- + Defines an enum with the `DscRepoSchema` trait. + stringVariant: + title: + en-US: Example string variant + description: + en-US: >- + Defines a string variant for the enum. + markdownDescription: + en-US: |- + Defines a `string` variant for the enum. + booleanVariant: + title: + en-US: Example boolean variant + description: + en-US: >- + Defines a boolean variant for the enum. + markdownDescription: + en-US: |- + Defines a `boolean` variant for the enum. + + struct: + title: + en-US: Example valid struct + description: + en-US: >- + Defines a struct with the DscRepoSchema trait. + markdownDescription: + en-US: |- + Defines a struct with the `DscRepoSchema` trait. + foo: + title: + en-US: foo field + description: + en-US: >- + Defines the foo field. + markdownDescription: + en-US: |- + Defines the `foo` field. + bar: + title: + en-US: bar field + description: + en-US: >- + Defines the bar field. + markdownDescription: + en-US: |- + Defines the `bar` field. + baz: + title: + en-US: baz field + description: + en-US: >- + Defines the baz field. + markdownDescription: + en-US: |- + Defines the `baz` field. From 6b00f72396898b83f100ec35b6a0f09652c29227 Mon Sep 17 00:00:00 2001 From: Mikey Lombardi Date: Fri, 10 Apr 2026 11:17:14 -0500 Subject: [PATCH 2/5] (GH-538) Use `schema_i18n!` for `dsc-lib::types` This change updates the type defininitons to use the newly available `schema_i18n!()` macro to lookup translations for schema documentation keywords, panicking when the translation doesn't exist. This makes the type definitions more readable and maintainable. --- lib/dsc-lib/src/types/date_version.rs | 12 +++++----- lib/dsc-lib/src/types/exit_codes_map.rs | 11 +++++----- .../src/types/fully_qualified_type_name.rs | 14 ++++++------ lib/dsc-lib/src/types/resource_version.rs | 22 +++++++++---------- lib/dsc-lib/src/types/resource_version_req.rs | 22 +++++++++---------- lib/dsc-lib/src/types/semantic_version.rs | 10 ++++----- lib/dsc-lib/src/types/semantic_version_req.rs | 19 +++++----------- lib/dsc-lib/src/types/tag.rs | 15 +++++++------ lib/dsc-lib/src/types/tag_list.rs | 16 +++++--------- 9 files changed, 65 insertions(+), 76 deletions(-) diff --git a/lib/dsc-lib/src/types/date_version.rs b/lib/dsc-lib/src/types/date_version.rs index 70652e347..55a96d1c0 100644 --- a/lib/dsc-lib/src/types/date_version.rs +++ b/lib/dsc-lib/src/types/date_version.rs @@ -19,7 +19,7 @@ use schemars::{JsonSchema, json_schema}; use serde::{Deserialize, Serialize}; use thiserror::Error; -use crate::schemas::dsc_repo::DscRepoSchema; +use crate::schemas::dsc_repo::{DscRepoSchema, schema_i18n}; /// Defines a version as an ISO8601 formatted date string for compatibility scenarios. /// @@ -44,8 +44,8 @@ use crate::schemas::dsc_repo::DscRepoSchema; /// If the date version is for a prerelease, the prerelease segment must be a string of ASCII /// alphabetic characters (`[a-zA-Z]`). #[derive(Debug, Clone, Serialize, Deserialize, DscRepoSchema)] -#[serde(try_from = "String", into = "String")] #[dsc_repo_schema(base_name = "dateVersion", folder_path = "definitions")] +#[serde(try_from = "String", into = "String")] pub struct DateVersion(NaiveDate, Option); /// Indicates an error with parsing or converting a [`DateVersion`]. @@ -488,12 +488,12 @@ impl JsonSchema for DateVersion { json_schema!({ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": Self::default_schema_id_uri(), - "title": t!("schemas.definitions.dateVersion.title"), - "description": t!("schemas.definitions.dateVersion.description"), - "markdownDescription": t!("schemas.definitions.dateVersion.markdownDescription"), + "title": schema_i18n!("title"), + "description": schema_i18n!("description"), + "markdownDescription": schema_i18n!("markdownDescription"), "type": "string", "pattern": Self::VALIDATING_PATTERN, - "patternErrorMessage": t!("schemas.definitions.dateVersion.patternErrorMessage"), + "patternErrorMessage": schema_i18n!("patternErrorMessage"), }) } } diff --git a/lib/dsc-lib/src/types/exit_codes_map.rs b/lib/dsc-lib/src/types/exit_codes_map.rs index 7bc915813..1252eb7d8 100644 --- a/lib/dsc-lib/src/types/exit_codes_map.rs +++ b/lib/dsc-lib/src/types/exit_codes_map.rs @@ -7,8 +7,7 @@ use rust_i18n::t; use schemars::{JsonSchema, json_schema}; use serde::{Deserialize, Serialize}; -use crate::{schemas::dsc_repo::DscRepoSchema, types::ExitCode}; - +use crate::{schemas::dsc_repo::{DscRepoSchema, schema_i18n}, types::ExitCode}; /// Defines a map of exit codes to their semantic meaning for operation commands. /// /// DSC resources and extensions may define any number of operation commands like `get` or @@ -103,14 +102,14 @@ impl JsonSchema for ExitCodesMap { fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema { json_schema!({ "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": t!("schemas.definitions.exitCodes.title"), - "description": t!("schemas.definitions.exitCodes.description"), - "markdownDescription": t!("schemas.definitions.exitCodes.markdownDescription"), + "title": schema_i18n!("title"), + "description": schema_i18n!("description"), + "markdownDescription": schema_i18n!("markdownDescription"), "type": "object", "minProperties": 1, "propertyNames": { "pattern": Self::KEY_VALIDATING_PATTERN, - "patternErrorMessage": t!("schemas.definitions.exitCodes.invalidKeyErrorMessage") + "patternErrorMessage": schema_i18n!("invalidKeyErrorMessage") }, "patternProperties": { Self::KEY_VALIDATING_PATTERN: { 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 4c4829c2d..6455d2671 100644 --- a/lib/dsc-lib/src/types/fully_qualified_type_name.rs +++ b/lib/dsc-lib/src/types/fully_qualified_type_name.rs @@ -17,7 +17,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use thiserror::Error; -use crate::schemas::dsc_repo::DscRepoSchema; +use crate::schemas::dsc_repo::{DscRepoSchema, schema_i18n}; /// Defines the fully qualified type name for a DSC resource or extension. The fully qualified name /// uniquely identifies each resource and extension. @@ -124,17 +124,17 @@ use crate::schemas::dsc_repo::DscRepoSchema; JsonSchema, DscRepoSchema, )] -#[serde(try_from = "String", into = "String")] +#[dsc_repo_schema(base_name = "resourceType", folder_path = "definitions")] #[schemars( - title = t!("schemas.definitions.resourceType.title"), - description = t!("schemas.definitions.resourceType.description"), + title = schema_i18n!("title"), + description = schema_i18n!("description"), extend( "pattern" = FullyQualifiedTypeName::VALIDATING_PATTERN, - "patternErrorMessage" = t!("schemas.definitions.resourceType.patternErrorMessage"), - "markdownDescription" = t!("schemas.definitions.resourceType.markdownDescription"), + "patternErrorMessage" = schema_i18n!("patternErrorMessage"), + "markdownDescription" = schema_i18n!("markdownDescription"), ) )] -#[dsc_repo_schema(base_name = "resourceType", folder_path = "definitions")] +#[serde(try_from = "String", into = "String")] pub struct FullyQualifiedTypeName(String); /// Defines the various errors that can occur when parsing and working with instances of diff --git a/lib/dsc-lib/src/types/resource_version.rs b/lib/dsc-lib/src/types/resource_version.rs index 5da031ce5..1a8982bd1 100644 --- a/lib/dsc-lib/src/types/resource_version.rs +++ b/lib/dsc-lib/src/types/resource_version.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; use thiserror::Error; use crate::{ - schemas::dsc_repo::DscRepoSchema, + schemas::dsc_repo::{DscRepoSchema, schema_i18n}, types::{ DateVersion, DateVersionError, @@ -161,10 +161,10 @@ use crate::{ #[serde(untagged, try_from = "String", into = "String")] #[schemars(!try_from, !into)] #[schemars( - title = t!("schemas.definitions.resourceVersion.title"), - description = t!("schemas.definitions.resourceVersion.description"), + title = schema_i18n!("title"), + description = schema_i18n!("description"), extend( - "markdownDescription" = t!("schemas.definitions.resourceVersion.markdownDescription") + "markdownDescription" = schema_i18n!("markdownDescription") ) )] pub enum ResourceVersion { @@ -176,10 +176,10 @@ pub enum ResourceVersion { /// /// [01]: https://semver.org #[schemars( - title = t!("schemas.definitions.resourceVersion.semanticVariant.title"), - description = t!("schemas.definitions.resourceVersion.semanticVariant.description"), + title = schema_i18n!("semanticVariant.title"), + description = schema_i18n!("semanticVariant.description"), extend( - "markdownDescription" = t!("schemas.definitions.resourceVersion.semanticVariant.markdownDescription") + "markdownDescription" = schema_i18n!("semanticVariant.markdownDescription") ) )] Semantic(SemanticVersion), @@ -202,12 +202,12 @@ pub enum ResourceVersion { /// [`ResourceVersionReq`]: crate::types::ResourceVersionReq /// [01]: https://doc.rust-lang.org/std/cmp/trait.Ord.html#lexicographical-comparison #[schemars( - title = t!("schemas.definitions.resourceVersion.dateVariant.title"), - description = t!("schemas.definitions.resourceVersion.dateVariant.description"), + title = schema_i18n!("dateVariant.title"), + description = schema_i18n!("dateVariant.description"), extend( "deprecated" = true, - "deprecationMessage" = t!("schemas.definitions.resourceVersion.dateVariant.deprecationMessage"), - "markdownDescription" = t!("schemas.definitions.resourceVersion.dateVariant.markdownDescription"), + "deprecationMessage" = schema_i18n!("dateVariant.deprecationMessage"), + "markdownDescription" = schema_i18n!("dateVariant.markdownDescription"), ) )] Date(DateVersion), diff --git a/lib/dsc-lib/src/types/resource_version_req.rs b/lib/dsc-lib/src/types/resource_version_req.rs index f6f6c89df..c3042ec17 100644 --- a/lib/dsc-lib/src/types/resource_version_req.rs +++ b/lib/dsc-lib/src/types/resource_version_req.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; use thiserror::Error; use crate::{ - schemas::dsc_repo::DscRepoSchema, + schemas::dsc_repo::{DscRepoSchema, schema_i18n}, types::{DateVersion, DateVersionError, ResourceVersion, SemanticVersionReq, SemanticVersionReqError} }; @@ -83,10 +83,10 @@ use crate::{ #[serde(untagged, try_from = "String", into = "String")] #[schemars(!try_from, !into)] #[schemars( - title = t!("schemas.definitions.resourceVersionReq.title"), - description = t!("schemas.definitions.resourceVersionReq.description"), + title = schema_i18n!("title"), + description = schema_i18n!("description"), extend( - "markdownDescription" = t!("schemas.definitions.resourceVersionReq.markdownDescription") + "markdownDescription" = schema_i18n!("markdownDescription") ) )] pub enum ResourceVersionReq { @@ -100,10 +100,10 @@ pub enum ResourceVersionReq { /// /// [01]: https://semver.org #[schemars( - title = t!("schemas.definitions.resourceVersionReq.semanticVariant.title"), - description = t!("schemas.definitions.resourceVersionReq.semanticVariant.description"), + title = schema_i18n!("semanticVariant.title"), + description = schema_i18n!("semanticVariant.description"), extend( - "markdownDescription" = t!("schemas.definitions.resourceVersionReq.semanticVariant.markdownDescription") + "markdownDescription" = schema_i18n!("semanticVariant.markdownDescription") ) )] Semantic(SemanticVersionReq), @@ -119,12 +119,12 @@ pub enum ResourceVersionReq { /// resource version and this version requirement are exactly the same. The comparison is /// case-sensitive for the prerelease segment, if present. #[schemars( - title = t!("schemas.definitions.resourceVersionReq.dateVariant.title"), - description = t!("schemas.definitions.resourceVersionReq.dateVariant.description"), + title = schema_i18n!("dateVariant.title"), + description = schema_i18n!("dateVariant.description"), extend( "deprecated" = true, - "deprecationMessage" = t!("schemas.definitions.resourceVersionReq.dateVariant.deprecationMessage"), - "markdownDescription" = t!("schemas.definitions.resourceVersionReq.dateVariant.markdownDescription"), + "deprecationMessage" = schema_i18n!("dateVariant.deprecationMessage"), + "markdownDescription" = schema_i18n!("dateVariant.markdownDescription"), "examples" = [ "2026-02-03", "2026-11-27-preview" diff --git a/lib/dsc-lib/src/types/semantic_version.rs b/lib/dsc-lib/src/types/semantic_version.rs index 709ade8fc..a098905e0 100644 --- a/lib/dsc-lib/src/types/semantic_version.rs +++ b/lib/dsc-lib/src/types/semantic_version.rs @@ -9,7 +9,7 @@ use schemars::{json_schema, JsonSchema}; use serde::{Deserialize, Serialize}; use thiserror::Error; -use crate::schemas::dsc_repo::DscRepoSchema; +use crate::schemas::dsc_repo::{DscRepoSchema, schema_i18n}; /// Defines a semantic version for use with DSC. /// @@ -459,12 +459,12 @@ impl JsonSchema for SemanticVersion { } fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema { json_schema!({ - "title": t!("schemas.definitions.semver.title"), - "description": t!("schemas.definitions.semver.description"), - "markdownDescription": t!("schemas.definitions.semver.markdownDescription"), + "title": schema_i18n!("title"), + "description": schema_i18n!("description"), + "markdownDescription": schema_i18n!("markdownDescription"), "type": "string", "pattern": Self::VALIDATING_PATTERN, - "patternErrorMessage": t!("schemas.definitions.semver.patternErrorMessage"), + "patternErrorMessage": schema_i18n!("patternErrorMessage"), }) } } diff --git a/lib/dsc-lib/src/types/semantic_version_req.rs b/lib/dsc-lib/src/types/semantic_version_req.rs index d1ce0bec8..576b746d3 100644 --- a/lib/dsc-lib/src/types/semantic_version_req.rs +++ b/lib/dsc-lib/src/types/semantic_version_req.rs @@ -13,7 +13,7 @@ use schemars::{json_schema, JsonSchema}; use serde::{Deserialize, Serialize}; use thiserror::Error; -use crate::{schemas::dsc_repo::DscRepoSchema, types::SemanticVersion}; +use crate::{schemas::dsc_repo::{DscRepoSchema, schema_i18n}, types::SemanticVersion}; /// Defines one or more limitations for a semantic version to enable version pinning. /// @@ -401,7 +401,7 @@ use crate::{schemas::dsc_repo::DscRepoSchema, types::SemanticVersion}; /// [01]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#version-requirement-syntax /// [`ComparatorIncludesForbiddenBuildMetadata`]: SemanticVersionReqError::ComparatorIncludesForbiddenBuildMetadata #[derive(Debug, Clone, Hash, PartialEq, Eq, Default, Serialize, Deserialize, DscRepoSchema)] -#[dsc_repo_schema(base_name = "semverRequirement", folder_path = "definitions")] +#[dsc_repo_schema(base_name = "semverReq", folder_path = "definitions")] pub struct SemanticVersionReq(semver::VersionReq); /// Defines the parsing errors and diagnostics for invalid string representations of a @@ -967,12 +967,12 @@ impl JsonSchema for SemanticVersionReq { } fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema { json_schema!({ - "title": t!("schemas.definitions.semverReq.title"), - "description": t!("schemas.definitions.semverReq.description"), - "markdownDescription": t!("schemas.definitions.semverReq.markdownDescription"), + "title": schema_i18n!("title"), + "description": schema_i18n!("description"), + "markdownDescription": schema_i18n!("markdownDescription"), "type": "string", "pattern": SemanticVersionReq::VALIDATING_PATTERN, - "patternErrorMessage": t!("schemas.definitions.semverReq.patternErrorMessage"), + "patternErrorMessage": schema_i18n!("patternErrorMessage"), "examples": [ "=1.2.3", ">=1.2.3, <2.0.0", @@ -1056,13 +1056,6 @@ impl Deref for SemanticVersionReq { } } -// Comparison traits -// impl PartialEq for SemanticVersionReq { -// fn eq(&self, other: &Self) -> bool { -// self.0 == other.0 -// } -// } - impl PartialEq for SemanticVersionReq { fn eq(&self, other: &semver::VersionReq) -> bool { &self.0 == other diff --git a/lib/dsc-lib/src/types/tag.rs b/lib/dsc-lib/src/types/tag.rs index feac8cfcc..dba3fe085 100644 --- a/lib/dsc-lib/src/types/tag.rs +++ b/lib/dsc-lib/src/types/tag.rs @@ -4,11 +4,10 @@ use std::{fmt::{Display, Formatter}, hash::Hash, ops::Deref, str::FromStr, sync::OnceLock}; use regex::Regex; -use rust_i18n::t; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use crate::dscerror::DscError; +use crate::{dscerror::DscError, schemas::dsc_repo::{DscRepoSchema, schema_i18n}}; /// Defines a short term that applies to a DSC resource or extension and can be used for filtering. /// @@ -34,16 +33,18 @@ use crate::dscerror::DscError; Debug, Serialize, Deserialize, - JsonSchema + JsonSchema, + DscRepoSchema )] +#[dsc_repo_schema(base_name = "tag", folder_path = "definitions")] #[serde(try_from = "String")] #[schemars( - title = t!("schemas.definitions.tag.title"), - description = t!("schemas.definitions.tag.description"), + title = schema_i18n!("title"), + description = schema_i18n!("description"), extend( "pattern" = Tag::VALIDATING_PATTERN, - "patternErrorMessage" = t!("schemas.definitions.tag.patternErrorMessage"), - "markdownDescription" = t!("schemas.definitions.tag.markdownDescription"), + "patternErrorMessage" = schema_i18n!("patternErrorMessage"), + "markdownDescription" = schema_i18n!("markdownDescription"), ), inline )] diff --git a/lib/dsc-lib/src/types/tag_list.rs b/lib/dsc-lib/src/types/tag_list.rs index 8300d8206..629c263fd 100644 --- a/lib/dsc-lib/src/types/tag_list.rs +++ b/lib/dsc-lib/src/types/tag_list.rs @@ -3,11 +3,10 @@ use std::{borrow::Borrow, collections::HashSet, ops::{Deref, DerefMut}}; -use rust_i18n::t; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use crate::{schemas::dsc_repo::DscRepoSchema, types::Tag}; +use crate::{schemas::dsc_repo::{DscRepoSchema, schema_i18n}, types::Tag}; /// Wraps a [`HashSet`] of [`Tag`] instances to enable defining a reusable canonical JSON Schema for /// manifests, resources, and extensions. @@ -16,18 +15,15 @@ use crate::{schemas::dsc_repo::DscRepoSchema, types::Tag}; /// the underlying type. It implements the [`AsRef`], [`Borrow`], [`Deref`], and [`DerefMut`] /// traits to enable ergonomically using instances of [`TagList`] as the underlying hash set. #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, DscRepoSchema)] -#[serde(into = "Vec")] +#[dsc_repo_schema(base_name = "tags", folder_path = "definitions")] #[schemars( - title = t!("schemas.definitions.tags.title"), - description = t!("schemas.definitions.tags.description"), + title = schema_i18n!("title"), + description = schema_i18n!("description"), extend( - "markdownDescription" = t!("schemas.definitions.tags.markdownDescription"), + "markdownDescription" = schema_i18n!("markdownDescription"), ) )] -#[dsc_repo_schema( - base_name = "tags", - folder_path = "definitions", -)] +#[serde(into = "Vec")] pub struct TagList(HashSet); impl TagList { From 3d0a8a55f9e55acf453b800d8acd6c8c5d866b56 Mon Sep 17 00:00:00 2001 From: Mikey Lombardi Date: Mon, 13 Apr 2026 11:32:51 -0500 Subject: [PATCH 3/5] (MAINT) Update i18n testing for `schema_i18n` macro This change removes the search for translations defined in YAML files from the `dsc_i18n` test suite to drop false positives for unused translations. Testing whether a schema uses an undefined translation for a documentation keyword is redundant, now that the implementation causes schema generation to _panic_ when it uses an undefined translation key. --- dsc/tests/dsc_i18n.tests.ps1 | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dsc/tests/dsc_i18n.tests.ps1 b/dsc/tests/dsc_i18n.tests.ps1 index 676c81477..049780c72 100644 --- a/dsc/tests/dsc_i18n.tests.ps1 +++ b/dsc/tests/dsc_i18n.tests.ps1 @@ -130,10 +130,6 @@ BeforeDiscovery { if (Test-Path -Path $tomlFile) { $this.LoadFile((Get-Item -Path $tomlFile)) } - $yamlFiles = Get-ChildItem -Path $localesFolder | Where-Object Extension -match 'ya?ml' - foreach ($yamlFile in $yamlFiles) { - $this.LoadFile($yamlFile) - } $this.CheckTranslations($projectFolder) } From 41d722cd0f9e5ba02e87c53e691c84b140155884 Mon Sep 17 00:00:00 2001 From: Mikey Lombardi Date: Mon, 13 Apr 2026 11:43:02 -0500 Subject: [PATCH 4/5] (MAINT) Fix i18n tests for `dsc-lib-jsonschema` This change updates the `dsc-lib-jsonschema` crate to fix failing i18n tests by: - Moving the VS Code schema keywords into the `toml` translation definition file. Because these keywords must generate their documentation regardless of whether the library is being used with the `DscRepoSchema` trait, the types need to be able to use the normative translation files for i18n tests to function corectly. - Renaming the `tests/locales` folder to `tests/integration_locales` to avoid incorrectly testing those translations in the `dsc_i18n` pester test suite. --- lib/dsc-lib-jsonschema/locales/en-us.toml | 371 ++++++++++++++ lib/dsc-lib-jsonschema/locales/vscode.yaml | 471 ------------------ .../src/vscode/keywords/allow_comments.rs | 6 +- .../vscode/keywords/allow_trailing_commas.rs | 6 +- .../src/vscode/keywords/completion_detail.rs | 6 +- .../src/vscode/keywords/default_snippets.rs | 42 +- .../vscode/keywords/deprecation_message.rs | 6 +- .../src/vscode/keywords/do_not_suggest.rs | 6 +- .../src/vscode/keywords/enum_descriptions.rs | 6 +- .../src/vscode/keywords/enum_details.rs | 6 +- .../src/vscode/keywords/enum_sort_texts.rs | 6 +- .../src/vscode/keywords/error_message.rs | 6 +- .../vscode/keywords/markdown_description.rs | 6 +- .../keywords/markdown_enum_descriptions.rs | 6 +- .../vscode/keywords/pattern_error_message.rs | 6 +- .../src/vscode/keywords/suggest_sort_text.rs | 6 +- .../tests/integration/main.rs | 2 +- .../schemas.yaml | 0 18 files changed, 432 insertions(+), 532 deletions(-) delete mode 100644 lib/dsc-lib-jsonschema/locales/vscode.yaml rename lib/dsc-lib-jsonschema/tests/{locales => integration_locales}/schemas.yaml (100%) diff --git a/lib/dsc-lib-jsonschema/locales/en-us.toml b/lib/dsc-lib-jsonschema/locales/en-us.toml index 3792216b1..92bc235dd 100644 --- a/lib/dsc-lib-jsonschema/locales/en-us.toml +++ b/lib/dsc-lib-jsonschema/locales/en-us.toml @@ -3,6 +3,7 @@ _version = 1 [dsc_repo.dsc_repo_schema] unrecognizedSchemaUri = "Unrecognized $schema URI" validSchemaUrisAre = "Valid schema URIs are" +missingTranslation = "unable to retrieve translation for undefined key '#{key}'" [transforms.idiomaticize_externally_tagged_enum] applies_to = "invalid application of idiomaticize_externally_tagged_enum; missing 'oneOf' keyword in transforming schema: %{transforming_schema}" @@ -117,55 +118,425 @@ invalid item: %{invalid_item} transforming schema: %{transforming_schema} """ +[vscode.dialect] +title = "VS Code dialect" +description = "Defines a meta schema combining Draft 2020-12 and the VS Code extended vocabulary." +markdownDescription = """ +Defines a meta schema combining Draft 2020-12 and the VS Code extended vocabulary. + +The VS Code extended vocabulary enables you to define custom keywords that enhance how VS +Code interprets schemas to provide better hover documentation, IntelliSense, validation +errors, and more. +""" + [vscode.keywords.allow_comments] factory_error_invalid_type = "The 'allowComments' VS Code keyword must be a boolean value." +title = "Allow comments" +description = "Indicates whether VS Code should allow comments in the JSON file, even when the file extension isn't '.jsonc'." +markdownDescription = """ +Indicates whether VS Code should allow comments in the JSON file, even when the file +extension isn't `.jsonc`. + +By default, JSON comments in `.json` files cause parsing errors. If you define a JSON +Schema with `allowComments` set to `true`, VS Code doesn't raise validation errors for +comments in JSON for that schema. +""" [vscode.keywords.allow_trailing_commas] factory_error_invalid_type = "The 'allowTrailingCommas' VS Code keyword must be a boolean value." +title = "Allow trailing commas" +description = "Indicates whether VS Code should allow trailing commas in the JSON file." +markdownDescription = """ +Indicates whether VS Code should allow trailing commas in the JSON file. + +By default, a comma after the last item in an array or last key-value pair in an object +causes a parsing error. If you define a JSON Schema with `allowTrailingCommas` set to +`true`, VS Code doesn't raise validation errors for commas after the last item in arrays +or last key-value pair in objects for that Schema. +""" [vscode.keywords.completion_detail] factory_error_invalid_type = "The 'completionDetail' VS Code keyword must be a string value." +title = "Completion detail" +description = "Defines additional information for IntelliSense when completing a proposed item, replacing the `title` keyword as code-formatted text." +markdownDescription = """ +Defines additional information for IntelliSense when completing a proposed item, replacing +the `title` keyword as code-formatted text. + +By default, when a user completes a value for a schema or subschema, VS Code displays +additional information in hover text. If the schema defines the `title` keyword, the +hover text includes the title string as the first line of the hover text. + +If you define the `completionDetail` keyword, VS Code displays the string as monospace +code-formatted text instead of the `title` keyword's value. + +If the schema defines the `description` or `markdownDescription` keywords, that text is +displayed in the hover text after the value from the `completionDetail` or `title` +keyword. +""" [vscode.keywords.default_snippets] factory_error_suffix = "The 'defaultSnippets' VS Code keyword must be an array of objects. Every object must be a valid snippet definition." factory_error_not_array = "Non-array value is invalid." factory_error_invalid_item = "Invalid definition for an object in the array." factory_error_non_object_item = "Array containing non-object items is invalid." +title = "Default Snippets" +description = "Provides snippets for completion of a schema or subschema value or property." +markdownDescription = """ +Provides snippets for completion of a schema or subschema value or property. + +By default, VS Code presents a set of completion options for data with an associated JSON +Schema like suggesting defined property names or enum values. You can use the +`defaultSnippets` keyword to provide an array of snippets with more control over the +presentation, default values, and enable users to quickly fill out the snippet. + +The keyword expects an array of objects that each define a snippet. For more information +about defining snippets, see [Define snippets in JSON Schemas][01]. For more information +about the snippet syntax, see [Snippet syntax][02]. + +[01]: https://code.visualstudio.com/Docs/languages/json#_define-snippets-in-json-schemas +[02]: https://code.visualstudio.com/docs/editing/userdefinedsnippets#_snippet-syntax +""" +[vscode.keywords.default_snippets.items] +title = "Snippet definition" +description = "Each item defines a snippet for users that VS Code will surface as part of IntelliSense." +markdownDescription = """ +Each item defines a snippet for users that VS Code will surface as part of IntelliSense. + +Every snippet must define either the `body` or `bodyText` property, which VS Code uses +to insert the snippet into the data file. If you specify both `body` and `bodyText`, the +value for `body` supercedes the value for `bodyText`. + +The `description`, and `markdownDescription` properties provide documentation for the +snippet and are displayed in the hover text when a user selects the snippet. If you +specify both `description` and `markdownDescription`, the text for +`markdownDescription` supercedes the text for `description`. + +The `label` property defines a short name for the snippet. If the snippet doesn't define +the `label` property, VS Code shows a stringified representation of the snippet instead. + +Snippets are presented to the user in alphabetical order by the value of their `label` +property (or the stringified representation of the snippet if it has no label). +""" + +[vscode.keywords.default_snippets.items.properties.label] +title = "Snippet label" +description = "Defines a short name for the snippet." +markdownDescription = """ +Defines a short name for the snippet instead of using the stringified representation +of the snippet's value. The `label` property also affects the order that VS Code +presents the snippets. VS Code sorts the snippets for completion alphabetically by +label. +""" + +[vscode.keywords.default_snippets.items.properties.description] +title = "Snippet description" +description = "Defines plain text documentation for the snippet displayed in the completion dialog." +markdownDescription = """ +Defines plain text documentation for the snippet displayed in the completion dialog. + +When the snippet doesn't define the `description` or `markdownDescription` property, +the snippet provides no additional context to the user aside from the label until +they select the snippet for completion. Use the `description` property to provide +information to the user about the snippet. If you need to provide rich formatting, +like links or text formatting, use the `markdownDescription` property. + +If you define both the `description` and `markdownDescription` property for a +snippet, the `markdownDescription` text overrides the `description` text. +""" + +[vscode.keywords.default_snippets.items.properties.markdownDescription] +title = "Snippet markdown description" +description = "Defines formatted documentation for the snippet displayed in the completion dialog." +markdownDescription = """ +Defines formatted documentation for the snippet displayed in the completion dialog. + +When the snippet doesn't define the `description` or `markdownDescription` property, +the snippet provides no additional context to the user aside from the label until +they select the snippet for completion. Use the `description` property to provide +information to the user about the snippet. If you need to provide rich formatting, +like links or text formatting, use the `markdownDescription` property. + +If you define both the `description` and `markdownDescription` property for a +snippet, the `markdownDescription` text overrides the `description` text. +""" + +[vscode.keywords.default_snippets.items.properties.body] +title = "Snippet body" +description = "Defines the data to insert for the snippet. The data can be any type." +markdownDescription = """ +Defines the data to insert for the snippet. The data can be any type. When the user +selects the snippet, VS Code inserts the data at the cursor. In string literals for +the `body` you can use [snippet syntax][01] to define tabstops, placeholders, and +variables. + +Alternatively, you can define the `bodyText` property for the snippet, which +specifies the text to insert for the snippet as a string. + +If you define both the `bodyText` and `body` properties for a snippet, the `body` +definition overrides the `bodyText` property. + +[01]: https://code.visualstudio.com/docs/editing/userdefinedsnippets#_snippet-syntax +""" + +[vscode.keywords.default_snippets.items.properties.bodyText] +title = "Snippet body text" +description = "Defines the data to insert for the snippet as a string literal." +markdownDescription = """ +Defines the data to insert for the snippet as a string literal. When the user +selects the snippet, VS Code inserts the text _without_ the enclosing quotation +marks at the cursor. You can use [snippet syntax][01] to define tabstops, +placeholders, and variables in the `bodyText`. + +Alternatively, you can define the `body` property for the snippet, which specifies +the text to insert for the snippet as data. + +If you define both the `bodyText` and `body` properties for a snippet, the `body` +definition overrides the `bodyText` property. + +[01]: https://code.visualstudio.com/docs/editing/userdefinedsnippets#_snippet-syntax +""" [vscode.keywords.deprecation_message] factory_error_invalid_type = "The 'deprecationMessage' VS Code keyword must be a string value." +title = "Deprecation message" +description = "Defines a message to surface as a warning to users when they specify a deprecated property in their data." +markdownDescription = """ +Defines a message to surface as a warning to users when they specify a deprecated property +in their data. + +This keyword only has an affect when defined in a schema or subschema that also defines +the `deprecated` keyword as `true`. When you define the `deprecationMessage` keyword for +a deprecated schema or subschema, VS Code displays the provided message instead of the +default warning about deprecation. +""" [vscode.keywords.do_not_suggest] factory_error_invalid_type = "The 'doNotSuggest' VS Code keyword must be a boolean value." +title = "Do not suggest" +description = "Indicates whether VS Code should avoid suggesting the property for IntelliSense." +markdownDescription = """ +Indicates whether VS Code should avoid suggesting the property for IntelliSense. + +By default, VS Code will show any defined property in the `properties` keyword as a +completion option with IntelliSense. You can define the `doNotSuggest` keyword in a +property subschema as `true` to indicate that VS Code should not show that property for +IntelliSense. +""" [vscode.keywords.enum_descriptions] factory_error_suffix = "The 'enumDescriptions' VS Code keyword must be an array of string values. The 'enumDescriptions' keyword should have the same number of items as the 'enum' keyword." factory_error_not_array = "Non-array value is invalid." factory_error_non_string_item = "Array containing non-string items is invalid." +title = "Enum descriptions" +description = "Defines per-value descriptions for schemas that use the enum keyword." +markdownDescription = """ +Defines per-value descriptions for schemas that use the `enum` keyword. + +The builtin keywords for JSON Schema includes the `description` keyword, which you can use +to document a given schema or subschema. However, for schemas that use the `enum` keyword +to define an array of valid values, JSON Schema provides no keyword for documenting each +value. + +With the `enumDescriptions` keyword from the VS Code vocabulary, you can document each +item in the `enum` keyword array. VS Code interprets each item in `enumDescriptions` as +documenting the item at the same index in the `enum` keyword. + +This documentation is surfaced in VS Code on hover for an enum value and for IntelliSense +when completing an enum value. + +If you want to use Markdown syntax for the annotation, specify the +`markdownEnumDescriptions` keyword instead. +""" [vscode.keywords.enum_details] factory_error_suffix = "The 'enumDetails' VS Code keyword must be an array of string values. The 'enumDetails' keyword should have the same number of items as the 'enum' keyword." factory_error_not_array = "Non-array value is invalid." factory_error_non_string_item = "Array containing non-string items is invalid." +title = "Enum details" +description = "Defines additional information for IntelliSense when completing a proposed enum value, shown before the description." +markdownDescription = """ +Defines additional information for IntelliSense when completing a proposed enum value, +shown before the description. + +By default, when VS Code suggests a completion for an item defined in the `enum` keyword, +VS Code displays hover text with a description. If the schema defined the `description`, +`enumDescriptions`, or `markdownEnumDescriptions` keywords, VS Code displays that text. +The `markdownEnumDescriptions` keyword overrides the `enumDescriptions` keyword, which +overrides the `description` keyword. + +When you define the `enumDetails` keyword, VS Code displays the string for that enum +value as monospace code-formatted text. The keyword expects an array of strings. VS Code +correlates the items in the `enumDetails` keyword to the items in the `enum` keyword by +their index. The first item in `enumDetails` maps to the first item in `enum` and so on. +""" [vscode.keywords.enum_sort_texts] factory_error_suffix = "The 'enumSortTexts' VS Code keyword must be an array of string values. The 'enumSortTexts' keyword should have the same number of items as the 'enum' keyword." factory_error_not_array = "Non-array value is invalid." factory_error_non_string_item = "Array containing non-string items is invalid." +title = "Enum sort text" +description = "Defines a set of alternate strings to use when sorting a suggestion for enum values." +markdownDescription = """ +Defines a set of alternate strings to use when sorting a suggestion for enum values. + +By default, suggestions are sorted alphabetically, not in the order that you define +items in the `enum` keyword array. You can use the `enumSortText` keyword to override +the order the values are displayed, providing a different string for each value. + +The keyword expects an array of strings. VS Code correlates the items in the +`enumSortText` keyword to the items in the `enum` keyword by their index. The first item +in `enumSortText` maps to the first item in `enum` and so on. + +For example, in the following schema, VS Code will suggest the `baz`, then `bar`, then +`foo` values: + +```json +{ + "type": "string", + "enum": ["foo", "bar", "baz"], + "enumSortText": ["c", "b", "a"] +} +``` +""" [vscode.keywords.error_message] factory_error_invalid_type = "The 'errorMessage' VS Code keyword must be a string value." +title = "Validation error message" +description = "Defines a friendly error message to raise when a schema or subschema fails validation." +markdownDescription = """ +Defines a friendly error message to raise when a schema or subschema fails validation. + +By default, VS Code surfaces a default error message for data that fails schema +validation, like specifying an invalid type. You can use the `errorMessage` keyword to +define a custom message to raise in the editor when the data fails validation for the +following cases: + +- When the data is an invalid type as validated by the `type` keyword. +- When the subschema defined for the `not` keyword is valid. +- When the data is invalid for the defined values in the `enum` keyword. +- When the data is invalid for the defined value in the `const` keyword. +- When a string doesn't match the regular expression defined in the `pattern` keyword. +This message is overridden by the `patternErrorMessage` keyword if it's defined. +- When a string value doesn't match a required format. +- When the data is for an array that is validated by the `minContains` or `maxContains` +keywords and fails those validations. +- When the data includes a property that was defined in the `properties` keyword as +`false`, forbidding the property. +- When the data includes a property that was defined in the `patternProperties` keyword as +`false`, forbidding matching property names. +- When the data includes a property that wasn't defined in the `properties` or +`patternProperties` keyword and the schema defines `additionalProperties` as `false`. +- When the data includes a property that isn't evaluated by any keywords and the schema +defines `unevaluatedProperties` as `false`. + +The value for the `errorMessage` keyword supercedes all default messages for the schema +or subschema where you define the keyword. You can provide per-validation failure +messages by defining the validating keywords in separate entries of the `allOf` keyword +and defining the `errorMessage` keyword for each entry. +""" [vscode.keywords.markdown_description] factory_error_invalid_type = "The 'markdownDescription' VS Code keyword must be a string value." +title = "Markdown description" +description = "Defines documentation for the schema or subschema displayed as hover text in VS Code." +markdownDescription = """ +Defines documentation for the schema or subschema displayed as hover text in VS Code. + +By default, VS Code displays the text defined in the `description` keyword in the hover +text for properties and values. VS Code interprets the `description` keyword literally, +without converting any apparent markup. + +You can define the `markdownDescription` keyword to provide descriptive text as markdown, +including links and code blocks. When a schema or subschema defines the +`markdownDescription` keyword, that value supercedes any defined text in the `description` +keyword. + +You can also use the `markdownEnumDescriptions` keyword to document the values defined +for the `enum` keyword. + +For more information, see [Use rich formatting in hovers][01]. + +[01]: https://code.visualstudio.com/Docs/languages/json#_use-rich-formatting-in-hovers +""" [vscode.keywords.markdown_enum_descriptions] factory_error_suffix = "The 'markdownEnumDescriptions' VS Code keyword must be an array of string values. The 'markdownEnumDescriptions' keyword should have the same number of items as the 'enum' keyword." factory_error_not_array = "Non-array value is invalid." factory_error_non_string_item = "Array containing non-string items is invalid." +title = "Markdown enum descriptions" +description = "Defines documentation for enum values displayed as hover text in VS Code." +markdownDescription = """ +Defines documentation for enum values displayed as hover text in VS Code. + +By default, when a user hovers on or selects completion for a value that is validated by +the `enum` keyword, VS Code displays the text from the `description` or +`markdownDescription` keywords for the schema or subschema. You can use the +`markdownEnumDescriptions` keyword to define documentation for each enum value. + +When a schema or subschema defines the `markdownEnumDescriptions` keyword, that value +supercedes any defined text in the `description`, `markdownDescription`, or +`enumDescriptions` keywords. + +The keyword expects an array of strings. VS Code correlates the items in the +`markdownEnumDescriptions` keyword to the items in the `enum` keyword by their index. The +first item in `markdownEnumDescriptions` maps to the first item in `enum` and so on. +""" [vscode.keywords.pattern_error_message] factory_error_invalid_type = "The 'patternErrorMessage' VS Code keyword must be a string value." +title = "Pattern validation error message" +description = "Defines a friendly error message to raise when a schema or subschema fails validation for the `pattern` keyword." +markdownDescription = """ +Defines a friendly error message to raise when a schema or subschema fails validation +for the `pattern` keyword. + +By default, when a value fails validation for the `pattern` keyword, VS Code raises an +error that informs the user that the value is invalid for the given regular expression, +which it displays in the message. + +Reading and parsing regular expressions can be difficult even for experienced users. You +can define the `patternErrorMessage` keyword to provide better information to the user +about the expected pattern for the string value. +""" [vscode.keywords.suggest_sort_text] factory_error_invalid_type = "The 'suggestSortText' VS Code keyword must be a string value." +title = "Suggest sort text" +description = "Defines an alternate string to use when sorting a suggestion." +markdownDescription = """ +Defines an alternate string to use when sorting a suggestion. + +By default, suggestions are displayed in alphabetical order. You can define the +`suggestSortText` keyword to change how the suggestions are sorted. For example, in +the following schema, VS Code will suggest the `baz`, then `bar`, then `foo` properties: + +```json +{ + "type": "object", + "properties": { + "foo": { + "suggestSortText": "c", + } + "bar": { + "suggestSortText": "b", + } + "baz": { + "suggestSortText": "a", + } + } +} +``` +""" + +[vscode.vocabulary] +title = "VS Code extended vocabulary" +description = "Defines custom keywords for enhancing the authoring and editing experience for data files in VS Code." +markdownDescription = """ +Defines custom keywords for enhancing the authoring and editing experience for data files +in VS Code. + +These custom keywords don't affect the validation of data. Instead, they provide +annotations that VS Code interprets to provide better hover documentation, IntelliSense, +validation errors, and more. +""" \ No newline at end of file diff --git a/lib/dsc-lib-jsonschema/locales/vscode.yaml b/lib/dsc-lib-jsonschema/locales/vscode.yaml deleted file mode 100644 index 936cb39b9..000000000 --- a/lib/dsc-lib-jsonschema/locales/vscode.yaml +++ /dev/null @@ -1,471 +0,0 @@ -_version: 2 - -vscode: - dialect: - title: - en-US: VS Code dialect - description: - en-US: >- - Defines a meta schema combining Draft 2020-12 and the VS Code extended vocabulary. - markdownDescription: - en-US: |- - Defines a meta schema combining Draft 2020-12 and the VS Code extended vocabulary. - - The VS Code extended vocabulary enables you to define custom keywords that enhance how VS - Code interprets schemas to provide better hover documentation, IntelliSense, validation - errors, and more. - - vocabulary: - title: - en-US: VS Code extended vocabulary - description: - en-US: >- - Defines custom keywords for enhancing the authoring and editing experience for data files - in VS Code. - markdownDescription: - en-US: |- - Defines custom keywords for enhancing the authoring and editing experience for data files - in VS Code. - - These custom keywords don't affect the validation of data. Instead, they provide - annotations that VS Code interprets to provide better hover documentation, IntelliSense, - validation errors, and more. - - keywords: - allowComments: - title: - en-US: Allow comments - description: - en-US: >- - Indicates whether VS Code should allow comments in the JSON file, even when the file - extension isn't '.jsonc'. - markdownDescription: - en-US: |- - Indicates whether VS Code should allow comments in the JSON file, even when the file - extension isn't `.jsonc`. - - By default, JSON comments in `.json` files cause parsing errors. If you define a JSON - Schema with `allowComments` set to `true`, VS Code doesn't raise validation errors for - comments in JSON for that schema. - - allowTrailingCommas: - title: - en-US: Allow trailing commas - description: - en-US: >- - Indicates whether VS Code should allow trailing commas in the JSON file. - markdownDescription: - en-US: |- - Indicates whether VS Code should allow trailing commas in the JSON file. - - By default, a comma after the last item in an array or last key-value pair in an object - causes a parsing error. If you define a JSON Schema with `allowTrailingCommas` set to - `true`, VS Code doesn't raise validation errors for commas after the last item in arrays - or last key-value pair in objects for that Schema. - - completionDetail: - title: - en-US: Completion detail - description: - en-US: >- - Defines additional information for IntelliSense when completing a proposed item, replacing - the `title` keyword as code-formatted text. - markdownDescription: - en-US: |- - Defines additional information for IntelliSense when completing a proposed item, replacing - the `title` keyword as code-formatted text. - - By default, when a user completes a value for a schema or subschema, VS Code displays - additional information in hover text. If the schema defines the `title` keyword, the - hover text includes the title string as the first line of the hover text. - - If you define the `completionDetail` keyword, VS Code displays the string as monospace - code-formatted text instead of the `title` keyword's value. - - If the schema defines the `description` or `markdownDescription` keywords, that text is - displayed in the hover text after the value from the `completionDetail` or `title` - keyword. - - defaultSnippets: - title: - en-US: Default Snippets - description: - en-US: >- - Provides snippets for completion of a schema or subschema value or property. - markdownDescription: - en-US: |- - Provides snippets for completion of a schema or subschema value or property. - - By default, VS Code presents a set of completion options for data with an associated JSON - Schema like suggesting defined property names or enum values. You can use the - `defaultSnippets` keyword to provide an array of snippets with more control over the - presentation, default values, and enable users to quickly fill out the snippet. - - The keyword expects an array of objects that each define a snippet. For more information - about defining snippets, see [Define snippets in JSON Schemas][01]. For more information - about the snippet syntax, see [Snippet syntax][02]. - - [01]: https://code.visualstudio.com/Docs/languages/json#_define-snippets-in-json-schemas - [02]: https://code.visualstudio.com/docs/editing/userdefinedsnippets#_snippet-syntax - - items: - title: - en-US: Snippet definition - description: - en-US: >- - Each item defines a snippet for users that VS Code will surface as part of IntelliSense. - markdownDescription: - en-US: |- - Each item defines a snippet for users that VS Code will surface as part of IntelliSense. - - Every snippet must define either the `body` or `bodyText` property, which VS Code uses - to insert the snippet into the data file. If you specify both `body` and `bodyText`, the - value for `body` supercedes the value for `bodyText`. - - The `description`, and `markdownDescription` properties provide documentation for the - snippet and are displayed in the hover text when a user selects the snippet. If you - specify both `description` and `markdownDescription`, the text for - `markdownDescription` supercedes the text for `description`. - - The `label` property defines a short name for the snippet. If the snippet doesn't define - the `label` property, VS Code shows a stringified representation of the snippet instead. - - Snippets are presented to the user in alphabetical order by the value of their `label` - property (or the stringified representation of the snippet if it has no label). - - properties: - label: - title: - en-US: Snippet label - description: - en-US: >- - Defines a short name for the snippet. - markdownDescription: - en-US: |- - Defines a short name for the snippet instead of using the stringified representation - of the snippet's value. The `label` property also affects the order that VS Code - presents the snippets. VS Code sorts the snippets for completion alphabetically by - label. - description: - title: - en-US: Snippet description - description: - en-US: >- - Defines plain text documentation for the snippet displayed in the completion dialog. - markdownDescription: - en-US: |- - Defines plain text documentation for the snippet displayed in the completion dialog. - - When the snippet doesn't define the `description` or `markdownDescription` property, - the snippet provides no additional context to the user aside from the label until - they select the snippet for completion. Use the `description` property to provide - information to the user about the snippet. If you need to provide rich formatting, - like links or text formatting, use the `markdownDescription` property. - - If you define both the `description` and `markdownDescription` property for a - snippet, the `markdownDescription` text overrides the `description` text. - markdownDescription: - title: - en-US: Snippet markdown description - description: - en-US: >- - Defines formatted documentation for the snippet displayed in the completion dialog. - markdownDescription: - en-US: |- - Defines formatted documentation for the snippet displayed in the completion dialog. - - When the snippet doesn't define the `description` or `markdownDescription` property, - the snippet provides no additional context to the user aside from the label until - they select the snippet for completion. Use the `description` property to provide - information to the user about the snippet. If you need to provide rich formatting, - like links or text formatting, use the `markdownDescription` property. - - If you define both the `description` and `markdownDescription` property for a - snippet, the `markdownDescription` text overrides the `description` text. - body: - title: - en-US: Snippet body - description: - en-US: >- - Defines the data to insert for the snippet. The data can be any type. - markdownDescription: - en-US: |- - Defines the data to insert for the snippet. The data can be any type. When the user - selects the snippet, VS Code inserts the data at the cursor. In string literals for - the `body` you can use [snippet syntax][01] to define tabstops, placeholders, and - variables. - - Alternatively, you can define the `bodyText` property for the snippet, which - specifies the text to insert for the snippet as a string. - - If you define both the `bodyText` and `body` properties for a snippet, the `body` - definition overrides the `bodyText` property. - - [01]: https://code.visualstudio.com/docs/editing/userdefinedsnippets#_snippet-syntax - bodyText: - title: - en-US: Snippet body text - description: - en-US: >- - Defines the data to insert for the snippet as a string literal. - markdownDescription: - en-US: |- - Defines the data to insert for the snippet as a string literal. When the user - selects the snippet, VS Code inserts the text _without_ the enclosing quotation - marks at the cursor. You can use [snippet syntax][01] to define tabstops, - placeholders, and variables in the `bodyText`. - - Alternatively, you can define the `body` property for the snippet, which specifies - the text to insert for the snippet as data. - - If you define both the `bodyText` and `body` properties for a snippet, the `body` - definition overrides the `bodyText` property. - - [01]: https://code.visualstudio.com/docs/editing/userdefinedsnippets#_snippet-syntax - - deprecationMessage: - title: - en-US: Deprecation message - description: - en-US: >- - Defines a message to surface as a warning to users when they specify a deprecated property - in their data. - markdownDescription: - en-US: |- - Defines a message to surface as a warning to users when they specify a deprecated property - in their data. - - This keyword only has an affect when defined in a schema or subschema that also defines - the `deprecated` keyword as `true`. When you define the `deprecationMessage` keyword for - a deprecated schema or subschema, VS Code displays the provided message instead of the - default warning about deprecation. - - doNotSuggest: - title: - en-US: Do not suggest - description: - en-US: >- - Indicates whether VS Code should avoid suggesting the property for IntelliSense. - markdownDescription: - en-US: |- - Indicates whether VS Code should avoid suggesting the property for IntelliSense. - - By default, VS Code will show any defined property in the `properties` keyword as a - completion option with IntelliSense. You can define the `doNotSuggest` keyword in a - property subschema as `true` to indicate that VS Code should not show that property for - IntelliSense. - - enumDescriptions: - title: - en-US: Enum descriptions - description: - en-US: >- - Defines per-value descriptions for schemas that use the enum keyword. - markdownDescription: - en-US: |- - Defines per-value descriptions for schemas that use the `enum` keyword. - - The builtin keywords for JSON Schema includes the `description` keyword, which you can use - to document a given schema or subschema. However, for schemas that use the `enum` keyword - to define an array of valid values, JSON Schema provides no keyword for documenting each - value. - - With the `enumDescriptions` keyword from the VS Code vocabulary, you can document each - item in the `enum` keyword array. VS Code interprets each item in `enumDescriptions` as - documenting the item at the same index in the `enum` keyword. - - This documentation is surfaced in VS Code on hover for an enum value and for IntelliSense - when completing an enum value. - - If you want to use Markdown syntax for the annotation, specify the - `markdownEnumDescriptions` keyword instead. - - enumDetails: - title: - en-US: Enum details - description: - en-US: >- - Defines additional information for IntelliSense when completing a proposed enum value, - shown before the description. - markdownDescription: - en-US: |- - Defines additional information for IntelliSense when completing a proposed enum value, - shown before the description. - - By default, when VS Code suggests a completion for an item defined in the `enum` keyword, - VS Code displays hover text with a description. If the schema defined the `description`, - `enumDescriptions`, or `markdownEnumDescriptions` keywords, VS Code displays that text. - The `markdownEnumDescriptions` keyword overrides the `enumDescriptions` keyword, which - overrides the `description` keyword. - - When you define the `enumDetails` keyword, VS Code displays the string for that enum - value as monospace code-formatted text. The keyword expects an array of strings. VS Code - correlates the items in the `enumDetails` keyword to the items in the `enum` keyword by - their index. The first item in `enumDetails` maps to the first item in `enum` and so on. - - enumSortTexts: - title: - en-US: Enum sort text - description: - en-US: >- - Defines a alternate strings to use when sorting a suggestion for enum values. - markdownDescription: - en-US: |- - Defines a alternate strings to use when sorting a suggestion for enum values. - - By default, suggestions are sorted alphabetically, not in the order that you define - items in the `enum` keyword array. You can use the `enumSortText` keyword to override - the order the values are displayed, providing a different string for each value. - - The keyword expects an array of strings. VS Code correlates the items in the - `enumSortText` keyword to the items in the `enum` keyword by their index. The first item - in `enumSortText` maps to the first item in `enum` and so on. - - For example, in the following schema, VS Code will suggest the `baz`, then `bar`, then - `foo` values: - - ```json - { - "type": "string", - "enum": ["foo", "bar", "baz"], - "enumSortText": ["c", "b", "a"] - } - ``` - - errorMessage: - title: - en-US: Validation error message - description: - en-US: >- - Defines a friendly error message to raise when a schema or subschema fails validation. - markdownDescription: - en-US: |- - Defines a friendly error message to raise when a schema or subschema fails validation. - - By default, VS Code surfaces a default error message for data that fails schema - validation, like specifying an invalid type. You can use the `errorMessage` keyword to - define a custom message to raise in the editor when the data fails validation for the - following cases: - - - When the data is an invalid type as validated by the `type` keyword. - - When the subschema defined for the `not` keyword is valid. - - When the data is invalid for the defined values in the `enum` keyword. - - When the data is invalid for the defined value in the `const` keyword. - - When a string doesn't match the regular expression defined in the `pattern` keyword. - This message is overridden by the `patternErrorMessage` keyword if it's defined. - - When a string value doesn't match a required format. - - When the data is for an array that is validated by the `minContains` or `maxContains` - keywords and fails those validations. - - When the data includes a property that was defined in the `properties` keyword as - `false`, forbidding the property. - - When the data includes a property that was defined in the `patternProperties` keyword as - `false`, forbidding matching property names. - - When the data includes a property that wasn't defined in the `properties` or - `patternProperties` keyword and the schema defines `additionalProperties` as `false`. - - When the data includes a property that isn't evaluated by any keywords and the schema - defines `unevaluatedProperties` as `false`. - - The value for the `errorMessage` keyword supercedes all default messages for the schema - or subschema where you define the keyword. You can provide per-validation failure - messages by defining the validating keywords in separate entries of the `allOf` keyword - and defining the `errorMessage` keyword for each entry. - - markdownDescription: - title: - en-US: Markdown description - description: - en-US: >- - Defines documentation for the schema or subschema displayed as hover text in VS Code. - markdownDescription: - en-US: |- - Defines documentation for the schema or subschema displayed as hover text in VS Code. - - By default, VS Code displays the text defined in the `description` keyword in the hover - text for properties and values. VS Code interprets the `description` keyword literally, - without converting any apparent markup. - - You can define the `markdownDescription` keyword to provide descriptive text as markdown, - including links and code blocks. When a schema or subschema defines the - `markdownDescription` keyword, that value supercedes any defined text in the `description` - keyword. - - You can also use the `markdownEnumDescriptions` keyword to document the values defined - for the `enum` keyword. - - For more information, see [Use rich formatting in hovers][01]. - - [01]: https://code.visualstudio.com/Docs/languages/json#_use-rich-formatting-in-hovers - - markdownEnumDescriptions: - title: - en-US: Markdown enum descriptions - description: - en-US: >- - Defines documentation for enum values displayed as hover text in VS Code. - markdownDescription: - en-US: |- - Defines documentation for enum values displayed as hover text in VS Code. - - By default, when a user hovers on or selects completion for a value that is validated by - the `enum` keyword, VS Code displays the text from the `description` or - `markdownDescription` keywords for the schema or subschema. You can use the - `markdownEnumDescriptions` keyword to define documentation for each enum value. - - When a schema or subschema defines the `markdownEnumDescriptions` keyword, that value - supercedes any defined text in the `description`, `markdownDescription`, or - `enumDescriptions` keywords. - - The keyword expects an array of strings. VS Code correlates the items in the - `markdownEnumDescriptions` keyword to the items in the `enum` keyword by their index. The - first item in `markdownEnumDescriptions` maps to the first item in `enum` and so on. - - patternErrorMessage: - title: - en-US: Pattern validation error message - description: - en-US: >- - Defines a friendly error message to raise when a schema or subschema fails validation - for the `pattern` keyword. - markdownDescription: - en-US: |- - Defines a friendly error message to raise when a schema or subschema fails validation - for the `pattern` keyword. - - By default, when a value fails validation for the `pattern` keyword, VS Code raises an - error that informs the user that the value is invalid for the given regular expression, - which it displays in the message. - - Reading and parsing regular expressions can be difficult even for experienced users. You - can define the `patternErrorMessage` keyword to provide better information to the user - about the expected pattern for the string value. - - suggestSortText: - title: - en-US: Suggest sort text - description: - en-US: >- - Defines an alternate string to use when sorting a suggestion. - markdownDescription: - en-US: |- - Defines an alternate string to use when sorting a suggestion. - - By default, suggestions are displayed in alphabetical order. You can define the - `suggestSortText` keyword to change how the suggestions are sorted. For example, in - the following schema, VS Code will suggest the `baz`, then `bar`, then `foo` properties: - - ```json - { - "type": "object", - "properties": { - "foo": { - "suggestSortText": "c", - } - "bar": { - "suggestSortText": "b", - } - "baz": { - "suggestSortText": "a", - } - } - } - ``` diff --git a/lib/dsc-lib-jsonschema/src/vscode/keywords/allow_comments.rs b/lib/dsc-lib-jsonschema/src/vscode/keywords/allow_comments.rs index 69c69bd4d..fccdda7ce 100644 --- a/lib/dsc-lib-jsonschema/src/vscode/keywords/allow_comments.rs +++ b/lib/dsc-lib-jsonschema/src/vscode/keywords/allow_comments.rs @@ -47,9 +47,9 @@ impl JsonSchema for AllowCommentsKeyword { json_schema!({ "$schema": Self::META_SCHEMA, "$id": Self::KEYWORD_ID, - "title": t!("vscode.keywords.allowComments.title"), - "description": t!("vscode.keywords.allowComments.description"), - "markdownDescription": t!("vscode.keywords.allowComments.markdownDescription"), + "title": t!("vscode.keywords.allow_comments.title"), + "description": t!("vscode.keywords.allow_comments.description"), + "markdownDescription": t!("vscode.keywords.allow_comments.markdownDescription"), "type": "boolean", "default": false }) diff --git a/lib/dsc-lib-jsonschema/src/vscode/keywords/allow_trailing_commas.rs b/lib/dsc-lib-jsonschema/src/vscode/keywords/allow_trailing_commas.rs index bcdff529a..69cc13133 100644 --- a/lib/dsc-lib-jsonschema/src/vscode/keywords/allow_trailing_commas.rs +++ b/lib/dsc-lib-jsonschema/src/vscode/keywords/allow_trailing_commas.rs @@ -48,9 +48,9 @@ impl JsonSchema for AllowTrailingCommasKeyword { json_schema!({ "$schema": Self::META_SCHEMA, "$id": Self::KEYWORD_ID, - "title": t!("vscode.keywords.allowTrailingCommas.title"), - "description": t!("vscode.keywords.allowTrailingCommas.description"), - "markdownDescription": t!("vscode.keywords.allowTrailingCommas.markdownDescription"), + "title": t!("vscode.keywords.allow_trailing_commas.title"), + "description": t!("vscode.keywords.allow_trailing_commas.description"), + "markdownDescription": t!("vscode.keywords.allow_trailing_commas.markdownDescription"), "type": "boolean", "default": false }) diff --git a/lib/dsc-lib-jsonschema/src/vscode/keywords/completion_detail.rs b/lib/dsc-lib-jsonschema/src/vscode/keywords/completion_detail.rs index 6be1a3f8c..0fe586c7d 100644 --- a/lib/dsc-lib-jsonschema/src/vscode/keywords/completion_detail.rs +++ b/lib/dsc-lib-jsonschema/src/vscode/keywords/completion_detail.rs @@ -55,9 +55,9 @@ impl JsonSchema for CompletionDetailKeyword { json_schema!({ "$schema": Self::META_SCHEMA, "$id": Self::KEYWORD_ID, - "title": t!("vscode.keywords.completionDetail.title"), - "description": t!("vscode.keywords.completionDetail.description"), - "markdownDescription": t!("vscode.keywords.completionDetail.markdownDescription"), + "title": t!("vscode.keywords.completion_detail.title"), + "description": t!("vscode.keywords.completion_detail.description"), + "markdownDescription": t!("vscode.keywords.completion_detail.markdownDescription"), "type": "string", }) } diff --git a/lib/dsc-lib-jsonschema/src/vscode/keywords/default_snippets.rs b/lib/dsc-lib-jsonschema/src/vscode/keywords/default_snippets.rs index b3c855bf8..2e6670046 100644 --- a/lib/dsc-lib-jsonschema/src/vscode/keywords/default_snippets.rs +++ b/lib/dsc-lib-jsonschema/src/vscode/keywords/default_snippets.rs @@ -166,45 +166,45 @@ impl JsonSchema for DefaultSnippetsKeyword { json_schema!({ "$schema": Self::META_SCHEMA, "$id": Self::KEYWORD_ID, - "title": t!("vscode.keywords.defaultSnippets.title"), - "description": t!("vscode.keywords.defaultSnippets.description"), - "markdownDescription": t!("vscode.keywords.defaultSnippets.markdownDescription"), + "title": t!("vscode.keywords.default_snippets.title"), + "description": t!("vscode.keywords.default_snippets.description"), + "markdownDescription": t!("vscode.keywords.default_snippets.markdownDescription"), "unevaluatedItems": false, "type": "array", "items": { - "title": t!("vscode.keywords.defaultSnippets.items.title"), - "description": t!("vscode.keywords.defaultSnippets.items.description"), - "markdownDescription": t!("vscode.keywords.defaultSnippets.items.markdownDescription"), + "title": t!("vscode.keywords.default_snippets.items.title"), + "description": t!("vscode.keywords.default_snippets.items.description"), + "markdownDescription": t!("vscode.keywords.default_snippets.items.markdownDescription"), "type": "object", "unevaluatedProperties": false, "properties": { "label": { - "title": t!("vscode.keywords.defaultSnippets.items.properties.label.title"), - "description": t!("vscode.keywords.defaultSnippets.items.properties.label.description"), - "markdownDescription": t!("vscode.keywords.defaultSnippets.items.properties.label.markdownDescription"), + "title": t!("vscode.keywords.default_snippets.items.properties.label.title"), + "description": t!("vscode.keywords.default_snippets.items.properties.label.description"), + "markdownDescription": t!("vscode.keywords.default_snippets.items.properties.label.markdownDescription"), "type": "string" }, "description": { - "title": t!("vscode.keywords.defaultSnippets.items.properties.description.title"), - "description": t!("vscode.keywords.defaultSnippets.items.properties.description.description"), - "markdownDescription": t!("vscode.keywords.defaultSnippets.items.properties.description.markdownDescription"), + "title": t!("vscode.keywords.default_snippets.items.properties.description.title"), + "description": t!("vscode.keywords.default_snippets.items.properties.description.description"), + "markdownDescription": t!("vscode.keywords.default_snippets.items.properties.description.markdownDescription"), "type": "string" }, "markdownDescription": { - "title": t!("vscode.keywords.defaultSnippets.items.properties.markdownDescription.title"), - "description": t!("vscode.keywords.defaultSnippets.items.properties.markdownDescription.description"), - "markdownDescription": t!("vscode.keywords.defaultSnippets.items.properties.markdownDescription.markdownDescription"), + "title": t!("vscode.keywords.default_snippets.items.properties.markdownDescription.title"), + "description": t!("vscode.keywords.default_snippets.items.properties.markdownDescription.description"), + "markdownDescription": t!("vscode.keywords.default_snippets.items.properties.markdownDescription.markdownDescription"), "type": "string" }, "body": { - "title": t!("vscode.keywords.defaultSnippets.items.properties.body.title"), - "description": t!("vscode.keywords.defaultSnippets.items.properties.body.description"), - "markdownDescription": t!("vscode.keywords.defaultSnippets.items.properties.body.markdownDescription"), + "title": t!("vscode.keywords.default_snippets.items.properties.body.title"), + "description": t!("vscode.keywords.default_snippets.items.properties.body.description"), + "markdownDescription": t!("vscode.keywords.default_snippets.items.properties.body.markdownDescription"), }, "bodyText": { - "title": t!("vscode.keywords.defaultSnippets.items.properties.bodyText.title"), - "description": t!("vscode.keywords.defaultSnippets.items.properties.bodyText.description"), - "markdownDescription": t!("vscode.keywords.defaultSnippets.items.properties.bodyText.markdownDescription"), + "title": t!("vscode.keywords.default_snippets.items.properties.bodyText.title"), + "description": t!("vscode.keywords.default_snippets.items.properties.bodyText.description"), + "markdownDescription": t!("vscode.keywords.default_snippets.items.properties.bodyText.markdownDescription"), "type": "string" }, }, diff --git a/lib/dsc-lib-jsonschema/src/vscode/keywords/deprecation_message.rs b/lib/dsc-lib-jsonschema/src/vscode/keywords/deprecation_message.rs index 14e9afb99..9badd6d28 100644 --- a/lib/dsc-lib-jsonschema/src/vscode/keywords/deprecation_message.rs +++ b/lib/dsc-lib-jsonschema/src/vscode/keywords/deprecation_message.rs @@ -49,9 +49,9 @@ impl JsonSchema for DeprecationMessageKeyword { json_schema!({ "$schema": Self::META_SCHEMA, "$id": Self::KEYWORD_ID, - "title": t!("vscode.keywords.deprecationMessage.title"), - "description": t!("vscode.keywords.deprecationMessage.description"), - "markdownDescription": t!("vscode.keywords.deprecationMessage.markdownDescription"), + "title": t!("vscode.keywords.deprecation_message.title"), + "description": t!("vscode.keywords.deprecation_message.description"), + "markdownDescription": t!("vscode.keywords.deprecation_message.markdownDescription"), "type": "string", }) } diff --git a/lib/dsc-lib-jsonschema/src/vscode/keywords/do_not_suggest.rs b/lib/dsc-lib-jsonschema/src/vscode/keywords/do_not_suggest.rs index 24b04a742..aae5aa1cb 100644 --- a/lib/dsc-lib-jsonschema/src/vscode/keywords/do_not_suggest.rs +++ b/lib/dsc-lib-jsonschema/src/vscode/keywords/do_not_suggest.rs @@ -48,9 +48,9 @@ impl JsonSchema for DoNotSuggestKeyword { json_schema!({ "$schema": Self::META_SCHEMA, "$id": Self::KEYWORD_ID, - "title": t!("vscode.keywords.doNotSuggest.title"), - "description": t!("vscode.keywords.doNotSuggest.description"), - "markdownDescription": t!("vscode.keywords.doNotSuggest.markdownDescription"), + "title": t!("vscode.keywords.do_not_suggest.title"), + "description": t!("vscode.keywords.do_not_suggest.description"), + "markdownDescription": t!("vscode.keywords.do_not_suggest.markdownDescription"), "type": "boolean", "default": false }) diff --git a/lib/dsc-lib-jsonschema/src/vscode/keywords/enum_descriptions.rs b/lib/dsc-lib-jsonschema/src/vscode/keywords/enum_descriptions.rs index 7637dbd1c..9f12d26a2 100644 --- a/lib/dsc-lib-jsonschema/src/vscode/keywords/enum_descriptions.rs +++ b/lib/dsc-lib-jsonschema/src/vscode/keywords/enum_descriptions.rs @@ -79,9 +79,9 @@ impl JsonSchema for EnumDescriptionsKeyword { json_schema!({ "$schema": Self::META_SCHEMA, "$id": Self::KEYWORD_ID, - "title": t!("vscode.keywords.enumDescriptions.title"), - "description": t!("vscode.keywords.enumDescriptions.description"), - "markdownDescription": t!("vscode.keywords.enumDescriptions.markdownDescription"), + "title": t!("vscode.keywords.enum_descriptions.title"), + "description": t!("vscode.keywords.enum_descriptions.description"), + "markdownDescription": t!("vscode.keywords.enum_descriptions.markdownDescription"), "type": "array", "items": { "type": "string" diff --git a/lib/dsc-lib-jsonschema/src/vscode/keywords/enum_details.rs b/lib/dsc-lib-jsonschema/src/vscode/keywords/enum_details.rs index 1130b8099..5ff7e9ac1 100644 --- a/lib/dsc-lib-jsonschema/src/vscode/keywords/enum_details.rs +++ b/lib/dsc-lib-jsonschema/src/vscode/keywords/enum_details.rs @@ -74,9 +74,9 @@ impl JsonSchema for EnumDetailsKeyword { json_schema!({ "$schema": Self::META_SCHEMA, "$id": Self::KEYWORD_ID, - "title": t!("vscode.keywords.enumDetails.title"), - "description": t!("vscode.keywords.enumDetails.description"), - "markdownDescription": t!("vscode.keywords.enumDetails.markdownDescription"), + "title": t!("vscode.keywords.enum_details.title"), + "description": t!("vscode.keywords.enum_details.description"), + "markdownDescription": t!("vscode.keywords.enum_details.markdownDescription"), "type": "array", "items": { "type": "string" diff --git a/lib/dsc-lib-jsonschema/src/vscode/keywords/enum_sort_texts.rs b/lib/dsc-lib-jsonschema/src/vscode/keywords/enum_sort_texts.rs index f5a5a5bfb..16f29329c 100644 --- a/lib/dsc-lib-jsonschema/src/vscode/keywords/enum_sort_texts.rs +++ b/lib/dsc-lib-jsonschema/src/vscode/keywords/enum_sort_texts.rs @@ -81,9 +81,9 @@ impl JsonSchema for EnumSortTextsKeyword { json_schema!({ "$schema": Self::META_SCHEMA, "$id": Self::KEYWORD_ID, - "title": t!("vscode.keywords.enumSortTexts.title"), - "description": t!("vscode.keywords.enumSortTexts.description"), - "markdownDescription": t!("vscode.keywords.enumSortTexts.markdownDescription"), + "title": t!("vscode.keywords.enum_sort_texts.title"), + "description": t!("vscode.keywords.enum_sort_texts.description"), + "markdownDescription": t!("vscode.keywords.enum_sort_texts.markdownDescription"), "type": "array", "items": { "type": "string" diff --git a/lib/dsc-lib-jsonschema/src/vscode/keywords/error_message.rs b/lib/dsc-lib-jsonschema/src/vscode/keywords/error_message.rs index 7e24e5aa8..2402a3811 100644 --- a/lib/dsc-lib-jsonschema/src/vscode/keywords/error_message.rs +++ b/lib/dsc-lib-jsonschema/src/vscode/keywords/error_message.rs @@ -71,9 +71,9 @@ impl JsonSchema for ErrorMessageKeyword { json_schema!({ "$schema": Self::META_SCHEMA, "$id": Self::KEYWORD_ID, - "title": t!("vscode.keywords.errorMessage.title"), - "description": t!("vscode.keywords.errorMessage.description"), - "markdownDescription": t!("vscode.keywords.errorMessage.markdownDescription"), + "title": t!("vscode.keywords.error_message.title"), + "description": t!("vscode.keywords.error_message.description"), + "markdownDescription": t!("vscode.keywords.error_message.markdownDescription"), "type": "string", }) } diff --git a/lib/dsc-lib-jsonschema/src/vscode/keywords/markdown_description.rs b/lib/dsc-lib-jsonschema/src/vscode/keywords/markdown_description.rs index 2f134e998..9070674bf 100644 --- a/lib/dsc-lib-jsonschema/src/vscode/keywords/markdown_description.rs +++ b/lib/dsc-lib-jsonschema/src/vscode/keywords/markdown_description.rs @@ -59,9 +59,9 @@ impl JsonSchema for MarkdownDescriptionKeyword { json_schema!({ "$schema": Self::META_SCHEMA, "$id": Self::KEYWORD_ID, - "title": t!("vscode.keywords.markdownDescription.title"), - "description": t!("vscode.keywords.markdownDescription.description"), - "markdownDescription": t!("vscode.keywords.markdownDescription.markdownDescription"), + "title": t!("vscode.keywords.markdown_description.title"), + "description": t!("vscode.keywords.markdown_description.description"), + "markdownDescription": t!("vscode.keywords.markdown_description.markdownDescription"), "type": "string", }) } diff --git a/lib/dsc-lib-jsonschema/src/vscode/keywords/markdown_enum_descriptions.rs b/lib/dsc-lib-jsonschema/src/vscode/keywords/markdown_enum_descriptions.rs index 3f1f53262..2a86f28ab 100644 --- a/lib/dsc-lib-jsonschema/src/vscode/keywords/markdown_enum_descriptions.rs +++ b/lib/dsc-lib-jsonschema/src/vscode/keywords/markdown_enum_descriptions.rs @@ -75,9 +75,9 @@ impl JsonSchema for MarkdownEnumDescriptionsKeyword { json_schema!({ "$schema": Self::META_SCHEMA, "$id": Self::KEYWORD_ID, - "title": t!("vscode.keywords.markdownEnumDescriptions.title"), - "description": t!("vscode.keywords.markdownEnumDescriptions.description"), - "markdownDescription": t!("vscode.keywords.markdownEnumDescriptions.markdownDescription"), + "title": t!("vscode.keywords.markdown_enum_descriptions.title"), + "description": t!("vscode.keywords.markdown_enum_descriptions.description"), + "markdownDescription": t!("vscode.keywords.markdown_enum_descriptions.markdownDescription"), "type": "array", "items": { "type": "string" diff --git a/lib/dsc-lib-jsonschema/src/vscode/keywords/pattern_error_message.rs b/lib/dsc-lib-jsonschema/src/vscode/keywords/pattern_error_message.rs index e911c9e8f..958898234 100644 --- a/lib/dsc-lib-jsonschema/src/vscode/keywords/pattern_error_message.rs +++ b/lib/dsc-lib-jsonschema/src/vscode/keywords/pattern_error_message.rs @@ -52,9 +52,9 @@ impl JsonSchema for PatternErrorMessageKeyword { json_schema!({ "$schema": Self::META_SCHEMA, "$id": Self::KEYWORD_ID, - "title": t!("vscode.keywords.patternErrorMessage.title"), - "description": t!("vscode.keywords.patternErrorMessage.description"), - "markdownDescription": t!("vscode.keywords.patternErrorMessage.markdownDescription"), + "title": t!("vscode.keywords.pattern_error_message.title"), + "description": t!("vscode.keywords.pattern_error_message.description"), + "markdownDescription": t!("vscode.keywords.pattern_error_message.markdownDescription"), "type": "string", }) } diff --git a/lib/dsc-lib-jsonschema/src/vscode/keywords/suggest_sort_text.rs b/lib/dsc-lib-jsonschema/src/vscode/keywords/suggest_sort_text.rs index affdb4b0b..8ba74bbef 100644 --- a/lib/dsc-lib-jsonschema/src/vscode/keywords/suggest_sort_text.rs +++ b/lib/dsc-lib-jsonschema/src/vscode/keywords/suggest_sort_text.rs @@ -64,9 +64,9 @@ impl JsonSchema for SuggestSortTextKeyword { json_schema!({ "$schema": Self::META_SCHEMA, "$id": Self::KEYWORD_ID, - "title": t!("vscode.keywords.suggestSortText.title"), - "description": t!("vscode.keywords.suggestSortText.description"), - "markdownDescription": t!("vscode.keywords.suggestSortText.markdownDescription"), + "title": t!("vscode.keywords.suggest_sort_text.title"), + "description": t!("vscode.keywords.suggest_sort_text.description"), + "markdownDescription": t!("vscode.keywords.suggest_sort_text.markdownDescription"), "type": "string", }) } diff --git a/lib/dsc-lib-jsonschema/tests/integration/main.rs b/lib/dsc-lib-jsonschema/tests/integration/main.rs index fc2b4e9e2..0b9ed4418 100644 --- a/lib/dsc-lib-jsonschema/tests/integration/main.rs +++ b/lib/dsc-lib-jsonschema/tests/integration/main.rs @@ -21,4 +21,4 @@ use rust_i18n::i18n; #[cfg(test)] mod dsc_repo; // Enable localization for emitted strings, needed for testing DscRepoSchema -i18n!("./tests/locales", fallback = "en-US"); +i18n!("./tests/integration_locales", fallback = "en-US"); diff --git a/lib/dsc-lib-jsonschema/tests/locales/schemas.yaml b/lib/dsc-lib-jsonschema/tests/integration_locales/schemas.yaml similarity index 100% rename from lib/dsc-lib-jsonschema/tests/locales/schemas.yaml rename to lib/dsc-lib-jsonschema/tests/integration_locales/schemas.yaml From e0e14edc584c69c89f2a23ed9b681c2507017de8 Mon Sep 17 00:00:00 2001 From: Mikey Lombardi Date: Mon, 13 Apr 2026 15:33:37 -0500 Subject: [PATCH 5/5] (MAINT) Address copilot feedback --- .../src/derive/dsc_repo_schema.rs | 2 +- lib/dsc-lib-jsonschema/locales/en-us.toml | 10 +++++----- lib/dsc-lib-jsonschema/src/dsc_repo/dsc_repo_schema.rs | 5 ----- lib/dsc-lib-jsonschema/src/dsc_repo/macros.rs | 4 ++-- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/lib/dsc-lib-jsonschema-macros/src/derive/dsc_repo_schema.rs b/lib/dsc-lib-jsonschema-macros/src/derive/dsc_repo_schema.rs index b25589553..b26ddcd34 100644 --- a/lib/dsc-lib-jsonschema-macros/src/derive/dsc_repo_schema.rs +++ b/lib/dsc-lib-jsonschema-macros/src/derive/dsc_repo_schema.rs @@ -192,7 +192,7 @@ fn generate_schema_property_metadata_fn(schema_field: &DscRepoSchemaField) -> pr } } -/// Generates a crate-local implementation for the `lookup_translation()` trait function. This is +/// Generates a crate-local implementation for the `schema_i18n()` trait function. This is /// required to ensure that the translations use the correct locale definitions. fn generate_schema_i18n_fn() -> proc_macro2::TokenStream { quote! { diff --git a/lib/dsc-lib-jsonschema/locales/en-us.toml b/lib/dsc-lib-jsonschema/locales/en-us.toml index 92bc235dd..d0a0b263b 100644 --- a/lib/dsc-lib-jsonschema/locales/en-us.toml +++ b/lib/dsc-lib-jsonschema/locales/en-us.toml @@ -205,12 +205,12 @@ Each item defines a snippet for users that VS Code will surface as part of Intel Every snippet must define either the `body` or `bodyText` property, which VS Code uses to insert the snippet into the data file. If you specify both `body` and `bodyText`, the -value for `body` supercedes the value for `bodyText`. +value for `body` supersedes the value for `bodyText`. The `description`, and `markdownDescription` properties provide documentation for the snippet and are displayed in the hover text when a user selects the snippet. If you specify both `description` and `markdownDescription`, the text for -`markdownDescription` supercedes the text for `description`. +`markdownDescription` supersedes the text for `description`. The `label` property defines a short name for the snippet. If the snippet doesn't define the `label` property, VS Code shows a stringified representation of the snippet instead. @@ -430,7 +430,7 @@ keywords and fails those validations. - When the data includes a property that isn't evaluated by any keywords and the schema defines `unevaluatedProperties` as `false`. -The value for the `errorMessage` keyword supercedes all default messages for the schema +The value for the `errorMessage` keyword supersedes all default messages for the schema or subschema where you define the keyword. You can provide per-validation failure messages by defining the validating keywords in separate entries of the `allOf` keyword and defining the `errorMessage` keyword for each entry. @@ -449,7 +449,7 @@ without converting any apparent markup. You can define the `markdownDescription` keyword to provide descriptive text as markdown, including links and code blocks. When a schema or subschema defines the -`markdownDescription` keyword, that value supercedes any defined text in the `description` +`markdownDescription` keyword, that value supersedes any defined text in the `description` keyword. You can also use the `markdownEnumDescriptions` keyword to document the values defined @@ -475,7 +475,7 @@ the `enum` keyword, VS Code displays the text from the `description` or `markdownEnumDescriptions` keyword to define documentation for each enum value. When a schema or subschema defines the `markdownEnumDescriptions` keyword, that value -supercedes any defined text in the `description`, `markdownDescription`, or +supersedes any defined text in the `description`, `markdownDescription`, or `enumDescriptions` keywords. The keyword expects an array of strings. VS Code correlates the items in the 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 04f1b8a78..f017a0780 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 @@ -356,11 +356,6 @@ pub trait DscRepoSchema : JsonSchema { /// # Errors /// /// Returns a [`DscRepoSchemaMissingTranslation`] error if the translation key doesn't exist. - /// - /// # Example - /// - /// ```ignore - /// ``` fn schema_i18n(suffix: &str) -> Result; } diff --git a/lib/dsc-lib-jsonschema/src/dsc_repo/macros.rs b/lib/dsc-lib-jsonschema/src/dsc_repo/macros.rs index 88a3c9458..8d05a3b9e 100644 --- a/lib/dsc-lib-jsonschema/src/dsc_repo/macros.rs +++ b/lib/dsc-lib-jsonschema/src/dsc_repo/macros.rs @@ -1,6 +1,6 @@ #[macro_export] macro_rules! schema_i18n { - ($dotPath: literal) => { - Self::schema_i18n($dotPath).unwrap() + ($dot_path: literal) => { + Self::schema_i18n($dot_path).unwrap() }; }