diff --git a/packages/quicktype-core/src/input/JSONSchemaInput.ts b/packages/quicktype-core/src/input/JSONSchemaInput.ts index 66b1c4104..83d6cdf4d 100644 --- a/packages/quicktype-core/src/input/JSONSchemaInput.ts +++ b/packages/quicktype-core/src/input/JSONSchemaInput.ts @@ -1139,14 +1139,22 @@ async function addTypesInSchema( } let additionalProperties = schema.additionalProperties; - // This is an incorrect hack to fix an issue with a Go->Schema generator: + // This is an incorrect hack to treat a single pattern property as + // additional properties: // https://github.com/quicktype/quicktype/issues/976 + // https://github.com/quicktype/quicktype/issues/1464 if ( additionalProperties === undefined && typeof schema.patternProperties === "object" && - hasOwnProperty(schema.patternProperties, ".*") + schema.patternProperties !== null ) { - additionalProperties = schema.patternProperties[".*"]; + const patterns = Object.getOwnPropertyNames( + schema.patternProperties, + ); + if (patterns.length === 1) { + additionalProperties = + schema.patternProperties[patterns[0]]; + } } // Handle unevaluatedProperties if additionalProperties is not defined diff --git a/test/inputs/schema/pattern-properties.1.fail.json b/test/inputs/schema/pattern-properties.1.fail.json new file mode 100644 index 000000000..79d21bcfc --- /dev/null +++ b/test/inputs/schema/pattern-properties.1.fail.json @@ -0,0 +1,3 @@ +{ + "enabled": {} +} diff --git a/test/inputs/schema/pattern-properties.1.json b/test/inputs/schema/pattern-properties.1.json new file mode 100644 index 000000000..4e609c71b --- /dev/null +++ b/test/inputs/schema/pattern-properties.1.json @@ -0,0 +1,3 @@ +{ + "enabled": true +} diff --git a/test/inputs/schema/pattern-properties.schema b/test/inputs/schema/pattern-properties.schema new file mode 100644 index 000000000..0aa1fd9aa --- /dev/null +++ b/test/inputs/schema/pattern-properties.schema @@ -0,0 +1,9 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "patternProperties": { + "^[a-zA-Z]\\w*$": { + "type": "boolean" + } + } +} diff --git a/test/languages.ts b/test/languages.ts index 120f3170b..2e2c028e9 100644 --- a/test/languages.ts +++ b/test/languages.ts @@ -56,6 +56,10 @@ const skipsUntypedUnions = [ const skipsMapValueValidation = [ "go-schema-pattern-properties.schema", "unevaluated-properties.schema", + // These languages deserialize a map without validating the value type + // (unchecked generic casts, raw map readers, or no runtime type checks), + // so the `{"enabled": {}}` fail sample round-trips instead of failing. + "pattern-properties.schema", ]; // The generated deserializer for a top-level array of scalars uses a @@ -263,6 +267,11 @@ export const JavaLanguage: Language = { skipSchema: [ "integer-before-number.schema", // Python-specific union-order regression. "keyword-unions.schema", // generates classes with names that are case-insensitively equal + // A top-level map deserializes via a raw `Map.class` reader + // (javaTypeWithoutGenerics drops the value type), so map value + // types are not validated on parse and the fail sample does not + // fail. Nested typed maps are still validated elsewhere. + "pattern-properties.schema", // The generated converter deserializes a top-level array with a raw // `List`, so a mistyped element round-trips instead of failing. ...skipsArrayElementValidation, @@ -1976,6 +1985,9 @@ export const PHPLanguage: Language = { "top-level-enum.schema", // The driver does not support top-level arrays. "union.schema", + // PHP has no type aliases, so a top-level map produces no named + // TopLevel class and the driver's TopLevel::from() call fails. + "pattern-properties.schema", "issue2680-top-level-array.schema", ], rendererOptions: {},