Add JSONResolver.

Moved resolvers to root package due to JSONResolver's reliance on the
manager.
このコミットが含まれているのは:
Cory Slep 2019-01-29 22:00:33 +01:00
コミット ba00f3f875
6個のファイルの変更278行の追加21行の削除

ファイルの表示

@ -364,7 +364,7 @@ func (c Converter) convertToFiles(v vocabulary) (f []*File, e error) {
Directory: pub.WriteDir(),
})
// Resolvers
files, e = c.resolverFiles(c.GenRoot.Sub(resolverPkg).PublicPackage(), v)
files, e = c.resolverFiles(c.GenRoot.PublicPackage(), v.Manager, v)
if e != nil {
return
}
@ -1087,9 +1087,9 @@ func (c Converter) propertyPackageFiles(pg *gen.PropertyGenerator, vocabName str
}
// resolverFiles creates the files necessary for the resolvers.
func (c Converter) resolverFiles(pkg gen.Package, root vocabulary) (files []*File, e error) {
rg := gen.NewResolverGenerator(root.allTypeArray(), pkg)
typeRes, intRes, typePredRes, intPredRes, errDefs, isUnFn, iFaces := rg.Definition()
func (c Converter) resolverFiles(pkg gen.Package, manGen *gen.ManagerGenerator, root vocabulary) (files []*File, e error) {
rg := gen.NewResolverGenerator(root.allTypeArray(), manGen, pkg)
jsonRes, typeRes, intRes, typePredRes, intPredRes, errDefs, isUnFn, iFaces := rg.Definition()
// Utils
file := jen.NewFilePath(pkg.Path())
for _, errDef := range errDefs {
@ -1104,6 +1104,14 @@ func (c Converter) resolverFiles(pkg gen.Package, root vocabulary) (files []*Fil
FileName: "gen_resolver_utils.go",
Directory: pkg.WriteDir(),
})
// JSON resolver
file = jen.NewFilePath(pkg.Path())
file.Add(jsonRes.Definition())
files = append(files, &File{
F: file,
FileName: "gen_json_resolver.go",
Directory: pkg.WriteDir(),
})
// Type, not predicated
file = jen.NewFilePath(pkg.Path())
file.Add(typeRes.Definition())

ファイルの表示

@ -338,7 +338,7 @@ func (p *FunctionalPropertyGenerator) serializationFuncs() (*codegen.Method, *co
jen.List(
jen.Id("v"),
jen.Err(),
).Op(":=").Add(kind.deserializeFnCode(variable, jen.Id("context"))),
).Op(":=").Add(kind.deserializeFnCode(variable, jen.Id("aliasMap"))),
jen.Err().Op("!=").Nil(),
).Block(
jen.Id(codegen.This()).Op(":=").Op("&").Id(p.StructName()).Values(
@ -362,7 +362,7 @@ func (p *FunctionalPropertyGenerator) serializationFuncs() (*codegen.Method, *co
deserialize = codegen.NewCommentedFunction(
p.GetPrivatePackage().Path(),
p.DeserializeFnName(),
[]jen.Code{jen.Id("i").Interface(), jen.Id("context").Map(jen.String()).String()},
[]jen.Code{jen.Id("i").Interface(), jen.Id("aliasMap").Map(jen.String()).String()},
[]jen.Code{jen.Op("*").Id(p.StructName()), jen.Error()},
[]jen.Code{
jen.Id("alias").Op(":=").Lit(""),
@ -370,7 +370,7 @@ func (p *FunctionalPropertyGenerator) serializationFuncs() (*codegen.Method, *co
jen.List(
jen.Id("a"),
jen.Id("ok"),
).Op(":=").Id("context").Index(jen.Lit(p.vocabURI.String())),
).Op(":=").Id("aliasMap").Index(jen.Lit(p.vocabURI.String())),
jen.Id("ok"),
).Block(
jen.Id("alias").Op("=").Id("a"),
@ -388,7 +388,7 @@ func (p *FunctionalPropertyGenerator) serializationFuncs() (*codegen.Method, *co
deserialize = codegen.NewCommentedFunction(
p.GetPrivatePackage().Path(),
p.DeserializeFnName(),
[]jen.Code{jen.Id("m").Map(jen.String()).Interface(), jen.Id("context").Map(jen.String()).String()},
[]jen.Code{jen.Id("m").Map(jen.String()).Interface(), jen.Id("aliasMap").Map(jen.String()).String()},
[]jen.Code{jen.Op("*").Id(p.StructName()), jen.Error()},
[]jen.Code{
jen.Id("alias").Op(":=").Lit(""),
@ -396,7 +396,7 @@ func (p *FunctionalPropertyGenerator) serializationFuncs() (*codegen.Method, *co
jen.List(
jen.Id("a"),
jen.Id("ok"),
).Op(":=").Id("context").Index(jen.Lit(p.vocabURI.String())),
).Op(":=").Id("aliasMap").Index(jen.Lit(p.vocabURI.String())),
jen.Id("ok"),
).Block(
jen.Id("alias").Op("=").Id("a"),

ファイルの表示

@ -212,7 +212,7 @@ func (m *ManagerGenerator) createDeserializationMethod(deserName string, pubPkg,
jen.Return(
jen.Func().Params(
jen.Id("m").Map(jen.String()).Interface(),
jen.Id("context").Map(jen.String()).String(),
jen.Id("aliasMap").Map(jen.String()).String(),
).Params(
jen.Qual(pubPkg.Path(), interfaceName),
jen.Error(),
@ -221,7 +221,7 @@ func (m *ManagerGenerator) createDeserializationMethod(deserName string, pubPkg,
// Note: this "i" must be the same as the "i" in the deserialization definition.
jen.Id("i"),
jen.Err(),
).Op(":=").Qual(privPkg.Path(), deserName).Call(jen.Id("m"), jen.Id("context")),
).Op(":=").Qual(privPkg.Path(), deserName).Call(jen.Id("m"), jen.Id("aliasMap")),
jen.Return(jen.List(
jen.Id("i"),
jen.Err(),

ファイルの表示

@ -592,7 +592,7 @@ func (p *NonFunctionalPropertyGenerator) serializationFuncs() (*codegen.Method,
jen.Err(),
).Op(":=").Id(p.elementTypeGenerator().DeserializeFnName()).Call(
jen.Id(variable),
jen.Id("context"),
jen.Id("aliasMap"),
),
jen.Err().Op("!=").Nil(),
).Block(
@ -612,7 +612,7 @@ func (p *NonFunctionalPropertyGenerator) serializationFuncs() (*codegen.Method,
deserialize := codegen.NewCommentedFunction(
p.GetPrivatePackage().Path(),
p.DeserializeFnName(),
[]jen.Code{jen.Id("m").Map(jen.String()).Interface(), jen.Id("context").Map(jen.String()).String()},
[]jen.Code{jen.Id("m").Map(jen.String()).Interface(), jen.Id("aliasMap").Map(jen.String()).String()},
[]jen.Code{jen.Qual(p.GetPublicPackage().Path(), p.InterfaceName()), jen.Error()},
[]jen.Code{
jen.Id("alias").Op(":=").Lit(""),
@ -620,7 +620,7 @@ func (p *NonFunctionalPropertyGenerator) serializationFuncs() (*codegen.Method,
jen.List(
jen.Id("a"),
jen.Id("ok"),
).Op(":=").Id("context").Index(jen.Lit(p.vocabURI.String())),
).Op(":=").Id("aliasMap").Index(jen.Lit(p.vocabURI.String())),
jen.Id("ok"),
).Block(
jen.Id("alias").Op("=").Id("a"),

ファイルの表示

@ -8,6 +8,9 @@ import (
)
const (
contextJSONLDName = "@context"
typePropertyName = "type"
jsonResolverStructName = "JSONResolver"
typeResolverStructName = "TypeResolver"
interfaceResolverStructName = "InterfaceResolver"
typePredicatedResolverStructName = "TypePredicatedResolver"
@ -25,6 +28,7 @@ const (
errorCannotTypeAssert = "errCannotTypeAssertType"
errorCannotTypeAssertPredicate = "errCannotTypeAssertPredicate"
isUnFnName = "IsUnmatchedErr"
toAliasMapFnName = "toAliasMap"
)
// ResolverGenerator generates the code required for the TypeResolver and the
@ -32,7 +36,9 @@ const (
type ResolverGenerator struct {
pkg Package
types []*TypeGenerator
manGen *ManagerGenerator
cacheOnce sync.Once
cachedJSON *codegen.Struct
cachedTypePredicate *codegen.Struct
cachedInterfacePredicate *codegen.Struct
cachedType *codegen.Struct
@ -53,16 +59,41 @@ type ResolverGenerator struct {
// Must be constructed after all TypeGenerators.
func NewResolverGenerator(
tgs []*TypeGenerator,
m *ManagerGenerator,
pkg Package) *ResolverGenerator {
return &ResolverGenerator{
pkg: pkg,
types: tgs,
pkg: pkg,
types: tgs,
manGen: m,
}
}
// Definition returns the TypeResolver and PredicateTypeResolver.
func (r *ResolverGenerator) Definition() (typeRes, interfaceRes, typePredRes, interfacePredRes *codegen.Struct, errs []jen.Code, isUnFn *codegen.Function, iFaces []*codegen.Interface) {
//
// This function signature is pure garbage and yet I keep heaping it on.
func (r *ResolverGenerator) Definition() (jsonRes, typeRes, interfaceRes, typePredRes, interfacePredRes *codegen.Struct, errs []jen.Code, isUnFn *codegen.Function, iFaces []*codegen.Interface) {
r.cacheOnce.Do(func() {
r.cachedJSON = codegen.NewStruct(
fmt.Sprintf("%s resolves a JSON-deserialized map into "+
"its concrete ActivityStreams type", jsonResolverStructName),
jsonResolverStructName,
r.jsonResolverMethods(),
append(r.resolverFunctions(jsonResolverStructName,
"creates a new Resolver that takes a "+
"JSON-deserialized generic map and determines "+
"the correct concrete Go type. The callback "+
"function is guaranteed to receive a value "+
"whose underlying ActivityStreams type "+
"matches the concrete interface name in its "+
"signature. The callback functions must be of "+
"the form:\n\n"+
" func(context.Context, <TypeInterface>) error\n\n"+
"where TypeInterface is the code-generated "+
"interface for an ActivityStream type. An "+
"error is returned if a callback function "+
"does not match this signature."),
r.toAliasFunction()),
r.resolverMembers())
r.cachedType = codegen.NewStruct(
fmt.Sprintf("%s resolves ActivityStreams values based "+
"on their type name.", typeResolverStructName),
@ -165,7 +196,7 @@ func (r *ResolverGenerator) Definition() (typeRes, interfaceRes, typePredRes, in
r.cachedASInterface = r.asInterface()
r.cachedResolverInterface = r.resolverInterface()
})
return r.cachedType, r.cachedInterface, r.cachedTypePredicate, r.cachedInterfacePredicate, []jen.Code{
return r.cachedJSON, r.cachedType, r.cachedInterface, r.cachedTypePredicate, r.cachedInterfacePredicate, []jen.Code{
r.cachedErrNoMatch,
r.cachedErrUnhandled,
r.cachedErrPredicateUnmatched,
@ -251,6 +282,106 @@ func (r *ResolverGenerator) isUnFn() *codegen.Function {
fmt.Sprintf("%s is true when the error indicates that a Resolver was unsuccessful due to the ActivityStreams value not matching its callbacks or predicates.", isUnFnName))
}
// jsonResolverMethods returns the methods for the TypeResolver.
func (r *ResolverGenerator) jsonResolverMethods() (m []*codegen.Method) {
impl := jen.Empty()
for _, t := range r.types {
impl = impl.Case(
jen.Lit(t.TypeName()),
).Block(
jen.List(
jen.Id("v"),
jen.Err(),
).Op(":=").Add(r.manGen.getDeserializationMethodForType(t).On(managerInitVarName).Call().Call(
jen.Id("m"),
jen.Id("aliasMap"),
)),
jen.If(
jen.Err().Op("!=").Nil(),
).Block(
jen.Return(jen.Err()),
),
jen.For(
jen.List(
jen.Id("_"),
jen.Id("i"),
).Op(":=").Range().Id(codegen.This()).Dot(callbackMember),
).Block(
jen.If(
jen.List(
jen.Id("fn"),
jen.Id("ok"),
).Op(":=").Id("i").Assert(
jen.Func().Parens(
jen.List(
jen.Qual("context", "Context"),
jen.Qual(t.PublicPackage().Path(), t.InterfaceName()),
),
).Error(),
),
jen.Id("ok"),
).Block(
jen.Return(
jen.Id("fn").Call(jen.Id("ctx"), jen.Id("v")),
),
),
),
jen.Return(
jen.Id(errorNoMatch),
),
).Line()
}
m = append(m, codegen.NewCommentedValueMethod(
r.pkg.Path(),
resolveMethod,
jsonResolverStructName,
[]jen.Code{
jen.Id("ctx").Qual("context", "Context"),
jen.Id("m").Map(jen.String()).Interface(),
},
[]jen.Code{
jen.Error(),
},
[]jen.Code{
jen.List(
jen.Id("typeValue"),
jen.Id("ok"),
).Op(":=").Id("m").Index(jen.Lit(typePropertyName)),
jen.If(
jen.Op("!").Id("ok"),
).Block(
jen.Return(
jen.Qual("fmt", "Errorf").Call(
jen.Lit("cannot determine ActivityStreams type: 'type' property is missing"),
),
),
),
jen.List(
jen.Id("rawContext"),
jen.Id("ok"),
).Op(":=").Id("m").Index(jen.Lit(contextJSONLDName)),
jen.If(
jen.Op("!").Id("ok"),
).Block(
jen.Return(
jen.Qual("fmt", "Errorf").Call(
jen.Lit("cannot determine ActivityStreams type: '@context' is missing"),
),
),
),
jen.Id("aliasMap").Op(":=").Id(toAliasMapFnName).Call(jen.Id("rawContext")),
jen.Switch(jen.Id("typeValue")).Block(
impl.Default().Block(
jen.Return(
jen.Id(errorUnhandled),
),
),
),
},
fmt.Sprintf("%s determines the ActivityStreams type of the payload, then applies the first callback function whose signature accepts the ActivityStreams value's type. This strictly assures that the callback function will only be passed ActivityStream objects whose type matches its interface. Returns an error if the ActivityStreams type does not match callbackers or is not a type handled by the generated code.", resolveMethod)))
return
}
// typeResolverMethods returns the methods for the TypeResolver.
func (r *ResolverGenerator) typeResolverMethods() (m []*codegen.Method) {
impl := jen.Empty()
@ -764,3 +895,121 @@ func (r *ResolverGenerator) resolverInterface() *codegen.Interface {
},
fmt.Sprintf("%s represents any %s or %s.", resolverInterface, typeResolverStructName, interfaceResolverStructName))
}
// toAliasFunction returns the toAliasMap function
func (r *ResolverGenerator) toAliasFunction() *codegen.Function {
return codegen.NewCommentedFunction(
r.pkg.Path(),
toAliasMapFnName,
[]jen.Code{
jen.Id("i").Interface(),
},
[]jen.Code{
jen.Id("m").Map(jen.String()).String(),
},
[]jen.Code{
jen.Id("toHttpHttpsFn").Op(":=").Func().Parens(
jen.Id("s").String(),
).Parens(
jen.List(
jen.Id("ok").Bool(),
jen.Id("http"),
jen.Id("https").String(),
),
).Block(
jen.If(
jen.Qual("strings", "HasPrefix").Call(
jen.Id("s"),
jen.Lit("http://"),
),
).Block(
jen.Id("ok").Op("=").True(),
jen.Id("http").Op("=").Id("s"),
jen.Id("https").Op("=").Lit("https").Op("+").Qual("strings", "TrimPrefix").Call(
jen.Id("s"),
jen.Lit("http"),
),
).Else().If(
jen.Qual("strings", "HasPrefix").Call(
jen.Id("s"),
jen.Lit("https://"),
),
).Block(
jen.Id("ok").Op("=").True(),
jen.Id("https").Op("=").Id("s"),
jen.Id("http").Op("=").Lit("http").Op("+").Qual("strings", "TrimPrefix").Call(
jen.Id("s"),
jen.Lit("https"),
),
),
jen.Return(),
),
jen.Switch(jen.Id("v").Op(":=").Id("i").Assert(jen.Type())).Block(
jen.Case(jen.String()).Block(
jen.Commentf("Single entry, no alias."),
jen.If(
jen.List(
jen.Id("ok"),
jen.Id("http"),
jen.Id("https"),
).Op(":=").Id("toHttpHttpsFn").Call(jen.Id("v")),
jen.Id("ok"),
).Block(
jen.Id("m").Index(
jen.Id("http"),
).Op("=").Lit(""),
jen.Id("m").Index(
jen.Id("https"),
).Op("=").Lit(""),
).Else().Block(
jen.Id("m").Index(
jen.Id("v"),
).Op("=").Lit(""),
),
),
jen.Case(jen.Index().Interface()).Block(
jen.Commentf("Recursively apply."),
jen.For(
jen.List(
jen.Id("_"),
jen.Id("elem"),
).Op(":=").Range().Id("v"),
).Block(
jen.Id("r").Op(":=").Id(toAliasMapFnName).Call(
jen.Id("elem"),
),
jen.For(
jen.List(
jen.Id("k"),
jen.Id("val"),
).Op(":=").Range().Id("r"),
).Block(
jen.Id("m").Index(
jen.Id("k"),
).Op("=").Id("val"),
),
),
),
jen.Case(jen.Map(jen.String()).Interface()).Block(
jen.Commentf("Map any aliases."),
jen.For(
jen.List(
jen.Id("k"),
jen.Id("val"),
).Op(":=").Range().Id("v"),
).Block(
jen.Commentf("Only handle string aliases."),
jen.Switch(jen.Id("conc").Op(":=").Id("val").Assert(jen.Type())).Block(
jen.Case(jen.String()).Block(
jen.Id("m").Index(
jen.Id("k"),
).Op("=").Id("conc"),
),
),
),
),
),
jen.Return(),
},
fmt.Sprintf("%s converts a JSONLD context into a map of vocabulary name to alias.", toAliasMapFnName))
}

ファイルの表示

@ -684,7 +684,7 @@ func (t *TypeGenerator) deserializationFn() (deser *codegen.Function) {
jen.List(
jen.Id("p"),
jen.Err(),
).Op(":=").Add(deserMethod.On(managerInitName()).Call().Call(jen.Id("m"), jen.Id("context"))),
).Op(":=").Add(deserMethod.On(managerInitName()).Call().Call(jen.Id("m"), jen.Id("aliasMap"))),
jen.Err().Op("!=").Nil(),
).Block(
jen.Return(jen.Nil(), jen.Err()),
@ -717,7 +717,7 @@ func (t *TypeGenerator) deserializationFn() (deser *codegen.Function) {
deser = codegen.NewCommentedFunction(
t.PrivatePackage().Path(),
t.deserializationFnName(),
[]jen.Code{jen.Id("m").Map(jen.String()).Interface(), jen.Id("context").Map(jen.String()).String()},
[]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.Id("alias").Op(":=").Lit(""),
@ -725,7 +725,7 @@ func (t *TypeGenerator) deserializationFn() (deser *codegen.Function) {
jen.List(
jen.Id("a"),
jen.Id("ok"),
).Op(":=").Id("context").Index(jen.Lit(t.vocabURI.String())),
).Op(":=").Id("aliasMap").Index(jen.Lit(t.vocabURI.String())),
jen.Id("ok"),
).Block(
jen.Id("alias").Op("=").Id("a"),