From 9628643e250c2f7ffd3076eb695e3b61b57ed85c Mon Sep 17 00:00:00 2001 From: Anders Cassidy Date: Wed, 19 Jan 2022 11:54:00 +0000 Subject: [PATCH 1/3] Pass through required properties to allOf children --- src/schema.js | 2 +- tests/generated/v3.0/allof-example.ts | 2 +- tests/schemas/v3.0/allof-example.yaml | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/schema.js b/src/schema.js index 8bd40ce77..a6b452993 100644 --- a/src/schema.js +++ b/src/schema.js @@ -187,7 +187,7 @@ const complexSchemaParsers = { }, [SCHEMA_TYPES.COMPLEX_ALL_OF]: (schema) => { // T1 & T2 - const combined = _.map(schema.allOf, complexTypeGetter); + const combined = _.map(schema.allOf.map(s => _.merge({ required: schema.required }, s)), complexTypeGetter); return checkAndAddNull( schema, filterContents(combined, [...JS_EMPTY_TYPES, ...JS_PRIMITIVE_TYPES, TS_KEYWORDS.ANY]).join( diff --git a/tests/generated/v3.0/allof-example.ts b/tests/generated/v3.0/allof-example.ts index 2c94a295c..4627b7be3 100644 --- a/tests/generated/v3.0/allof-example.ts +++ b/tests/generated/v3.0/allof-example.ts @@ -13,7 +13,7 @@ export interface Pet { pet_type: string; } -export type Dog = Pet & { bark?: boolean; breed?: "Dingo" | "Husky" | "Retriever" | "Shepherd" }; +export type Dog = Pet & { bark?: boolean; breed: "Dingo" | "Husky" | "Retriever" | "Shepherd" }; export type Cat = Pet & { hunts?: boolean; age?: number }; diff --git a/tests/schemas/v3.0/allof-example.yaml b/tests/schemas/v3.0/allof-example.yaml index 20085b326..470f2c8a3 100644 --- a/tests/schemas/v3.0/allof-example.yaml +++ b/tests/schemas/v3.0/allof-example.yaml @@ -29,7 +29,9 @@ components: discriminator: propertyName: pet_type Dog: # "Dog" is a value for the pet_type property (the discriminator value) - allOf: # Combines the main `Pet` schema with `Dog`-specific properties + required: + - breed + allOf: # Combines the main `Pet` schema with `Dog`-specific properties - $ref: '#/components/schemas/Pet' - type: object # all other properties specific to a `Dog` @@ -48,4 +50,4 @@ components: hunts: type: boolean age: - type: integer \ No newline at end of file + type: integer From 3ff93cf29aa61f22583564806e42d696b549c695 Mon Sep 17 00:00:00 2001 From: Daniel Playfair Cal Date: Tue, 15 Feb 2022 18:45:29 +1100 Subject: [PATCH 2/3] extend fix to anyOf and oneOf --- src/schema.js | 15 ++++++++++++--- tests/generated/v3.0/full-swagger-scheme.ts | 4 ++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/schema.js b/src/schema.js index a6b452993..7662af9dc 100644 --- a/src/schema.js +++ b/src/schema.js @@ -181,13 +181,19 @@ const filterContents = (contents, types) => _.filter(contents, (type) => !_.incl const complexSchemaParsers = { [SCHEMA_TYPES.COMPLEX_ONE_OF]: (schema) => { // T1 | T2 - const combined = _.map(schema.oneOf, complexTypeGetter); + const combined = _.map( + schema.oneOf.map((s) => _.merge({ required: schema.required }, s)), + complexTypeGetter, + ); return checkAndAddNull(schema, filterContents(combined, [TS_KEYWORDS.ANY]).join(" | ")); }, [SCHEMA_TYPES.COMPLEX_ALL_OF]: (schema) => { // T1 & T2 - const combined = _.map(schema.allOf.map(s => _.merge({ required: schema.required }, s)), complexTypeGetter); + const combined = _.map( + schema.allOf.map((s) => _.merge({ required: schema.required }, s)), + complexTypeGetter, + ); return checkAndAddNull( schema, filterContents(combined, [...JS_EMPTY_TYPES, ...JS_PRIMITIVE_TYPES, TS_KEYWORDS.ANY]).join( @@ -197,7 +203,10 @@ const complexSchemaParsers = { }, [SCHEMA_TYPES.COMPLEX_ANY_OF]: (schema) => { // T1 | T2 | (T1 & T2) - const combined = _.map(schema.anyOf, complexTypeGetter); + const combined = _.map( + schema.anyOf.map((s) => _.merge({ required: schema.required }, s)), + complexTypeGetter, + ); const nonEmptyTypesCombined = filterContents(combined, [ ...JS_EMPTY_TYPES, ...JS_PRIMITIVE_TYPES, diff --git a/tests/generated/v3.0/full-swagger-scheme.ts b/tests/generated/v3.0/full-swagger-scheme.ts index 4d47f75ee..898624fbe 100644 --- a/tests/generated/v3.0/full-swagger-scheme.ts +++ b/tests/generated/v3.0/full-swagger-scheme.ts @@ -15947,13 +15947,13 @@ export class Api extends HttpClient Date: Wed, 16 Feb 2022 13:57:05 +1100 Subject: [PATCH 3/3] fix: account for children making parent fields required --- src/schema.js | 56 +++++++++++++---- tests/generated/v3.0/full-swagger-scheme.ts | 70 ++++++++++++++++++--- 2 files changed, 105 insertions(+), 21 deletions(-) diff --git a/src/schema.js b/src/schema.js index 7662af9dc..bcfee43a6 100644 --- a/src/schema.js +++ b/src/schema.js @@ -178,22 +178,57 @@ const getObjectTypeContent = (schema) => { const complexTypeGetter = (schema) => getInlineParseContent(schema); const filterContents = (contents, types) => _.filter(contents, (type) => !_.includes(types, type)); +const makeAddRequiredToChildSchema = (parentSchema) => (childSchema) => { + let required = childSchema.required || []; + let properties = childSchema.properties || {}; + + // Inherit all the required fields from the parent schema that are defined + // either on the parent schema or on the child schema + // TODO: any that are defined at grandparents or higher are ignored + required = required.concat( + (parentSchema.required || []).filter( + (key) => + !required.includes(key) && (_.keys(properties).includes(key) || _.keys(parentSchema.properties).includes(key)), + ), + ); + + // Identify properties that are required in the child schema, but + // defined only in the parent schema (TODO: this only works one level deep) + const parentPropertiesRequiredByChild = required.filter( + (key) => !_.keys(childSchema.properties).includes(key) && _.keys(parentSchema.properties).includes(key), + ); + + // Add such properties to the child so that they can be overriden and made required + properties = { + ...properties, + ...parentPropertiesRequiredByChild.reduce( + (additionalProperties, key) => ({ + ...additionalProperties, + [key]: (parentSchema.properties || {})[key], + }), + {}, + ), + }; + + return _.merge( + { + required: required, + properties: properties, + }, + childSchema, + ); +}; + const complexSchemaParsers = { [SCHEMA_TYPES.COMPLEX_ONE_OF]: (schema) => { // T1 | T2 - const combined = _.map( - schema.oneOf.map((s) => _.merge({ required: schema.required }, s)), - complexTypeGetter, - ); + const combined = _.map(schema.oneOf.map(makeAddRequiredToChildSchema(schema)), complexTypeGetter); return checkAndAddNull(schema, filterContents(combined, [TS_KEYWORDS.ANY]).join(" | ")); }, [SCHEMA_TYPES.COMPLEX_ALL_OF]: (schema) => { // T1 & T2 - const combined = _.map( - schema.allOf.map((s) => _.merge({ required: schema.required }, s)), - complexTypeGetter, - ); + const combined = _.map(schema.allOf.map(makeAddRequiredToChildSchema(schema)), complexTypeGetter); return checkAndAddNull( schema, filterContents(combined, [...JS_EMPTY_TYPES, ...JS_PRIMITIVE_TYPES, TS_KEYWORDS.ANY]).join( @@ -203,10 +238,7 @@ const complexSchemaParsers = { }, [SCHEMA_TYPES.COMPLEX_ANY_OF]: (schema) => { // T1 | T2 | (T1 & T2) - const combined = _.map( - schema.anyOf.map((s) => _.merge({ required: schema.required }, s)), - complexTypeGetter, - ); + const combined = _.map(makeAddRequiredToChildSchema(schema), complexTypeGetter); const nonEmptyTypesCombined = filterContents(combined, [ ...JS_EMPTY_TYPES, ...JS_PRIMITIVE_TYPES, diff --git a/tests/generated/v3.0/full-swagger-scheme.ts b/tests/generated/v3.0/full-swagger-scheme.ts index 898624fbe..97661dc21 100644 --- a/tests/generated/v3.0/full-swagger-scheme.ts +++ b/tests/generated/v3.0/full-swagger-scheme.ts @@ -10636,9 +10636,41 @@ export class Api extends HttpClient; + } + | ({ description: string } & { + files: Record< + string, + ( + | { content: string } + | { filename: string | null } + | object + | ({ content: string } & { filename: string | null } & object) + ) & { content?: string; filename?: string | null } + >; + }) + ) & { description?: string; - files?: Record; + files?: Record< + string, + ( + | { content: string } + | { filename: string | null } + | object + | ({ content: string } & { filename: string | null } & object) + ) & { content?: string; filename?: string | null } + >; }, params: RequestParams = {}, ) => @@ -15943,17 +15975,29 @@ export class Api extends HttpClient extends HttpClient