Skip to content

Commit

Permalink
Add --attribute-comment argument to JS and TSD clients (#268)
Browse files Browse the repository at this point in the history
Add --attribute-comment field to js_client.py and tsd_client.py, like the one added to python_client.py in #262. This is a prerequisite for dropbox/dropbox-sdk-js#891 which adds scopes to the outputted clients for easier reference.

Also adds appropriate testing and updates the docstring for the python_client.py, making it more succinct and aligned with the other two.
  • Loading branch information
sderickson committed Feb 1, 2022
1 parent 90dd831 commit 9600065
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 10 deletions.
23 changes: 23 additions & 0 deletions stone/backends/js_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@
from stone.ir import Void

_cmdline_parser = argparse.ArgumentParser(prog='js-client-backend')

_cmdline_parser.add_argument(
'filename',
help=('The name to give the single Javascript file that is created and '
'contains all of the routes.'),
)

_cmdline_parser.add_argument(
'-c',
'--class-name',
Expand All @@ -38,6 +40,7 @@
'The name will be added to each function documentation, which makes '
'it available for tools like JSDoc.'),
)

_cmdline_parser.add_argument(
'--wrap-response-in',
type=str,
Expand All @@ -52,6 +55,15 @@
help=('Wraps the error in an error class')
)

_cmdline_parser.add_argument(
'-a',
'--attribute-comment',
action='append',
type=str,
default=[],
help=('Attributes to include in route documentation comments.'),
)

_header = """\
// Auto-generated by Stone, do not modify.
var routes = {};
Expand Down Expand Up @@ -88,6 +100,17 @@ def _generate_route(self, route_schema, namespace, route):
self.emit('/**')
if route.doc:
self.emit_wrapped_text(self.process_doc(route.doc, self._docf), prefix=' * ')

attrs_lines = []
if self.args.attribute_comment and route.attrs:
for attribute in self.args.attribute_comment:
if attribute in route.attrs and route.attrs[attribute] is not None:
attrs_lines.append(' * {}: {}'.format(attribute, route.attrs[attribute]))
if attrs_lines:
self.emit(' * Route attributes:')
for a in attrs_lines:
self.emit(a)

if self.args.class_name:
self.emit(' * @function {}#{}'.format(self.args.class_name,
function_name))
Expand Down
5 changes: 1 addition & 4 deletions stone/backends/python_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,7 @@
action='append',
type=str,
default=[],
help=('Route attributes that the backend will have access to and '
'presumably expose in generated code. Use ":all" to select all '
'attributes defined in stone_cfg.Route. Attributes will be '
"exposed in the documentation, as the client doesn't use them."),
help=('Attributes to include in route documentation comments.'),
)


Expand Down
20 changes: 20 additions & 0 deletions stone/backends/tsd_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,14 @@
help=('If using the --import-namespaces flag, this is the file that contains '
'the named exports to import here.')
)
_cmdline_parser.add_argument(
'-a',
'--attribute-comment',
action='append',
type=str,
default=[],
help=('Attributes to include in route documentation comments.'),
)

_header = """\
// Auto-generated by Stone, do not modify.
Expand Down Expand Up @@ -178,6 +186,18 @@ def _generate_route(self, namespace, route):
if route.doc:
self.emit_wrapped_text(self.process_doc(route.doc, self._docf), prefix=' * ')
self.emit(' *')

attrs_lines = []
if self.args.attribute_comment and route.attrs:
for attribute in self.args.attribute_comment:
if attribute in route.attrs and route.attrs[attribute] is not None:
attrs_lines.append(' * {}: {}'.format(attribute, route.attrs[attribute]))
if attrs_lines:
self.emit(' * Route attributes:')
for a in attrs_lines:
self.emit(a)
self.emit(' *')

