-
Notifications
You must be signed in to change notification settings - Fork 10
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
resource methods: deduplicate request types between regular and body methods #166
base: master
Are you sure you want to change the base?
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 |
---|---|---|
@@ -1,17 +1,18 @@ | ||
import {promisify} from 'bluebird'; | ||
import sortObject from 'deep-sort-object'; | ||
import fs from 'fs'; | ||
import lineReader from 'line-reader'; | ||
import _ from 'lodash'; | ||
import path, {basename, join, resolve} from 'path'; | ||
import request from 'request'; | ||
import sortObject from 'deep-sort-object'; | ||
import lineReader from 'line-reader'; | ||
import {promisify} from 'bluebird'; | ||
import {Template} from './template'; | ||
import { | ||
camelCaseParts, | ||
ensureDirectoryExists, | ||
getResourceTypeName, | ||
parseVersion, | ||
} from './utils'; | ||
import {StreamWriter, TextWriter} from './writer'; | ||
import {Template} from './template'; | ||
|
||
type JsonSchema = gapi.client.discovery.JsonSchema; | ||
type RestResource = gapi.client.discovery.RestResource; | ||
|
@@ -417,10 +418,11 @@ function getMethodReturn( | |
const name = schemas['Request'] ? 'client.Request' : 'Request'; | ||
|
||
if (method.response) { | ||
const schema = schemas[checkExists(method.response.$ref)]; | ||
const schemaName = method.response.$ref; | ||
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. Unrelated refactoring |
||
const schema = schemas[checkExists(schemaName)]; | ||
|
||
if (schema && !_.isEmpty(schema.properties)) { | ||
return `${name}<${method.response.$ref}>`; | ||
if (schema && !isEmptySchema(schema)) { | ||
return `${name}<${schemaName}>`; | ||
} else { | ||
return `${name}<{}>`; | ||
} | ||
|
@@ -461,34 +463,6 @@ export class App { | |
return dir; | ||
} | ||
|
||
/** | ||
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. No longer consumed or needed, since we've replaced it with a simpler method write. |
||
* Creates a callback that writes request parameters. | ||
*/ | ||
private static createRequestParameterWriterCallback( | ||
parameters: Record<string, JsonSchema>, | ||
schemas: Record<string, JsonSchema>, | ||
ref?: string | ||
) { | ||
return function requestParameterWriterCallback( | ||
writer: TypescriptTextWriter | ||
) { | ||
writer.anonymousType(() => { | ||
_.forEach(parameters, (data, key) => { | ||
if (data.description) { | ||
writer.comment(formatComment(data.description)); | ||
} | ||
|
||
writer.property(key, getType(data, schemas), Boolean(data.required)); | ||
}); | ||
|
||
if (ref) { | ||
writer.comment('Request body'); | ||
writer.property('resource', ref, true); | ||
} | ||
}); | ||
}; | ||
} | ||
|
||
/** | ||
* Writes specified resource definition. | ||
*/ | ||
|
@@ -498,38 +472,83 @@ export class App { | |
parameters: Record<string, JsonSchema> = {}, | ||
schemas: Record<string, JsonSchema> | ||
) { | ||
_.forEach(resources, (resource, resourceName) => { | ||
const resourceInterfaceName = getResourceTypeName(resourceName); | ||
// Accumulates the request method parameter types, to be written after all of the resource interfaces. | ||
const requestTypeWriters: (() => void)[] = []; | ||
|
||
// Write all resource interfaces | ||
_.forEach(resources, (resource, resourceName) => { | ||
if (resource.resources) { | ||
this.writeResources(out, resource.resources, parameters, schemas); | ||
} | ||
|
||
out.interface(resourceInterfaceName, () => { | ||
out.interface(getResourceTypeName(resourceName), () => { | ||
if (resource.resources) { | ||
_.forEach(resource.resources, (_, childResourceName) => { | ||
const childResourceInterfaceName = getResourceTypeName( | ||
childResourceName | ||
); | ||
out.property(childResourceName, childResourceInterfaceName); | ||
}); | ||
} | ||
Comment on lines
+485
to
+492
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 has just been moved up from below, wasn't touched |
||
|
||
_.forEach(resource.methods, method => { | ||
if (method.description) { | ||
out.comment(formatComment(method.description)); | ||
} | ||
|
||
const requestRef = method.request?.$ref; | ||
const requestParameters: Record<string, JsonSchema> = sortObject({ | ||
...parameters, | ||
...method.parameters, | ||
// Construct request type, e.g. get(...) on InvitationsResource -> GetInvitationsRequest | ||
const methodType = checkExists(getName(method.id)); | ||
const methodParts = method.id?.split('.'); | ||
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. As raised in the previous PR, we weren't including the parent path down to the resource method, which meant we'd get some interface duplication, e.g. Using |
||
const methodName = methodParts | ||
? camelCaseParts(methodParts.slice(1, methodParts.length - 1)) | ||
: ''; | ||
const requestTypeName = | ||
methodType[0].toUpperCase() + | ||
methodType.slice(1) + | ||
methodName + | ||
'Request'; | ||
|
||
const hasResourcePolicy = !!( | ||
parameters.resource || method.parameters?.resource | ||
); | ||
|
||
// Prepare the request object to be written | ||
requestTypeWriters.push(() => { | ||
out.interface(requestTypeName, (writer: TypescriptTextWriter) => { | ||
const requestParams: Record<string, JsonSchema> = sortObject({ | ||
...parameters, | ||
...method.parameters, | ||
}); | ||
|
||
_.forEach(requestParams, (data, key) => { | ||
if (data.description) { | ||
writer.comment(formatComment(data.description)); | ||
} | ||
writer.property( | ||
key, | ||
getType(data, schemas), | ||
data.required || false | ||
); | ||
}); | ||
|
||
// If the request takes a body (e.g. a POST request), add it as the 'resource' property. | ||
if (method.request?.$ref && !hasResourcePolicy) { | ||
writer.comment('Request body'); | ||
writer.property('resource', method.request.$ref, true); | ||
} | ||
}); | ||
}); | ||
|
||
if (!requestParameters.resource || !requestRef) { | ||
const requestRef = method.request?.$ref; | ||
if (!hasResourcePolicy || !requestRef) { | ||
// generate method(request) | ||
out.method( | ||
formatPropertyName(checkExists(getName(method.id))), | ||
formatPropertyName(methodType), | ||
[ | ||
{ | ||
parameter: 'request', | ||
type: App.createRequestParameterWriterCallback( | ||
requestParameters, | ||
schemas, | ||
requestRef | ||
), | ||
required: Boolean(requestRef), | ||
type: requestTypeName, | ||
required: !!method.parameters, | ||
}, | ||
], | ||
getMethodReturn(method, schemas) | ||
|
@@ -539,37 +558,30 @@ export class App { | |
if (requestRef) { | ||
// generate method(request, body) | ||
out.method( | ||
formatPropertyName(checkExists(getName(method.id))), | ||
formatPropertyName(methodType), | ||
[ | ||
{ | ||
parameter: 'request', | ||
type: App.createRequestParameterWriterCallback( | ||
requestParameters, | ||
schemas | ||
), | ||
required: true, | ||
type: `Omit<${requestTypeName}, 'resource'>`, | ||
required: !!method.parameters, | ||
}, | ||
{ | ||
parameter: 'body', | ||
type: requestRef, | ||
type: hasResourcePolicy | ||
? requestRef | ||
: `${requestTypeName}['resource']`, | ||
required: true, | ||
}, | ||
], | ||
getMethodReturn(method, schemas) | ||
); | ||
} | ||
}); | ||
|
||
if (resource.resources) { | ||
_.forEach(resource.resources, (_, childResourceName) => { | ||
const childResourceInterfaceName = getResourceTypeName( | ||
childResourceName | ||
); | ||
out.property(childResourceName, childResourceInterfaceName); | ||
}); | ||
} | ||
}); | ||
}); | ||
|
||
// Then write all request types | ||
requestTypeWriters.forEach(write => write()); | ||
} | ||
|
||
private static getTypingsName(api: string, version: string | null) { | ||
|
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.
My import sorter auto formatted this to be alphabetical 😅