Default `#[schemars(deny_unknown_fields)] for json-language-server schemas (#33883)

Followup to #33678, doing the same thing for all JSON Schema files
provided to json-language-server

Release Notes:

* Added warnings for unknown fields when editing `tasks.json` /
`snippets.json`.
This commit is contained in:
Michael Sloan 2025-07-03 18:57:43 -06:00 committed by GitHub
parent 38544e514a
commit ed7552d3e3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 136 additions and 149 deletions

View file

@ -1,10 +1,8 @@
use anyhow::Result;
use gpui::SharedString;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_json::json;
/// Represents a schema for a specific adapter
/// JSON schema for a specific adapter
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
pub struct AdapterSchema {
/// The adapter name identifier
@ -16,47 +14,3 @@ pub struct AdapterSchema {
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(transparent)]
pub struct AdapterSchemas(pub Vec<AdapterSchema>);
impl AdapterSchemas {
pub fn generate_json_schema(&self) -> Result<serde_json_lenient::Value> {
let adapter_conditions = self
.0
.iter()
.map(|adapter_schema| {
let adapter_name = adapter_schema.adapter.to_string();
json!({
"if": {
"properties": {
"adapter": { "const": adapter_name }
}
},
"then": adapter_schema.schema
})
})
.collect::<Vec<_>>();
let schema = serde_json_lenient::json!({
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Debug Adapter Configurations",
"description": "Configuration for debug adapters. Schema changes based on the selected adapter.",
"type": "array",
"items": {
"type": "object",
"required": ["adapter", "label"],
"properties": {
"adapter": {
"type": "string",
"description": "The name of the debug adapter"
},
"label": {
"type": "string",
"description": "The name of the debug configuration"
},
},
"allOf": adapter_conditions
}
});
Ok(serde_json_lenient::to_value(schema)?)
}
}

View file

@ -6,7 +6,7 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::net::Ipv4Addr;
use std::path::PathBuf;
use util::debug_panic;
use util::{debug_panic, schemars::add_new_subschema};
use crate::{TaskTemplate, adapter_schema::AdapterSchemas};
@ -286,11 +286,10 @@ pub struct DebugScenario {
pub struct DebugTaskFile(pub Vec<DebugScenario>);
impl DebugTaskFile {
pub fn generate_json_schema(schemas: &AdapterSchemas) -> serde_json_lenient::Value {
pub fn generate_json_schema(schemas: &AdapterSchemas) -> serde_json::Value {
let mut generator = schemars::generate::SchemaSettings::draft2019_09().into_generator();
let build_task_schema = generator.root_schema_for::<BuildTaskDefinition>();
let mut build_task_value =
serde_json_lenient::to_value(&build_task_schema).unwrap_or_default();
let mut build_task_value = BuildTaskDefinition::json_schema(&mut generator).to_value();
if let Some(template_object) = build_task_value
.get_mut("anyOf")
@ -322,32 +321,54 @@ impl DebugTaskFile {
);
}
let task_definitions = build_task_value.get("$defs").cloned().unwrap_or_default();
let adapter_conditions = schemas
.0
.iter()
.map(|adapter_schema| {
let adapter_name = adapter_schema.adapter.to_string();
serde_json::json!({
"if": {
"properties": {
"adapter": { "const": adapter_name }
}
},
"then": adapter_schema.schema
})
add_new_subschema(
&mut generator,
&format!("{adapter_name}DebugSettings"),
serde_json::json!({
"if": {
"properties": {
"adapter": { "const": adapter_name }
}
},
"then": adapter_schema.schema
}),
)
})
.collect::<Vec<_>>();
serde_json_lenient::json!({
"$schema": "http://json-schema.org/draft-07/schema#",
let build_task_definition_ref = add_new_subschema(
&mut generator,
BuildTaskDefinition::schema_name().as_ref(),
build_task_value,
);
let meta_schema = generator
.settings()
.meta_schema
.as_ref()
.expect("meta_schema should be present in schemars settings")
.to_string();
serde_json::json!({
"$schema": meta_schema,
"title": "Debug Configurations",
"description": "Configuration for debug scenarios",
"type": "array",
"items": {
"type": "object",
"required": ["adapter", "label"],
// TODO: Uncommenting this will cause json-language-server to provide warnings for
// unrecognized properties. It should be enabled if/when there's an adapter JSON
// schema that's comprehensive. In order to not get warnings for the other schemas,
// `additionalProperties` or `unevaluatedProperties` (to handle "allOf" etc style
// schema combinations) could be set to `true` for that schema.
//
// "unevaluatedProperties": false,
"properties": {
"adapter": {
"type": "string",
@ -357,7 +378,7 @@ impl DebugTaskFile {
"type": "string",
"description": "The name of the debug configuration"
},
"build": build_task_value,
"build": build_task_definition_ref,
"tcp_connection": {
"type": "object",
"description": "Optional TCP connection information for connecting to an already running debug adapter",
@ -380,7 +401,7 @@ impl DebugTaskFile {
},
"allOf": adapter_conditions
},
"$defs": task_definitions
"$defs": generator.take_definitions(true),
})
}
}

View file

@ -4,6 +4,7 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::path::PathBuf;
use util::schemars::DefaultDenyUnknownFields;
use util::serde::default_true;
use util::{ResultExt, truncate_and_remove_front};
@ -116,6 +117,7 @@ impl TaskTemplates {
/// Generates JSON schema of Tasks JSON template format.
pub fn generate_json_schema() -> serde_json_lenient::Value {
let schema = schemars::generate::SchemaSettings::draft2019_09()
.with_transform(DefaultDenyUnknownFields)
.into_generator()
.root_schema_for::<Self>();