Skip to content
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

Add --attribute-comment argument to JS and TSD clients #268

Merged
merged 6 commits into from
Feb 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)