Repository: googleapis/api-linter
Pull request #240 (2019-10-17 22:19:21)

[AIP-140] Add rule prohibiting prepositions.


Patch:
diff --git a/go.mod b/go.mod
index 4a9426f..4b61ad8 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,7 @@ module github.com/googleapis/api-linter
 go 1.12
 
 require (
+	bitbucket.org/creachadair/stringset v0.0.8
 	github.com/bmatcuk/doublestar v1.1.5
 	github.com/gertd/go-pluralize v0.1.1
 	github.com/golang/protobuf v1.3.2
diff --git a/go.sum b/go.sum
index 779b44d..3195b53 100644
--- a/go.sum
+++ b/go.sum
@@ -1,3 +1,5 @@
+bitbucket.org/creachadair/stringset v0.0.8 h1:gQqe4vs8XWgMyijfyKE6K8o4TcyGGrRXe0JvHgx5H+M=
+bitbucket.org/creachadair/stringset v0.0.8/go.mod h1:AgthVMyMxC/6FK1KBJ2ALdqkZObGN8hOetgpwXyMn34=
 cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/bmatcuk/doublestar v1.1.5 h1:2bNwBOmhyFEFcoB3tGvTD5xanq+4kyOZlB8wFYbMjkk=
@@ -5,6 +7,7 @@ github.com/bmatcuk/doublestar v1.1.5/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creachadair/staticfile v0.1.2/go.mod h1:a3qySzCIXEprDGxk6tSxSI+dBBdLzqeBOMhZ+o2d3pM=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/gertd/go-pluralize v0.1.1 h1:fQhql/WRRwr4TVp+TCw12s2esCacvEVBdkTUUwNqF/Q=
diff --git a/rules/aip0140/aip0140.go b/rules/aip0140/aip0140.go
index 475c64c..f6c4f78 100644
--- a/rules/aip0140/aip0140.go
+++ b/rules/aip0140/aip0140.go
@@ -34,6 +34,7 @@ func AddRules(r lint.RuleRegistry) {
 		abbreviationsService,
 		base64,
 		lowerSnake,
+		noPrepositions,
 	)
 }
 
diff --git a/rules/aip0140/prepositions.go b/rules/aip0140/prepositions.go
new file mode 100644
index 0000000..71ec48f
--- /dev/null
+++ b/rules/aip0140/prepositions.go
@@ -0,0 +1,46 @@
+// Copyright 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 		https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package aip0140
+
+import (
+	"fmt"
+	"strings"
+
+	"bitbucket.org/creachadair/stringset"
+	"github.com/googleapis/api-linter/lint"
+	"github.com/jhump/protoreflect/desc"
+)
+
+var noPrepositions = &lint.FieldRule{
+	Name: lint.NewRuleName("core", "0140", "prepositions"),
+	URI:  "https://aip.dev/140#prepositions",
+	LintField: func(f *desc.FieldDescriptor) (problems []lint.Problem) {
+		banned := stringset.New(
+			"after", "at", "before", "between", "but", "by", "except",
+			"for", "in", "including", "into", "of", "over", "since", "to",
+			"toward", "under", "upon", "with", "within", "without",
+		)
+		for _, word := range strings.Split(f.GetName(), "_") {
+			if banned.Contains(word) {
+				problems = append(problems, lint.Problem{
+					Message:    fmt.Sprintf("Avoid using %q in field names.", word),
+					Descriptor: f,
+					Location:   lint.DescriptorNameLocation(f),
+				})
+			}
+		}
+		return
+	},
+}


Test patch:
diff --git a/rules/aip0140/prepositions_test.go b/rules/aip0140/prepositions_test.go
new file mode 100644
index 0000000..f1455e6
--- /dev/null
+++ b/rules/aip0140/prepositions_test.go
@@ -0,0 +1,45 @@
+// Copyright 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 		https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package aip0140
+
+import (
+	"testing"
+
+	"github.com/googleapis/api-linter/rules/internal/testutils"
+)
+
+func TestNoPrepositions(t *testing.T) {
+	tests := []struct {
+		Name     string
+		problems testutils.Problems
+	}{
+		{"author", testutils.Problems{}},
+		{"written_by", testutils.Problems{{Message: "by"}}},
+		{"move_toward_shelf_at_front", testutils.Problems{{Message: "toward"}, {Message: "at"}}},
+	}
+	for _, test := range tests {
+		t.Run(test.Name, func(t *testing.T) {
+			file := testutils.ParseProto3Tmpl(t, `
+				message Book {
+					string {{.Name}} = 1;
+				}
+			`, test)
+			field := file.GetMessageTypes()[0].GetFields()[0]
+			if diff := test.problems.SetDescriptor(field).Diff(noPrepositions.Lint(file)); diff != "" {
+				t.Errorf(diff)
+			}
+		})
+	}
+}