summaryrefslogtreecommitdiff
path: root/plugins/grpc/protoc_plugins/protoc-gen-php-grpc/php/ns.go
blob: c1dc3898ec452eab83ce3a1c2e865791ca3be273 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package php

import (
	"bytes"
	"fmt"
	"strings"

	desc "google.golang.org/protobuf/types/descriptorpb"
	plugin "google.golang.org/protobuf/types/pluginpb"
)

// manages internal name representation of the package
type ns struct {
	// Package defines file package.
	Package string

	// Root namespace of the package
	Namespace string

	// Import declares what namespaces to be imported
	Import map[string]string
}

// newNamespace creates new work namespace.
func newNamespace(req *plugin.CodeGeneratorRequest, file *desc.FileDescriptorProto, service *desc.ServiceDescriptorProto) *ns {
	ns := &ns{
		Package:   *file.Package,
		Namespace: namespace(file.Package, "\\"),
		Import:    make(map[string]string),
	}

	if file.Options != nil && file.Options.PhpNamespace != nil {
		ns.Namespace = *file.Options.PhpNamespace
	}

	for k := range service.Method {
		ns.importMessage(req, service.Method[k].InputType)
		ns.importMessage(req, service.Method[k].OutputType)
	}

	return ns
}

// importMessage registers new import message namespace (only the namespace).
func (ns *ns) importMessage(req *plugin.CodeGeneratorRequest, msg *string) {
	if msg == nil {
		return
	}

	chunks := strings.Split(*msg, ".")
	pkg := strings.Join(chunks[:len(chunks)-1], ".")

	result := bytes.NewBuffer(nil)
	for _, p := range chunks[:len(chunks)-1] {
		result.WriteString(identifier(p, ""))
		result.WriteString(`\`)
	}

	if pkg == "."+ns.Package {
		// root package
		return
	}

	for _, f := range req.ProtoFile {
		if pkg == "."+*f.Package {
			if f.Options != nil && f.Options.PhpNamespace != nil {
				// custom imported namespace
				ns.Import[pkg] = *f.Options.PhpNamespace
				return
			}
		}
	}

	ns.Import[pkg] = strings.Trim(result.String(), `\`)
}

// resolve message alias
func (ns *ns) resolve(msg *string) string {
	chunks := strings.Split(*msg, ".")
	pkg := strings.Join(chunks[:len(chunks)-1], ".")

	if pkg == "."+ns.Package {
		// root message
		return identifier(chunks[len(chunks)-1], "")
	}

	for iPkg, ns := range ns.Import {
		if pkg == iPkg {
			// use last namespace chunk
			nsChunks := strings.Split(ns, `\`)
			identifier := identifier(chunks[len(chunks)-1], "")

			return fmt.Sprintf(
				`%s\%s`,
				nsChunks[len(nsChunks)-1],
				resolveReserved(identifier, pkg),
			)
		}
	}

	// fully clarified name (fallback)
	return "\\" + namespace(msg, "\\")
}