diff --git a/schema/2025-11-25/schema.json b/schema/2025-11-25/schema.json index 9d2e662a2..c722dd45b 100644 --- a/schema/2025-11-25/schema.json +++ b/schema/2025-11-25/schema.json @@ -2107,16 +2107,16 @@ "NumberSchema": { "properties": { "default": { - "type": "integer" + "type": "number" }, "description": { "type": "string" }, "maximum": { - "type": "integer" + "type": "number" }, "minimum": { - "type": "integer" + "type": "number" }, "title": { "type": "string" diff --git a/schema/draft/schema.json b/schema/draft/schema.json index 4cc8b3bc8..d0ef9b44f 100644 --- a/schema/draft/schema.json +++ b/schema/draft/schema.json @@ -2509,16 +2509,16 @@ "NumberSchema": { "properties": { "default": { - "type": "integer" + "type": "number" }, "description": { "type": "string" }, "maximum": { - "type": "integer" + "type": "number" }, "minimum": { - "type": "integer" + "type": "number" }, "title": { "type": "string" diff --git a/scripts/generate-schemas.ts b/scripts/generate-schemas.ts index 294dad44e..d4dbe0f55 100644 --- a/scripts/generate-schemas.ts +++ b/scripts/generate-schemas.ts @@ -19,6 +19,31 @@ const ALL_SCHEMAS = [...LEGACY_SCHEMAS, ...MODERN_SCHEMAS]; // Check if we're in check mode (validate existing schemas match generated ones) const CHECK_MODE = process.argv.includes('--check'); +/** + * Fix NumberSchema properties that should be `number` type instead of `integer`. + * + * The `--defaultNumberType integer` flag used during schema generation converts + * all TypeScript `number` types to JSON Schema `integer`. This is correct for + * most fields (request IDs, ports, etc.) but wrong for `NumberSchema.minimum`, + * `NumberSchema.maximum`, and `NumberSchema.default`, which must accept number + * values because they define constraints for schemas with `"type": "number"`. + */ +function fixNumberSchemaTypes(schemaPath: string): void { + let content = readFileSync(schemaPath, 'utf-8'); + const schema = JSON.parse(content); + + const numberSchema = schema.$defs?.NumberSchema ?? schema.definitions?.NumberSchema; + if (numberSchema?.properties) { + for (const prop of ['minimum', 'maximum', 'default']) { + if (numberSchema.properties[prop]?.type === 'integer') { + numberSchema.properties[prop].type = 'number'; + } + } + } + + writeFileSync(schemaPath, JSON.stringify(schema, null, 2) + '\n', 'utf-8'); +} + /** * Apply JSON Schema 2020-12 transformations to a schema file */ @@ -76,6 +101,18 @@ async function generateSchema(version: string, check: boolean = false): Promise< expectedSchema = expectedSchema.replace(/#\/definitions\//g, '#/$defs/'); } + // Fix NumberSchema properties that were incorrectly converted to integer + const parsedSchema = JSON.parse(expectedSchema); + const numberSchema = parsedSchema.$defs?.NumberSchema ?? parsedSchema.definitions?.NumberSchema; + if (numberSchema?.properties) { + for (const prop of ['minimum', 'maximum', 'default']) { + if (numberSchema.properties[prop]?.type === 'integer') { + numberSchema.properties[prop].type = 'number'; + } + } + } + expectedSchema = JSON.stringify(parsedSchema, null, 2) + '\n'; + // Compare if (existingSchema.trim() !== expectedSchema.trim()) { console.error(` ✗ Schema ${version} is out of date!`); @@ -99,6 +136,9 @@ async function generateSchema(version: string, check: boolean = false): Promise< throw error; } + // Fix NumberSchema properties that were incorrectly converted to integer + fixNumberSchemaTypes(schemaJson); + // Apply transformations for non-legacy schemas if (!LEGACY_SCHEMAS.includes(version)) { applyJsonSchema202012Transformations(schemaJson);