diff --git a/activity-servist.asd b/activity-servist.asd index a916c8f..6cf5587 100644 --- a/activity-servist.asd +++ b/activity-servist.asd @@ -9,31 +9,41 @@ :homepage "https://hak.xwx.moe/jadedctrl/activity-servist" :in-order-to ((test-op (test-op "activitypub/tests"))) - :depends-on ("activity-servist/signatures" - "alexandria" "clack" "dexador" - "local-time" "purl" "str" "webtentacle" "yason") + :depends-on (:activity-servist/signatures + :alexandria :clack :dexador + :local-time :purl :str :webtentacle :yason) :components ((:file "src/activity-servist"))) -(asdf:defsystem "activity-servist/activity-vocabulary" +(asdf:defsystem "activity-servist/vocab" + :version "0.0" + :license "AGPLv3" + :description "A-S subpackage providing a standard vocabulary for ActivityPub programs." + :author "Jaidyn Ann " + :homepage "https://hak.xwx.moe/jadedctrl/activity-servist" + + :depends-on (:activity-servist/vocab/activity :activity-servist/vocab/litepub)) + + +(asdf:defsystem "activity-servist/vocab/activity" :version "0.0" :license "AGPLv3" :description "A-S subpackage containing ActivityVocabulary class-definitions." :author "Jaidyn Ann " :homepage "https://hak.xwx.moe/jadedctrl/activity-servist" - :depends-on ("activity-servist/json-ld") + :depends-on (:activity-servist/json-ld) :components ((:file "src/activity-vocabulary"))) -(asdf:defsystem "activity-servist/litepub" +(asdf:defsystem "activity-servist/vocab/litepub" :version "0.0" :license "AGPLv3" :description "A-S subpackage providing an expanded vocabulary." :author "Jaidyn Ann " :homepage "https://hak.xwx.moe/jadedctrl/activity-servist" - :depends-on ("activity-servist/activity-vocabulary") + :depends-on (:activity-servist/vocab/activity) :components ((:file "src/litepub"))) @@ -44,7 +54,7 @@ :author "Jaidyn Ann " :homepage "https://hak.xwx.moe/jadedctrl/activity-servist" - :depends-on ("alexandria" "dexador" "str" "yason") + :depends-on (:alexandria :dexador :str :yason) :components ((:file "src/json-ld"))) @@ -55,21 +65,22 @@ :author "Jaidyn Ann " :homepage "https://hak.xwx.moe/jadedctrl/activity-servist" - :depends-on ("cl-base64" "flexi-streams" "inferior-shell" "ironclad" "str") + :depends-on (:cl-base64 :flexi-streams :inferior-shell :ironclad :str) :components ((:file "src/signatures"))) ;;; Tests ;;; ————————————————————————————————————— -(asdf:defsystem "activity-servist/tests/activity-vocabulary" +(asdf:defsystem "activity-servist/tests/vocab/activity" :version "0.0" :license "AGPLv3" :author "Jaidyn Ann " - :description "Tests the activity-servist/activity-vocabulary package, and indirectly /json-ld." + :description "Tests the activity-servist/vocab/activity package, and indirectly /json-ld." - :depends-on (:activity-servist/activity-vocabulary :alexandria :lisp-unit2) - :components ((:file "t/activity-vocabulary"))) + :depends-on (:activity-servist/vocab/activity + :alexandria :lisp-unit2) + :components ((:file "t/vocab/activity"))) (asdf:defsystem "activity-servist/tests/signatures" @@ -78,7 +89,8 @@ :author "Jaidyn Ann " :description "Tests for the the activity-servist/signatures package." - :depends-on (:activity-servist/signatures :lisp-unit2) + :depends-on (:activity-servist/signatures + :lisp-unit2) :components ((:file "t/signatures"))) @@ -88,7 +100,7 @@ :author "Jaidyn Ann " :description "Tests for all activity-servist subpacakges." - :depends-on (:activity-servist/tests/activity-vocabulary + :depends-on (:activity-servist/tests/vocab/activity :activity-servist/tests/signatures :alexandria :lisp-unit2) :components ((:file "t/t"))) @@ -100,6 +112,6 @@ `(defmethod asdf:perform ((o asdf:test-op) (c (eql (asdf:find-system ',package)))) (eval (read-from-string (format nil "(~A:run-with-summary)" ',package))))) -(define-asdf-testing activity-servist/tests/activity-vocabulary) +(define-asdf-testing activity-servist/tests/vocab/activity) (define-asdf-testing activity-servist/tests/signatures) (define-asdf-testing activity-servist/tests) diff --git a/src/activity-vocabulary.lisp b/src/activity-vocabulary.lisp index fef201f..5aa682c 100644 --- a/src/activity-vocabulary.lisp +++ b/src/activity-vocabulary.lisp @@ -1,4 +1,4 @@ -;;;; activity-vocabulary: Base classes for ActivityStreams. +;;;; activity-vocabulary: Base vocabulary classes for ActivityStreams. ;; Copyright © 2024 Jaidyn Ann ;; @@ -15,9 +15,9 @@ ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . -(defpackage #:activity-servist/activity-vocabulary +(defpackage #:activity-servist/vocab/activity (:use #:cl) - (:nicknames "AS/AV" "ACTIVITY-VOCABULARY") + (:nicknames "AS/V/A" "ACTIVITY-VOCABULARY") (:shadow #:block #:delete #:ignore #:listen #:read #:remove) ;; One should never USE this package, since some class-names shadow ;; core Common Lisp symbols! Beware! :P @@ -53,7 +53,7 @@ :relationship-object :relationship-relationship :relationship-subject :tombstone-former-type :tombstone-deleted)) -(in-package #:activity-servist/activity-vocabulary) +(in-package #:activity-servist/vocab/activity) (defmacro define-json-empty-types (superclass context &rest direct-children) "For each list of DIRECT-CHILDREN, a “hollow” JSON subtype and CLOS subclass @@ -176,10 +176,10 @@ The notion of “context” used is intentionally vague. The intended function i ;; looking at Link’s properties), but it’s implied by the Mention example. (json-ld:define-json-type (link "Link") () "https://www.w3.org/ns/activitystreams" - ((@id + ((json-ld:@id "id" :documentation "Provides the globally unique identifier for a Link.") - (@type + (json-ld:@type "type" :documentation "Identifies the Link type. Multiple values may be specified.") (height diff --git a/src/json-ld.lisp b/src/json-ld.lisp index d2b0262..16e1c00 100644 --- a/src/json-ld.lisp +++ b/src/json-ld.lisp @@ -44,9 +44,19 @@ For example: “https://www.w3.org/ns/activitystreams#Object” The default value “*” refers to the base JSON-LD-OBJECT type.") -(defvar *http-cache* (make-hash-table :test #'equal)) -(defvar *json-types* (make-hash-table :test #'equal)) -(defvar *class-defs* (make-hash-table)) +(defvar *json-types* (make-hash-table :test #'equal) + "Stores descriptions of each JSON-type, mapping type-IRI to class-name and property-name to slot-name. +Used during encoding an object to JSON, for finding type/property-names from class/slot-names. +Keys are the type-IRI (e.g., (“https://www.w3.org/ns/activitystreams#Accept”), and values are an irregular association list, of the form: + ((CLASS-NAME-SYMBOL . TYPE-NAME) (PROPERTY-IRI SLOT-NAME-SYMBOL . PROPERTY-NAME) ⋯)") + +(defvar *class-defs* (make-hash-table) + "Stores the slot definitions of classes, stored directly from DEFINE-JSON-TYPE. +Used for the :UPDATE feature of DEFINE-JSON-TYPE, so you can add a slot to a pre-existing class without having to redefine the old slots.") + +(defvar *http-cache* (make-hash-table :test #'equal) + "Caches context-texts fetched over HTTP. +Maps URLs to text-content, so we don’t have to download the same context again and again.") diff --git a/src/litepub.lisp b/src/litepub.lisp index c0de14e..b1e8be4 100644 --- a/src/litepub.lisp +++ b/src/litepub.lisp @@ -15,11 +15,11 @@ ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . -(defpackage #:activity-servist/litepub +(defpackage #:activity-servist/vocab/litepub (:use #:cl) - (:nicknames "AS/LP" "LITEPUB")) + (:nicknames "AS/V/LP" "LITEPUB")) -(in-package #:activity-servist/litepub) +(in-package #:activity-servist/vocab/litepub) ;;; Globals @@ -38,7 +38,7 @@ Defaults to a copy at jam.xwx.moe — because why not? ¯\_(ツ)_/¯") () (:documentation "The base class used for Litepub objects.")) -(json-ld:define-json-type (as/av:object "Object") (as/jld::json-ld-object litepub-object) *litepub-uri* +(json-ld:define-json-type (as/v/a:object "Object") (as/jld::json-ld-object litepub-object) *litepub-uri* ((atom-uri "atomUri" :documentation "A string containing a URI to an Atom-feed alternative representation of an object. @@ -60,7 +60,7 @@ Seemingly may be set in the Activity modifying the Note, or the Note itself.") (:update 't)) -(json-ld:define-json-type (as/av:activity "Activity") (as/av:object) *litepub-uri* +(json-ld:define-json-type (as/v/a:activity "Activity") (as/v/a:object) *litepub-uri* (;; https://blog.dereferenced.org/leveraging-json-ld-compound-typing-for-behavioural-hinting-in-activitypub (invisible "invisible" @@ -86,7 +86,7 @@ Potentially deprecated/very uncommon.") ;;; Extended Activity types ;;; ———————————————————————————————————————— -(json-ld:define-json-type (as/av:update "Update") (as/av:activity) *litepub-uri* +(json-ld:define-json-type (as/v/a:update "Update") (as/v/a:activity) *litepub-uri* (;; https://ostatus.github.io/spec/OStatus%201.0%20Draft%202.html#rfc.section.6 (conversation "conversation" @@ -98,7 +98,7 @@ The target and origin typically have no defined meaning.") ;; https://codeberg.org/fediverse/fep/src/branch/main/fep/c0e0/fep-c0e0.md -(json-ld:define-json-type (emoji-react "EmojiReact") (as/av:like) *litepub-uri* +(json-ld:define-json-type (emoji-react "EmojiReact") (as/v/a:like) *litepub-uri* () (:documentation "This activity is similar to Like activity. In addition to standard properties of Like activity, EmojiReact activity MUST have a content property. Reaction content MUST be either a single unicode grapheme, or a shortcode of a custom emoji. If custom emoji is used, EmojiReact activity MUST have a tag property containing a single Emoji object.")) @@ -106,7 +106,7 @@ The target and origin typically have no defined meaning.") ;;; Extended Actor types ;;; ———————————————————————————————————————— -(json-ld:define-json-type (as/av:person "Person") (as/av:object) *litepub-uri* +(json-ld:define-json-type (as/v/a:person "Person") (as/v/a:object) *litepub-uri* (;; https://docs.joinmastodon.org/spec/activitypub/#discoverable (public-key "publicKey" @@ -135,12 +135,12 @@ One known capabilitity-name is Pleroma’s “acceptsChatMessages”.")) ;;; Extended Object types ;;; ———————————————————————————————————————— ;; https://docs.joinmastodon.org/spec/activitypub/#Emoji -(json-ld:define-json-type (emoji "Emoji") (as/av:object) *litepub-uri* +(json-ld:define-json-type (emoji "Emoji") (as/v/a:object) *litepub-uri* () (:documentation "Represents a custom-emoji, with a shortcode (NAME), ID, and ICON (containing MEDIA-TYPE and URL).")) -(json-ld:define-json-type (as/av:note "Note") (as/av:object) *litepub-uri* +(json-ld:define-json-type (as/v/a:note "Note") (as/v/a:object) *litepub-uri* (;; https://misskey-hub.net/ns#_misskey_quote (quote-url "quoteUrl" @@ -162,7 +162,7 @@ It is, however, unclear which one will win out in the end. The implementer prefe ;; https://docs-develop.pleroma.social/backend/development/ap_extensions/#chatmessages -(json-ld:define-json-type (chat-message "ChatMessage") (as/av:note) *litepub-uri* +(json-ld:define-json-type (chat-message "ChatMessage") (as/v/a:note) *litepub-uri* () (:documentation "Represents a private and one-on-one chat-message. Similar to Notes in creation and use, but TO may contain only one recipient. @@ -174,12 +174,12 @@ Potentially very uncommon — it is used by at least Pleroma.")) Will set/get the value of either QUOTE-URL or QUOTE-URI, depending on which is currently in use. In case of doubt, QUOTE-URL is preferred.")) -(defmethod note-quote-url ((obj as/av:note)) +(defmethod note-quote-url ((obj as/v/a:note)) (or (and (slot-boundp note 'quote-url) (slot-value note 'quote-url)) (and (slot-boundp note 'quote-uri) (slot-value note 'quote-uri)))) (defgeneric (setf note-quote-url) (obj value)) -(defmethod (setf note-quote-url) ((obj as/av:note) value) +(defmethod (setf note-quote-url) ((obj as/v/a:note) value) (if (slot-boundp note 'quote-uri) (setf (slot-value note 'quote-uri) value) (setf (slot-value note 'quote-url) value))) @@ -189,6 +189,6 @@ In case of doubt, QUOTE-URL is preferred.")) ;;; Extended Link types ;;; ———————————————————————————————————————— ;; https://docs.joinmastodon.org/spec/activitypub/#Hashtag -(json-ld:define-json-type (hashtag "Hashtag") (as/av:link litepub-object) *litepub-uri* +(json-ld:define-json-type (hashtag "Hashtag") (as/v/a:link litepub-object) *litepub-uri* () (:documentation "Similar to Mentions, a Hashtag is used to link a post to given topics. Should be stored in a TAG slot, and contain NAME (#hashtag) and HREF (link to a server’s hashtag listing).")) diff --git a/t/t.lisp b/t/t.lisp index bd22108..2ef26f7 100644 --- a/t/t.lisp +++ b/t/t.lisp @@ -25,7 +25,7 @@ (defun run () "Run tests from all activity-servist subpackages." (activity-servist/tests/signatures:run) - (activity-servist/tests/activity-vocabulary:run)) + (activity-servist/tests/vocab/activity:run)) (defun run-with-summary () "Run tests with summary for all activity-servist subpackages." diff --git a/t/activity-vocabulary.lisp b/t/vocab/activity.lisp similarity index 88% rename from t/activity-vocabulary.lisp rename to t/vocab/activity.lisp index 049ee7f..57cf1ea 100644 --- a/t/activity-vocabulary.lisp +++ b/t/vocab/activity.lisp @@ -1,4 +1,4 @@ -;;;; activity-servist/tests/activity-vocabulary: Testing activity-vocabulary. +;;;; activity-servist/tests/vocab/activity: Testing activity-vocabulary. ;; Copyright © 2024 Jaidyn Levesque ;; @@ -15,17 +15,17 @@ ;; You should have received a copy of the GNU Affero General Public License ;; along with this program. If not, see . -(defpackage :activity-servist/tests/activity-vocabulary +(defpackage :activity-servist/tests/vocab/activity (:use :cl :lisp-unit2) - (:nicknames "AS/T/AV") + (:nicknames "AS/T/V/AV") (:export :run :run-with-summary)) -(in-package :activity-servist/tests/activity-vocabulary) +(in-package :activity-servist/tests/vocab/activity) (defun run () "Run all ACTIVITY-VOCABULARY tests." (let ((json-ld:*default-json-type* "https://www.w3.org/ns/activitystreams#Object")) - (lisp-unit2:run-tests :package :activity-servist/tests/activity-vocabulary))) + (lisp-unit2:run-tests :package :activity-servist/tests/vocab/activity))) (defun run-with-summary () "Run tests with summary for ACTIVITY-VOCABULARY." @@ -38,7 +38,7 @@ ;;; ———————————————————————————————————————— (defmacro relative-pathname (path) "Return an absolute path adding the relative PATH to the system’s path." - `(asdf:system-relative-pathname :activity-servist/tests/activity-vocabulary ,path)) + `(asdf:system-relative-pathname :activity-servist/tests/vocab/activity ,path)) (defmacro define-json-test (path tags) "Define a lisp-unit2 test for parsing of the given JSON file. @@ -92,4 +92,4 @@ Any nested hash-tables found as values are also sorted, recursively." (mapcar (lambda (file) (eval `(define-json-test ,file '(:activity-vocabulary)))) (uiop:directory-files - (relative-pathname "t/activity-vocabulary/"))) + (relative-pathname "t/vocab/activity/"))) diff --git a/t/activity-vocabulary/accept-2.json b/t/vocab/activity/accept-2.json similarity index 100% rename from t/activity-vocabulary/accept-2.json rename to t/vocab/activity/accept-2.json diff --git a/t/activity-vocabulary/accept.json b/t/vocab/activity/accept.json similarity index 100% rename from t/activity-vocabulary/accept.json rename to t/vocab/activity/accept.json diff --git a/t/activity-vocabulary/activity.json b/t/vocab/activity/activity.json similarity index 100% rename from t/activity-vocabulary/activity.json rename to t/vocab/activity/activity.json diff --git a/t/activity-vocabulary/add-2.json b/t/vocab/activity/add-2.json similarity index 100% rename from t/activity-vocabulary/add-2.json rename to t/vocab/activity/add-2.json diff --git a/t/activity-vocabulary/add.json b/t/vocab/activity/add.json similarity index 100% rename from t/activity-vocabulary/add.json rename to t/vocab/activity/add.json diff --git a/t/activity-vocabulary/announce.json b/t/vocab/activity/announce.json similarity index 100% rename from t/activity-vocabulary/announce.json rename to t/vocab/activity/announce.json diff --git a/t/activity-vocabulary/application.json b/t/vocab/activity/application.json similarity index 100% rename from t/activity-vocabulary/application.json rename to t/vocab/activity/application.json diff --git a/t/activity-vocabulary/arrive.json b/t/vocab/activity/arrive.json similarity index 100% rename from t/activity-vocabulary/arrive.json rename to t/vocab/activity/arrive.json diff --git a/t/activity-vocabulary/article.json b/t/vocab/activity/article.json similarity index 100% rename from t/activity-vocabulary/article.json rename to t/vocab/activity/article.json diff --git a/t/activity-vocabulary/audio.json b/t/vocab/activity/audio.json similarity index 100% rename from t/activity-vocabulary/audio.json rename to t/vocab/activity/audio.json diff --git a/t/activity-vocabulary/block.json b/t/vocab/activity/block.json similarity index 100% rename from t/activity-vocabulary/block.json rename to t/vocab/activity/block.json diff --git a/t/activity-vocabulary/collection-page.json b/t/vocab/activity/collection-page.json similarity index 100% rename from t/activity-vocabulary/collection-page.json rename to t/vocab/activity/collection-page.json diff --git a/t/activity-vocabulary/collection.json b/t/vocab/activity/collection.json similarity index 100% rename from t/activity-vocabulary/collection.json rename to t/vocab/activity/collection.json diff --git a/t/activity-vocabulary/create.json b/t/vocab/activity/create.json similarity index 100% rename from t/activity-vocabulary/create.json rename to t/vocab/activity/create.json diff --git a/t/activity-vocabulary/delete.json b/t/vocab/activity/delete.json similarity index 100% rename from t/activity-vocabulary/delete.json rename to t/vocab/activity/delete.json diff --git a/t/activity-vocabulary/dislike.json b/t/vocab/activity/dislike.json similarity index 100% rename from t/activity-vocabulary/dislike.json rename to t/vocab/activity/dislike.json diff --git a/t/activity-vocabulary/document.json b/t/vocab/activity/document.json similarity index 100% rename from t/activity-vocabulary/document.json rename to t/vocab/activity/document.json diff --git a/t/activity-vocabulary/event.json b/t/vocab/activity/event.json similarity index 100% rename from t/activity-vocabulary/event.json rename to t/vocab/activity/event.json diff --git a/t/activity-vocabulary/flag.json b/t/vocab/activity/flag.json similarity index 100% rename from t/activity-vocabulary/flag.json rename to t/vocab/activity/flag.json diff --git a/t/activity-vocabulary/follow.json b/t/vocab/activity/follow.json similarity index 100% rename from t/activity-vocabulary/follow.json rename to t/vocab/activity/follow.json diff --git a/t/activity-vocabulary/group.json b/t/vocab/activity/group.json similarity index 100% rename from t/activity-vocabulary/group.json rename to t/vocab/activity/group.json diff --git a/t/activity-vocabulary/ignore.json b/t/vocab/activity/ignore.json similarity index 100% rename from t/activity-vocabulary/ignore.json rename to t/vocab/activity/ignore.json diff --git a/t/activity-vocabulary/image.json b/t/vocab/activity/image.json similarity index 100% rename from t/activity-vocabulary/image.json rename to t/vocab/activity/image.json diff --git a/t/activity-vocabulary/intransitive-activity.json b/t/vocab/activity/intransitive-activity.json similarity index 100% rename from t/activity-vocabulary/intransitive-activity.json rename to t/vocab/activity/intransitive-activity.json diff --git a/t/activity-vocabulary/invite.json b/t/vocab/activity/invite.json similarity index 100% rename from t/activity-vocabulary/invite.json rename to t/vocab/activity/invite.json diff --git a/t/activity-vocabulary/join.json b/t/vocab/activity/join.json similarity index 100% rename from t/activity-vocabulary/join.json rename to t/vocab/activity/join.json diff --git a/t/activity-vocabulary/leave-2.json b/t/vocab/activity/leave-2.json similarity index 100% rename from t/activity-vocabulary/leave-2.json rename to t/vocab/activity/leave-2.json diff --git a/t/activity-vocabulary/leave.json b/t/vocab/activity/leave.json similarity index 100% rename from t/activity-vocabulary/leave.json rename to t/vocab/activity/leave.json diff --git a/t/activity-vocabulary/like.json b/t/vocab/activity/like.json similarity index 100% rename from t/activity-vocabulary/like.json rename to t/vocab/activity/like.json diff --git a/t/activity-vocabulary/link.json b/t/vocab/activity/link.json similarity index 100% rename from t/activity-vocabulary/link.json rename to t/vocab/activity/link.json diff --git a/t/activity-vocabulary/listen.json b/t/vocab/activity/listen.json similarity index 100% rename from t/activity-vocabulary/listen.json rename to t/vocab/activity/listen.json diff --git a/t/activity-vocabulary/mention.json b/t/vocab/activity/mention.json similarity index 100% rename from t/activity-vocabulary/mention.json rename to t/vocab/activity/mention.json diff --git a/t/activity-vocabulary/move.json b/t/vocab/activity/move.json similarity index 100% rename from t/activity-vocabulary/move.json rename to t/vocab/activity/move.json diff --git a/t/activity-vocabulary/note.json b/t/vocab/activity/note.json similarity index 100% rename from t/activity-vocabulary/note.json rename to t/vocab/activity/note.json diff --git a/t/activity-vocabulary/object.json b/t/vocab/activity/object.json similarity index 100% rename from t/activity-vocabulary/object.json rename to t/vocab/activity/object.json diff --git a/t/activity-vocabulary/offer.json b/t/vocab/activity/offer.json similarity index 100% rename from t/activity-vocabulary/offer.json rename to t/vocab/activity/offer.json diff --git a/t/activity-vocabulary/ordered-collection-page.json b/t/vocab/activity/ordered-collection-page.json similarity index 100% rename from t/activity-vocabulary/ordered-collection-page.json rename to t/vocab/activity/ordered-collection-page.json diff --git a/t/activity-vocabulary/ordered-collection.json b/t/vocab/activity/ordered-collection.json similarity index 100% rename from t/activity-vocabulary/ordered-collection.json rename to t/vocab/activity/ordered-collection.json diff --git a/t/activity-vocabulary/organization.json b/t/vocab/activity/organization.json similarity index 100% rename from t/activity-vocabulary/organization.json rename to t/vocab/activity/organization.json diff --git a/t/activity-vocabulary/page.json b/t/vocab/activity/page.json similarity index 100% rename from t/activity-vocabulary/page.json rename to t/vocab/activity/page.json diff --git a/t/activity-vocabulary/person.json b/t/vocab/activity/person.json similarity index 100% rename from t/activity-vocabulary/person.json rename to t/vocab/activity/person.json diff --git a/t/activity-vocabulary/place-2.json b/t/vocab/activity/place-2.json similarity index 100% rename from t/activity-vocabulary/place-2.json rename to t/vocab/activity/place-2.json diff --git a/t/activity-vocabulary/place.json b/t/vocab/activity/place.json similarity index 100% rename from t/activity-vocabulary/place.json rename to t/vocab/activity/place.json diff --git a/t/activity-vocabulary/profile.json b/t/vocab/activity/profile.json similarity index 100% rename from t/activity-vocabulary/profile.json rename to t/vocab/activity/profile.json diff --git a/t/activity-vocabulary/question-2.json b/t/vocab/activity/question-2.json similarity index 100% rename from t/activity-vocabulary/question-2.json rename to t/vocab/activity/question-2.json diff --git a/t/activity-vocabulary/question.json b/t/vocab/activity/question.json similarity index 100% rename from t/activity-vocabulary/question.json rename to t/vocab/activity/question.json diff --git a/t/activity-vocabulary/read.json b/t/vocab/activity/read.json similarity index 100% rename from t/activity-vocabulary/read.json rename to t/vocab/activity/read.json diff --git a/t/activity-vocabulary/reject.json b/t/vocab/activity/reject.json similarity index 100% rename from t/activity-vocabulary/reject.json rename to t/vocab/activity/reject.json diff --git a/t/activity-vocabulary/relationship.json b/t/vocab/activity/relationship.json similarity index 100% rename from t/activity-vocabulary/relationship.json rename to t/vocab/activity/relationship.json diff --git a/t/activity-vocabulary/remove-2.json b/t/vocab/activity/remove-2.json similarity index 100% rename from t/activity-vocabulary/remove-2.json rename to t/vocab/activity/remove-2.json diff --git a/t/activity-vocabulary/remove.json b/t/vocab/activity/remove.json similarity index 100% rename from t/activity-vocabulary/remove.json rename to t/vocab/activity/remove.json diff --git a/t/activity-vocabulary/service.json b/t/vocab/activity/service.json similarity index 100% rename from t/activity-vocabulary/service.json rename to t/vocab/activity/service.json diff --git a/t/activity-vocabulary/tentative-accept.json b/t/vocab/activity/tentative-accept.json similarity index 100% rename from t/activity-vocabulary/tentative-accept.json rename to t/vocab/activity/tentative-accept.json diff --git a/t/activity-vocabulary/tentative-reject.json b/t/vocab/activity/tentative-reject.json similarity index 100% rename from t/activity-vocabulary/tentative-reject.json rename to t/vocab/activity/tentative-reject.json diff --git a/t/activity-vocabulary/tombstone.json b/t/vocab/activity/tombstone.json similarity index 100% rename from t/activity-vocabulary/tombstone.json rename to t/vocab/activity/tombstone.json diff --git a/t/activity-vocabulary/travel.json b/t/vocab/activity/travel.json similarity index 100% rename from t/activity-vocabulary/travel.json rename to t/vocab/activity/travel.json diff --git a/t/activity-vocabulary/undo.json b/t/vocab/activity/undo.json similarity index 100% rename from t/activity-vocabulary/undo.json rename to t/vocab/activity/undo.json diff --git a/t/activity-vocabulary/update.json b/t/vocab/activity/update.json similarity index 100% rename from t/activity-vocabulary/update.json rename to t/vocab/activity/update.json diff --git a/t/activity-vocabulary/video.json b/t/vocab/activity/video.json similarity index 100% rename from t/activity-vocabulary/video.json rename to t/vocab/activity/video.json diff --git a/t/activity-vocabulary/view.json b/t/vocab/activity/view.json similarity index 100% rename from t/activity-vocabulary/view.json rename to t/vocab/activity/view.json