Skip to content

Instantly share code, notes, and snippets.

@ngerakines
Last active March 19, 2020 10:40
Show Gist options
  • Save ngerakines/1a01762032e838e53c462f9db6d47d03 to your computer and use it in GitHub Desktop.
Save ngerakines/1a01762032e838e53c462f9db6d47d03 to your computer and use it in GitHub Desktop.
package main
import (
"bufio"
"encoding/json"
"fmt"
"net/http"
"os"
"github.com/kr/pretty"
"github.com/piprate/json-gold/ld"
)
/*
Input OK
{"@context":["https://www.w3.org/ns/activitystreams",{"ostatus":"http://ostatus.org#","atomUri":"ostatus:atomUri","inReplyToAtomUri":"ostatus:inReplyToAtomUri","conversation":"ostatus:conversation","sensitive":"as:sensitive","toot":"http://joinmastodon.org/ns#","votersCount":"toot:votersCount"}],"id":"https://mastodon.social/users/ngerakines/statuses/103849134994060072/activity","type":"Create","actor":"https://mastodon.social/users/ngerakines","published":"2020-03-19T10:00:45Z","to":["https://www.w3.org/ns/activitystreams#Public"],"cc":["https://mastodon.social/users/ngerakines/followers"],"object":{"id":"https://mastodon.social/users/ngerakines/statuses/103849134994060072","type":"Note","summary":null,"inReplyTo":null,"published":"2020-03-19T10:00:45Z","url":"https://mastodon.social/@ngerakines/103849134994060072","attributedTo":"https://mastodon.social/users/ngerakines","to":["https://www.w3.org/ns/activitystreams#Public"],"cc":["https://mastodon.social/users/ngerakines/followers"],"sensitive":false,"atomUri":"https://mastodon.social/users/ngerakines/statuses/103849134994060072","inReplyToAtomUri":null,"conversation":"tag:mastodon.social,2020-03-19:objectId=160727436:objectType=Conversation","content":"\u003cp\u003eld+json is kind of weird\u003c/p\u003e","contentMap":{"lb":"\u003cp\u003eld+json is kind of weird\u003c/p\u003e"},"attachment":[],"tag":[],"replies":{"id":"https://mastodon.social/users/ngerakines/statuses/103849134994060072/replies","type":"Collection","first":{"type":"CollectionPage","next":"https://mastodon.social/users/ngerakines/statuses/103849134994060072/replies?only_other_accounts=true\u0026page=true","partOf":"https://mastodon.social/users/ngerakines/statuses/103849134994060072/replies","items":[]}}},"signature":{"type":"RsaSignature2017","creator":"https://mastodon.social/users/ngerakines#main-key","created":"2020-03-19T10:00:45Z","signatureValue":"OA35CkmjxaUGh/aO6HYbqQ9T2Rkj6Agt0vp+Qif7/PUBuMpRed/eXg4O+NXkIEvv6s4DHhwsQbUuQf792fj4u1KlUTQVGVrMzx1uBvf06ye/Gz74jpn9I2h41a3B3MZP02tgBXWrB4PaNBEFlg58y8vk3yK/FTRZ4hlcy5FFFZKJNzfP8F2UqQb61aqwkavEwme2Tn8KpDWR/HoR8Qh2WsymESObX/4GxavuZD9hxszaqhOterpZuDOT0FbMS32NsLXUr7Vhlr3DYkau+54icUbl9qlD1JCl/0VN7fQ6Xcu8LX4nQF74BwJtQrB7h3bIfCFVP7uRBhLmUkAahLkotQ=="}}
Input not OK
{"cc": ["https://aqueous-sea-10253.herokuapp.com/users/nick/followers"], "id": "https://aqueous-sea-10253.herokuapp.com/activities/8d9d8241-db6a-4979-9f57-f34e3a42f391", "to": ["https://www.w3.org/ns/activitystreams#Public"], "type": "Create", "actor": "https://aqueous-sea-10253.herokuapp.com/users/nick", "object": {"cc": ["https://aqueous-sea-10253.herokuapp.com/users/nick/followers"], "id": "https://aqueous-sea-10253.herokuapp.com/objects/1c8c7965-e333-476e-877e-118d67cc267a", "to": ["https://www.w3.org/ns/activitystreams#Public"], "tag": [{"id": "https://aqueous-sea-10253.herokuapp.com/emoji/Firefox.gif", "icon": {"url": "https://aqueous-sea-10253.herokuapp.com/emoji/Firefox.gif", "type": "Image"}, "name": ":firefox:", "type": "Emoji", "updated": "1970-01-01T00:00:00Z"}], "type": "Note", "actor": "https://aqueous-sea-10253.herokuapp.com/users/nick", "content": "<p>:firefox: How does emoji work? 🔢</p>\n", "context": "https://aqueous-sea-10253.herokuapp.com/contexts/11969b9d-a81b-4cc0-bf23-ab82731efaab", "summary": "", "published": "2020-03-14T20:22:09.614896Z", "sensitive": false, "attachment": [], "attributedTo": "https://aqueous-sea-10253.herokuapp.com/users/nick", "conversation": "https://aqueous-sea-10253.herokuapp.com/contexts/11969b9d-a81b-4cc0-bf23-ab82731efaab"}, "context": "https://aqueous-sea-10253.herokuapp.com/contexts/11969b9d-a81b-4cc0-bf23-ab82731efaab", "@context": ["https://www.w3.org/ns/activitystreams", "https://aqueous-sea-10253.herokuapp.com/schemas/litepub-0.1.jsonld", {"@language": "und"}], "published": "2020-03-14T20:22:09.608456Z", "context_id": 4441, "directMessage": false}
*/
func main() {
reader := bufio.NewReader(os.Stdin)
decoder := json.NewDecoder(reader)
var doc map[string]interface{}
if err := decoder.Decode(&doc); err != nil {
panic(err)
}
fmt.Println("=== PRETTY ===")
pretty.Println(doc)
documentContext := map[string]interface{}{
"@context": "https://www.w3.org/ns/activitystreams",
}
fmt.Println("=== JSON LD ===")
result, err := compactJSONLD(doc, documentContext)
if err != nil {
panic(err)
}
pretty.Println(result)
}
func compactJSONLD(document, context map[string]interface{}) (map[string]interface{}, error) {
proc := ld.NewJsonLdProcessor()
options := ld.NewJsonLdOptions("https://www.w3.org/ns/activitystreams")
// options.ProcessingMode = ld.JsonLd_1_1
options.DocumentLoader = DebugDocLoader{ld.NewDefaultDocumentLoader(http.DefaultClient)}
return proc.Compact(document, context, options)
}
type DebugDocLoader struct {
DocumentLoader ld.DocumentLoader
}
func (ddl DebugDocLoader) LoadDocument(u string) (*ld.RemoteDocument, error) {
fmt.Println("=== LoadDocument ===")
pretty.Println(u)
r, err := ddl.DocumentLoader.LoadDocument(u)
pretty.Println(r)
pretty.Println(err)
return r, err
}
go run bug.go
{"cc": ["https://aqueous-sea-10253.herokuapp.com/users/nick/followers"], "id": "https://aqueous-sea-10253.herokuapp.com/activities/8d9d8241-db6a-4979-9f57-f34e3a42f391", "to": ["https://www.w3.org/ns/activitystreams#Public"], "type": "Create", "actor": "https://aqueous-sea-10253.herokuapp.com/users/nick", "object": {"cc": ["https://aqueous-sea-10253.herokuapp.com/users/nick/followers"], "id": "https://aqueous-sea-10253.herokuapp.com/objects/1c8c7965-e333-476e-877e-118d67cc267a", "to": ["https://www.w3.org/ns/activitystreams#Public"], "tag": [{"id": "https://aqueous-sea-10253.herokuapp.com/emoji/Firefox.gif", "icon": {"url": "https://aqueous-sea-10253.herokuapp.com/emoji/Firefox.gif", "type": "Image"}, "name": ":firefox:", "type": "Emoji", "updated": "1970-01-01T00:00:00Z"}], "type": "Note", "actor": "https://aqueous-sea-10253.herokuapp.com/users/nick", "content": "<p>:firefox: How does emoji work? 🔢</p>\n", "context": "https://aqueous-sea-10253.herokuapp.com/contexts/11969b9d-a81b-4cc0-bf23-ab82731efaab", "summary": "", "published": "2020-03-14T20:22:09.614896Z", "sensitive": false, "attachment": [], "attributedTo": "https://aqueous-sea-10253.herokuapp.com/users/nick", "conversation": "https://aqueous-sea-10253.herokuapp.com/contexts/11969b9d-a81b-4cc0-bf23-ab82731efaab"}, "context": "https://aqueous-sea-10253.herokuapp.com/contexts/11969b9d-a81b-4cc0-bf23-ab82731efaab", "@context": ["https://www.w3.org/ns/activitystreams", "https://aqueous-sea-10253.herokuapp.com/schemas/litepub-0.1.jsonld", {"@language": "und"}], "published": "2020-03-14T20:22:09.608456Z", "context_id": 4441, "directMessage": false}
=== PRETTY ===
map[string]interface {}{
"id": "https://aqueous-sea-10253.herokuapp.com/activities/8d9d8241-db6a-4979-9f57-f34e3a42f391",
"to": []interface {}{
"https://www.w3.org/ns/activitystreams#Public",
},
"type": "Create",
"context": "https://aqueous-sea-10253.herokuapp.com/contexts/11969b9d-a81b-4cc0-bf23-ab82731efaab",
"@context": []interface {}{
"https://www.w3.org/ns/activitystreams",
"https://aqueous-sea-10253.herokuapp.com/schemas/litepub-0.1.jsonld",
map[string]interface {}{
"@language": "und",
},
},
"directMessage": bool(false),
"cc": []interface {}{
"https://aqueous-sea-10253.herokuapp.com/users/nick/followers",
},
"object": map[string]interface {}{
"sensitive": bool(false),
"conversation": "https://aqueous-sea-10253.herokuapp.com/contexts/11969b9d-a81b-4cc0-bf23-ab82731efaab",
"tag": []interface {}{
map[string]interface {}{
"id": "https://aqueous-sea-10253.herokuapp.com/emoji/Firefox.gif",
"icon": map[string]interface {}{
"type": "Image",
"url": "https://aqueous-sea-10253.herokuapp.com/emoji/Firefox.gif",
},
"name": ":firefox:",
"type": "Emoji",
"updated": "1970-01-01T00:00:00Z",
},
},
"type": "Note",
"attributedTo": "https://aqueous-sea-10253.herokuapp.com/users/nick",
"summary": "",
"published": "2020-03-14T20:22:09.614896Z",
"context": "https://aqueous-sea-10253.herokuapp.com/contexts/11969b9d-a81b-4cc0-bf23-ab82731efaab",
"attachment": []interface {}{
},
"cc": []interface {}{
"https://aqueous-sea-10253.herokuapp.com/users/nick/followers",
},
"id": "https://aqueous-sea-10253.herokuapp.com/objects/1c8c7965-e333-476e-877e-118d67cc267a",
"content": "<p>:firefox: How does emoji work? 🔢</p>\n",
"to": []interface {}{
"https://www.w3.org/ns/activitystreams#Public",
},
"actor": "https://aqueous-sea-10253.herokuapp.com/users/nick",
},
"published": "2020-03-14T20:22:09.608456Z",
"context_id": float64(4441),
"actor": "https://aqueous-sea-10253.herokuapp.com/users/nick",
}
=== JSON LD ===
=== LoadDocument ===
https://www.w3.org/ns/activitystreams
&ld.RemoteDocument{
DocumentURL: "https://www.w3.org/ns/activitystreams",
Document: map[string]interface {}{
"@context": map[string]interface {}{
"Like": "as:Like",
"OrderedCollectionPage": "as:OrderedCollectionPage",
"location": map[string]interface {}{
"@id": "as:location",
"@type": "@id",
},
"rel": "as:rel",
"uploadMedia": map[string]interface {}{
"@id": "as:uploadMedia",
"@type": "@id",
},
"oauthTokenEndpoint": map[string]interface {}{
"@id": "as:oauthTokenEndpoint",
"@type": "@id",
},
"altitude": map[string]interface {}{
"@id": "as:altitude",
"@type": "xsd:float",
},
"name": "as:name",
"Group": "as:Group",
"Note": "as:Note",
"Page": "as:Page",
"IsContact": "as:IsContact",
"origin": map[string]interface {}{
"@id": "as:origin",
"@type": "@id",
},
"Mention": "as:Mention",
"radius": map[string]interface {}{
"@type": "xsd:float",
"@id": "as:radius",
},
"followers": map[string]interface {}{
"@id": "as:followers",
"@type": "@id",
},
"streams": map[string]interface {}{
"@id": "as:streams",
"@type": "@id",
},
"Public": map[string]interface {}{
"@id": "as:Public",
"@type": "@id",
},
"as": "https://www.w3.org/ns/activitystreams#",
"next": map[string]interface {}{
"@id": "as:next",
"@type": "@id",
},
"following": map[string]interface {}{
"@id": "as:following",
"@type": "@id",
},
"attachment": map[string]interface {}{
"@id": "as:attachment",
"@type": "@id",
},
"current": map[string]interface {}{
"@id": "as:current",
"@type": "@id",
},
"mediaType": "as:mediaType",
"liked": map[string]interface {}{
"@id": "as:liked",
"@type": "@id",
},
"Add": "as:Add",
"IsFollowedBy": "as:IsFollowedBy",
"relationship": map[string]interface {}{
"@id": "as:relationship",
"@type": "@id",
},
"last": map[string]interface {}{
"@id": "as:last",
"@type": "@id",
},
"result": map[string]interface {}{
"@id": "as:result",
"@type": "@id",
},
"oneOf": map[string]interface {}{
"@id": "as:oneOf",
"@type": "@id",
},
"startTime": map[string]interface {}{
"@id": "as:startTime",
"@type": "xsd:dateTime",
},
"Place": "as:Place",
"Move": "as:Move",
"partOf": map[string]interface {}{
"@id": "as:partOf",
"@type": "@id",
},
"Flag": "as:Flag",
"attributedTo": map[string]interface {}{
"@id": "as:attributedTo",
"@type": "@id",
},
"closed": map[string]interface {}{
"@id": "as:closed",
"@type": "xsd:dateTime",
},
"summary": "as:summary",
"Activity": "as:Activity",
"Undo": "as:Undo",
"audience": map[string]interface {}{
"@id": "as:audience",
"@type": "@id",
},
"inbox": map[string]interface {}{
"@id": "ldp:inbox",
"@type": "@id",
},
"to": map[string]interface {}{
"@id": "as:to",
"@type": "@id",
},
"source": "as:source",
"Document": "as:Document",
"Ignore": "as:Ignore",
"Leave": "as:Leave",
"Reject": "as:Reject",
"bcc": map[string]interface {}{
"@id": "as:bcc",
"@type": "@id",
},
"Arrive": "as:Arrive",
"Collection": "as:Collection",
"Person": "as:Person",
"units": "as:units",
"deleted": map[string]interface {}{
"@type": "xsd:dateTime",
"@id": "as:deleted",
},
"CollectionPage": "as:CollectionPage",
"nameMap": map[string]interface {}{
"@id": "as:name",
"@container": "@language",
},
"totalItems": map[string]interface {}{
"@id": "as:totalItems",
"@type": "xsd:nonNegativeInteger",
},
"startIndex": map[string]interface {}{
"@id": "as:startIndex",
"@type": "xsd:nonNegativeInteger",
},
"id": "@id",
"Announce": "as:Announce",
"Service": "as:Service",
"TentativeAccept": "as:TentativeAccept",
"target": map[string]interface {}{
"@id": "as:target",
"@type": "@id",
},
"preview": map[string]interface {}{
"@id": "as:preview",
"@type": "@id",
},
"summaryMap": map[string]interface {}{
"@id": "as:summary",
"@container": "@language",
},
"describes": map[string]interface {}{
"@id": "as:describes",
"@type": "@id",
},
"Link": "as:Link",
"Organization": "as:Organization",
"Remove": "as:Remove",
"Update": "as:Update",
"subject": map[string]interface {}{
"@id": "as:subject",
"@type": "@id",
},
"oauthAuthorizationEndpoint": map[string]interface {}{
"@type": "@id",
"@id": "as:oauthAuthorizationEndpoint",
},
"xsd": "http://www.w3.org/2001/XMLSchema#",
"Video": "as:Video",
"items": map[string]interface {}{
"@type": "@id",
"@id": "as:items",
},
"Event": "as:Event",
"Listen": "as:Listen",
"contentMap": map[string]interface {}{
"@id": "as:content",
"@container": "@language",
},
"width": map[string]interface {}{
"@id": "as:width",
"@type": "xsd:nonNegativeInteger",
},
"Block": "as:Block",
"Travel": "as:Travel",
"height": map[string]interface {}{
"@id": "as:height",
"@type": "xsd:nonNegativeInteger",
},
"longitude": map[string]interface {}{
"@id": "as:longitude",
"@type": "xsd:float",
},
"ldp": "http://www.w3.org/ns/ldp#",
"Audio": "as:Audio",
"Tombstone": "as:Tombstone",
"context": map[string]interface {}{
"@id": "as:context",
"@type": "@id",
},
"orderedItems": map[string]interface {}{
"@id": "as:items",
"@type": "@id",
"@container": "@list",
},
"IntransitiveActivity": "as:IntransitiveActivity",
"Relationship": "as:Relationship",
"Read": "as:Read",
"first": map[string]interface {}{
"@id": "as:first",
"@type": "@id",
},
"Application": "as:Application",
"Image": "as:Image",
"object": map[string]interface {}{
"@id": "as:object",
"@type": "@id",
},
"outbox": map[string]interface {}{
"@id": "as:outbox",
"@type": "@id",
},
"endpoints": map[string]interface {}{
"@type": "@id",
"@id": "as:endpoints",
},
"View": "as:View",
"bto": map[string]interface {}{
"@id": "as:bto",
"@type": "@id",
},
"prev": map[string]interface {}{
"@id": "as:prev",
"@type": "@id",
},
"likes": map[string]interface {}{
"@type": "@id",
"@id": "as:likes",
},
"Follow": "as:Follow",
"Object": "as:Object",
"image": map[string]interface {}{
"@id": "as:image",
"@type": "@id",
},
"anyOf": map[string]interface {}{
"@id": "as:anyOf",
"@type": "@id",
},
"preferredUsername": "as:preferredUsername",
"@vocab": "_:",
"generator": map[string]interface {}{
"@id": "as:generator",
"@type": "@id",
},
"icon": map[string]interface {}{
"@id": "as:icon",
"@type": "@id",
},
"hreflang": "as:hreflang",
"shares": map[string]interface {}{
"@id": "as:shares",
"@type": "@id",
},
"Dislike": "as:Dislike",
"Invite": "as:Invite",
"cc": map[string]interface {}{
"@id": "as:cc",
"@type": "@id",
},
"content": "as:content",
"formerType": map[string]interface {}{
"@id": "as:formerType",
"@type": "@id",
},
"IsFollowing": "as:IsFollowing",
"published": map[string]interface {}{
"@id": "as:published",
"@type": "xsd:dateTime",
},
"provideClientKey": map[string]interface {}{
"@id": "as:provideClientKey",
"@type": "@id",
},
"signClientKey": map[string]interface {}{
"@id": "as:signClientKey",
"@type": "@id",
},
"OrderedCollection": "as:OrderedCollection",
"inReplyTo": map[string]interface {}{
"@id": "as:inReplyTo",
"@type": "@id",
},
"tag": map[string]interface {}{
"@id": "as:tag",
"@type": "@id",
},
"url": map[string]interface {}{
"@id": "as:url",
"@type": "@id",
},
"updated": map[string]interface {}{
"@id": "as:updated",
"@type": "xsd:dateTime",
},
"Offer": "as:Offer",
"Profile": "as:Profile",
"IsMember": "as:IsMember",
"instrument": map[string]interface {}{
"@id": "as:instrument",
"@type": "@id",
},
"endTime": map[string]interface {}{
"@type": "xsd:dateTime",
"@id": "as:endTime",
},
"Accept": "as:Accept",
"Delete": "as:Delete",
"duration": map[string]interface {}{
"@id": "as:duration",
"@type": "xsd:duration",
},
"proxyUrl": map[string]interface {}{
"@id": "as:proxyUrl",
"@type": "@id",
},
"sharedInbox": map[string]interface {}{
"@id": "as:sharedInbox",
"@type": "@id",
},
"TentativeReject": "as:TentativeReject",
"actor": map[string]interface {}{
"@id": "as:actor",
"@type": "@id",
},
"latitude": map[string]interface {}{
"@id": "as:latitude",
"@type": "xsd:float",
},
"type": "@type",
"Article": "as:Article",
"Create": "as:Create",
"Join": "as:Join",
"Question": "as:Question",
"accuracy": map[string]interface {}{
"@id": "as:accuracy",
"@type": "xsd:float",
},
"replies": map[string]interface {}{
"@id": "as:replies",
"@type": "@id",
},
"href": map[string]interface {}{
"@id": "as:href",
"@type": "@id",
},
},
},
ContextURL: "",
}
nil
=== LoadDocument ===
https://aqueous-sea-10253.herokuapp.com/schemas/litepub-0.1.jsonld
&ld.RemoteDocument{
DocumentURL: "https://aqueous-sea-10253.herokuapp.com/schemas/litepub-0.1.jsonld",
Document: map[string]interface {}{
"@context": []interface {}{
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
map[string]interface {}{
"Hashtag": "as:Hashtag",
"atomUri": "ostatus:atomUri",
"schema": "http://schema.org#",
"value": "schema:value",
"listMessage": map[string]interface {}{
"@id": "litepub:listMessage",
"@type": "@id",
},
"oauthRegistrationEndpoint": map[string]interface {}{
"@id": "litepub:oauthRegistrationEndpoint",
"@type": "@id",
},
"EmojiReaction": "litepub:EmojiReaction",
"alsoKnownAs": map[string]interface {}{
"@type": "@id",
"@id": "as:alsoKnownAs",
},
"PropertyValue": "schema:PropertyValue",
"conversation": map[string]interface {}{
"@id": "ostatus:conversation",
"@type": "@id",
},
"toot": "http://joinmastodon.org/ns#",
"sensitive": "as:sensitive",
"Emoji": "toot:Emoji",
"discoverable": "toot:discoverable",
"directMessage": "litepub:directMessage",
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
"ostatus": "http://ostatus.org#",
"litepub": "http://litepub.social/ns#",
"invisible": "litepub:invisible",
},
},
},
ContextURL: "",
}
nil
panic: recursive context inclusion: https://www.w3.org/ns/activitystreams
goroutine 1 [running]:
main.main()
/home/ngerakines/development/github.com/ngerakines/tavern/tmp/bug.go:40 +0x413
exit status 2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment