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

Generate a method providing TypeUrl for Protobuf types compiled to JS #255

Merged
merged 122 commits into from
Dec 27, 2018

Conversation

dmytro-grankin
Copy link
Contributor

@dmytro-grankin dmytro-grankin commented Dec 17, 2018

A possibility to obtain a TypeUrl for a message is convenient, but Protobuf definitions compiled to JS don't provide such a possibility.

So, to allow convenient obtaining of TypeUrl, this PR enhances ProtoJsPlugin. The plugin now generates the static typeUrl() method for every message and enum type.

Other changes:

  • The naming of classes related to JS code-generation was improved.
  • The package structure for ProtoJsPlugin was changed to keep related classes in a single package.
  • A code Snippet was introduced as a replacement of JsCodeGenerator. The Snippet has no side effects as the generator does.
  • CodeLine was made abstract and now have different implementations.
  • The configuration of test projects via GradleProject was changed. Now, instead of copying config submodule and version.gradle, the path to the root of spine-base is supplied. So, test configuration can reference e.g. the version.gradle via ${enclosingRootDir}/version.gradle.

The further improvements is a matter of SpineEventEngine/mc-js#8.

@dmytro-grankin dmytro-grankin self-assigned this Dec 17, 2018
@codecov
Copy link

codecov bot commented Dec 17, 2018

Codecov Report

Merging #255 into master will increase coverage by 0.05%.
The diff coverage is 87.63%.

@@             Coverage Diff              @@
##             master     SpineEventEngine/base#255      +/-   ##
============================================
+ Coverage     74.68%   74.74%   +0.05%     
- Complexity      649      689      +40     
============================================
  Files           292      302      +10     
  Lines          8051     8236     +185     
  Branches        537      551      +14     
============================================
+ Hits           6013     6156     +143     
- Misses         1911     1944      +33     
- Partials        127      136       +9

@dmytro-grankin
Copy link
Contributor Author

@dmdashenkov PTAL.

Copy link
Contributor

@dmdashenkov dmdashenkov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmytro-grankin, please see my comments.
As a general notice, some classes seem a bit ad hoc, e.g. when using raw String type to represent a piece of JS code. Maybe, there is a layer of abstraction missing.

@@ -46,7 +47,8 @@ private EnumType(EnumDescriptor descriptor,
super(descriptor, descriptorProto, className, typeUrl);
}

