diff --git a/pkg/modules/2_backend_optimizer.go b/pkg/modules/2_backend_optimizer.go index fbd1f5a..ab44031 100644 --- a/pkg/modules/2_backend_optimizer.go +++ b/pkg/modules/2_backend_optimizer.go @@ -23,13 +23,13 @@ func NewOptimizerImpl(pluginOptions *proto.PluginOptions) *OptimizerImpl { return &OptimizerImpl{schemaByRef: jsonschema.NewOrderedSchemaMap(), pluginOptions: pluginOptions} } -const refCountKey = "refCount" +const linkedFromEntrypoint = "linkedFromEntrypoint" func (o *OptimizerImpl) Optimize(registry *jsonschema.Registry, entrypointMessage pgs.Message) { entrypointSchemaRef := toRefId(entrypointMessage) entrypointSchema := registry.GetSchema(entrypointSchemaRef.String()) - o.increaseSchemaRefCount(registry, entrypointSchemaRef.String()) + o.checkAndMarkSchemaToVisitable(registry, entrypointSchemaRef.String()) o.visitSchema(registry, entrypointSchema) o.optimizeDefinitions(registry) @@ -39,9 +39,9 @@ func (o *OptimizerImpl) optimizeDefinitions(registry *jsonschema.Registry) { var deleteKeys []string for _, key := range registry.GetKeys() { schema := registry.GetSchema(key) - if schema.GetExtrasItem(refCountKey) == nil { + if schema.GetExtrasItem(linkedFromEntrypoint) == nil { deleteKeys = append(deleteKeys, key) - } else if schema.GetExtrasItem(refCountKey).(int) == 0 { + } else if schema.GetExtrasItem(linkedFromEntrypoint).(bool) == false { deleteKeys = append(deleteKeys, key) } } @@ -66,17 +66,19 @@ func (o *OptimizerImpl) getEntrypointMessage(messages []pgs.Message, fileOptions return nil } -func (o *OptimizerImpl) increaseSchemaRefCount(registry *jsonschema.Registry, ref string) { +// return true if first visit to schema +func (o *OptimizerImpl) checkAndMarkSchemaToVisitable(registry *jsonschema.Registry, ref string) bool { schema := registry.GetSchema(ref) if schema == nil { panic(fmt.Sprintf("schema not found: %s", ref)) } - rawValue := schema.GetExtrasItem(refCountKey) + rawValue := schema.GetExtrasItem(linkedFromEntrypoint) if rawValue == nil { - schema.SetExtrasItem(refCountKey, int(1)) + schema.SetExtrasItem(linkedFromEntrypoint, true) + return true } else { - schema.SetExtrasItem(refCountKey, rawValue.(int)+1) + return false } } @@ -86,8 +88,9 @@ func (o *OptimizerImpl) visitSchema(registry *jsonschema.Registry, schema *jsons } if !schema.Ref.IsEmpty() { - o.increaseSchemaRefCount(registry, schema.Ref.String()) - o.visitSchema(registry, registry.GetSchema(schema.Ref.String())) + if o.checkAndMarkSchemaToVisitable(registry, schema.Ref.String()) { + o.visitSchema(registry, registry.GetSchema(schema.Ref.String())) + } } o.visitSchemaMap(registry, schema.Definitions) diff --git a/testdata/README.md b/testdata/README.md index efd30f8..e1c1571 100644 --- a/testdata/README.md +++ b/testdata/README.md @@ -82,6 +82,8 @@ proto-optional optional이 있다면 required에서 빠지는지 테스트 proto-message message가 object로 잘 전환되는지 테스트 +proto-circular-dependent 순환 의존성이 있는 메시지를 잘 전환하는지 테스트 + proto-enum enum이 enum으로 잘 전환되는지 테스트 plugin-preserve-field-name-false json_name이 잘 적용되는지 테스트 diff --git a/testdata/cases/proto-circular-dependent/test.proto b/testdata/cases/proto-circular-dependent/test.proto new file mode 100644 index 0000000..cd7cd07 --- /dev/null +++ b/testdata/cases/proto-circular-dependent/test.proto @@ -0,0 +1,23 @@ +syntax = "proto3"; + +package tests; + +import "jsonschema.proto"; + +option (pubg.jsonschema.file) = {entrypoint_message: "Values"}; + +message Values { + SelfReference entry = 1; +} + +//message CircularDependentTwoDepth { +// CircularDependentTwoDepth0 child = 1; +//} +// +//message CircularDependentTwoDepth0 { +// CircularDependentTwoDepth parent = 1; +//} + +message SelfReference { + SelfReference self = 1; +} diff --git a/testdata/cases/proto-circular-dependent/test.schema.json b/testdata/cases/proto-circular-dependent/test.schema.json new file mode 100644 index 0000000..1f076f7 --- /dev/null +++ b/testdata/cases/proto-circular-dependent/test.schema.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "#/$defs/.tests.Values", + "$defs": { + ".tests.Values": { + "properties": { + "entry": { + "$ref": "#/$defs/.tests.Values.entry" + } + }, + "type": "object", + "required": [ + "entry" + ] + }, + ".tests.Values.entry": { + "$ref": "#/$defs/.tests.SelfReference" + }, + ".tests.SelfReference": { + "properties": { + "self": { + "$ref": "#/$defs/.tests.SelfReference.self" + } + }, + "type": "object", + "required": [ + "self" + ], + "description": "message CircularDependentTwoDepth {\n CircularDependentTwoDepth0 child = 1;\n}\n\nmessage CircularDependentTwoDepth0 {\n CircularDependentTwoDepth parent = 1;\n}" + }, + ".tests.SelfReference.self": { + "$ref": "#/$defs/.tests.SelfReference" + } + }, + "type": "object" +} \ No newline at end of file diff --git a/testdata/cases/proto-circular-dependent/test.yaml b/testdata/cases/proto-circular-dependent/test.yaml new file mode 100644 index 0000000..a112f44 --- /dev/null +++ b/testdata/cases/proto-circular-dependent/test.yaml @@ -0,0 +1,11 @@ +name: "proto-circular-dependent" +description: "Test for circular dependent message in proto file" + +inputFiles: ["test.proto"] +inputParameters: {} + +expectResultFiles: ["test.schema.json"] +expectResultIsNull: false +expectFail: false + +expectedBehaviorDescription: ""