blob: d3053c91a551692b5f350b329012b3119941ad82 [file] [log] [blame]
// Copyright 2020 Google LLC. All Rights Reserved.
//
// 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
//
// http://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.
// gnostic-complexity is a plugin that generates a complexity summary of an API.
package main
import (
"encoding/json"
"path/filepath"
"github.com/golang/protobuf/proto"
metrics "github.com/googleapis/gnostic/metrics"
openapiv2 "github.com/googleapis/gnostic/openapiv2"
openapiv3 "github.com/googleapis/gnostic/openapiv3"
plugins "github.com/googleapis/gnostic/plugins"
)
// This is the main function for the plugin.
func main() {
env, err := plugins.NewEnvironment()
env.RespondAndExitIfError(err)
var complexity *metrics.Complexity
for _, model := range env.Request.Models {
switch model.TypeUrl {
case "openapi.v2.Document":
documentv2 := &openapiv2.Document{}
err = proto.Unmarshal(model.Value, documentv2)
if err == nil {
complexity = analyzeOpenAPIv2Document(documentv2)
}
case "openapi.v3.Document":
documentv3 := &openapiv3.Document{}
err = proto.Unmarshal(model.Value, documentv3)
if err == nil {
complexity = analyzeOpenAPIv3Document(documentv3)
}
}
}
if complexity != nil {
// Return JSON-serialized output.
file := &plugins.File{}
file.Name = filepath.Join(filepath.Dir(env.Request.SourceName), "complexity.json")
file.Data, err = json.MarshalIndent(complexity, "", " ")
env.RespondAndExitIfError(err)
file.Data = append(file.Data, []byte("\n")...)
env.Response.Files = append(env.Response.Files, file)
// Return binary-serialized output.
file2 := &plugins.File{}
file2.Name = filepath.Join(filepath.Dir(env.Request.SourceName), "complexity.pb")
file2.Data, err = proto.Marshal(complexity)
env.RespondAndExitIfError(err)
env.Response.Files = append(env.Response.Files, file2)
}
env.RespondAndExit()
}
func newComplexity() *metrics.Complexity {
return &metrics.Complexity{}
}
func analyzeOpenAPIv2Document(document *openapiv2.Document) *metrics.Complexity {
summary := newComplexity()
if document.Definitions != nil && document.Definitions.AdditionalProperties != nil {
for _, pair := range document.Definitions.AdditionalProperties {
analyzeSchema(summary, pair.Value)
}
}
for _, pair := range document.Paths.Path {
summary.PathCount++
v := pair.Value
if v.Get != nil {
summary.GetCount++
}
if v.Post != nil {
summary.PostCount++
}
if v.Put != nil {
summary.PutCount++
}
if v.Delete != nil {
summary.DeleteCount++
}
}
return summary
}
func analyzeSchema(summary *metrics.Complexity, schema *openapiv2.Schema) {
summary.SchemaCount++
if schema.Properties != nil {
for _, pair := range schema.Properties.AdditionalProperties {
summary.SchemaPropertyCount++
analyzeSchema(summary, pair.Value)
}
}
}
func analyzeOpenAPIv3Document(document *openapiv3.Document) *metrics.Complexity {
summary := newComplexity()
if document.Components != nil && document.Components.Schemas != nil {
for _, pair := range document.Components.Schemas.AdditionalProperties {
analyzeOpenAPIv3Schema(summary, pair.Value)
}
}
for _, pair := range document.Paths.Path {
summary.PathCount++
v := pair.Value
if v.Get != nil {
summary.GetCount++
}
if v.Post != nil {
summary.PostCount++
}
if v.Put != nil {
summary.PutCount++
}
if v.Delete != nil {
summary.DeleteCount++
}
}
return summary
}
func analyzeOpenAPIv3Schema(summary *metrics.Complexity, schemaOrReference *openapiv3.SchemaOrReference) {
summary.SchemaCount++
schema := schemaOrReference.GetSchema()
if schema != nil && schema.Properties != nil {
for _, pair := range schema.Properties.AdditionalProperties {
summary.SchemaPropertyCount++
analyzeOpenAPIv3Schema(summary, pair.Value)
}
}
}