private static EnumType create(EnumDescriptor descriptor) {
@VisibleForTesting
public static EnumType create(EnumDescriptor descriptor) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please find a way to make this method package-private. public is way too broad.

* Creates a message type for the provided descriptor.
*/
@VisibleForTesting
public static MessageType create(Descriptor descriptor) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

* <p>Does nothing if there are no Protobuf files to process.
*/
public final void perform() {
if (!hasFilesToProcess()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please (un-)invert the condition. This way the code becomes a bit more descriptive.

* Obtains the name of the type in the generated code.
*/
public TypeName name() {
return TypeName.from(type.descriptor());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is the Type.name() method for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a different TypeName, from io.spine.code.js.

@@ -37,13 +36,13 @@
* <p>The class generates the {@code fromJson} and {@code fromObject} methods for each message
* declared in the {@link FileDescriptor}.
*/
public final class FileGenerator extends JsCodeGenerator {
public final class TypesParsingExtension extends JsCodeGenerator {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public final class TypesParsingExtension extends JsCodeGenerator {
public final class TypeParsingExtension extends JsCodeGenerator {

@Override
public void generate() {
generateStaticMethod();
jsOutput().addEmptyLine();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The TypeUrlMethod class, apparently, as well as all JsCodeGenerators use an output parameter jsOutput instead of returning values. Such a pattern adds a side effect to the JsCodeGenerator.generate() method.

Instead, we should make the method pure and write the result to the output when necessary.

/**
* An enhancement of generated Protobuf sources.
*/
public abstract class FileSetEnhancement {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please elaborate on the class description. Maybe, you'll come up with a better name while doing so. Currently, I do not entirely understand the concept.

@@ -60,57 +58,34 @@
* message stored in a file.
* </ol>
*/
public final class JsonParsersWriter {
public final class ParsingOfObjects extends FileSetEnhancement {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class name is strange. From the name, it seems like the object describes the process of parsing.
Please think of a better name.

@SpineEventEngine SpineEventEngine deleted a comment Dec 25, 2018
@SpineEventEngine SpineEventEngine deleted a comment Dec 26, 2018
@SpineEventEngine SpineEventEngine deleted a comment Dec 26, 2018
@SpineEventEngine SpineEventEngine deleted a comment Dec 26, 2018
@SpineEventEngine SpineEventEngine deleted a comment Dec 26, 2018
@dmytro-grankin
Copy link
Contributor Author

@armiol PTAL.

Copy link
Collaborator

@armiol armiol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmytro-grankin please see my comments.

import static com.google.common.base.Preconditions.checkNotNull;

/**
* A reference to a method.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To a method of what? Please update the description so that it's clear without analyzing the fields of this class.

* @param fileSet
* the Protobuf files to generate code for
*/
public final void perform(FileSet fileSet) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perform hardly reads with fileSet. It's either performAt or performFor.

*
* @return {@code true} if there are files to process and {@code false} otherwise
*/
private boolean shouldPerform(FileSet fileSet) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's call it by what it really does, e.g. hasFiles.

/**
* The declaration of a method in Javascript code.
*/
public class Method implements Snippet {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's weird to me that Method has no relation to MethodReference. They seem to describe the same thing twice.

@@ -76,5 +76,6 @@ protobuf {
build.dependsOn compileProtoToJs

dependencies {
protobuf "io.spine:spine-base:${spineVersion}"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems wrong, as it references the "previously" published artifact, not the current one.

You can refer to base protos via filesystem if you need those to be taken into account during their generation. If you are not completely sure, let's discuss.

@@ -58,7 +62,7 @@
* <p>The parsers may be used to parse JSON via their {@code parse(value)} method.
*/
@SuppressWarnings("OverlyCoupledClass") // Dependencies for the listed Protobuf types.
public final class ProtoParsersGenerator extends JsCodeGenerator {
public final class ExportStandardParsersMap implements Snippet {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand calling this snipped ending with Map. Will we need to rename the class if it stops generating a Map but generates a JS class instead?

@SpineEventEngine SpineEventEngine deleted a comment Dec 26, 2018
@dmytro-grankin
Copy link
Contributor Author

@armiol PTAL.

Copy link
Collaborator

@armiol armiol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmytro-grankin LGTM with some minor changes to be made. And please create an issue to migrate from implementation dependency onto base artifact in JS tests.

* the value to adjust the depth by
* @return a new line with increased depth
*/
IndentedLine adjustDepthBy(int depthChange) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not called depth anymore. Let's fix the code and the documentation to reference an indentation level.

import static com.google.common.base.Preconditions.checkNotNull;

/**
* A single-lined comment.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

single-line.


@Override
public String content() {
return "// " + text;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not do that every time. This class is immutable, so we can compose the content right away.


private final MethodReference reference;
private final List<String> arguments;
private final List<CodeLine> bodyLines;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why this isn't CodeLines.

I also think that this is just body.

public class Method implements Snippet {

private final MethodReference reference;
private final List<String> arguments;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Arguments" are real values, "parameters" are declarations. I.e.

// `a` and `b` are the names of parameters.
int sum(int a, int b) {...};

// `5` and `10` are arguments.
int result = sum(5, 10);

I am not sure what you meant, so please adjust the code with the account of parameter/argument difference.

@@ -18,7 +18,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package io.spine.code;
package io.spine.code.generate;

/**
* Constants for code generation.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As long as we repackage.

Let's move ModelCompilerAnnotation to the top level, kill Generation (as it isn't what it claims to be) and rename ModelCompilerAnnotation to GeneratedBySpine. Ideally we need to relate this new class to the Generated annotation itself, e.g. return it from this class.

@dmytro-grankin dmytro-grankin merged commit e876685 into master Dec 27, 2018
@dmytro-grankin dmytro-grankin deleted the generate-type-url-for-js-messages branch December 27, 2018 17:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants