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

File-level go.lint option #32

Merged
merged 1 commit into from
Jan 1, 2021
Merged

File-level go.lint option #32

merged 1 commit into from
Jan 1, 2021

Conversation

ydnar
Copy link
Contributor

@ydnar ydnar commented Dec 25, 2020

This PR borrows code from https://golang.org/x/lint to automatically fix initialisms and stuttering in generated names.

Thanks to @Green7 for the initial implementation in #22!

@ydnar ydnar self-assigned this Dec 25, 2020
@ydnar
Copy link
Contributor Author

ydnar commented Dec 26, 2020

I’m not sure about this. It’s kind of gross, kind of magic.

@ydnar ydnar force-pushed the ydnar/lint branch 2 times, most recently from f45e414 to 6ddf957 Compare December 28, 2020 00:10
@ydnar ydnar changed the title File-level (go.lint) option File-level go.lint option Dec 28, 2020
ydnar added a commit that referenced this pull request Dec 28, 2020
ydnar added a commit that referenced this pull request Dec 29, 2020
@ydnar
Copy link
Contributor Author

ydnar commented Dec 29, 2020

Feeling better about this now. @Green7 want to take a look?

@ydnar ydnar marked this pull request as ready for review December 29, 2020 00:50
@Green7
Copy link

Green7 commented Dec 29, 2020

Feeling better about this now. @Green7 want to take a look?

I tried and I have such observations:
If option go.lint is set, common initialisms are always used. Even if we set option (go.initialisms) = "MYOWN".
This can be problematic because we cannot turn off standard initialisms and they change type names too.
Also if we want to change only the enums all common initlialism will be changed.

Regarding the enums:
In this version I was unable to truncate the enum prefix. For example I have value OriginalEnum_A, and it has been changed to OriginalenumA but how to get A ?

@ydnar
Copy link
Contributor Author

ydnar commented Dec 29, 2020

If option go.lint is set, common initialisms are always used. Even if we set option (go.initialisms) = "MYOWN".

This can be problematic because we cannot turn off standard initialisms and they change type names too.

Do you have an example of this? What do you want or expect to happen?

Also if we want to change only the enums all common initlialism will be changed.

What do you mean by this?

Regarding the enums:

In this version I was unable to truncate the enum prefix. For example I have value OriginalEnum_A, and it has been changed to OriginalenumA but how to get A ?

Idiomatic Go specifies that global vars or const values should be prefixed with the type name.

https://talks.golang.org/2014/names.slide#14

@Green7
Copy link

Green7 commented Dec 29, 2020

Do you have an example of this? What do you want or expect to happen?

Here is an example proto file:

syntax = "proto3";
package tests.enum;
import "patch/go.proto";

option go_package = "test/test";
option (go.lint) = true;
option (go.initialisms) = "ID";

enum OriginalEnum {
  INVALID = 0;
  A = 1;
  B = 2;
  C = 3;
}
message IdFieldsTest {
  string id = 1;
  string customer_id = 2;
  string api_path = 3;
}

I have: option (go.initialisms) = "ID";
So I expect that only fields named id will be changed.
But there are more changes:
ApiPath -> APIPath
IdFieldsTest -> IDFieldsTest
OriginalEnum_A -> OriginalenumA etc.

Idiomatic Go specifies that global vars or const values should be prefixed with the type name.

Yes, but i have codebase without prefixes because I used gogoprotobuf with option goproto_enum_prefix_all to generate my files. Now I want replace gogoprotobuf with protopatch and get the same result.

ydnar added a commit that referenced this pull request Dec 29, 2020
ydnar added a commit that referenced this pull request Dec 29, 2020
Thanks to @Green7 for the breaking examples:
#32 (comment)
@ydnar
Copy link
Contributor Author

ydnar commented Dec 30, 2020

@Green7 I added your examples as test cases and fixed an issue with enum value name generation.

Fixed: OriginalEnum_AOriginalEnumA

Are you saying you don’t want all names like ApiPath to be linted?

@Green7
Copy link

Green7 commented Dec 30, 2020

Are you saying you don’t want all names like ApiPath to be linted?

I think it should be fully configurable. It should be possible to disable common initlialism if we don't want them.
Why? I have many proto files in my current project. Until now, I only changed the ID fields (through gogoprotobuf). If I use common initlialism now, I think many other fields will be fixed, which will result in a lot of code changes.
What's worse, some messages are saved to the database, which may also require conversion in the database.
Generally, this may be relevant for existing projects.

@ydnar
Copy link
Contributor Author

ydnar commented Dec 30, 2020

Makes sense. In your case I'd recommend using an explicit (go.value).name option on the enum values with ID.

@Green7
Copy link

Green7 commented Dec 30, 2020

Makes sense. In your case I'd recommend using an explicit (go.value).name option on the enum values with ID.

I do not understand. It's not just about the enum values. I would like to change only the ID fields in all files without touching other names. How can this be achieved?

@ydnar
Copy link
Contributor Author

ydnar commented Dec 30, 2020

Makes sense. In your case I'd recommend using an explicit (go.value).name option on the enum values with ID.

I do not understand. It's not just about the enum values. I would like to change only the ID fields in all files without touching other names. How can this be achieved?

For messages:

message ExampleId {
    option (go.message).name = "ExampleID";
    // ...
}

For fields:

message Account {
    string id = 1; [(go.field).name = "ID"];
}

etc.

@ydnar
Copy link
Contributor Author

ydnar commented Dec 30, 2020

To be clear, it doesn’t make sense to use a hammer (linting/renaming) when you only want to selectively rename certain things. It’s better to be explicit at the declaration of the specific field or enum value you wish to rename, particularly if you only care about renames with ID.

@Green7
Copy link

Green7 commented Dec 30, 2020

For fields:

message Account {
    string id = 1; [(go.field).name = "ID"];
}

I have about 50 proto files. There are many fields in each with the name id or _id. Tagging each one separately is a lot of work. And I will have to remember to tag each newly added field as well.
Don't you think it would be simpler to be able to enable this option once for the entire file?

@ydnar
Copy link
Contributor Author

ydnar commented Dec 30, 2020

For fields:

message Account {
    string id = 1; [(go.field).name = "ID"];
}

I have about 50 proto files. There are many fields in each with the name id or _id. Tagging each one separately is a lot of work. And I will have to remember to tag each newly added field as well.
Don't you think it would be simpler to be able to enable this option once for the entire file?

I actually think it’s simpler for you to add this to your fields. It’s one change, ideally a straightforward regexp find and replace. Assuming you have tests, it’s a single commit, and you’re done.

I prefer that to a specialized code path in this package that will have to be maintained forever just to rename some things with the word ID in them.

To explain further: a goal of this project is to have a minimal interface, with fewer options, and in general, one way to do something. Second, if something can be accomplished with a bit more typing, but is simpler and more understandable by folks reading the code, that’s preferable to a global option.

@Green7
Copy link

Green7 commented Dec 30, 2020

To explain further: a goal of this project is to have a minimal interface, with fewer options, and in general, one way to do something. Second, if something can be accomplished with a bit more typing, but is simpler and more understandable by folks reading the code, that’s preferable to a global option.

I understand your point of view: but I have a different. For me, a tool is good when it allows me to achieve the effect I want. gogoprotobuf was such a tool, it was easy to add any code modifying field names.

Summarizing my attempt to make changes in protopatch:

  • I can set the id fields manually (through (go.value).name) exactly as before
  • I can't disable enum prefixes
    Basically nothing has changed and after 25 days I am at the starting point. I am honestly disappointed :(

@ydnar
Copy link
Contributor Author

ydnar commented Dec 30, 2020

  • I can't disable enum prefixes

This is a separate feature, and I agree it’s worth implementing.

@Green7
Copy link

Green7 commented Dec 31, 2020

  • I can't disable enum prefixes

This is a separate feature, and I agree it’s worth implementing.

that's good 👍 when it may be available ?
After thinking: I will try to enable the liner option in my project - it will correct the ID fields and others. Then for the other fields I will set old name (through go.field), or change the code.
It will probably be a lot less work. This could be the solution.

Usage:

option (go.all.values.prefix = '') // To omit all enum type prefixes by default

patch: de-nested FileOptions

patch/gopb: recompile protos

lint: copy lintName func from golang.org/x/lint

patch, patch/gopb: simplify file-level options interface

patch: add file-level name linting via (go.lint) = true

This will fix non-idiomatic generated Go code with initialisms like Url→URL and Id→ID.

tests/lint: smoke tests for (go.lint) option

patch: introduce comments into dense Patcher methods

CHANGELOG: add note about go.lint option, thanks to @Green7

patch, tests/lint: lint extension names

patch, patch/gopb: remove unused Prefix option

CHANGELOG: update for changes in #32

patch: look at enum value parent file, not enum, even though they are the same

patch, tests/lint: new file-level go.initialisms option to specify additional initialisms for linting

Example: (go.initialisms) = 'RGB'; // Will convert RgbColor to RGBColor

tests/lint: add tests from @Green7 in #32

patch: improve enum value name linting

Thanks to @Green7 for the breaking examples:
#32 (comment)

patch, tests/lint: correctly lint nested enum value names

patch: replacePrefix should only replace prefix if it exists

patch: dry up enum value renaming logic

patch: remove unnecessary duplicate branch

tests/lint: improve nested enum tests

tests/lint: test case for linting (and fixing) a custom name

tests/enum: conformance tests for deeply-nested enums

patch: correctly mimic protogen’s name generation for nested enum values

tests/lint: additional lint tests for renamed nested enums

tests/enum: rework enum conformance and renaming tests

CHANGELOG: added note about correct nested enum value renaming

tests/message: improve message tests
@ydnar ydnar merged commit a553e85 into main Jan 1, 2021
@ydnar ydnar deleted the ydnar/lint branch January 1, 2021 00:25
@ydnar ydnar restored the ydnar/lint branch January 1, 2021 00:26
@ydnar ydnar deleted the ydnar/lint branch January 1, 2021 00:26
@ydnar ydnar mentioned this pull request Jan 1, 2021
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.

2 participants