Skip to content

Commit

Permalink
feat(cli): readonly support for non nested request schemas (#4810)
Browse files Browse the repository at this point in the history
  • Loading branch information
dsinghvi authored Oct 6, 2024
1 parent 466b47a commit 6fbdca3
Show file tree
Hide file tree
Showing 236 changed files with 234,003 additions and 2,596 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ module.exports = {
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-unnecessary-condition": "off",
"eslint-comments/no-unused-disable": "off",
"jest/expect-expect": "off"
"jest/expect-expect": "off",
"jest/no-conditional-expect": "off"
},
overrides: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export class ExampleEndpointFactory {

if (requestSchemaIdResponse.examples.length === 0) {
const example = this.exampleTypeFactory.buildExample({
skipReadonly: endpoint.method === "POST" || endpoint.method === "PUT",
schema: requestSchemaIdResponse.schema,
exampleId: undefined,
example: undefined,
Expand All @@ -66,6 +67,7 @@ export class ExampleEndpointFactory {
} else {
for (const { name: exampleId, value: rawExample } of requestSchemaIdResponse.examples) {
const example = this.exampleTypeFactory.buildExample({
skipReadonly: endpoint.method === "POST" || endpoint.method === "PUT",
schema: requestSchemaIdResponse.schema,
exampleId,
example: rawExample,
Expand Down Expand Up @@ -94,6 +96,7 @@ export class ExampleEndpointFactory {

if (responseSchemaIdResponse.examples.length === 0) {
const example = this.exampleTypeFactory.buildExample({
skipReadonly: false,
schema: responseSchemaIdResponse.schema,
exampleId: undefined,
example: undefined,
Expand All @@ -109,6 +112,7 @@ export class ExampleEndpointFactory {
} else {
for (const { name: exampleId, value: rawExample } of responseSchemaIdResponse.examples) {
const example = this.exampleTypeFactory.buildExample({
skipReadonly: false,
schema: responseSchemaIdResponse.schema,
exampleId,
example: rawExample,
Expand Down Expand Up @@ -557,7 +561,8 @@ function convertMultipartRequestToSchema(request: RequestWithExample.Multipart):
conflict: {},
generatedName: property.key,
nameOverride: undefined,
availability: undefined
availability: undefined,
readonly: undefined
};
})
.filter(isNonNullish),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ export function convertObject({
const audiences = getExtension<string[]>(propertySchema, FernOpenAPIExtension.AUDIENCES) ?? [];
const availability = convertAvailability(propertySchema);

const readonly = isReferenceObject(propertySchema) ? false : propertySchema.readOnly;

const propertyNameOverride = getExtension<string | undefined>(
propertySchema,
FernOpenAPIExtension.FERN_PROPERTY_NAME
Expand Down Expand Up @@ -208,7 +210,8 @@ export function convertObject({
audiences,
conflict: conflicts,
generatedName: getGeneratedPropertyName([...breadcrumbs, propertyName]),
availability
availability,
readonly
};
}
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@ export class ExampleTypeFactory {
schema,
exampleId,
example,
options
options,
skipReadonly
}: {
schema: SchemaWithExample;
exampleId: string | undefined;
example: unknown | undefined;
options: ExampleTypeFactory.Options;
skipReadonly?: boolean;
}): FullExample | undefined {
return this.buildExampleHelper({
schema,
Expand All @@ -56,7 +58,8 @@ export class ExampleTypeFactory {
example,
// Default maxCheckerDepth to 5
options: { ...options, maxCheckerDepth: options.maxCheckerDepth ?? 5 },
depth: 0
depth: 0,
skipReadonly: skipReadonly ?? false
});
}

Expand All @@ -66,14 +69,16 @@ export class ExampleTypeFactory {
schema,
depth,
visitedSchemaIds,
options
options,
skipReadonly
}: {
exampleId: string | undefined;
example: unknown | undefined;
schema: SchemaWithExample;
depth: number;
visitedSchemaIds: Set<SchemaId>;
options: ExampleTypeFactory.Options;
skipReadonly: boolean;
}): FullExample | undefined {
switch (schema.type) {
case "enum":
Expand All @@ -97,7 +102,8 @@ export class ExampleTypeFactory {
exampleId,
example,
depth,
options
options,
skipReadonly: false // TODO(dsinghvi): nested readonly are not respected yet
});
if (result != null && result.type === "array" && result.value.length === 0) {
return undefined;
Expand All @@ -124,7 +130,8 @@ export class ExampleTypeFactory {
exampleId,
example,
depth,
options
options,
skipReadonly: false // TODO(dsinghvi): nested readonly are not respected yet
});
if (result != null && result.type === "array" && result.value.length === 0) {
return undefined;
Expand All @@ -151,7 +158,8 @@ export class ExampleTypeFactory {
exampleId,
visitedSchemaIds,
depth,
options
options,
skipReadonly: false // TODO(dsinghvi): nested readonly are not respected yet
});
visitedSchemaIds.delete(schema.schema);
return referencedExample;
Expand All @@ -163,7 +171,7 @@ export class ExampleTypeFactory {
case "discriminated": {
const result: Record<string, FullExample> = {};

let allProperties: Record<string, SchemaWithExample> = {};
let allProperties: Record<string, { schema: SchemaWithExample; readonly: boolean }> = {};
let requiredProperties: Record<string, SchemaWithExample> = {};

const fullExample = getFullExampleAsObject(example);
Expand Down Expand Up @@ -206,7 +214,7 @@ export class ExampleTypeFactory {
}

for (const commonProperty of schema.value.commonProperties) {
allProperties[commonProperty.key] = commonProperty.schema;
allProperties[commonProperty.key] = { schema: commonProperty.schema, readonly: false };
const resolvedSchema = this.getResolvedSchema(commonProperty.schema);
if (resolvedSchema.type !== "optional" && resolvedSchema.type !== "nullable") {
requiredProperties[commonProperty.key] = commonProperty.schema;
Expand All @@ -217,12 +225,13 @@ export class ExampleTypeFactory {
const required = property in requiredProperties;
if (required && fullExample?.[property] != null) {
const propertyExample = this.buildExampleHelper({
schema,
schema: schema.schema,
exampleId,
example: fullExample[property],
visitedSchemaIds,
depth: depth + 1,
options
options,
skipReadonly: false // TODO(dsinghvi): nested readonly are not respected yet
});
if (propertyExample != null) {
result[property] = propertyExample;
Expand All @@ -232,11 +241,12 @@ export class ExampleTypeFactory {
} else {
const propertyExample = this.buildExampleHelper({
exampleId,
schema,
schema: schema.schema,
example: fullExample?.[property],
visitedSchemaIds,
depth: depth + 1,
options
options,
skipReadonly: false // TODO(dsinghvi): nested readonly are not respected yet
});
if (propertyExample != null) {
result[property] = propertyExample;
Expand All @@ -257,7 +267,8 @@ export class ExampleTypeFactory {
schema: unionVariantSchema,
visitedSchemaIds,
depth,
options
options,
skipReadonly: false // TODO(dsinghvi): nested readonly are not respected yet
});
}
break;
Expand Down Expand Up @@ -295,7 +306,8 @@ export class ExampleTypeFactory {
schema: schema.value,
depth: depth + 1,
visitedSchemaIds,
options
options,
skipReadonly: false // TODO(dsinghvi): nested readonly are not respected yet
});
if (itemExample != null) {
itemExamples.push(itemExample);
Expand All @@ -310,7 +322,8 @@ export class ExampleTypeFactory {
schema: schema.value,
depth: depth + 1,
visitedSchemaIds,
options
options,
skipReadonly: false // TODO(dsinghvi): nested readonly are not respected yet
});
if (itemExample != null) {
itemExamples.push(itemExample);
Expand All @@ -324,7 +337,8 @@ export class ExampleTypeFactory {
schema: schema.value,
depth: depth + 1,
visitedSchemaIds,
options
options,
skipReadonly: false // TODO(dsinghvi): nested readonly are not respected yet
});
if (itemExample != null) {
itemExamples.push(itemExample);
Expand All @@ -349,7 +363,8 @@ export class ExampleTypeFactory {
schema: schema.value,
visitedSchemaIds,
depth: depth + 1,
options
options,
skipReadonly: false // TODO(dsinghvi): nested readonly are not respected yet
});
if (valueExample != null) {
kvs.push({
Expand Down Expand Up @@ -392,7 +407,8 @@ export class ExampleTypeFactory {
// override the name to be "value" for map value otherwise you can start to get key name
// nesting since primitive examples use their name e.g. "metadata": {"metadata": "metadata"}
name: "value"
}
},
skipReadonly: false // TODO(dsinghvi): nested readonly are not respected yet
});
if (valueExample != null) {
return FullExample.map([
Expand All @@ -417,18 +433,23 @@ export class ExampleTypeFactory {
const allProperties = this.getAllProperties(schema);
const requiredProperties = this.getAllRequiredProperties(schema);
for (const [property, schema] of Object.entries(allProperties)) {
if (skipReadonly && schema.readonly) {
continue;
}

const required = property in requiredProperties;
const inExample = Object.keys(fullExample).includes(property);
const propertyExample = this.buildExampleHelper({
schema,
schema: schema.schema,
exampleId,
example: fullExample[property],
visitedSchemaIds,
depth: depth + 1,
options: {
...options,
name: property
}
},
skipReadonly: false // TODO(dsinghvi): nested readonly are not respected yet
});
if (required && propertyExample != null) {
result[property] = propertyExample;
Expand Down Expand Up @@ -525,7 +546,7 @@ export class ExampleTypeFactory {
for (const [property, schema] of Object.entries(allProperties)) {
if (fullExample[property] != null) {
heuristic++;
heuristic += this.calcExampleHeuristic(schema, fullExample[property]);
heuristic += this.calcExampleHeuristic(schema.schema, fullExample[property]);
} else {
heuristic--;
}
Expand Down Expand Up @@ -662,10 +683,12 @@ export class ExampleTypeFactory {
return depth > (options.maxDepth ?? 0);
}

private getAllProperties(object: ObjectSchemaWithExample): Record<string, SchemaWithExample> {
let properties: Record<string, SchemaWithExample> = {};
private getAllProperties(
object: ObjectSchemaWithExample
): Record<string, { schema: SchemaWithExample; readonly: boolean }> {
let properties: Record<string, { schema: SchemaWithExample; readonly: boolean }> = {};
for (const property of object.properties) {
properties[property.key] = property.schema;
properties[property.key] = { schema: property.schema, readonly: property.readonly ?? false };
}
for (const allOf of object.allOf) {
const allOfSchema = this.schemas[allOf.schema];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ function convertToObjectProperty(objectProperty: ObjectProperty): ObjectProperty
schema: convertSchemaToSchemaWithExample(objectProperty.schema),
audiences: objectProperty.audiences,
nameOverride: objectProperty.nameOverride,
availability: objectProperty.availability
availability: objectProperty.availability,
readonly: objectProperty.readonly
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ function convertToObjectProperty(objectProperty: ObjectPropertyWithExample): Obj
schema: convertSchemaWithExampleToSchema(objectProperty.schema),
audiences: objectProperty.audiences,
nameOverride: objectProperty.nameOverride,
availability: objectProperty.availability
availability: objectProperty.availability,
readonly: objectProperty.readonly
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -12462,10 +12462,6 @@ docs: Simple messaging
"docs": "Message identifier",
"type": "optional<string>",
},
"@type": {
"docs": "Message type",
"type": "optional<string>",
},
"did": {
"docs": "DID for connection invitation",
"type": "optional<string>",
Expand Down Expand Up @@ -12976,9 +12972,6 @@ service:
'@id':
type: optional<string>
docs: Message identifier
'@type':
type: optional<string>
docs: Message type
did:
type: optional<string>
docs: DID for connection invitation
Expand Down Expand Up @@ -14835,10 +14828,6 @@ docs: Holder credential management
"docs": "Message identifier",
"type": "optional<string>",
},
"@type": {
"docs": "Message type",
"type": "optional<string>",
},
"did": {
"docs": "DID of exchange",
"type": "optional<string>",
Expand Down Expand Up @@ -14976,9 +14965,6 @@ service:
'@id':
type: optional<string>
docs: Message identifier
'@type':
type: optional<string>
docs: Message type
did:
type: optional<string>
docs: DID of exchange
Expand Down
Loading

0 comments on commit 6fbdca3

Please sign in to comment.