// Package RFC contains ontology values that are defined in RFCs, BCPs, and // other miscellaneous standards. package rfc import ( "fmt" "github.com/dave/jennifer/jen" "github.com/go-fed/activity/astool/codegen" "github.com/go-fed/activity/astool/rdf" "net/url" "strings" ) const ( rfcName = "RFC" rfcSpec = "https://tools.ietf.org/html/" bcp47Spec = "bcp47" mimeSpec = "rfc2045" // See also: rfc2046 and rfc6838 relSpec = "rfc5988" ) // RFCOntology represents standards and values that originate from RFC // specifications. type RFCOntology struct { Package string } // SpecURI returns the RFC specifications URI. func (o *RFCOntology) SpecURI() string { return rfcSpec } // Load without an alias. func (o *RFCOntology) Load() ([]rdf.RDFNode, error) { return o.LoadAsAlias("") } // LoadAsAlias loads with the given alias. func (o *RFCOntology) LoadAsAlias(s string) ([]rdf.RDFNode, error) { return []rdf.RDFNode{ &rdf.AliasedDelegate{ Spec: rfcSpec, Alias: s, Name: bcp47Spec, Delegate: &bcp47{pkg: o.Package}, }, &rdf.AliasedDelegate{ Spec: rfcSpec, Alias: s, Name: mimeSpec, Delegate: &mime{pkg: o.Package}, }, &rdf.AliasedDelegate{ Spec: rfcSpec, Alias: s, Name: relSpec, Delegate: &rel{pkg: o.Package}, }, }, nil } // LoadSpecificAsAlias loads a specific item with a given alias. func (o *RFCOntology) LoadSpecificAsAlias(alias, name string) ([]rdf.RDFNode, error) { switch name { case bcp47Spec: return []rdf.RDFNode{ &rdf.AliasedDelegate{ Spec: "", Alias: "", Name: alias, Delegate: &bcp47{pkg: o.Package}, }, }, nil case mimeSpec: return []rdf.RDFNode{ &rdf.AliasedDelegate{ Spec: "", Alias: "", Name: alias, Delegate: &mime{pkg: o.Package}, }, }, nil case relSpec: return []rdf.RDFNode{ &rdf.AliasedDelegate{ Spec: "", Alias: "", Name: alias, Delegate: &rel{pkg: o.Package}, }, }, nil } return nil, fmt.Errorf("rfc ontology cannot find %q to alias to %q", name, alias) } // LoadElement does nothing. func (o *RFCOntology) LoadElement(name string, payload map[string]interface{}) ([]rdf.RDFNode, error) { return nil, nil } // GetByName obtains a bare node by name. func (o *RFCOntology) GetByName(name string) (rdf.RDFNode, error) { name = strings.TrimPrefix(name, o.SpecURI()) switch name { case bcp47Spec: return &bcp47{pkg: o.Package}, nil case mimeSpec: return &mime{pkg: o.Package}, nil case relSpec: return &rel{pkg: o.Package}, nil } return nil, fmt.Errorf("rfc ontology could not find node for name %s", name) } var _ rdf.RDFNode = &bcp47{} // BCP47 represents a BCP47 value. // // No validation is done on deserialized values. type bcp47 struct { pkg string } // Enter does nothing. func (b *bcp47) Enter(key string, ctx *rdf.ParsingContext) (bool, error) { return true, fmt.Errorf("bcp47 langaugetag cannot be entered") } // Exit does nothing. func (b *bcp47) Exit(key string, ctx *rdf.ParsingContext) (bool, error) { return true, fmt.Errorf("bcp47 languagetag cannot be exited") } // Apply adds BCP47 as a value Kind. func (b *bcp47) Apply(key string, value interface{}, ctx *rdf.ParsingContext) (bool, error) { v, err := ctx.GetResultReferenceWithDefaults(rfcSpec, rfcName) if err != nil { return true, err } if len(v.Values[bcp47Spec].Name) == 0 { u, err := url.Parse(rfcSpec + bcp47Spec) if err != nil { return true, err } val := &rdf.VocabularyValue{ Name: bcp47Spec, URI: u, DefinitionType: jen.String(), Zero: "\"\"", IsNilable: false, SerializeFn: rdf.SerializeValueFunction( b.pkg, bcp47Spec, jen.String(), []jen.Code{ jen.Return( jen.Id(codegen.This()), jen.Nil(), ), }), DeserializeFn: rdf.DeserializeValueFunction( b.pkg, bcp47Spec, jen.String(), []jen.Code{ jen.If( jen.List( jen.Id("s"), jen.Id("ok"), ).Op(":=").Id(codegen.This()).Assert(jen.String()), jen.Id("ok"), ).Block( jen.Return( jen.Id("s"), jen.Nil(), ), ).Else().Block( jen.Return( jen.Lit(""), jen.Qual("fmt", "Errorf").Call( jen.Lit("%v cannot be interpreted as a string for bcp47 languagetag"), jen.Id(codegen.This()), ), ), ), }), LessFn: rdf.LessFunction( b.pkg, bcp47Spec, jen.String(), []jen.Code{ jen.Return( jen.Id("lhs").Op("<").Id("rhs"), ), }), } if err = v.SetValue(bcp47Spec, val); err != nil { return true, err } } return true, nil } var _ rdf.RDFNode = &mime{} // mime represents MIME values. type mime struct { pkg string } // Enter does nothing. func (*mime) Enter(key string, ctx *rdf.ParsingContext) (bool, error) { return true, fmt.Errorf("MIME media type cannot be entered") } // Exit does nothing. func (*mime) Exit(key string, ctx *rdf.ParsingContext) (bool, error) { return true, fmt.Errorf("MIME media type cannot be exited") } // Apply adds MIME as a value Kind. func (m *mime) Apply(key string, value interface{}, ctx *rdf.ParsingContext) (bool, error) { v, err := ctx.GetResultReferenceWithDefaults(rfcSpec, rfcName) if err != nil { return true, err } if len(v.Values[mimeSpec].Name) == 0 { u, err := url.Parse(rfcSpec + mimeSpec) if err != nil { return true, err } val := &rdf.VocabularyValue{ Name: mimeSpec, URI: u, DefinitionType: jen.String(), Zero: "\"\"", IsNilable: false, SerializeFn: rdf.SerializeValueFunction( m.pkg, mimeSpec, jen.String(), []jen.Code{ jen.Return( jen.Id(codegen.This()), jen.Nil(), ), }), DeserializeFn: rdf.DeserializeValueFunction( m.pkg, mimeSpec, jen.String(), []jen.Code{ jen.If( jen.List( jen.Id("s"), jen.Id("ok"), ).Op(":=").Id(codegen.This()).Assert(jen.String()), jen.Id("ok"), ).Block( jen.Return( jen.Id("s"), jen.Nil(), ), ).Else().Block( jen.Return( jen.Lit(""), jen.Qual("fmt", "Errorf").Call( jen.Lit("%v cannot be interpreted as a string for MIME media type"), jen.Id(codegen.This()), ), ), ), }), LessFn: rdf.LessFunction( m.pkg, mimeSpec, jen.String(), []jen.Code{ jen.Return( jen.Id("lhs").Op("<").Id("rhs"), ), }), } if err = v.SetValue(mimeSpec, val); err != nil { return true, err } } return true, nil } var _ rdf.RDFNode = &rel{} // rel is a Link Relation. type rel struct { pkg string } // Enter does nothing. func (*rel) Enter(key string, ctx *rdf.ParsingContext) (bool, error) { return true, fmt.Errorf("rel cannot be entered") } // Exit does nothing. func (*rel) Exit(key string, ctx *rdf.ParsingContext) (bool, error) { return true, fmt.Errorf("rel cannot be exited") } // Apply adds rel as a supported value Kind. func (r *rel) Apply(key string, value interface{}, ctx *rdf.ParsingContext) (bool, error) { v, err := ctx.GetResultReferenceWithDefaults(rfcSpec, rfcName) if err != nil { return true, err } if len(v.Values[relSpec].Name) == 0 { u, err := url.Parse(rfcSpec + relSpec) if err != nil { return true, err } val := &rdf.VocabularyValue{ Name: relSpec, URI: u, DefinitionType: jen.String(), Zero: "\"\"", IsNilable: false, SerializeFn: rdf.SerializeValueFunction( r.pkg, relSpec, jen.String(), []jen.Code{ jen.Return( jen.Id(codegen.This()), jen.Nil(), ), }), DeserializeFn: rdf.DeserializeValueFunction( r.pkg, relSpec, jen.String(), []jen.Code{ jen.If( jen.List( jen.Id("s"), jen.Id("ok"), ).Op(":=").Id(codegen.This()).Assert(jen.String()), jen.Id("ok"), ).Block( jen.Return( jen.Id("s"), jen.Nil(), ), ).Else().Block( jen.Return( jen.Lit(""), jen.Qual("fmt", "Errorf").Call( jen.Lit("%v cannot be interpreted as a string for rel"), jen.Id(codegen.This()), ), ), ), }), LessFn: rdf.LessFunction( r.pkg, relSpec, jen.String(), []jen.Code{ jen.Return( jen.Id("lhs").Op("<").Id("rhs"), ), }), } if err = v.SetValue(relSpec, val); err != nil { return true, err } } return true, nil }