2018-12-02 21:55:29 +09:00
|
|
|
package rdf
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
typeSpec = "@type"
|
|
|
|
typeActivityStreamsSpec = "type"
|
|
|
|
IdSpec = "@id"
|
|
|
|
IdActivityStreamsSpec = "id"
|
|
|
|
ContainerSpec = "@container"
|
|
|
|
IndexSpec = "@index"
|
2018-12-09 01:50:26 +09:00
|
|
|
// ActivityStreams specifically disallows the 'object' property on
|
|
|
|
// certain IntransitiveActivity and subtypes. There is no RDF mechanism
|
|
|
|
// to describe this. So this is a stupid hack, based on the assumption
|
|
|
|
// that no one -- W3C or otherwise -- will name a reserved word with a
|
|
|
|
// "@wtf_" prefix due to the reserved '@', the use of the unprofessional
|
|
|
|
// 'wtf', and a style-breaking underscore.
|
|
|
|
withoutPropertySpec = "@wtf_without_property"
|
2018-12-02 21:55:29 +09:00
|
|
|
)
|
|
|
|
|
|
|
|
// jsonLDNodes contains the well-known set of nodes as defined by the JSON-LD
|
|
|
|
// specification.
|
2018-12-03 07:48:54 +09:00
|
|
|
func jsonLDNodes(r *RDFRegistry) []RDFNode {
|
2018-12-02 21:55:29 +09:00
|
|
|
// Order matters -- we want to be able to distinguish the types of
|
2018-12-06 06:53:26 +09:00
|
|
|
// things without other nodes hijacking the flow.
|
2018-12-03 07:48:54 +09:00
|
|
|
return []RDFNode{
|
2018-12-02 21:55:29 +09:00
|
|
|
&AliasedDelegate{
|
|
|
|
Spec: "",
|
|
|
|
Alias: "",
|
|
|
|
Name: typeSpec,
|
2018-12-03 07:48:54 +09:00
|
|
|
Delegate: &typeLD{r: r},
|
2018-12-02 21:55:29 +09:00
|
|
|
},
|
|
|
|
&AliasedDelegate{
|
|
|
|
Spec: "",
|
|
|
|
Alias: "",
|
|
|
|
Name: typeActivityStreamsSpec,
|
2018-12-03 07:48:54 +09:00
|
|
|
Delegate: &typeLD{r: r},
|
2018-12-02 21:55:29 +09:00
|
|
|
},
|
|
|
|
&AliasedDelegate{
|
|
|
|
Spec: "",
|
|
|
|
Alias: "",
|
|
|
|
Name: IdSpec,
|
|
|
|
Delegate: &idLD{},
|
|
|
|
},
|
|
|
|
&AliasedDelegate{
|
|
|
|
Spec: "",
|
|
|
|
Alias: "",
|
|
|
|
Name: IdActivityStreamsSpec,
|
|
|
|
Delegate: &idLD{},
|
|
|
|
},
|
|
|
|
&AliasedDelegate{
|
|
|
|
Spec: "",
|
|
|
|
Alias: "",
|
|
|
|
Name: ContainerSpec,
|
|
|
|
Delegate: &ContainerLD{},
|
|
|
|
},
|
|
|
|
&AliasedDelegate{
|
|
|
|
Spec: "",
|
|
|
|
Alias: "",
|
|
|
|
Name: IndexSpec,
|
|
|
|
Delegate: &IndexLD{},
|
|
|
|
},
|
2018-12-09 01:50:26 +09:00
|
|
|
&AliasedDelegate{
|
|
|
|
Spec: "",
|
|
|
|
Alias: "",
|
|
|
|
Name: withoutPropertySpec,
|
|
|
|
Delegate: &withoutProperty{},
|
|
|
|
},
|
2018-12-02 21:55:29 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ RDFNode = &idLD{}
|
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// idLD is an RDFNode for the 'id' property.
|
2018-12-02 21:55:29 +09:00
|
|
|
type idLD struct{}
|
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// Enter returns an error.
|
2018-12-02 21:55:29 +09:00
|
|
|
func (i *idLD) Enter(key string, ctx *ParsingContext) (bool, error) {
|
|
|
|
return true, fmt.Errorf("id cannot be entered")
|
|
|
|
}
|
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// Exit returns an error.
|
2018-12-02 21:55:29 +09:00
|
|
|
func (i *idLD) Exit(key string, ctx *ParsingContext) (bool, error) {
|
|
|
|
return true, fmt.Errorf("id cannot be exited")
|
|
|
|
}
|
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// Apply sets the URI for the context's Current item.
|
2018-12-02 21:55:29 +09:00
|
|
|
func (i *idLD) Apply(key string, value interface{}, ctx *ParsingContext) (bool, error) {
|
|
|
|
if ctx.Current == nil {
|
2018-12-03 06:37:43 +09:00
|
|
|
return true, nil
|
2018-12-02 21:55:29 +09:00
|
|
|
} else if ider, ok := ctx.Current.(URISetter); !ok {
|
|
|
|
return true, fmt.Errorf("id apply called with non-URISetter")
|
|
|
|
} else if str, ok := value.(string); !ok {
|
|
|
|
return true, fmt.Errorf("id apply called with non-string value")
|
|
|
|
} else {
|
|
|
|
return true, ider.SetURI(str)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ RDFNode = &typeLD{}
|
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// typeLD is an RDFNode for the 'type' property.
|
2018-12-03 07:48:54 +09:00
|
|
|
type typeLD struct {
|
|
|
|
r *RDFRegistry
|
|
|
|
}
|
2018-12-02 21:55:29 +09:00
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// Enter does nothing.
|
2018-12-02 21:55:29 +09:00
|
|
|
func (t *typeLD) Enter(key string, ctx *ParsingContext) (bool, error) {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// Exit does nothing.
|
2018-12-02 21:55:29 +09:00
|
|
|
func (t *typeLD) Exit(key string, ctx *ParsingContext) (bool, error) {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// Apply attempts to get the RDFNode for the type and apply it.
|
2018-12-02 21:55:29 +09:00
|
|
|
func (t *typeLD) Apply(key string, value interface{}, ctx *ParsingContext) (bool, error) {
|
2018-12-03 07:48:54 +09:00
|
|
|
vs, ok := value.(string)
|
|
|
|
if !ok {
|
|
|
|
return true, fmt.Errorf("@type is not string")
|
|
|
|
}
|
|
|
|
n, e := t.r.getNode(vs)
|
|
|
|
if e != nil {
|
|
|
|
return true, e
|
|
|
|
}
|
|
|
|
return n.Apply(vs, nil, ctx)
|
2018-12-02 21:55:29 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
var _ RDFNode = &ContainerLD{}
|
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// ContainerLD is an RDFNode that delegates to an RDFNode but only at this
|
|
|
|
// next level.
|
2018-12-02 21:55:29 +09:00
|
|
|
type ContainerLD struct {
|
|
|
|
ContainsNode RDFNode
|
|
|
|
}
|
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// Enter sets OnlyApplyThisNodeNextLevel on the ParsingContext.
|
|
|
|
//
|
|
|
|
// Returns an error if this is the second time Enter is called in a row.
|
2018-12-02 21:55:29 +09:00
|
|
|
func (c *ContainerLD) Enter(key string, ctx *ParsingContext) (bool, error) {
|
2018-12-03 04:04:56 +09:00
|
|
|
if ctx.OnlyApplyThisNodeNextLevel != nil {
|
|
|
|
return true, fmt.Errorf("@container parsing context exit already has non-nil node")
|
|
|
|
}
|
|
|
|
ctx.SetOnlyApplyThisNodeNextLevel(c.ContainsNode)
|
2018-12-02 21:55:29 +09:00
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// Exit clears OnlyApplyThisNodeNextLevel on the ParsingContext.
|
|
|
|
//
|
|
|
|
// Returns an error if this is the second time Exit is called in a row.
|
2018-12-02 21:55:29 +09:00
|
|
|
func (c *ContainerLD) Exit(key string, ctx *ParsingContext) (bool, error) {
|
2018-12-03 04:04:56 +09:00
|
|
|
if ctx.OnlyApplyThisNodeNextLevel == nil {
|
|
|
|
return true, fmt.Errorf("@container parsing context exit already has nil node")
|
|
|
|
}
|
|
|
|
ctx.ResetOnlyAppliedThisNodeNextLevel()
|
2018-12-02 21:55:29 +09:00
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// Apply does nothing.
|
2018-12-02 21:55:29 +09:00
|
|
|
func (c *ContainerLD) Apply(key string, value interface{}, ctx *ParsingContext) (bool, error) {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ RDFNode = &IndexLD{}
|
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// IndexLD does nothing.
|
|
|
|
//
|
|
|
|
// It could try to manage human-defined indices, but the machine doesn't care.
|
2018-12-02 21:55:29 +09:00
|
|
|
type IndexLD struct{}
|
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// Enter does nothing.
|
2018-12-02 21:55:29 +09:00
|
|
|
func (i *IndexLD) Enter(key string, ctx *ParsingContext) (bool, error) {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// Exit does nothing.
|
2018-12-02 21:55:29 +09:00
|
|
|
func (i *IndexLD) Exit(key string, ctx *ParsingContext) (bool, error) {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// Apply does nothing.
|
2018-12-02 21:55:29 +09:00
|
|
|
func (i *IndexLD) Apply(key string, value interface{}, ctx *ParsingContext) (bool, error) {
|
|
|
|
return true, nil
|
|
|
|
}
|
2018-12-09 01:50:26 +09:00
|
|
|
|
|
|
|
var _ RDFNode = &withoutProperty{}
|
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// withoutProperty is a hacky-as-hell way to manage ActivityStream's concept of
|
|
|
|
// "WithoutProperty". It isn't a defined RDF relationship, so this is
|
|
|
|
// non-standard but required of the ActivityStreams Core or Extended Types spec.
|
2018-12-09 01:50:26 +09:00
|
|
|
type withoutProperty struct{}
|
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// Enter pushes a VocabularyReference. It is expected further nodes will
|
|
|
|
// populate it with information before dxiting this node.
|
2018-12-09 01:50:26 +09:00
|
|
|
func (w *withoutProperty) Enter(key string, ctx *ParsingContext) (bool, error) {
|
|
|
|
ctx.Push()
|
|
|
|
ctx.Current = &VocabularyReference{}
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// Exit pops a VocabularyReferences and sets DoesNotApplyTo on the parent
|
|
|
|
// VocabularyProperty on the stack.
|
2018-12-09 01:50:26 +09:00
|
|
|
func (w *withoutProperty) Exit(key string, ctx *ParsingContext) (bool, error) {
|
|
|
|
i := ctx.Current
|
|
|
|
ctx.Pop()
|
|
|
|
vr, ok := i.(*VocabularyReference)
|
|
|
|
if !ok {
|
|
|
|
return true, fmt.Errorf("hacky withoutProperty exit did not get *rdf.VocabularyReference")
|
|
|
|
}
|
|
|
|
vp, ok := ctx.Current.(*VocabularyProperty)
|
|
|
|
if !ok {
|
|
|
|
return true, fmt.Errorf("hacky withoutProperty exit Current is not *rdf.VocabularyProperty")
|
|
|
|
}
|
|
|
|
vp.DoesNotApplyTo = append(vp.DoesNotApplyTo, *vr)
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
2019-01-13 04:53:00 +09:00
|
|
|
// Apply returns an error.
|
2018-12-09 01:50:26 +09:00
|
|
|
func (w *withoutProperty) Apply(key string, value interface{}, ctx *ParsingContext) (bool, error) {
|
|
|
|
return true, fmt.Errorf("hacky withoutProperty cannot be applied")
|
|
|
|
}
|