self.emit_wrapped_text('When an error occurs, the route rejects the promise with type %s.'
% fmt_error_type(route.error_data_type,
wrap_error_in=self.args.wrap_error_in), prefix=' * ')
Expand Down
63 changes: 60 additions & 3 deletions test/test_js_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,17 @@ def _get_api(self):
api = Api(version='0.1b1')
api.route_schema = Struct('Route', 'stone_cfg', None)
route1 = ApiRoute('get_metadata', 1, None)
route1.set_attributes(None, ':route:`get_metadata`', Void(), Void(), Void(), {})
route1.set_attributes(None, ':route:`get_metadata`', Void(), Void(), Void(), {
'scope': 'events.read'
})
route2 = ApiRoute('get_metadata', 2, None)
route2.set_attributes(None, ':route:`get_metadata:2`', Void(), Int32(), Void(), {})
route2.set_attributes(None, ':route:`get_metadata:2`', Void(), Int32(), Void(), {
'scope': 'events.read'
})
route3 = ApiRoute('get_metadata', 3, None)
route3.set_attributes(None, ':route:`get_metadata:3`', Int32(), Int32(), Void(), {})
route3.set_attributes(None, ':route:`get_metadata:3`', Int32(), Int32(), Void(), {
'scope': None
})
ns = ApiNamespace('files')
ns.add_route(route1)
ns.add_route(route2)
Expand Down Expand Up @@ -141,3 +147,54 @@ def test_route_with_version_number_conflict(self):
backend.generate(api)
self.assertTrue(str(cm.exception).startswith(
'There is a name conflict between'))

def test_route_with_attributes_in_docstring(self):
# type: () -> None

api, _ = self._get_api()
backend = JavascriptClientBackend(
target_folder_path='output',
args=['files', '-c', 'DropboxBase', '-a', 'scope'])
get_result = _mock_output(backend)
backend.generate(api)
result = get_result()

expected = textwrap.dedent('''\
// Auto-generated by Stone, do not modify.
var routes = {};
/**
* get_metadata
* Route attributes:
* scope: events.read
* @function DropboxBase#filesGetMetadata
* @returns {Promise.<void, Error.<void>>}
*/
routes.filesGetMetadata = function () {
return this.request("files/get_metadata", null);
};
/**
* get_metadata_v2
* Route attributes:
* scope: events.read
* @function DropboxBase#filesGetMetadataV2
* @returns {Promise.<number, Error.<void>>}
*/
routes.filesGetMetadataV2 = function () {
return this.request("files/get_metadata_v2", null);
};
/**
* get_metadata_v3
* @function DropboxBase#filesGetMetadataV3
* @arg {number} arg - The request parameters.
* @returns {Promise.<number, Error.<void>>}
*/
routes.filesGetMetadataV3 = function (arg) {
return this.request("files/get_metadata_v3", arg);
};
export { routes };
''')
assert result == expected
54 changes: 51 additions & 3 deletions test/test_tsd_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,17 @@ def _get_api(self):
api = Api(version='0.1b1')
api.route_schema = Struct('Route', 'stone_cfg', None)
route1 = ApiRoute('get_metadata', 1, None)
route1.set_attributes(None, ':route:`get_metadata`', Void(), Void(), Void(), {})
route1.set_attributes(None, ':route:`get_metadata`', Void(), Void(), Void(), {
'scope': 'events.read'
})
route2 = ApiRoute('get_metadata', 2, None)
route2.set_attributes(None, ':route:`get_metadata:2`', Void(), Int32(), Void(), {})
route2.set_attributes(None, ':route:`get_metadata:2`', Void(), Int32(), Void(), {
'scope': 'events.read'
})
route3 = ApiRoute('get_metadata', 3, None)
route3.set_attributes(None, ':route:`get_metadata:3`', Int32(), Int32(), Void(), {})
route3.set_attributes(None, ':route:`get_metadata:3`', Int32(), Int32(), Void(), {
'scope': None
})
ns = ApiNamespace('files')
ns.add_route(route1)
ns.add_route(route2)
Expand Down Expand Up @@ -120,3 +126,45 @@ def test_route_with_version_number_conflict(self):
backend._generate_routes(api, 0, 0)
self.assertTrue(str(cm.exception).startswith(
'There is a name conflict between'))

def test_route_with_attributes_in_docstring(self):
# type: () -> None
api, _ = self._get_api()
backend = TSDClientBackend(
target_folder_path="output",
args=['files', 'files', '-a', 'scope']
)
backend._generate_routes(api, 0, 0)
result = backend.output_buffer_to_string()
expected = textwrap.dedent(
'''\
/**
* getMetadata()
*
* Route attributes:
* scope: events.read
*
* When an error occurs, the route rejects the promise with type Error<void>.
*/
public filesGetMetadata(): Promise<void>;
/**
* getMetadataV2()
*
* Route attributes:
* scope: events.read
*
* When an error occurs, the route rejects the promise with type Error<void>.
*/
public filesGetMetadataV2(): Promise<number>;
/**
* getMetadataV3()
*
* When an error occurs, the route rejects the promise with type Error<void>.
* @param arg The request parameters.
*/
public filesGetMetadataV3(arg: number): Promise<number>;
''')
self.assertEqual(result, expected)

0 comments on commit 9600065

Please sign in to comment.