2019-01-12 23:28:21 +09:00
|
|
|
package gen
|
2018-09-05 06:44:16 +09:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"github.com/dave/jennifer/jen"
|
2019-01-29 05:51:12 +09:00
|
|
|
"github.com/go-fed/activity/astool/codegen"
|
2019-01-19 23:17:39 +09:00
|
|
|
"net/url"
|
2019-01-14 06:17:43 +09:00
|
|
|
"strings"
|
2018-09-05 06:44:16 +09:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2018-10-10 07:32:37 +09:00
|
|
|
// Method names for generated code
|
2018-09-16 07:02:11 +09:00
|
|
|
getMethod = "Get"
|
|
|
|
setMethod = "Set"
|
2019-01-08 04:33:03 +09:00
|
|
|
hasAnyMethod = "HasAny"
|
2018-09-16 07:02:11 +09:00
|
|
|
clearMethod = "Clear"
|
|
|
|
iteratorClearMethod = "clear"
|
|
|
|
isMethod = "Is"
|
2019-01-14 06:17:43 +09:00
|
|
|
atMethodName = "At"
|
2019-01-08 04:33:03 +09:00
|
|
|
isIRIMethod = "IsIRI"
|
|
|
|
getIRIMethod = "GetIRI"
|
|
|
|
setIRIMethod = "SetIRI"
|
2018-09-16 07:02:11 +09:00
|
|
|
appendMethod = "Append"
|
|
|
|
prependMethod = "Prepend"
|
|
|
|
removeMethod = "Remove"
|
|
|
|
lenMethod = "Len"
|
2018-09-26 06:21:07 +09:00
|
|
|
swapMethod = "Swap"
|
|
|
|
lessMethod = "Less"
|
2019-01-06 07:49:18 +09:00
|
|
|
kindIndexMethod = "KindIndex"
|
2018-09-16 07:02:11 +09:00
|
|
|
serializeMethod = "Serialize"
|
|
|
|
deserializeMethod = "Deserialize"
|
|
|
|
nameMethod = "Name"
|
|
|
|
serializeIteratorMethod = "serialize"
|
|
|
|
deserializeIteratorMethod = "deserialize"
|
2018-10-17 05:00:18 +09:00
|
|
|
hasLanguageMethod = "HasLanguage"
|
|
|
|
getLanguageMethod = "GetLanguage"
|
|
|
|
setLanguageMethod = "SetLanguage"
|
2019-01-14 06:17:43 +09:00
|
|
|
nextMethod = "Next"
|
|
|
|
prevMethod = "Prev"
|
|
|
|
beginMethod = "Begin"
|
|
|
|
endMethod = "End"
|
|
|
|
emptyMethod = "Empty"
|
2019-01-19 23:17:39 +09:00
|
|
|
// Context string management
|
|
|
|
contextMethod = "JSONLDContext"
|
2018-10-11 19:15:55 +09:00
|
|
|
// Member names for generated code
|
|
|
|
unknownMemberName = "unknown"
|
2019-02-09 21:22:20 +09:00
|
|
|
// Reference to the rdf:langString member! Kludge: both of these must be
|
|
|
|
// kept in sync with the generated code.
|
2019-02-10 05:23:17 +09:00
|
|
|
langMapMember = "rdfLangStringMember"
|
|
|
|
isLanguageMapMethod = "IsRDFLangString"
|
2019-01-08 04:33:03 +09:00
|
|
|
// Kind Index constants
|
|
|
|
iriKindIndex = -2
|
|
|
|
noneOrUnknownKindIndex = -1
|
2019-01-14 06:17:43 +09:00
|
|
|
// iterator specific
|
|
|
|
myIndexMemberName = "myIdx"
|
|
|
|
parentMemberName = "parent"
|
2018-09-05 06:44:16 +09:00
|
|
|
)
|
|
|
|
|
2018-10-10 07:32:37 +09:00
|
|
|
// join appends a bunch of Go Code together, each on their own line.
|
2018-10-09 05:19:10 +09:00
|
|
|
func join(s []jen.Code) *jen.Statement {
|
2018-10-10 07:32:37 +09:00
|
|
|
r := jen.Empty()
|
2018-09-13 05:45:59 +09:00
|
|
|
for i, stmt := range s {
|
|
|
|
if i > 0 {
|
|
|
|
r.Line()
|
|
|
|
}
|
2018-10-09 05:19:10 +09:00
|
|
|
r.Add(stmt)
|
2018-09-13 05:45:59 +09:00
|
|
|
}
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
2018-10-10 07:32:37 +09:00
|
|
|
// Identifier determines how a name will appear in documentation and Go code.
|
2018-09-05 06:44:16 +09:00
|
|
|
type Identifier struct {
|
2018-10-10 07:32:37 +09:00
|
|
|
// LowerName is the typical name used in documentation.
|
2018-09-05 06:44:16 +09:00
|
|
|
LowerName string
|
2018-10-10 07:32:37 +09:00
|
|
|
// CamelName is the typical name used in identifiers in code.
|
2018-09-05 06:44:16 +09:00
|
|
|
CamelName string
|
|
|
|
}
|
|
|
|
|
2018-10-10 07:32:37 +09:00
|
|
|
// Kind is data that describes a concrete Go type, how to serialize and
|
|
|
|
// deserialize such types, compare the types, and other meta-information to use
|
|
|
|
// during Go code generation.
|
2019-01-01 00:49:25 +09:00
|
|
|
//
|
|
|
|
// Only represents values and other types.
|
2018-09-05 06:44:16 +09:00
|
|
|
type Kind struct {
|
2019-02-10 05:23:17 +09:00
|
|
|
Name Identifier
|
|
|
|
Vocab string
|
2019-01-01 02:42:39 +09:00
|
|
|
// ConcreteKind is expected to be properly qualified.
|
2019-01-01 00:49:25 +09:00
|
|
|
ConcreteKind *jen.Statement
|
2018-12-31 00:09:14 +09:00
|
|
|
Nilable bool
|
2019-01-07 03:44:24 +09:00
|
|
|
IsURI bool
|
2019-01-05 08:00:51 +09:00
|
|
|
|
|
|
|
// TODO: Untangle the package management mess so that the below do not
|
|
|
|
// need to be duplicated.
|
|
|
|
|
|
|
|
// These <FuncName>Fn types are for qualified names of the functions.
|
2019-01-01 02:42:39 +09:00
|
|
|
// Expected to always be non-nil: a function is needed to deserialize.
|
2018-12-31 00:09:14 +09:00
|
|
|
DeserializeFn *jen.Statement
|
2019-01-01 02:42:39 +09:00
|
|
|
// If any of these are nil at generation time, assume to call the method
|
|
|
|
// on the object directly (instead of a qualified function).
|
|
|
|
SerializeFn *jen.Statement
|
|
|
|
LessFn *jen.Statement
|
2019-01-05 08:00:51 +09:00
|
|
|
|
|
|
|
// The following are only used for values, not types, as actual implementations
|
|
|
|
SerializeDef *codegen.Function
|
|
|
|
DeserializeDef *codegen.Function
|
|
|
|
LessDef *codegen.Function
|
2018-09-05 06:44:16 +09:00
|
|
|
}
|
|
|
|
|
2019-02-05 06:06:50 +09:00
|
|
|
// NewKindForValue creates a Kind for a value type.
|
2019-02-10 05:23:17 +09:00
|
|
|
func NewKindForValue(docName, idName, vocab string,
|
2019-02-05 06:06:50 +09:00
|
|
|
defType *jen.Statement,
|
|
|
|
isNilable, isURI bool,
|
|
|
|
serializeFn, deserializeFn, lessFn *codegen.Function) *Kind {
|
|
|
|
return &Kind{
|
|
|
|
Name: Identifier{
|
|
|
|
LowerName: docName,
|
|
|
|
CamelName: idName,
|
|
|
|
},
|
2019-02-10 05:23:17 +09:00
|
|
|
Vocab: vocab,
|
2019-02-05 06:06:50 +09:00
|
|
|
ConcreteKind: defType,
|
|
|
|
Nilable: isNilable,
|
|
|
|
IsURI: isURI,
|
|
|
|
SerializeFn: serializeFn.QualifiedName(),
|
|
|
|
DeserializeFn: deserializeFn.QualifiedName(),
|
|
|
|
LessFn: lessFn.QualifiedName(),
|
|
|
|
SerializeDef: serializeFn,
|
|
|
|
DeserializeDef: deserializeFn,
|
|
|
|
LessDef: lessFn,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewKindForType creates a Kind for an ActivitySteams type.
|
2019-02-10 05:23:17 +09:00
|
|
|
func NewKindForType(docName, idName, vocab string) *Kind {
|
2019-02-05 06:06:50 +09:00
|
|
|
return &Kind{
|
|
|
|
// Name must use toIdentifier for vocabValuePackage and
|
|
|
|
// valuePackage to be the same.
|
|
|
|
Name: Identifier{
|
|
|
|
LowerName: docName,
|
|
|
|
CamelName: idName,
|
|
|
|
},
|
2019-02-10 05:23:17 +09:00
|
|
|
Vocab: vocab,
|
2019-02-05 06:06:50 +09:00
|
|
|
Nilable: true,
|
|
|
|
IsURI: false,
|
|
|
|
// Instead of populating:
|
|
|
|
// - ConcreteKind
|
|
|
|
// - DeserializeFn
|
|
|
|
// - SerializeFn (Not populated for types)
|
|
|
|
// - LessFn (Not populated for types)
|
|
|
|
//
|
|
|
|
// The TypeGenerator is responsible for calling SetKindFns on
|
|
|
|
// the properties, to property wire a Property's Kind back to
|
|
|
|
// the Type's implementation.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// lessFnCode creates the correct code calling this Kind's less function
|
|
|
|
// depending on whether the Kind is a value or a type.
|
2019-01-05 05:56:29 +09:00
|
|
|
func (k Kind) lessFnCode(this, other *jen.Statement) *jen.Statement {
|
|
|
|
// LessFn is nil case -- call comparison Less method directly on the LHS
|
|
|
|
lessCall := this.Clone().Dot(compareLessMethod).Call(other.Clone())
|
2019-01-07 06:15:07 +09:00
|
|
|
if k.isValue() {
|
2019-01-05 05:56:29 +09:00
|
|
|
// LessFn is indeed a function -- call this function
|
|
|
|
lessCall = k.LessFn.Clone().Call(
|
|
|
|
this.Clone(),
|
|
|
|
other.Clone(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
return lessCall
|
|
|
|
}
|
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// lessFnCode creates the correct code calling this Kind's deserialize function
|
|
|
|
// depending on whether the Kind is a value or a type.
|
2019-01-20 00:56:19 +09:00
|
|
|
func (k Kind) deserializeFnCode(m, ctx *jen.Statement) *jen.Statement {
|
2019-01-07 06:15:07 +09:00
|
|
|
if k.isValue() {
|
2019-01-20 00:56:19 +09:00
|
|
|
return k.DeserializeFn.Clone().Call(m)
|
2019-01-06 20:26:58 +09:00
|
|
|
} else {
|
|
|
|
// If LessFn is nil, this means it is a type. Which requires an
|
2019-01-20 00:56:19 +09:00
|
|
|
// additional Call and the context.
|
|
|
|
return k.DeserializeFn.Clone().Call().Call(m, ctx)
|
2019-01-06 20:26:58 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// isValue returns true if this Kind is a value, or false if it is a type.
|
2019-01-07 06:15:07 +09:00
|
|
|
func (k Kind) isValue() bool {
|
|
|
|
// LessFn is not nil, this means it is a value.
|
|
|
|
// If LessFn is nil, this means it is a type. Types will have their
|
|
|
|
// LessThan method called directly on the type.
|
|
|
|
return k.LessFn != nil
|
|
|
|
}
|
|
|
|
|
2018-10-10 07:32:37 +09:00
|
|
|
// PropertyGenerator is a common base struct used in both Functional and
|
|
|
|
// NonFunctional ActivityStreams properties. It provides common naming patterns,
|
|
|
|
// logic, and common Go code to be generated.
|
|
|
|
//
|
|
|
|
// It also properly handles the concept of generating Go code for property
|
|
|
|
// iterators, which are needed for NonFunctional properties.
|
2018-09-05 06:44:16 +09:00
|
|
|
type PropertyGenerator struct {
|
2019-01-12 20:30:08 +09:00
|
|
|
vocabName string
|
2019-01-19 23:17:39 +09:00
|
|
|
vocabURI *url.URL
|
|
|
|
vocabAlias string
|
2019-01-12 20:30:08 +09:00
|
|
|
managerMethods []*codegen.Method
|
2019-01-09 04:47:55 +09:00
|
|
|
packageManager *PackageManager
|
|
|
|
name Identifier
|
|
|
|
comment string
|
|
|
|
kinds []Kind
|
|
|
|
hasNaturalLanguageMap bool
|
2018-10-17 05:00:18 +09:00
|
|
|
asIterator bool
|
2018-09-05 06:44:16 +09:00
|
|
|
}
|
|
|
|
|
2019-02-09 21:22:20 +09:00
|
|
|
// HasNaturalLanguageMap returns whether this property has a natural language
|
|
|
|
// map.
|
|
|
|
func (p *PropertyGenerator) HasNaturalLanguageMap() bool {
|
|
|
|
return p.hasNaturalLanguageMap
|
|
|
|
}
|
|
|
|
|
2019-01-06 00:22:37 +09:00
|
|
|
// VocabName returns this property's vocabulary name.
|
|
|
|
func (p *PropertyGenerator) VocabName() string {
|
|
|
|
return p.vocabName
|
|
|
|
}
|
|
|
|
|
2019-01-09 04:47:55 +09:00
|
|
|
// GetKinds gets this property's kinds.
|
|
|
|
func (p *PropertyGenerator) GetKinds() []Kind {
|
|
|
|
return p.kinds
|
|
|
|
}
|
|
|
|
|
2019-01-03 08:16:54 +09:00
|
|
|
// GetPrivatePackage gets this property's private Package.
|
|
|
|
func (p *PropertyGenerator) GetPrivatePackage() Package {
|
2019-01-09 04:47:55 +09:00
|
|
|
return p.packageManager.PrivatePackage()
|
2019-01-03 08:16:54 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetPublicPackage gets this property's public Package.
|
|
|
|
func (p *PropertyGenerator) GetPublicPackage() Package {
|
2019-01-09 04:47:55 +09:00
|
|
|
return p.packageManager.PublicPackage()
|
2018-10-09 05:19:10 +09:00
|
|
|
}
|
|
|
|
|
2018-12-18 07:11:55 +09:00
|
|
|
// SetKindFns allows TypeGenerators to later notify this Property what functions
|
|
|
|
// to use when generating the serialization code.
|
|
|
|
//
|
|
|
|
// The name parameter must match the LowerName of an Identifier.
|
|
|
|
//
|
|
|
|
// This feels very hacky.
|
2019-02-10 05:23:17 +09:00
|
|
|
func (p *PropertyGenerator) SetKindFns(docName, idName, vocab string, qualKind *jen.Statement, deser *codegen.Method) error {
|
2019-01-09 04:47:55 +09:00
|
|
|
for i, kind := range p.kinds {
|
2019-02-10 05:23:17 +09:00
|
|
|
if kind.Name.LowerName == docName && kind.Vocab == vocab {
|
2018-12-18 07:11:55 +09:00
|
|
|
if kind.SerializeFn != nil || kind.DeserializeFn != nil || kind.LessFn != nil {
|
2019-02-06 08:23:47 +09:00
|
|
|
return fmt.Errorf("property kind already has serialization functions set for %q: %s", docName, p.PropertyName())
|
2018-12-18 07:11:55 +09:00
|
|
|
}
|
2019-01-01 00:49:25 +09:00
|
|
|
kind.ConcreteKind = qualKind
|
2019-01-06 08:13:24 +09:00
|
|
|
kind.DeserializeFn = deser.On(managerInitName())
|
|
|
|
p.managerMethods = append(p.managerMethods, deser)
|
2019-01-09 04:47:55 +09:00
|
|
|
p.kinds[i] = kind
|
2018-12-18 07:11:55 +09:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
2019-02-05 06:06:50 +09:00
|
|
|
// In the case of extended types applying themselves to their parents'
|
|
|
|
// range, they will be missing from the property's kinds list. Append a
|
|
|
|
// new kind to handle this use case.
|
2019-02-10 05:23:17 +09:00
|
|
|
k := NewKindForType(docName, idName, vocab)
|
2019-02-05 06:06:50 +09:00
|
|
|
k.ConcreteKind = qualKind
|
|
|
|
k.DeserializeFn = deser.On(managerInitName())
|
|
|
|
p.managerMethods = append(p.managerMethods, deser)
|
|
|
|
p.kinds = append(p.kinds, *k)
|
|
|
|
return nil
|
2018-12-18 07:11:55 +09:00
|
|
|
}
|
|
|
|
|
2019-01-06 08:13:24 +09:00
|
|
|
// getAllManagerMethods returns the list of manager methods used by this
|
|
|
|
// property.
|
|
|
|
func (p *PropertyGenerator) getAllManagerMethods() []*codegen.Method {
|
|
|
|
return p.managerMethods
|
|
|
|
}
|
|
|
|
|
2018-11-04 00:56:09 +09:00
|
|
|
// StructName returns the name of the type, which may or may not be a struct,
|
2018-10-10 07:32:37 +09:00
|
|
|
// to generate.
|
2018-11-04 00:56:09 +09:00
|
|
|
func (p *PropertyGenerator) StructName() string {
|
2018-09-05 06:44:16 +09:00
|
|
|
if p.asIterator {
|
2019-01-09 04:47:55 +09:00
|
|
|
return p.name.CamelName
|
2018-09-05 06:44:16 +09:00
|
|
|
}
|
2019-02-10 05:23:17 +09:00
|
|
|
return fmt.Sprintf("%s%sProperty", p.VocabName(), p.name.CamelName)
|
2018-09-05 06:44:16 +09:00
|
|
|
}
|
|
|
|
|
2019-01-09 04:37:04 +09:00
|
|
|
// iteratorTypeName determines the identifier to use for the iterator type.
|
|
|
|
func (p *PropertyGenerator) iteratorTypeName() Identifier {
|
2019-02-10 05:23:17 +09:00
|
|
|
s := fmt.Sprintf("%s%s", p.VocabName(), p.name.CamelName)
|
2019-01-09 04:37:04 +09:00
|
|
|
return Identifier{
|
2019-02-10 05:23:17 +09:00
|
|
|
LowerName: s,
|
|
|
|
CamelName: fmt.Sprintf("%sPropertyIterator", s),
|
2019-01-09 04:37:04 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-04 05:36:10 +09:00
|
|
|
// InterfaceName returns the interface name of the property type.
|
2018-12-31 00:09:14 +09:00
|
|
|
func (p *PropertyGenerator) InterfaceName() string {
|
2019-02-10 05:23:17 +09:00
|
|
|
return fmt.Sprintf("%s", p.StructName())
|
2018-12-31 00:09:14 +09:00
|
|
|
}
|
|
|
|
|
2019-01-14 06:17:43 +09:00
|
|
|
// parentTypeInterfaceName is useful for iterators that need the base property
|
|
|
|
// type's interface name.
|
|
|
|
func (p *PropertyGenerator) parentTypeInterfaceName() string {
|
2019-02-10 05:23:17 +09:00
|
|
|
return fmt.Sprintf("%s", strings.TrimSuffix(p.StructName(), "Iterator"))
|
2019-01-14 06:17:43 +09:00
|
|
|
}
|
|
|
|
|
2018-11-04 00:56:09 +09:00
|
|
|
// PropertyName returns the name of this property, as defined in
|
2018-10-10 07:32:37 +09:00
|
|
|
// specifications. It is not suitable for use in generated code function
|
|
|
|
// identifiers.
|
2018-11-04 00:56:09 +09:00
|
|
|
func (p *PropertyGenerator) PropertyName() string {
|
2019-01-09 04:47:55 +09:00
|
|
|
return p.name.LowerName
|
2018-09-13 05:45:59 +09:00
|
|
|
}
|
|
|
|
|
2018-12-31 00:54:16 +09:00
|
|
|
// Comments returns the comment for this property.
|
|
|
|
func (p *PropertyGenerator) Comments() string {
|
2019-01-09 04:47:55 +09:00
|
|
|
return p.comment
|
2018-12-31 00:54:16 +09:00
|
|
|
}
|
|
|
|
|
2018-12-18 07:11:55 +09:00
|
|
|
// DeserializeFnName returns the identifier of the function that deserializes
|
2018-10-10 07:32:37 +09:00
|
|
|
// raw JSON into the generated Go type.
|
2018-12-18 07:11:55 +09:00
|
|
|
func (p *PropertyGenerator) DeserializeFnName() string {
|
2018-09-16 07:02:11 +09:00
|
|
|
if p.asIterator {
|
2019-01-09 04:47:55 +09:00
|
|
|
return fmt.Sprintf("%s%s", deserializeIteratorMethod, p.name.CamelName)
|
2018-09-16 07:02:11 +09:00
|
|
|
}
|
2019-01-09 04:47:55 +09:00
|
|
|
return fmt.Sprintf("%s%sProperty", deserializeMethod, p.name.CamelName)
|
2018-09-16 07:02:11 +09:00
|
|
|
}
|
|
|
|
|
2018-10-10 07:32:37 +09:00
|
|
|
// getFnName returns the identifier of the function that fetches concrete types
|
|
|
|
// of the property.
|
2018-09-16 07:02:11 +09:00
|
|
|
func (p *PropertyGenerator) getFnName(i int) string {
|
2019-01-09 04:47:55 +09:00
|
|
|
if len(p.kinds) == 1 {
|
2018-09-16 07:02:11 +09:00
|
|
|
return getMethod
|
|
|
|
}
|
2019-02-10 05:23:17 +09:00
|
|
|
return fmt.Sprintf("%s%s%s", getMethod, p.kinds[i].Vocab, p.kindCamelName(i))
|
2018-09-16 07:02:11 +09:00
|
|
|
}
|
|
|
|
|
2018-10-17 05:00:18 +09:00
|
|
|
// setFnName returns the identifier of the function that sets concrete types
|
|
|
|
// of the property.
|
|
|
|
func (p *PropertyGenerator) setFnName(i int) string {
|
2019-01-09 04:47:55 +09:00
|
|
|
if len(p.kinds) == 1 {
|
2018-10-17 05:00:18 +09:00
|
|
|
return setMethod
|
|
|
|
}
|
2019-02-10 05:23:17 +09:00
|
|
|
return fmt.Sprintf("%s%s%s", setMethod, p.kinds[i].Vocab, p.kindCamelName(i))
|
2018-10-17 05:00:18 +09:00
|
|
|
}
|
|
|
|
|
2018-10-10 07:32:37 +09:00
|
|
|
// serializeFnName returns the identifier of the function that serializes the
|
|
|
|
// generated Go type into raw JSON.
|
2018-09-16 07:02:11 +09:00
|
|
|
func (p *PropertyGenerator) serializeFnName() string {
|
|
|
|
if p.asIterator {
|
|
|
|
return serializeIteratorMethod
|
|
|
|
}
|
|
|
|
return serializeMethod
|
2018-09-13 05:45:59 +09:00
|
|
|
}
|
|
|
|
|
2018-10-10 07:32:37 +09:00
|
|
|
// kindCamelName returns an identifier-friendly name for the kind at the
|
|
|
|
// specified index.
|
|
|
|
//
|
|
|
|
// It will panic if 'i' is out of range.
|
2018-09-05 06:44:16 +09:00
|
|
|
func (p *PropertyGenerator) kindCamelName(i int) string {
|
2019-01-09 04:47:55 +09:00
|
|
|
return p.kinds[i].Name.CamelName
|
2018-09-05 06:44:16 +09:00
|
|
|
}
|
|
|
|
|
2018-10-10 07:32:37 +09:00
|
|
|
// memberName returns the identifier to use for the kind at the specified index.
|
|
|
|
//
|
|
|
|
// It will panic if 'i' is out of range.
|
2018-09-05 06:44:16 +09:00
|
|
|
func (p *PropertyGenerator) memberName(i int) string {
|
2019-02-10 05:23:17 +09:00
|
|
|
k := p.kinds[i]
|
|
|
|
v := strings.ToLower(k.Vocab)
|
|
|
|
return fmt.Sprintf("%s%sMember", v, k.Name.CamelName)
|
2018-09-05 06:44:16 +09:00
|
|
|
}
|
|
|
|
|
2018-10-10 07:32:37 +09:00
|
|
|
// hasMemberName returns the identifier to use for struct members that determine
|
|
|
|
// whether non-nilable types have been set. Panics if called for a Kind that is
|
|
|
|
// nilable.
|
2018-09-05 06:44:16 +09:00
|
|
|
func (p *PropertyGenerator) hasMemberName(i int) string {
|
2019-01-09 04:47:55 +09:00
|
|
|
if len(p.kinds) == 1 && p.kinds[0].Nilable {
|
2018-09-05 06:44:16 +09:00
|
|
|
panic("PropertyGenerator.hasMemberName called for nilable single value")
|
|
|
|
}
|
2019-01-09 04:47:55 +09:00
|
|
|
return fmt.Sprintf("has%sMember", p.kinds[i].Name.CamelName)
|
2018-09-05 06:44:16 +09:00
|
|
|
}
|
|
|
|
|
2018-10-10 07:32:37 +09:00
|
|
|
// clearMethodName returns the identifier to use for methods that clear all
|
|
|
|
// values from the property.
|
2018-09-13 05:45:59 +09:00
|
|
|
func (p *PropertyGenerator) clearMethodName() string {
|
|
|
|
if p.asIterator {
|
|
|
|
return iteratorClearMethod
|
|
|
|
}
|
|
|
|
return clearMethod
|
|
|
|
}
|
|
|
|
|
2018-10-10 07:32:37 +09:00
|
|
|
// commonMethods returns methods common to every property.
|
2019-02-09 21:22:20 +09:00
|
|
|
func (p *PropertyGenerator) commonMethods() (m []*codegen.Method) {
|
2019-01-14 06:17:43 +09:00
|
|
|
if p.asIterator {
|
2019-01-19 23:17:39 +09:00
|
|
|
// Next & Prev methods
|
2019-01-14 06:17:43 +09:00
|
|
|
m = append(m, codegen.NewCommentedValueMethod(
|
|
|
|
p.GetPrivatePackage().Path(),
|
|
|
|
nextMethod,
|
|
|
|
p.StructName(),
|
|
|
|
/*params=*/ nil,
|
|
|
|
[]jen.Code{jen.Qual(p.GetPublicPackage().Path(), p.InterfaceName())},
|
|
|
|
[]jen.Code{
|
|
|
|
jen.If(
|
|
|
|
jen.Id(codegen.This()).Dot(myIndexMemberName).Op("+").Lit(1).Op(">=").Id(codegen.This()).Dot(parentMemberName).Dot(lenMethod).Call(),
|
|
|
|
).Block(
|
|
|
|
jen.Return(jen.Nil()),
|
|
|
|
).Else().Block(
|
|
|
|
jen.Return(
|
|
|
|
jen.Id(codegen.This()).Dot(parentMemberName).Dot(atMethodName).Call(jen.Id(codegen.This()).Dot(myIndexMemberName).Op("+").Lit(1)),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
},
|
|
|
|
fmt.Sprintf("%s returns the next iterator, or nil if there is no next iterator.", nextMethod)))
|
|
|
|
m = append(m, codegen.NewCommentedValueMethod(
|
|
|
|
p.GetPrivatePackage().Path(),
|
|
|
|
prevMethod,
|
|
|
|
p.StructName(),
|
|
|
|
/*params=*/ nil,
|
|
|
|
[]jen.Code{jen.Qual(p.GetPublicPackage().Path(), p.InterfaceName())},
|
|
|
|
[]jen.Code{
|
|
|
|
jen.If(
|
|
|
|
jen.Id(codegen.This()).Dot(myIndexMemberName).Op("-").Lit(1).Op("<").Lit(0),
|
|
|
|
).Block(
|
|
|
|
jen.Return(jen.Nil()),
|
|
|
|
).Else().Block(
|
|
|
|
jen.Return(
|
|
|
|
jen.Id(codegen.This()).Dot(parentMemberName).Dot(atMethodName).Call(jen.Id(codegen.This()).Dot(myIndexMemberName).Op("-").Lit(1)),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
},
|
|
|
|
fmt.Sprintf("%s returns the previous iterator, or nil if there is no previous iterator.", prevMethod)))
|
|
|
|
}
|
|
|
|
return m
|
2018-09-16 07:02:11 +09:00
|
|
|
}
|
|
|
|
|
2018-10-10 07:32:37 +09:00
|
|
|
// isMethodName returns the identifier to use for methods that determine if a
|
|
|
|
// property holds a specific Kind of value.
|
2018-09-26 06:21:07 +09:00
|
|
|
func (p *PropertyGenerator) isMethodName(i int) string {
|
2019-02-10 05:23:17 +09:00
|
|
|
return fmt.Sprintf("%s%s%s", isMethod, p.kinds[i].Vocab, p.kindCamelName(i))
|
2018-09-05 06:44:16 +09:00
|
|
|
}
|
2019-01-27 03:46:25 +09:00
|
|
|
|
2019-02-06 08:51:35 +09:00
|
|
|
// ConstructorFn creates a constructor function with a default vocabulary
|
2019-01-27 03:46:25 +09:00
|
|
|
// alias.
|
2019-02-06 08:51:35 +09:00
|
|
|
func (p *PropertyGenerator) ConstructorFn() *codegen.Function {
|
2019-01-27 03:46:25 +09:00
|
|
|
return codegen.NewCommentedFunction(
|
|
|
|
p.GetPrivatePackage().Path(),
|
|
|
|
fmt.Sprintf("%s%s", constructorName, p.StructName()),
|
|
|
|
/*params=*/ nil,
|
|
|
|
[]jen.Code{
|
|
|
|
jen.Op("*").Qual(p.GetPrivatePackage().Path(), p.StructName()),
|
|
|
|
},
|
|
|
|
[]jen.Code{
|
|
|
|
jen.Return(
|
|
|
|
jen.Op("&").Qual(p.GetPrivatePackage().Path(), p.StructName()).Values(
|
|
|
|
jen.Dict{
|
|
|
|
jen.Id(aliasMember): jen.Lit(p.vocabAlias),
|
|
|
|
},
|
|
|
|
),
|
|
|
|
),
|
|
|
|
},
|
|
|
|
fmt.Sprintf("%s%s creates a new %s property.", constructorName, p.StructName(), p.PropertyName()))
|
|
|
|
}
|
2019-02-05 06:06:50 +09:00
|
|
|
|
|
|
|
// hasURIKind returns true if this property already has a Kind that is a URI.
|
|
|
|
func (p *PropertyGenerator) hasURIKind() bool {
|
|
|
|
for _, k := range p.kinds {
|
|
|
|
if k.IsURI {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2019-02-16 07:54:09 +09:00
|
|
|
|
|
|
|
// hasTypeKind returns true if this property has a Kind that is a type.
|
|
|
|
func (p *PropertyGenerator) hasTypeKind() bool {
|
|
|
|
for _, k := range p.kinds {
|
|
|
|
if !k.isValue() {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|