-
-
Notifications
You must be signed in to change notification settings - Fork 0
Fully support allOf
#25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| export type AllOfIntersection_1Age = number; | ||
|
|
||
| export type AllOfIntersection_1AdditionalProperties = never; | ||
|
|
||
| export interface AllOfIntersection_1 { | ||
| "age": AllOfIntersection_1Age; | ||
| } | ||
|
|
||
| export type AllOfIntersection_0Name = string; | ||
|
|
||
| export type AllOfIntersection_0AdditionalProperties = never; | ||
|
|
||
| export interface AllOfIntersection_0 { | ||
| "name": AllOfIntersection_0Name; | ||
| } | ||
|
|
||
| export type AllOfIntersection = | ||
| AllOfIntersection_0 & | ||
| AllOfIntersection_1; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| { | ||
| "defaultPrefix": "AllOfIntersection" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| { | ||
| "$schema": "https://json-schema.org/draft/2020-12/schema", | ||
| "allOf": [ | ||
| { | ||
| "type": "object", | ||
| "properties": { | ||
| "name": { "type": "string" } | ||
| }, | ||
| "required": [ "name" ], | ||
| "additionalProperties": false | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Severity: medium Other Locations
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage. |
||
| }, | ||
| { | ||
| "type": "object", | ||
| "properties": { | ||
| "age": { "type": "integer" } | ||
| }, | ||
| "required": [ "age" ], | ||
| "additionalProperties": false | ||
| } | ||
| ] | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| import { AllOfIntersection } from "./expected"; | ||
|
|
||
| // Valid: satisfies both branches | ||
| const valid: AllOfIntersection = { | ||
| name: "Alice", | ||
| age: 30 | ||
| }; | ||
|
|
||
| // Invalid: missing age from second branch | ||
| // @ts-expect-error | ||
| const missingAge: AllOfIntersection = { | ||
| name: "Bob" | ||
| }; | ||
|
|
||
| // Invalid: missing name from first branch | ||
| // @ts-expect-error | ||
| const missingName: AllOfIntersection = { | ||
| age: 25 | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| export type Person_1 = PersonAged; | ||
|
|
||
| export type Person_0 = PersonNamed; | ||
|
|
||
| export type PersonNamedName = string; | ||
|
|
||
| export type PersonNamedAdditionalProperties = never; | ||
|
|
||
| export interface PersonNamed { | ||
| "name": PersonNamedName; | ||
| } | ||
|
|
||
| export type PersonAgedAge = number; | ||
|
|
||
| export type PersonAgedAdditionalProperties = never; | ||
|
|
||
| export interface PersonAged { | ||
| "age": PersonAgedAge; | ||
| } | ||
|
|
||
| export type Person = | ||
| Person_0 & | ||
| Person_1; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| { | ||
| "defaultPrefix": "Person" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| { | ||
| "$schema": "https://json-schema.org/draft/2020-12/schema", | ||
| "$defs": { | ||
| "Named": { | ||
| "type": "object", | ||
| "properties": { | ||
| "name": { "type": "string" } | ||
| }, | ||
| "required": [ "name" ], | ||
| "additionalProperties": false | ||
| }, | ||
| "Aged": { | ||
| "type": "object", | ||
| "properties": { | ||
| "age": { "type": "integer" } | ||
| }, | ||
| "required": [ "age" ], | ||
| "additionalProperties": false | ||
| } | ||
| }, | ||
| "allOf": [ | ||
| { "$ref": "#/$defs/Named" }, | ||
| { "$ref": "#/$defs/Aged" } | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| import { Person } from "./expected"; | ||
|
|
||
| // Valid: satisfies both $ref branches | ||
| const valid: Person = { | ||
| name: "Alice", | ||
| age: 30 | ||
| }; | ||
|
|
||
| // Invalid: missing age | ||
| // @ts-expect-error | ||
| const missingAge: Person = { | ||
| name: "Bob" | ||
| }; | ||
|
|
||
| // Invalid: missing name | ||
| // @ts-expect-error | ||
| const missingName: Person = { | ||
| age: 25 | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| export type Wrapper_0Value = string; | ||
|
|
||
| export type Wrapper_0AdditionalProperties = never; | ||
|
|
||
| export interface Wrapper_0 { | ||
| "value": Wrapper_0Value; | ||
| } | ||
|
|
||
| export type Wrapper = Wrapper_0; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| { | ||
| "defaultPrefix": "Wrapper" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| { | ||
| "$schema": "https://json-schema.org/draft/2020-12/schema", | ||
| "allOf": [ | ||
| { | ||
| "type": "object", | ||
| "properties": { | ||
| "value": { "type": "string" } | ||
| }, | ||
| "required": [ "value" ], | ||
| "additionalProperties": false | ||
| } | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| import { Wrapper } from "./expected"; | ||
|
|
||
| // Valid: single-element allOf acts as the element itself | ||
| const valid: Wrapper = { | ||
| value: "hello" | ||
| }; | ||
|
|
||
| // Invalid: missing required value | ||
| // @ts-expect-error | ||
| const missingValue: Wrapper = {}; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1393,3 +1393,170 @@ TEST(IR_2020_12, dynamic_anchor_on_typed_schema) { | |
| EXPECT_EQ(result.size(), 1); | ||
| EXPECT_IR_SCALAR(result, 0, String, ""); | ||
| } | ||
|
|
||
| TEST(IR_2020_12, allof_two_objects) { | ||
| const sourcemeta::core::JSON schema{sourcemeta::core::parse_json(R"JSON({ | ||
| "$schema": "https://json-schema.org/draft/2020-12/schema", | ||
| "allOf": [ | ||
| { | ||
| "type": "object", | ||
| "properties": { "name": { "type": "string" } }, | ||
| "required": [ "name" ], | ||
| "additionalProperties": false | ||
| }, | ||
| { | ||
| "type": "object", | ||
| "properties": { "age": { "type": "integer" } }, | ||
| "required": [ "age" ], | ||
| "additionalProperties": false | ||
| } | ||
| ] | ||
| })JSON")}; | ||
|
|
||
| const auto result{ | ||
| sourcemeta::codegen::compile(schema, sourcemeta::core::schema_walker, | ||
| sourcemeta::core::schema_resolver, | ||
| sourcemeta::codegen::default_compiler)}; | ||
|
|
||
| using namespace sourcemeta::codegen; | ||
|
|
||
| ASSERT_EQ(result.size(), 7); | ||
| EXPECT_IR_INTERSECTION(result, 6, "", 2); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This test hard-codes the intersection node at index Severity: low 🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage. |
||
| } | ||
|
|
||
| TEST(IR_2020_12, allof_ref_and_object) { | ||
| const sourcemeta::core::JSON schema{sourcemeta::core::parse_json(R"JSON({ | ||
| "$schema": "https://json-schema.org/draft/2020-12/schema", | ||
| "allOf": [ | ||
| { "$ref": "#/$defs/Base" }, | ||
| { | ||
| "type": "object", | ||
| "properties": { "extra": { "type": "string" } }, | ||
| "additionalProperties": false | ||
| } | ||
| ], | ||
| "$defs": { | ||
| "Base": { | ||
| "type": "object", | ||
| "properties": { "id": { "type": "integer" } }, | ||
| "required": [ "id" ], | ||
| "additionalProperties": false | ||
| } | ||
| } | ||
| })JSON")}; | ||
|
|
||
| const auto result{ | ||
| sourcemeta::codegen::compile(schema, sourcemeta::core::schema_walker, | ||
| sourcemeta::core::schema_resolver, | ||
| sourcemeta::codegen::default_compiler)}; | ||
|
|
||
| using namespace sourcemeta::codegen; | ||
|
|
||
| EXPECT_IR_INTERSECTION(result, result.size() - 1, "", 2); | ||
| } | ||
|
|
||
| TEST(IR_2020_12, allof_single_element) { | ||
| const sourcemeta::core::JSON schema{sourcemeta::core::parse_json(R"JSON({ | ||
| "$schema": "https://json-schema.org/draft/2020-12/schema", | ||
| "allOf": [ | ||
| { "type": "string" } | ||
| ] | ||
| })JSON")}; | ||
|
|
||
| const auto result{ | ||
| sourcemeta::codegen::compile(schema, sourcemeta::core::schema_walker, | ||
| sourcemeta::core::schema_resolver, | ||
| sourcemeta::codegen::default_compiler)}; | ||
|
|
||
| using namespace sourcemeta::codegen; | ||
|
|
||
| ASSERT_EQ(result.size(), 2); | ||
| EXPECT_IR_SCALAR(result, 0, String, "/allOf/0"); | ||
| EXPECT_IR_REFERENCE(result, 1, "", "/allOf/0"); | ||
| } | ||
|
|
||
| TEST(IR_2020_12, allof_three_branches) { | ||
| const sourcemeta::core::JSON schema{sourcemeta::core::parse_json(R"JSON({ | ||
| "$schema": "https://json-schema.org/draft/2020-12/schema", | ||
| "allOf": [ | ||
| { | ||
| "type": "object", | ||
| "properties": { "a": { "type": "string" } }, | ||
| "additionalProperties": false | ||
| }, | ||
| { | ||
| "type": "object", | ||
| "properties": { "b": { "type": "integer" } }, | ||
| "additionalProperties": false | ||
| }, | ||
| { | ||
| "type": "object", | ||
| "properties": { "c": { "type": "number" } }, | ||
| "additionalProperties": false | ||
| } | ||
| ] | ||
| })JSON")}; | ||
|
|
||
| const auto result{ | ||
| sourcemeta::codegen::compile(schema, sourcemeta::core::schema_walker, | ||
| sourcemeta::core::schema_resolver, | ||
| sourcemeta::codegen::default_compiler)}; | ||
|
|
||
| using namespace sourcemeta::codegen; | ||
|
|
||
| EXPECT_IR_INTERSECTION(result, result.size() - 1, "", 3); | ||
| } | ||
|
|
||
| TEST(IR_2020_12, allof_with_defs) { | ||
| const sourcemeta::core::JSON schema{sourcemeta::core::parse_json(R"JSON({ | ||
| "$schema": "https://json-schema.org/draft/2020-12/schema", | ||
| "$defs": { | ||
| "Named": { | ||
| "type": "object", | ||
| "properties": { "name": { "type": "string" } }, | ||
| "required": [ "name" ], | ||
| "additionalProperties": false | ||
| }, | ||
| "Aged": { | ||
| "type": "object", | ||
| "properties": { "age": { "type": "integer" } }, | ||
| "required": [ "age" ], | ||
| "additionalProperties": false | ||
| } | ||
| }, | ||
| "allOf": [ | ||
| { "$ref": "#/$defs/Named" }, | ||
| { "$ref": "#/$defs/Aged" } | ||
| ] | ||
| })JSON")}; | ||
|
|
||
| const auto result{ | ||
| sourcemeta::codegen::compile(schema, sourcemeta::core::schema_walker, | ||
| sourcemeta::core::schema_resolver, | ||
| sourcemeta::codegen::default_compiler)}; | ||
|
|
||
| using namespace sourcemeta::codegen; | ||
|
|
||
| EXPECT_IR_INTERSECTION(result, result.size() - 1, "", 2); | ||
|
|
||
| // Both allOf branches should be references to their respective $defs | ||
| bool found_named{false}; | ||
| bool found_aged{false}; | ||
| for (const auto &entry : result) { | ||
| if (std::holds_alternative<IRReference>(entry)) { | ||
| const auto &reference{std::get<IRReference>(entry)}; | ||
| const auto pointer_string{sourcemeta::core::to_string(reference.pointer)}; | ||
| const auto target_string{ | ||
| sourcemeta::core::to_string(reference.target.pointer)}; | ||
| if (pointer_string == "/allOf/0" && target_string == "/$defs/Named") { | ||
| found_named = true; | ||
| } else if (pointer_string == "/allOf/1" && | ||
| target_string == "/$defs/Aged") { | ||
| found_aged = true; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| EXPECT_TRUE(found_named); | ||
| EXPECT_TRUE(found_aged); | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: These closed
allOfbranches make the schema unsatisfiable; the fixture never admits an object with bothnameandage.Prompt for AI agents