From f769e201b2a0f3896a9bf492b8c2999407b724e4 Mon Sep 17 00:00:00 2001 From: Cory Slep Date: Sat, 9 Feb 2019 21:23:17 +0100 Subject: [PATCH] astool can handle colliding type and property names. --- astool/convert/convert.go | 24 ++++--- astool/example_custom_spec.jsonld | 51 ++++++++++++++ astool/gen/nonfuncprop.go | 7 +- astool/gen/pkg.go | 2 +- astool/gen/property.go | 40 ++++++----- astool/gen/resolver.go | 112 ++++++++++++++++++++++-------- astool/gen/type.go | 92 ++++++++++++++++-------- 7 files changed, 239 insertions(+), 89 deletions(-) diff --git a/astool/convert/convert.go b/astool/convert/convert.go index bcfeea4..758768e 100644 --- a/astool/convert/convert.go +++ b/astool/convert/convert.go @@ -399,7 +399,7 @@ func (c *Converter) convertVocabulary(p *rdf.ParsedVocabulary, refs map[string]* v.Name = p.Vocab.Name v.URI = p.Vocab.URI for k, val := range p.Vocab.Values { - v.Values[k] = c.convertValue(val) + v.Values[k] = c.convertValue(p.Vocab.Name, val) } for k, prop := range p.Vocab.Properties { if prop.Functional { @@ -735,7 +735,7 @@ func (c *Converter) convertNonFunctionalProperty(p rdf.VocabularyProperty, } // convertValue turns a rdf.VocabularyValue into a Kind. -func (c *Converter) convertValue(v rdf.VocabularyValue) *gen.Kind { +func (c *Converter) convertValue(vocabName string, v rdf.VocabularyValue) *gen.Kind { s := v.SerializeFn.CloneToPackage(c.vocabValuePackage(v).Path()) d := v.DeserializeFn.CloneToPackage(c.vocabValuePackage(v).Path()) l := v.LessFn.CloneToPackage(c.vocabValuePackage(v).Path()) @@ -744,6 +744,7 @@ func (c *Converter) convertValue(v rdf.VocabularyValue) *gen.Kind { id := toIdentifier(v) return gen.NewKindForValue(id.LowerName, id.CamelName, + vocabName, v.DefinitionType, v.IsNilable, v.IsURI, @@ -773,7 +774,7 @@ func (c *Converter) propertyKinds(v rdf.VocabularyProperty, return } else { id := toIdentifier(t) - kt := gen.NewKindForType(id.LowerName, id.CamelName) + kt := gen.NewKindForType(id.LowerName, id.CamelName, vocab.Name) k = append(k, *kt) } } else { @@ -799,12 +800,12 @@ func (c *Converter) propertyKinds(v rdf.VocabularyProperty, return } else { id := toIdentifier(t) - kt := gen.NewKindForType(id.LowerName, id.CamelName) + kt := gen.NewKindForType(id.LowerName, id.CamelName, refVocab.Name) k = append(k, *kt) } } else { // It is a Value of the vocabulary - k = append(k, *c.convertValue(val)) + k = append(k, *c.convertValue(refVocab.Name, val)) } } } @@ -1160,6 +1161,7 @@ func (c *Converter) allExtendsAreIn(registry *rdf.RDFRegistry, t rdf.VocabularyT // toFiles converts a vocabulary's types and properties to files. func (c *Converter) toFiles(v vocabulary) (f []*File, e error) { + vName := strings.ToLower(v.Name) for _, i := range v.FProps { var pm *gen.PackageManager pm, e = c.propertyPackageManager(i, v.Name) @@ -1172,7 +1174,7 @@ func (c *Converter) toFiles(v vocabulary) (f []*File, e error) { file.Add(i.Definition().Definition()) f = append(f, &File{ F: file, - FileName: fmt.Sprintf("gen_property_%s.go", i.PropertyName()), + FileName: fmt.Sprintf("gen_property_%s_%s.go", vName, i.PropertyName()), Directory: priv.WriteDir(), }) // Interface @@ -1181,7 +1183,7 @@ func (c *Converter) toFiles(v vocabulary) (f []*File, e error) { file.Add(i.InterfaceDefinition(pm.PublicPackage()).Definition()) f = append(f, &File{ F: file, - FileName: fmt.Sprintf("gen_property_%s_interface.go", i.PropertyName()), + FileName: fmt.Sprintf("gen_property_%s_%s_interface.go", vName, i.PropertyName()), Directory: pub.WriteDir(), }) } @@ -1199,7 +1201,7 @@ func (c *Converter) toFiles(v vocabulary) (f []*File, e error) { file.Add(s.Definition()).Line().Add(t.Definition()) f = append(f, &File{ F: file, - FileName: fmt.Sprintf("gen_property_%s.go", i.PropertyName()), + FileName: fmt.Sprintf("gen_property_%s_%s.go", vName, i.PropertyName()), Directory: priv.WriteDir(), }) // Interface @@ -1210,7 +1212,7 @@ func (c *Converter) toFiles(v vocabulary) (f []*File, e error) { } f = append(f, &File{ F: file, - FileName: fmt.Sprintf("gen_property_%s_interface.go", i.PropertyName()), + FileName: fmt.Sprintf("gen_property_%s_%s_interface.go", vName, i.PropertyName()), Directory: pub.WriteDir(), }) } @@ -1227,7 +1229,7 @@ func (c *Converter) toFiles(v vocabulary) (f []*File, e error) { file.Add(i.Definition().Definition()) f = append(f, &File{ F: file, - FileName: fmt.Sprintf("gen_type_%s.go", strings.ToLower(i.TypeName())), + FileName: fmt.Sprintf("gen_type_%s_%s.go", vName, strings.ToLower(i.TypeName())), Directory: priv.WriteDir(), }) // Interface @@ -1236,7 +1238,7 @@ func (c *Converter) toFiles(v vocabulary) (f []*File, e error) { file.Add(i.InterfaceDefinition(pm.PublicPackage()).Definition()) f = append(f, &File{ F: file, - FileName: fmt.Sprintf("gen_type_%s_interface.go", strings.ToLower(i.TypeName())), + FileName: fmt.Sprintf("gen_type_%s_%s_interface.go", vName, strings.ToLower(i.TypeName())), Directory: pub.WriteDir(), }) } diff --git a/astool/example_custom_spec.jsonld b/astool/example_custom_spec.jsonld index 9cc2bea..a935afb 100644 --- a/astool/example_custom_spec.jsonld +++ b/astool/example_custom_spec.jsonld @@ -112,6 +112,57 @@ }, "name": "customproperty", "url": "https://example.com/fake-vocabulary#dfn-customproperty" + }, + { + "id": "https://example.com/fake-vocabulary#Update", + "type": "owl:Class", + "notes": "Collides with the ActivityStreams Update type.", + "subClassOf": { + "type": "owl:Class", + "url": "https://www.w3.org/TR/activitystreams-vocabulary/#dfn-activity", + "name": "as:Activity" + }, + "disjointWith": [], + "name": "Update", + "url": "https://example.com/fake-vocabulary#dfn-update" + }, + { + "id": "https://example.com/fake-vocabulary#accuracy", + "type": "rdf:Property", + "notes": "Collides with the ActivityStreams accuracy property", + "domain": { + "type": "owl:Class", + "unionOf": [ + { + "type": "owl:Class", + "url": "https://www.w3.org/TR/activitystreams-vocabulary/#dfn-update", + "name": "as:Update" + }, + { + "type": "owl:Class", + "url": "https://example.com/fake-vocabulary#dfn-update", + "name": "Update" + } + ] + }, + "isDefinedBy": "https://example.com/fake-vocabulary#dfn-accuracy", + "range": { + "type": "owl:Class", + "unionOf": [ + { + "type": "owl:Class", + "url": "https://www.w3.org/TR/activitystreams-vocabulary/#dfn-update", + "name": "as:Update" + }, + { + "type": "owl:Class", + "url": "https://example.com/fake-vocabulary#dfn-update", + "name": "Update" + } + ] + }, + "name": "accuracy", + "url": "https://example.com/fake-vocabulary#dfn-accuracy" } ] } diff --git a/astool/gen/nonfuncprop.go b/astool/gen/nonfuncprop.go index b817f5d..21737bd 100644 --- a/astool/gen/nonfuncprop.go +++ b/astool/gen/nonfuncprop.go @@ -5,6 +5,7 @@ import ( "github.com/dave/jennifer/jen" "github.com/go-fed/activity/astool/codegen" "net/url" + "strings" "sync" ) @@ -104,7 +105,7 @@ func (p *NonFunctionalPropertyGenerator) Definitions() (*codegen.Struct, *codege // iteratorInterfaceName gets the interface name for the iterator. func (p *NonFunctionalPropertyGenerator) iteratorInterfaceName() string { - return fmt.Sprintf("%sInterface", p.iteratorTypeName().CamelName) + return fmt.Sprintf("%s", strings.Title(p.iteratorTypeName().CamelName)) } // elementTypeGenerator produces a FunctionalPropertyGenerator for the iterator @@ -143,7 +144,7 @@ func (p *NonFunctionalPropertyGenerator) funcs() []*codegen.Method { prependDict[k] = v } prependDict[jen.Id(myIndexMemberName)] = jen.Lit(0) - prependMethodName := fmt.Sprintf("%s%s", prependMethod, p.kindCamelName(i)) + prependMethodName := fmt.Sprintf("%s%s%s", prependMethod, kind.Vocab, p.kindCamelName(i)) methods = append(methods, codegen.NewCommentedPointerMethod( p.GetPrivatePackage().Path(), @@ -175,7 +176,7 @@ func (p *NonFunctionalPropertyGenerator) funcs() []*codegen.Method { appendDict[k] = v } appendDict[jen.Id(myIndexMemberName)] = jen.Id(codegen.This()).Dot(lenMethod).Call() - appendMethodName := fmt.Sprintf("%s%s", appendMethod, p.kindCamelName(i)) + appendMethodName := fmt.Sprintf("%s%s%s", appendMethod, kind.Vocab, p.kindCamelName(i)) methods = append(methods, codegen.NewCommentedPointerMethod( p.GetPrivatePackage().Path(), diff --git a/astool/gen/pkg.go b/astool/gen/pkg.go index a4b813b..d7de273 100644 --- a/astool/gen/pkg.go +++ b/astool/gen/pkg.go @@ -469,7 +469,7 @@ func genInit(pkg Package, func toPublicConstructor(vocabName string, m *ManagerGenerator, pg *PropertyGenerator) *codegen.Function { return codegen.NewCommentedFunction( m.pkg.Path(), - fmt.Sprintf("New%s%s", vocabName, pg.StructName()), + fmt.Sprintf("New%s%sProperty", vocabName, strings.Title(pg.PropertyName())), /*params=*/ nil, []jen.Code{jen.Qual(pg.GetPublicPackage().Path(), pg.InterfaceName())}, []jen.Code{ diff --git a/astool/gen/property.go b/astool/gen/property.go index b198f34..5588eb7 100644 --- a/astool/gen/property.go +++ b/astool/gen/property.go @@ -46,8 +46,8 @@ const ( unknownMemberName = "unknown" // Reference to the rdf:langString member! Kludge: both of these must be // kept in sync with the generated code. - langMapMember = "langStringMember" - isLanguageMapMethod = "IsLangString" + langMapMember = "rdfLangStringMember" + isLanguageMapMethod = "IsRDFLangString" // Kind Index constants iriKindIndex = -2 noneOrUnknownKindIndex = -1 @@ -82,7 +82,8 @@ type Identifier struct { // // Only represents values and other types. type Kind struct { - Name Identifier + Name Identifier + Vocab string // ConcreteKind is expected to be properly qualified. ConcreteKind *jen.Statement Nilable bool @@ -106,7 +107,7 @@ type Kind struct { } // NewKindForValue creates a Kind for a value type. -func NewKindForValue(docName, idName string, +func NewKindForValue(docName, idName, vocab string, defType *jen.Statement, isNilable, isURI bool, serializeFn, deserializeFn, lessFn *codegen.Function) *Kind { @@ -115,6 +116,7 @@ func NewKindForValue(docName, idName string, LowerName: docName, CamelName: idName, }, + Vocab: vocab, ConcreteKind: defType, Nilable: isNilable, IsURI: isURI, @@ -128,7 +130,7 @@ func NewKindForValue(docName, idName string, } // NewKindForType creates a Kind for an ActivitySteams type. -func NewKindForType(docName, idName string) *Kind { +func NewKindForType(docName, idName, vocab string) *Kind { return &Kind{ // Name must use toIdentifier for vocabValuePackage and // valuePackage to be the same. @@ -136,6 +138,7 @@ func NewKindForType(docName, idName string) *Kind { LowerName: docName, CamelName: idName, }, + Vocab: vocab, Nilable: true, IsURI: false, // Instead of populating: @@ -236,9 +239,9 @@ func (p *PropertyGenerator) GetPublicPackage() Package { // The name parameter must match the LowerName of an Identifier. // // This feels very hacky. -func (p *PropertyGenerator) SetKindFns(docName, idName string, qualKind *jen.Statement, deser *codegen.Method) error { +func (p *PropertyGenerator) SetKindFns(docName, idName, vocab string, qualKind *jen.Statement, deser *codegen.Method) error { for i, kind := range p.kinds { - if kind.Name.LowerName == docName { + if kind.Name.LowerName == docName && kind.Vocab == vocab { if kind.SerializeFn != nil || kind.DeserializeFn != nil || kind.LessFn != nil { return fmt.Errorf("property kind already has serialization functions set for %q: %s", docName, p.PropertyName()) } @@ -252,7 +255,7 @@ func (p *PropertyGenerator) SetKindFns(docName, idName string, qualKind *jen.Sta // 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. - k := NewKindForType(docName, idName) + k := NewKindForType(docName, idName, vocab) k.ConcreteKind = qualKind k.DeserializeFn = deser.On(managerInitName()) p.managerMethods = append(p.managerMethods, deser) @@ -272,26 +275,27 @@ func (p *PropertyGenerator) StructName() string { if p.asIterator { return p.name.CamelName } - return fmt.Sprintf("%sProperty", p.name.CamelName) + return fmt.Sprintf("%s%sProperty", p.VocabName(), p.name.CamelName) } // iteratorTypeName determines the identifier to use for the iterator type. func (p *PropertyGenerator) iteratorTypeName() Identifier { + s := fmt.Sprintf("%s%s", p.VocabName(), p.name.CamelName) return Identifier{ - LowerName: p.name.LowerName, - CamelName: fmt.Sprintf("%sPropertyIterator", p.name.CamelName), + LowerName: s, + CamelName: fmt.Sprintf("%sPropertyIterator", s), } } // InterfaceName returns the interface name of the property type. func (p *PropertyGenerator) InterfaceName() string { - return fmt.Sprintf("%sInterface", p.StructName()) + return fmt.Sprintf("%s", p.StructName()) } // parentTypeInterfaceName is useful for iterators that need the base property // type's interface name. func (p *PropertyGenerator) parentTypeInterfaceName() string { - return fmt.Sprintf("%sInterface", strings.TrimSuffix(p.StructName(), "Iterator")) + return fmt.Sprintf("%s", strings.TrimSuffix(p.StructName(), "Iterator")) } // PropertyName returns the name of this property, as defined in @@ -321,7 +325,7 @@ func (p *PropertyGenerator) getFnName(i int) string { if len(p.kinds) == 1 { return getMethod } - return fmt.Sprintf("%s%s", getMethod, p.kindCamelName(i)) + return fmt.Sprintf("%s%s%s", getMethod, p.kinds[i].Vocab, p.kindCamelName(i)) } // setFnName returns the identifier of the function that sets concrete types @@ -330,7 +334,7 @@ func (p *PropertyGenerator) setFnName(i int) string { if len(p.kinds) == 1 { return setMethod } - return fmt.Sprintf("%s%s", setMethod, p.kindCamelName(i)) + return fmt.Sprintf("%s%s%s", setMethod, p.kinds[i].Vocab, p.kindCamelName(i)) } // serializeFnName returns the identifier of the function that serializes the @@ -354,7 +358,9 @@ func (p *PropertyGenerator) kindCamelName(i int) string { // // It will panic if 'i' is out of range. func (p *PropertyGenerator) memberName(i int) string { - return fmt.Sprintf("%sMember", p.kinds[i].Name.LowerName) + k := p.kinds[i] + v := strings.ToLower(k.Vocab) + return fmt.Sprintf("%s%sMember", v, k.Name.CamelName) } // hasMemberName returns the identifier to use for struct members that determine @@ -423,7 +429,7 @@ func (p *PropertyGenerator) commonMethods() (m []*codegen.Method) { // isMethodName returns the identifier to use for methods that determine if a // property holds a specific Kind of value. func (p *PropertyGenerator) isMethodName(i int) string { - return fmt.Sprintf("%s%s", isMethod, p.kindCamelName(i)) + return fmt.Sprintf("%s%s%s", isMethod, p.kinds[i].Vocab, p.kindCamelName(i)) } // ConstructorFn creates a constructor function with a default vocabulary diff --git a/astool/gen/resolver.go b/astool/gen/resolver.go index cf25e41..f0a594a 100644 --- a/astool/gen/resolver.go +++ b/astool/gen/resolver.go @@ -231,10 +231,55 @@ func (r *ResolverGenerator) isUnFn() *codegen.Function { // jsonResolverMethods returns the methods for the TypeResolver. func (r *ResolverGenerator) jsonResolverMethods() (m []*codegen.Method) { + aliasToId := make(map[string]string) + aliasFetching := jen.Empty() impl := jen.Empty() - for _, t := range r.types { - impl = impl.Case( - jen.Lit(t.TypeName()), + for i, t := range r.types { + if i > 0 { + impl = impl.Else() + } + // Get the vocab URI in http and https forms + vocabHttps := *t.vocabURI + vocabHttps.Scheme = "https" + vocabHttp := vocabHttps + vocabHttp.Scheme = "http" + // Determine if we've already generated the code for fetching + // the alias for this vocabulary. + if _, ok := aliasToId[vocabHttps.String()]; !ok { + // If not, generate the code. + vocabId := t.vocabName + "Alias" + aliasToId[vocabHttps.String()] = vocabId + aliasFetching = aliasFetching.Add( + jen.List( + jen.Id(vocabId), + jen.Id("ok"), + ).Op(":=").Id("aliasMap").Index( + jen.Lit(vocabHttps.String()), + ), + ).Line().Add( + jen.If( + jen.Op("!").Id("ok"), + ).Block( + jen.List( + jen.Id(vocabId), + jen.Id("_"), + ).Op("=").Id("aliasMap").Index( + jen.Lit(vocabHttp.String()), + ), + ), + ).Line().Add( + // If it is not empty post-pend with a ":". + jen.If( + jen.Len(jen.Id(vocabId)).Op(">").Lit(0), + ).Block( + jen.Id(vocabId).Op("+=").Lit(":"), + ), + ).Line() + } + // Fetch the identifier holding the alias for this vocabulary, + aliasId := aliasToId[vocabHttps.String()] + impl = impl.If( + jen.Id("typeString").Op("==").Id(aliasId).Op("+").Lit(t.TypeName()), ).Block( jen.List( jen.Id("v"), @@ -276,7 +321,7 @@ func (r *ResolverGenerator) jsonResolverMethods() (m []*codegen.Method) { jen.Return( jen.Id(errorNoMatch), ), - ).Line() + ) } m = append(m, codegen.NewCommentedValueMethod( r.pkg.Path(), @@ -321,11 +366,10 @@ func (r *ResolverGenerator) jsonResolverMethods() (m []*codegen.Method) { jen.Id("handleFn").Op(":=").Func().Parens( jen.Id("typeString").String(), ).Error().Block( - jen.Switch(jen.Id("typeString")).Block( - impl.Default().Block( - jen.Return( - jen.Id(errorUnhandled), - ), + aliasFetching, + impl.Else().Block( + jen.Return( + jen.Id(errorUnhandled), ), ), ), @@ -393,9 +437,14 @@ func (r *ResolverGenerator) jsonResolverMethods() (m []*codegen.Method) { // typeResolverMethods returns the methods for the TypeResolver. func (r *ResolverGenerator) typeResolverMethods() (m []*codegen.Method) { impl := jen.Empty() - for _, t := range r.types { - impl = impl.Case( - jen.Lit(t.TypeName()), + for i, t := range r.types { + if i > 0 { + impl = impl.Else() + } + impl = impl.If( + jen.Id("o").Dot(vocabURIMethod).Call().Op("==").Lit(t.vocabURI.String()).Op( + "&&", + ).Id("o").Dot(typeNameMethod).Call().Op("==").Lit(t.TypeName()), ).Block( jen.If( jen.List( @@ -430,7 +479,7 @@ func (r *ResolverGenerator) typeResolverMethods() (m []*codegen.Method) { ), ), ), - ).Line() + ) } m = append(m, codegen.NewCommentedValueMethod( r.pkg.Path(), @@ -450,11 +499,9 @@ func (r *ResolverGenerator) typeResolverMethods() (m []*codegen.Method) { jen.Id("i"), ).Op(":=").Range().Id(codegen.This()).Dot(callbackMember), ).Block( - jen.Switch(jen.Id("o").Dot(typeNameMethod).Call()).Block( - impl.Default().Block( - jen.Return( - jen.Id(errorUnhandled), - ), + impl.Else().Block( + jen.Return( + jen.Id(errorUnhandled), ), ), ), @@ -469,9 +516,14 @@ func (r *ResolverGenerator) typeResolverMethods() (m []*codegen.Method) { // typePredicatedResolverMethods returns the methods for the TypePredicatedResolver. func (r *ResolverGenerator) typePredicatedResolverMethods() (m []*codegen.Method) { impl := jen.Empty() - for _, t := range r.types { - impl = impl.Case( - jen.Lit(t.TypeName()), + for i, t := range r.types { + if i > 0 { + impl = impl.Else() + } + impl = impl.If( + jen.Id("o").Dot(vocabURIMethod).Call().Op("==").Lit(t.vocabURI.String()).Op( + "&&", + ).Id("o").Dot(typeNameMethod).Call().Op("==").Lit(t.TypeName()), ).Block( jen.If( jen.List( @@ -518,7 +570,7 @@ func (r *ResolverGenerator) typePredicatedResolverMethods() (m []*codegen.Method jen.Id(errorPredicateUnmatched), ), ), - ).Line() + ) } m = append(m, codegen.NewCommentedValueMethod( r.pkg.Path(), @@ -535,12 +587,10 @@ func (r *ResolverGenerator) typePredicatedResolverMethods() (m []*codegen.Method []jen.Code{ jen.Var().Id("predicatePasses").Bool(), jen.Var().Err().Error(), - jen.Switch(jen.Id("o").Dot(typeNameMethod).Call()).Block( - impl.Default().Block( - jen.Return( - jen.False(), - jen.Id(errorUnhandled), - ), + impl.Else().Block( + jen.Return( + jen.False(), + jen.Id(errorUnhandled), ), ), jen.If( @@ -726,6 +776,12 @@ func (r *ResolverGenerator) asInterface() *codegen.Interface { Ret: []jen.Code{jen.String()}, Comment: fmt.Sprintf("%s returns the ActiivtyStreams value's type.", typeNameMethod), }, + { + Name: vocabURIMethod, + Params: nil, + Ret: []jen.Code{jen.String()}, + Comment: fmt.Sprintf("%s returns the vocabulary's URI as a string.", vocabURIMethod), + }, }, fmt.Sprintf("%s represents any ActivityStream value code-generated by go-fed or compatible with the generated interfaces.", activityStreamInterface)) } diff --git a/astool/gen/type.go b/astool/gen/type.go index 898cf63..34789a7 100644 --- a/astool/gen/type.go +++ b/astool/gen/type.go @@ -12,7 +12,7 @@ import ( const ( typeInterfaceName = "Type" - typeMember = "Type" // This specifically must match the "type" property member generated! Kludge that this happens to just work. + typeMember = "ActivityStreamsType" // This specifically must match the "type" property member generated! Kludge that this happens to just work. typePropertyConstructor = "typePropertyConstructor" jsonLDContextInterfaceName = "jsonldContexter" extendedByMethod = "IsExtendedBy" @@ -20,6 +20,7 @@ const ( extendsMethod = "Extends" disjointWithMethod = "IsDisjointWith" typeNameMethod = "GetName" + vocabURIMethod = "VocabularyURI" serializeMethodName = "Serialize" deserializeFnName = "Deserialize" compareLessMethod = "LessThan" @@ -48,6 +49,12 @@ func TypeInterface(pkg Package) *codegen.Interface { Ret: []jen.Code{jen.String()}, Comment: fmt.Sprintf("%s returns the ActivityStreams type name.", typeNameMethod), }, + { + Name: vocabURIMethod, + Params: nil, + Ret: []jen.Code{jen.String()}, + Comment: fmt.Sprintf("%s returns the vocabulary's URI as a string.", vocabURIMethod), + }, } return codegen.NewInterface(pkg.Path(), typeInterfaceName, funcs, comment) } @@ -77,10 +84,12 @@ func ContextInterface(pkg Package) *codegen.Interface { // Property represents a property of an ActivityStreams type. type Property interface { + VocabName() string GetPublicPackage() Package PropertyName() string + StructName() string InterfaceName() string - SetKindFns(docName, idName string, kind *jen.Statement, deser *codegen.Method) error + SetKindFns(docName, idName, vocab string, kind *jen.Statement, deser *codegen.Method) error DeserializeFnName() string HasNaturalLanguageMap() bool } @@ -150,10 +159,10 @@ func NewTypeGenerator(vocabName string, } } for _, wop := range withoutProperties { - if _, has := t.withoutProperties[wop.PropertyName()]; has { - return nil, fmt.Errorf("type already has withoutproperty with name %q", wop.PropertyName()) + if _, has := t.withoutProperties[wop.StructName()]; has { + return nil, fmt.Errorf("type already has withoutproperty with name %q", wop.StructName()) } - t.withoutProperties[wop.PropertyName()] = wop + t.withoutProperties[wop.StructName()] = wop } // Complete doubly-linked extends/extendedBy lists. for _, ext := range extends { @@ -169,10 +178,10 @@ func NewTypeGenerator(vocabName string, // AddPropertyGenerator adds a property generator to this type. It must be // called before Definition is called. func (t *TypeGenerator) AddPropertyGenerator(property Property) error { - if _, has := t.properties[property.PropertyName()]; has { - return fmt.Errorf("type already has property with name %q", property.PropertyName()) + if _, has := t.properties[property.StructName()]; has { + return fmt.Errorf("type already has property with name %q", property.StructName()) } - t.properties[property.PropertyName()] = property + t.properties[property.StructName()] = property return nil } @@ -206,7 +215,7 @@ func (t *TypeGenerator) apply(m *ManagerGenerator) error { continue } // Kluge: convert.toIdentifier must match this! - if e := p.SetKindFns(t.TypeName(), strings.Title(t.TypeName()), kind, deser); e != nil { + if e := p.SetKindFns(t.TypeName(), strings.Title(t.TypeName()), t.vocabName, kind, deser); e != nil { return e } propsSet[p] = true @@ -249,9 +258,14 @@ func (t *TypeGenerator) TypeName() string { return t.typeName } +// StructName returns the Go name for this type. +func (t *TypeGenerator) StructName() string { + return fmt.Sprintf("%s%s", t.VocabName(), t.typeName) +} + // InterfaceName returns the interface name for this type. func (t *TypeGenerator) InterfaceName() string { - return fmt.Sprintf("%sInterface", t.TypeName()) + return fmt.Sprintf("%s", t.StructName()) } // Extends returns the generators of types that this ActivityStreams type @@ -287,7 +301,7 @@ func (t *TypeGenerator) WithoutProperties() map[string]Property { // extendsFnName determines the name of the Extends function, which // determines if this ActivityStreams type extends another one. func (t *TypeGenerator) extendsFnName() string { - return fmt.Sprintf("%s%s", t.TypeName(), extendsMethod) + return fmt.Sprintf("%s%s", t.StructName(), extendsMethod) } // extendedByFnName determines the name of the ExtendedBy function, which @@ -332,10 +346,11 @@ func (t *TypeGenerator) Definition() *codegen.Struct { ctxMethods := t.contextMethods() t.cachedStruct = codegen.NewStruct( t.Comments(), - t.TypeName(), + t.StructName(), append(append(append( []*codegen.Method{ t.nameDefinition(), + t.vocabURIDefinition(), extendsMethod, ser, less, @@ -410,7 +425,10 @@ func (t *TypeGenerator) allProperties() []Property { // memberName returns the member name for this property. func (*TypeGenerator) memberName(p Property) string { - return strings.Title(p.PropertyName()) + return fmt.Sprintf( + "%s%s", + p.VocabName(), + strings.Title(p.PropertyName())) } // members returns all the properties this type has as its members. @@ -433,7 +451,7 @@ func (t *TypeGenerator) nameDefinition() *codegen.Method { return codegen.NewCommentedValueMethod( t.PrivatePackage().Path(), typeNameMethod, - t.TypeName(), + t.StructName(), /*params=*/ nil, []jen.Code{jen.String()}, []jen.Code{ @@ -442,6 +460,22 @@ func (t *TypeGenerator) nameDefinition() *codegen.Method { fmt.Sprintf("%s returns the name of this type.", typeNameMethod)) } +// vocabURIDefinition generates the golang method for returning this type's +// vocabulary URI as a string. +func (t *TypeGenerator) vocabURIDefinition() *codegen.Method { + return codegen.NewCommentedValueMethod( + t.PrivatePackage().Path(), + vocabURIMethod, + t.StructName(), + /*params=*/ nil, + []jen.Code{jen.String()}, + []jen.Code{ + jen.Return(jen.Lit(t.vocabURI.String())), + }, + fmt.Sprintf("%s returns the vocabulary's URI as a string.", vocabURIMethod)) + +} + // getAllParentExtends recursively determines all the parent types that this // type extends from. func (t *TypeGenerator) getAllParentExtends(s map[*TypeGenerator]string, tg *TypeGenerator) map[*TypeGenerator]string { @@ -495,7 +529,7 @@ func (t *TypeGenerator) extendsDefinition() (*codegen.Function, *codegen.Method) m := codegen.NewCommentedValueMethod( t.PrivatePackage().Path(), extendingMethod, - t.TypeName(), + t.StructName(), []jen.Code{jen.Id("other").Qual(t.PublicPackage().Path(), typeInterfaceName)}, []jen.Code{jen.Bool()}, []jen.Code{ @@ -646,7 +680,7 @@ func (t *TypeGenerator) serializationMethod() (ser *codegen.Method) { ser = codegen.NewCommentedValueMethod( t.PrivatePackage().Path(), serializeMethodName, - t.TypeName(), + t.StructName(), /*params=*/ nil, []jen.Code{jen.Map(jen.String()).Interface(), jen.Error()}, []jen.Code{ @@ -734,7 +768,7 @@ func (t *TypeGenerator) lessMethod() (less *codegen.Method) { less = codegen.NewCommentedValueMethod( t.PrivatePackage().Path(), compareLessMethod, - t.TypeName(), + t.StructName(), []jen.Code{ jen.Id("o").Qual(t.PublicPackage().Path(), t.InterfaceName()), }, @@ -803,7 +837,7 @@ func (t *TypeGenerator) deserializationFn() (deser *codegen.Function) { t.PrivatePackage().Path(), t.deserializationFnName(), []jen.Code{jen.Id("m").Map(jen.String()).Interface(), jen.Id("aliasMap").Map(jen.String()).String()}, - []jen.Code{jen.Op("*").Id(t.TypeName()), jen.Error()}, + []jen.Code{jen.Op("*").Id(t.StructName()), jen.Error()}, []jen.Code{ jen.Id("alias").Op(":=").Lit(""), jen.Id("aliasPrefix").Op(":=").Lit(""), @@ -817,7 +851,7 @@ func (t *TypeGenerator) deserializationFn() (deser *codegen.Function) { jen.Id("alias").Op("=").Id("a"), jen.Id("aliasPrefix").Op("=").Id("a").Op("+").Lit(":"), ), - jen.Id(codegen.This()).Op(":=").Op("&").Id(t.TypeName()).Values(jen.Dict{ + jen.Id(codegen.This()).Op(":=").Op("&").Id(t.StructName()).Values(jen.Dict{ jen.Id(aliasMember): jen.Id("alias"), jen.Id(unknownMember): jen.Make(jen.Map(jen.String()).Interface()), }), @@ -910,7 +944,7 @@ func (t *TypeGenerator) getUnknownMethod() (get *codegen.Method) { get = codegen.NewCommentedValueMethod( t.PrivatePackage().Path(), getUnknownMethod, - t.TypeName(), + t.StructName(), /*params=*/ nil, []jen.Code{jen.Map(jen.String()).Interface()}, []jen.Code{ @@ -929,7 +963,7 @@ func (t *TypeGenerator) allGetters() (m []*codegen.Method) { m = append(m, codegen.NewCommentedValueMethod( t.PrivatePackage().Path(), fmt.Sprintf(getMethodFormat, t.memberName(property)), - t.TypeName(), + t.StructName(), /*params=*/ nil, []jen.Code{jen.Qual(property.GetPublicPackage().Path(), property.InterfaceName())}, []jen.Code{ @@ -948,7 +982,7 @@ func (t *TypeGenerator) allSetters() (m []*codegen.Method) { m = append(m, codegen.NewCommentedPointerMethod( t.PrivatePackage().Path(), fmt.Sprintf("Set%s", t.memberName(property)), - t.TypeName(), + t.StructName(), []jen.Code{jen.Id("i").Qual(property.GetPublicPackage().Path(), property.InterfaceName())}, /*ret=*/ nil, []jen.Code{ @@ -972,16 +1006,16 @@ func (t *TypeGenerator) getAllManagerMethods() (m []*codegen.Method) { func (t *TypeGenerator) constructorFn() *codegen.Function { return codegen.NewCommentedFunction( t.PrivatePackage().Path(), - fmt.Sprintf("%s%s", constructorName, t.TypeName()), + fmt.Sprintf("%s%s", constructorName, t.StructName()), /*params=*/ nil, []jen.Code{ - jen.Op("*").Qual(t.PrivatePackage().Path(), t.TypeName()), + jen.Op("*").Qual(t.PrivatePackage().Path(), t.StructName()), }, []jen.Code{ jen.Id("typeProp").Op(":=").Id(typePropertyConstructorName()).Call(), - jen.Id("typeProp").Dot("AppendString").Call(jen.Lit(t.TypeName())), + jen.Id("typeProp").Dot("AppendXMLSchemaString").Call(jen.Lit(t.TypeName())), jen.Return( - jen.Op("&").Qual(t.PrivatePackage().Path(), t.TypeName()).Values( + jen.Op("&").Qual(t.PrivatePackage().Path(), t.StructName()).Values( jen.Dict{ jen.Id(aliasMember): jen.Lit(t.vocabAlias), jen.Id(unknownMember): jen.Make(jen.Map(jen.String()).Interface(), jen.Lit(0)), @@ -990,7 +1024,7 @@ func (t *TypeGenerator) constructorFn() *codegen.Function { ), ), }, - fmt.Sprintf("%s%s creates a new %s type", constructorName, t.TypeName(), t.TypeName())) + fmt.Sprintf("%s%s creates a new %s type", constructorName, t.StructName(), t.TypeName())) } // contextMethod returns a map of the context's vocabulary @@ -999,7 +1033,7 @@ func (t *TypeGenerator) contextMethods() []*codegen.Method { helper := codegen.NewCommentedValueMethod( t.PrivatePackage().Path(), helperName, - t.TypeName(), + t.StructName(), []jen.Code{jen.Id("i").Id(jsonLDContextInterfaceName), jen.Id("toMerge").Map(jen.String()).String()}, []jen.Code{jen.Map(jen.String()).String()}, []jen.Code{ @@ -1034,7 +1068,7 @@ func (t *TypeGenerator) contextMethods() []*codegen.Method { ctxMethod := codegen.NewCommentedValueMethod( t.PrivatePackage().Path(), contextMethod, - t.TypeName(), + t.StructName(), /*params=*/ nil, []jen.Code{jen.Map(jen.String()).String()}, []jen.Code{