Skip to content

Commit

Permalink
feat: add jsdoc comment for parameters (#94)
Browse files Browse the repository at this point in the history
* logic for printing comments for parameters

* render comment for parameters

* align asterisks

* escape */ to break the comment

* actual type

* update baseline

* replace all */

* add unit test for replace all helper function

* render real js type

* update baseline

* add request object comment

* add return comment

* reformat comments

* gts

* add return comments for simple method

* return comment for all methods

* update baseline test

* feedback

* update baseline

* simplify logic for printing return comments
  • Loading branch information
xiaozhenliu-gg5 authored and alexander-fenster committed Nov 4, 2019
1 parent 355cec8 commit 48011c6
Show file tree
Hide file tree
Showing 11 changed files with 1,230 additions and 242 deletions.
101 changes: 101 additions & 0 deletions templates/typescript_gapic/_util.njk
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,104 @@ limitations under the License.
{{ chain }}.{{ method.headerRequestParams.slice(-1)[0] }} = '';
{%- endif %}
{%- endmacro -%}

{%- macro printCommentsForParams(method) -%}
{%- set commentsMap = method.paramComment -%}
{%- for oneComment in commentsMap -%}
{%- set type = oneComment.paramType -%}
{%- if type.startsWith('.') %}
* @param { {{- type.substring(1) -}} } request.{{ oneComment.paramName }}
{%- else %}
* @param { {{- convertParamType(oneComment.paramType) -}} } request.{{ oneComment.paramName }}
{%- endif -%}
{%- set lines = oneComment.comments -%}
{%- for line in lines %}
* {{ line.replaceAll('*/', '* /') | safe}}
{%- endfor -%}
{%- endfor -%}
{%- endmacro -%}

{%- macro printCommentsForMethod(method) -%}
{%- set lines = method.comments -%}
{% for line in lines %}
*{{ line | safe}}
{%- endfor %}
{%- endmacro -%}

{%- macro printCommentsForService(service) -%}
{%- set lines = service.comments -%}
{% for line in lines %}
* {{ line | safe}}
{%- endfor %}
{%- endmacro -%}

{%- macro printRequest() %}
* @param {Object} request
* The request object that will be sent.
{%- endmacro -%}

{%- macro printReturn(method, service) -%}
{%- if method.longRunning %}
{{- printReturnSimpleMethod(method) }}
{%- elif method.serverStreaming and method.clientStreaming %}
{{- printReturnBidiStreamingMethod(method) }}
{%- elif method in service.paging %}
{{- printReturnPagingServerMethod(method) }}
{%- elif method.serverStreaming %}
{{- printReturnPagingServerMethod(method) }}
{%- elif method.clientStreaming %}
{{- printReturnClientStreamingMethod(method) }}
{%- else %}
{{- printReturnSimpleMethod(method) }}
{%- endif -%}
{%- endmacro -%}

{%- macro printReturnSimpleMethod(method) %}
* @returns {Promise} - The promise which resolves to an array.
* The first element of the array is an object representing [{{- toMessageName(method.outputType) -}}]{@link {{ method.outputType.substring(1) }}}.
* The promise has a method named "cancel" which cancels the ongoing API call.
{%- endmacro -%}

{%- macro printReturnPagingServerMethod(method) %}
* @returns {Promise} - The promise which resolves to an array.
* The first element of the array is an object representing [{{- toMessageName(method.outputType) -}}]{@link {{ method.outputType.substring(1) }}}.
*
* When autoPaginate: false is specified through options, the array has three elements.
* The first element is Array of [{{- toMessageName(method.outputType) -}}]{@link {{ method.outputType.substring(1) }}} in a single response.
* The second element is the next request object if the response
* indicates the next page exists, or null. The third element is
* an object representing [{{- toMessageName(method.outputType) -}}]{@link {{ method.outputType.substring(1) }}}.
*
* The promise has a method named "cancel" which cancels the ongoing API call.
{%- endmacro -%}


{%- macro printReturnClientStreamingMethod(method) %}
* @returns {Stream} - A writable stream which accepts objects representing
* [{{- toMessageName(method.outputType) -}}]{@link {{ method.outputType.substring(1) }}}.
{%- endmacro -%}

{%- macro printReturnBidiStreamingMethod(method) %}
* @returns {Stream}
* An object stream which is both readable and writable. It accepts objects
* representing [[{{- toMessageName(method.outputType) -}}]{@link {{ method.outputType.substring(1) }}} for write() method, and
* will emit objects representing [{{- toMessageName(method.outputType) -}}]{@link {{ method.outputType.substring(1) }}} on 'data' event asynchronously.
{%- endmacro -%}

{%- macro toMessageName(messageType) -%}
{%- set arr = messageType.split('.') %}
{{- arr[arr.length - 1] -}}
{%- endmacro -%}

{%- macro convertParamType(paramType) -%}
{%- if paramType.includes('TYPE_BYTES') %}
{%- set type = paramType.replace('TYPE_BYTES', 'Buffer') %}
{%- elif paramType.includes('TYPE_BOOL') %}
{%- set type = paramType.replace('TYPE_BOOL', 'boolean') %}
{%- elif paramType.includes('TYPE_STRING') %}
{%- set type = paramType.replace('TYPE_STRING', 'string') %}
{%- else %}
{%- set type = 'number' %}
{%- endif %}
{{- type -}}
{%- endmacro -%}
43 changes: 28 additions & 15 deletions templates/typescript_gapic/src/$version/$service_client.ts.njk
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
-#}
{% import "../../_license.njk" as license -%}
{{license.license()}}
{% import "../../_util.njk" as util -%}
import * as gax from 'google-gax';
import * as path from 'path';

Expand Down Expand Up @@ -67,9 +68,9 @@ export interface PaginationResponse<
}
{% endif %}
export class {{ service.name }}Client {
/*
{{ service.comments }}
*/
/**
{{- util.printCommentsForService(service) }}
*/
private _descriptors: Descriptors = {page: {}, stream: {}, longrunning: {}};
private _innerApiCalls: {[name: string]: Function};
{%- if (service.pathTemplates.length > 0) %}
Expand Down Expand Up @@ -337,9 +338,12 @@ export class {{ service.name }}Client {
// -------------------

{%- for method in service.simpleMethods %}
/*
{{ method.comments }}
*/
/**
{{- util.printCommentsForMethod(method) }}
{{- util.printRequest() -}}
{{- util.printCommentsForParams(method) -}}
{{- util.printReturn(method, service) }}
*/
{{ method.name.toCamelCase() }}(
request: protosTypes{{ method.inputInterface }},
options?: gax.CallOptions):
Expand Down Expand Up @@ -390,9 +394,12 @@ export class {{ service.name }}Client {
}
{%- endfor %}
{% for method in service.streaming %}
/*
{{ method.comments }}
*/
/**
{{- util.printCommentsForMethod(method) }}
{{- util.printRequest() -}}
{{- util.printCommentsForParams(method) -}}
{{- util.printReturn(method, service) }}
*/
{%- if method.serverStreaming and method.clientStreaming %}
{{ method.name.toCamelCase() }}(
options?: gax.CallOptions):
Expand Down Expand Up @@ -439,9 +446,12 @@ export class {{ service.name }}Client {
{%- endif %}
{% endfor %}
{%- for method in service.longRunning %}
/*
{{ method.comments }}
*/
/**
{{- util.printCommentsForMethod(method) }}
{{- util.printRequest() -}}
{{- util.printCommentsForParams(method) -}}
{{- util.printReturn(method, service) }}
*/
{{ method.name.toCamelCase() }}(
request: protosTypes{{ method.inputInterface }},
options?: gax.CallOptions):
Expand Down Expand Up @@ -492,9 +502,12 @@ export class {{ service.name }}Client {
}
{%- endfor %}
{%- for method in service.paging %}
/*
{{ method.comments }}
*/
/**
{{- util.printCommentsForMethod(method) }}
{{- util.printRequest() -}}
{{- util.printCommentsForParams(method) -}}
{{- util.printReturn(method, service) }}
*/
{{ method.name.toCamelCase() }}(
request: protosTypes{{ method.inputInterface }},
options?: gax.CallOptions):
Expand Down
1 change: 1 addition & 0 deletions typescript/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ interface String {
toPascalCase(): string;
toKebabCase(): string;
toSnakeCase(): string;
replaceAll(this: string, search: string, replacement: string): string;
}

interface Array<T> {
Expand Down
109 changes: 99 additions & 10 deletions typescript/src/schema/comments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,20 @@
// limitations under the License.

import * as plugin from '../../../pbjs-genfiles/plugin';

// For one comment in service and method level, paramName & paramName will be ''.
// Only field has name and type of parameters.
export interface Comment {
paramName: string;
paramType: string;
comments: string[];
}

// For service, one item will be <serviceName, comment>
// For method, one item will be <serviceName:methodName, comment>
// For field, one item will be <messageInputType:fieldname, comment>
export interface Comments {
[name: string]: string;
[name: string]: Comment;
}

export class CommentsMap {
Expand All @@ -37,20 +49,88 @@ export class CommentsMap {
const p = location.path!;
if (p.length === 2 && p[0] === 6) {
if (fd.service && fd.service[p[1]] && fd.service[p[1]].name) {
commentsMap[fd.service[p[1]].name! + 'Service'] =
location.leadingComments || '';
const serviceName = fd.service[p[1]].name!;
const comments = (location.leadingComments || '')
.split('\n')
.slice(0, -1);
const serviceComment: Comment = {
paramName: '',
paramType: '',
comments,
};
commentsMap[serviceName] = serviceComment;
}
} else if (p.length === 4 && p[2] === 2) {
} else if (p.length === 4 && p[2] === 2 && p[0] === 6) {
if (
fd.service &&
fd.service[p[1]] &&
fd.service[p[1]].method &&
fd.service[p[1]].method![p[3]] &&
fd.service[p[1]].method![p[3]].name
) {
const name = fd.service[p[1]].method![p[3]].name!;
if (!commentsMap[name]) {
commentsMap[name] = location.leadingComments || '';
const serviceName = fd.service[p[1]].name!;
// add method comment into the map
const methodName = fd.service[p[1]].method![p[3]].name!;
if (!commentsMap[methodName]) {
const comments = (location.leadingComments || '').split('\n');
const key = serviceName + ':' + methodName;
const methodComment: Comment = {
paramName: '',
paramType: '',
comments,
};
commentsMap[key] = methodComment;
}
}
} else if (p.length === 4 && p[0] === 4 && p[2] === 2) {
// This contains a field's information
// example, this path:
// [ 4, 3, 2, 7, 1 ]
// refers to:
// file.message_type(3) // 4, 3
// .field(7) // 2, 7
// .name() // 1
// This is because FileDescriptorProto.message_type has field number 4:
// repeated DescriptorProto message_type = 4;
// and DescriptorProto.field has field number 2:
// repeated FieldDescriptorProto field = 2;
// and FieldDescriptorProto.name has field number 1:
// optional string name = 1;
if (
fd.messageType &&
fd.messageType[p[1]] &&
fd.messageType[p[1]].field &&
fd.messageType[p[1]].field![p[3]]
) {
const messageType = fd.messageType[p[1]].name;
const field = fd.messageType[p[1]].field![p[3]];
// console.warn(field);
if (field) {
//Type Enum: TYPE_STRING, TYPE_BOOL, etc.
let paramType =
plugin.google.protobuf.FieldDescriptorProto.Type[field.type!];
// If field.label is 'REPEATED' then the paramType is an array.
if (field.label === 3) {
paramType += '[]';
}
const paramName = field.name || '';
if (
paramType === 'TYPE_MESSAGE' ||
paramType === 'TYPE_ENUM' ||
paramType === 'TYPE_GROUP'
) {
paramType = field.typeName!;
}
const comments = (location.leadingComments || '')
.split('\n')
.slice(0, -1);
const fieldComment: Comment = {
paramName,
paramType,
comments,
};
const key = messageType + ':' + field.name;
commentsMap[key] = fieldComment;
}
}
}
Expand All @@ -63,9 +143,18 @@ export class CommentsMap {
return this.comments;
}
getServiceComment(serviceName: string) {
return this.comments[serviceName + 'Service'].trim();
return this.comments[serviceName]
? this.comments[serviceName].comments
: [];
}
getMethodComments(serviceName: string, methodName: string) {
const key = serviceName + ':' + methodName;
return this.comments[key] ? this.comments[key].comments : [];
}
getMethodComments(methodName: string): string {
return this.comments[methodName].trim();
getParamComments(messageName: string, fieldName: string): Comment {
const key = messageName + ':' + fieldName;
return this.comments[key]
? this.comments[key]
: { paramName: '', paramType: '', comments: [] };
}
}

0 comments on commit 48011c6

Please sign in to comment.