From cd8679e81a2d3c32b10bf65a3d583b6886d2a2f3 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Thu, 4 Dec 2025 12:37:32 -0800 Subject: [PATCH] Allow trailing commas in builtin JSONC schemas (#43854) The JSON language server looks for a top-level `allowTrailingCommas` flag to decide whether it should warn for trailing commas. Since the JSONC parser for these builtin files can handles trailing commas, adding this flag to the schema also prevents a warning for those commas. I don't think there's an issue that is only for this specific issue, but it relates to *many* existing / older issues: - #18509 - #17487 - #40970 - #18509 - #21303 Release Notes: - Suppress warning for trailing commas in builtin JSON files (`settings.json`, `keymap.json`, etc.) --- crates/settings/src/keymap_file.rs | 5 ++++- crates/settings/src/settings_store.rs | 3 ++- crates/snippet_provider/src/format.rs | 3 ++- crates/task/src/debug_format.rs | 1 + crates/task/src/task_template.rs | 3 ++- crates/util/src/schemars.rs | 17 +++++++++++++++++ 6 files changed, 28 insertions(+), 4 deletions(-) diff --git a/crates/settings/src/keymap_file.rs b/crates/settings/src/keymap_file.rs index fc86afca2a1cbcd0a26777aa2ccb1fcb29b193a5..2ef1dfc5385592b9757eff5ec631af818ae1869c 100644 --- a/crates/settings/src/keymap_file.rs +++ b/crates/settings/src/keymap_file.rs @@ -15,6 +15,7 @@ use util::ResultExt as _; use util::{ asset_str, markdown::{MarkdownEscaped, MarkdownInlineCode, MarkdownString}, + schemars::AllowTrailingCommas, }; use crate::SettingsAssets; @@ -451,7 +452,9 @@ impl KeymapFile { /// Creates a JSON schema generator, suitable for generating json schemas /// for actions pub fn action_schema_generator() -> schemars::SchemaGenerator { - schemars::generate::SchemaSettings::draft2019_09().into_generator() + schemars::generate::SchemaSettings::draft2019_09() + .with_transform(AllowTrailingCommas) + .into_generator() } pub fn generate_json_schema_for_registered_actions(cx: &mut App) -> Value { diff --git a/crates/settings/src/settings_store.rs b/crates/settings/src/settings_store.rs index 181b8b417879be63fe85dbe6d08adca2d97929bd..72e2d3ef099659c5ad27e7f1aaafaee24354d4a9 100644 --- a/crates/settings/src/settings_store.rs +++ b/crates/settings/src/settings_store.rs @@ -25,7 +25,7 @@ use std::{ use util::{ ResultExt as _, rel_path::RelPath, - schemars::{DefaultDenyUnknownFields, replace_subschema}, + schemars::{AllowTrailingCommas, DefaultDenyUnknownFields, replace_subschema}, }; pub type EditorconfigProperties = ec4rs::Properties; @@ -1010,6 +1010,7 @@ impl SettingsStore { pub fn json_schema(&self, params: &SettingsJsonSchemaParams) -> Value { let mut generator = schemars::generate::SchemaSettings::draft2019_09() .with_transform(DefaultDenyUnknownFields) + .with_transform(AllowTrailingCommas) .into_generator(); UserSettingsContent::json_schema(&mut generator); diff --git a/crates/snippet_provider/src/format.rs b/crates/snippet_provider/src/format.rs index 0bbf137aed506f4cc7793f5dbe80ee144b620bf4..f9abb987d919b3a8bc7ab558e4bc86bac5e0b5a9 100644 --- a/crates/snippet_provider/src/format.rs +++ b/crates/snippet_provider/src/format.rs @@ -2,7 +2,7 @@ use collections::HashMap; use schemars::{JsonSchema, json_schema}; use serde::Deserialize; use std::borrow::Cow; -use util::schemars::DefaultDenyUnknownFields; +use util::schemars::{AllowTrailingCommas, DefaultDenyUnknownFields}; #[derive(Deserialize)] pub struct VsSnippetsFile { @@ -14,6 +14,7 @@ impl VsSnippetsFile { pub fn generate_json_schema() -> serde_json::Value { let schema = schemars::generate::SchemaSettings::draft2019_09() .with_transform(DefaultDenyUnknownFields) + .with_transform(AllowTrailingCommas) .into_generator() .root_schema_for::(); diff --git a/crates/task/src/debug_format.rs b/crates/task/src/debug_format.rs index 38089670e23f815221c274a2ccc4619b9e8bb327..5609e2565c8497ad2e92fb8b7d0e6738a1cb663c 100644 --- a/crates/task/src/debug_format.rs +++ b/crates/task/src/debug_format.rs @@ -357,6 +357,7 @@ impl DebugTaskFile { "$schema": meta_schema, "title": "Debug Configurations", "description": "Configuration for debug scenarios", + "allowTrailingCommas": true, "type": "array", "items": { "type": "object", diff --git a/crates/task/src/task_template.rs b/crates/task/src/task_template.rs index 33ff610b6e1ba509c75138ad4bf35478e69deaf1..0c319db0616862489b7b7d21912142a01ee89fcb 100644 --- a/crates/task/src/task_template.rs +++ b/crates/task/src/task_template.rs @@ -4,7 +4,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use std::path::PathBuf; -use util::schemars::DefaultDenyUnknownFields; +use util::schemars::{AllowTrailingCommas, DefaultDenyUnknownFields}; use util::serde::default_true; use util::{ResultExt, truncate_and_remove_front}; @@ -118,6 +118,7 @@ impl TaskTemplates { pub fn generate_json_schema() -> serde_json::Value { let schema = schemars::generate::SchemaSettings::draft2019_09() .with_transform(DefaultDenyUnknownFields) + .with_transform(AllowTrailingCommas) .into_generator() .root_schema_for::(); diff --git a/crates/util/src/schemars.rs b/crates/util/src/schemars.rs index 9314eda4ac4d5003d7186c3115137e2e54c66794..8124ca8cfef62cb4ea320da6423d7ad95a09eb78 100644 --- a/crates/util/src/schemars.rs +++ b/crates/util/src/schemars.rs @@ -53,3 +53,20 @@ impl schemars::transform::Transform for DefaultDenyUnknownFields { transform_subschemas(self, schema); } } + +/// Defaults `allowTrailingCommas` to `true`, for use with `json-language-server`. +/// This can be applied to any schema that will be treated as `jsonc`. +/// +/// Note that this is non-recursive and only applied to the root schema. +#[derive(Clone)] +pub struct AllowTrailingCommas; + +impl schemars::transform::Transform for AllowTrailingCommas { + fn transform(&mut self, schema: &mut schemars::Schema) { + if let Some(object) = schema.as_object_mut() + && !object.contains_key("allowTrailingCommas") + { + object.insert("allowTrailingCommas".to_string(), true.into()); + } + } +}