]> Lady’s Gitweb - Etiquette/blobdiff - model.js
Apply some reformatting and make Reuse‐compliant
[Etiquette] / model.js
index 3f0b6adea4b7cd3281070a62b314df26be673f08..d2990ebbd47f2e6efb84d0c708e2f7b37f0b6211 100644 (file)
--- a/model.js
+++ b/model.js
@@ -1,66 +1,72 @@
-// 📧🏷️ Étiquette ∷ model.js
-// ====================================================================
-//
-// Copyright © 2023 Lady [@ Lady’s Computer].
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
+// SPDX-FileCopyrightText: 2023, 2025 Lady <https://www.ladys.computer/about/#lady>
+// SPDX-License-Identifier: MPL-2.0
+/**
+ * ⁌ 📧🏷️ Étiquette ∷ model.js
+ *
+ * Copyright © 2023, 2025 Lady [@ Ladys Computer].
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
+ */
 
 
+import { identity } from "./deps.js";
 import { Storage } from "./memory.js";
 import { taggingDiscoveryContext } from "./names.js";
 import schema from "./schema.js";
 
 import { Storage } from "./memory.js";
 import { taggingDiscoveryContext } from "./names.js";
 import schema from "./schema.js";
 
+const ÉTIQUETTE = "📧🏷️ Étiquette";
+
 /**
  * A tag.
  *
 /**
  * A tag.
  *
- * `Tag`s are not assigned identifiers and do not have side·effects on
- * other tags in the `TagSystem` until they are persisted with
- * `::persist`, at which point changes to their relationships are
+ * `Tag´s are not assigned identifiers and do not have side·effects on
+ * other tags in the `TagSystem´ until they are persisted with
+ * `::persist´, at which point changes to their relationships are
  * applied.
  *
  * applied.
  *
- * `Tag`s are also not kept up‐to‐date, but persisting an outdated
- * `Tag` will *not* undo subsequent changes.
+ * `Tag´s are also not kept up‐to‐date, but persisting an outdated
+ * `Tag´ will ⹐not⹑ undo subsequent changes.
  *
  * ※ This class is not itself directly exposed, although bound
  *
  * ※ This class is not itself directly exposed, although bound
- * versions of it are via `TagSystem::Tag`.
+ * versions of it are via `TagSystem::Tag´.
  */
 class Tag {
  */
 class Tag {
-  /** The `TagSystem` this `Tag` belongs to. */
+  /** The `TagSystem´ this `Tag´ belongs to. */
   #system;
 
   #system;
 
-  /** The `Storage` managed by this `Tag`’s `TagSystem`. */
+  /** The `Storage´ managed by this `Tag´s `TagSystem´. */
   #storage;
 
   #storage;
 
-  /** The schema in use for this `Tag`. */
+  /** The schema in use for this `Tag´. */
   #schema;
 
   /**
    * The 30‐bit W·R·M·G base32 identifier with leading checksum which
   #schema;
 
   /**
    * The 30‐bit W·R·M·G base32 identifier with leading checksum which
-   * has been assigned to this `Tag`.
+   * has been assigned to this `Tag´.
    *
    *
-   * Will be `null` if this `Tag` has not been persisted. Otherwise,
-   * the format is `cxx-xxxx` (`c` = checksum; `x` = digit).
+   * Will be `null´ if this `Tag´ has not been persisted. Otherwise,
+   * the format is `cxx-xxxx´ (`c´ = checksum; `x´ = digit).
    */
   #identifier = null;
 
    */
   #identifier = null;
 
-  /** The kind of this `Tag`. */
+  /** The kind of this `Tag´. */
   #kind = "Tag";
 
   /**
   #kind = "Tag";
 
   /**
-   * The data which was attached to this `Tag` the last time it was
+   * The data which was attached to this `Tag´ the last time it was
    * persisted or retrieved from storage.
    *
    * Diffing with this will reveal changes.
    */
   #persistedData = null;
 
    * persisted or retrieved from storage.
    *
    * Diffing with this will reveal changes.
    */
   #persistedData = null;
 
-  /** The current (modified) data associated with this `Tag`. */
+  /** The current (modified) data associated with this `Tag´. */
   #data = tagData();
 
   /**
   #data = tagData();
 
   /**
-   * Adds the provided label(s) to this `Tag` as the provided
-   * predicate, then returns this `Tag`.
+   * Adds the provided label(s) to this `Tag´ as the provided
+   * predicate, then returns this `Tag´.
    */
   #addLabel(predicate, ...labels) {
     const values = this.#data[predicate];
    */
   #addLabel(predicate, ...labels) {
     const values = this.#data[predicate];
@@ -73,11 +79,11 @@ class Tag {
   }
 
   /**
   }
 
   /**
-   * Adds the provided tags to the list of tags that this `Tag` is
-   * related to by the provided predicate, then returns this `Tag`.
+   * Adds the provided tags to the list of tags that this `Tag´ is
+   * related to by the provided predicate, then returns this `Tag´.
    *
    * Arguments may be string identifiers or objects with an
    *
    * Arguments may be string identifiers or objects with an
-   * `.identifier` property.
+   * `.identifier´ property.
    */
   #addTag(predicate, ...tags) {
     const storage = this.#storage;
    */
   #addTag(predicate, ...tags) {
     const storage = this.#storage;
@@ -88,26 +94,26 @@ class Tag {
       if (identifier == null) {
         // ☡ The current tag has no identifier.
         throw new TypeError(
       if (identifier == null) {
         // ☡ The current tag has no identifier.
         throw new TypeError(
-          `Cannot state ${predicate} of Tag: Identifier must not be nullish.`,
+          `${ÉTIQUETTE}: Cannot state ${predicate} of Tag: Identifier must not be nullish.`,
         );
       } else if (values.has(identifier)) {
         // Short‐circuit: The identifier has already been stated with
         // this predicate.
         /* do nothing */
       } else {
         );
       } else if (values.has(identifier)) {
         // Short‐circuit: The identifier has already been stated with
         // this predicate.
         /* do nothing */
       } else {
-        // The current tag has an identifier, but it hasnt been stated
+        // The current tag has an identifier, but it hasn¦t been stated
         // with this predicate yet.
         const tag = storage.get(identifier);
         if (tag == null) {
         // with this predicate yet.
         const tag = storage.get(identifier);
         if (tag == null) {
-          // ☡ The current tag has not been persisted to this `Tag`’s
+          // ☡ The current tag has not been persisted to this `Tag´s
           // storage.
           throw new RangeError(
           // storage.
           throw new RangeError(
-            `Cannot state ${predicate} of Tag: Identifier is not persisted: ${identifier}.`,
+            `${ÉTIQUETTE}: Cannot state ${predicate} of Tag: Identifier is not persisted: ${identifier}.`,
           );
         } else if (!this.#isTagInStorage(tag)) {
           // ☡ The current tag is not a tag in the correct tag system.
           throw new TypeError(
           );
         } else if (!this.#isTagInStorage(tag)) {
           // ☡ The current tag is not a tag in the correct tag system.
           throw new TypeError(
-            `Cannot state ${predicate} of Tag: Tags must be from the same Tag System, but got: ${identifier}.`,
+            `${ÉTIQUETTE}: Cannot state ${predicate} of Tag: Tags must be from the same Tag System, but got: ${identifier}.`,
           );
         } else if (
           !isObjectPredicateOK(
           );
         } else if (
           !isObjectPredicateOK(
@@ -120,7 +126,7 @@ class Tag {
           // ☡ This tag and the current tag form an invalid pair for
           // this predicate.
           throw new TypeError(
           // ☡ This tag and the current tag form an invalid pair for
           // this predicate.
           throw new TypeError(
-            `Cannot state ${predicate} of Tag: Not valid for domain and range: ${this.#kind}, ${tag.#kind}.`,
+            `${ÉTIQUETTE}: Cannot state ${predicate} of Tag: Not valid for domain and range: ${this.#kind}, ${tag.#kind}.`,
           );
         } else {
           // The current tag is a tag in the correct tag system; add
           );
         } else {
           // The current tag is a tag in the correct tag system; add
@@ -133,8 +139,8 @@ class Tag {
   }
 
   /**
   }
 
   /**
-   * Removes the provided string label(s) from this `Tag` as the
-   * provided predicate, then returns this `Tag`.
+   * Removes the provided string label(s) from this `Tag´ as the
+   * provided predicate, then returns this `Tag´.
    */
   #deleteLabel(predicate, ...labels) {
     const values = this.#data[predicate];
    */
   #deleteLabel(predicate, ...labels) {
     const values = this.#data[predicate];
@@ -147,11 +153,11 @@ class Tag {
   }
 
   /**
   }
 
   /**
-   * Removes the provided tags from the list of tags that this `Tag` is
-   * related to by the provided predicate, then returns this `Tag`.
+   * Removes the provided tags from the list of tags that this `Tag´ is
+   * related to by the provided predicate, then returns this `Tag´.
    *
    * Arguments may be string identifiers or objects with an
    *
    * Arguments may be string identifiers or objects with an
-   * `.identifier` property.
+   * `.identifier´ property.
    */
   #deleteTag(predicate, ...tags) {
     const values = this.#data[predicate];
    */
   #deleteTag(predicate, ...tags) {
     const values = this.#data[predicate];
@@ -166,11 +172,11 @@ class Tag {
    * Returns whether or not the provided value is a tag which shares a
    * storage with this tag.
    *
    * Returns whether or not the provided value is a tag which shares a
    * storage with this tag.
    *
-   * Sharing a storage also implies sharing a `TagSystem`.
+   * Sharing a storage also implies sharing a `TagSystem´.
    */
   #isTagInStorage($) {
     try {
    */
   #isTagInStorage($) {
     try {
-      // Try to compare the provided values internal store with
+      // Try to compare the provided values internal store with
       // the provided storage.
       return $.#storage == this.#storage;
     } catch {
       // the provided storage.
       return $.#storage == this.#storage;
     } catch {
@@ -180,7 +186,7 @@ class Tag {
   }
 
   /**
   }
 
   /**
-   * Yields the labels of this `Tag` according to the provided
+   * Yields the labels of this `Tag´ according to the provided
    * predicate.
    */
   *#yieldLabels(predicate) {
    * predicate.
    */
   *#yieldLabels(predicate) {
@@ -188,7 +194,7 @@ class Tag {
   }
 
   /**
   }
 
   /**
-   * Yields the tags that this `Tag` is related to by the provided
+   * Yields the tags that this `Tag´ is related to by the provided
    * predicate.
    */
   *#yieldTags(predicate) {
    * predicate.
    */
   *#yieldTags(predicate) {
@@ -216,7 +222,7 @@ class Tag {
   }
 
   /**
   }
 
   /**
-   * Yields the tags that this `Tag` is related to by the provided
+   * Yields the tags that this `Tag´ is related to by the provided
    * predicate, figured transitively.
    */
   *#yieldTransitiveTags(transitivePredicate, basePredicate) {
    * predicate, figured transitively.
    */
   *#yieldTransitiveTags(transitivePredicate, basePredicate) {
@@ -268,11 +274,11 @@ class Tag {
   }
 
   /**
   }
 
   /**
-   * Constructs a new `Tag` of the provided kind and with the provided
+   * Constructs a new `Tag´ of the provided kind and with the provided
    * preferred label.
    *
    * ※ The first two arguments of this constructor are bound when
    * preferred label.
    *
    * ※ The first two arguments of this constructor are bound when
-   * generating the value of `TagSystem::Tag`. It isn’t possible to
+   * generating the value of `TagSystem::Tag´. It isn¦t possible to
    * access this constructor in its unbound form from outside this
    * module.
    *
    * access this constructor in its unbound form from outside this
    * module.
    *
@@ -286,7 +292,7 @@ class Tag {
     if (!(kindString in schema.classes)) {
       // The provided kind is not supported.
       throw new RangeError(
     if (!(kindString in schema.classes)) {
       // The provided kind is not supported.
       throw new RangeError(
-        `Cannot construct Tag: Unrecognized kind: ${kind}.`,
+        `${ÉTIQUETTE}: Cannot construct Tag: Unrecognized kind: ${kind}.`,
       );
     } else {
       // The provided kind is one of the recognized tag kinds.
       );
     } else {
       // The provided kind is one of the recognized tag kinds.
@@ -296,7 +302,7 @@ class Tag {
   }
 
   /**
   }
 
   /**
-   * Returns a new `Tag` constructor for the provided system, storage,
+   * Returns a new `Tag´ constructor for the provided system, storage,
    * schema, created with an appropriate prototype for the properties
    * so defined.
    *
    * schema, created with an appropriate prototype for the properties
    * so defined.
    *
@@ -316,6 +322,7 @@ class Tag {
       );
     };
     Object.defineProperties(constructor, {
       );
     };
     Object.defineProperties(constructor, {
+      name: { value: "TagSystem::Tag" },
       prototype: {
         configurable: false,
         enumerable: false,
       prototype: {
         configurable: false,
         enumerable: false,
@@ -324,21 +331,30 @@ class Tag {
           Object.fromEntries(Array.from(
             function* () {
               for (const key in objectProperties) {
           Object.fromEntries(Array.from(
             function* () {
               for (const key in objectProperties) {
+                // Iterate over each object property and yield any
+                // necessary method definitions.
                 const {
                   inverseOf,
                   subPropertyOf,
                 } = objectProperties[key];
                 if (key in transitiveProperties) {
                 const {
                   inverseOf,
                   subPropertyOf,
                 } = objectProperties[key];
                 if (key in transitiveProperties) {
+                  // The current key indicates a transitive property.
+                  //
                   // Transitive property methods are added by their
                   // nontransitive subproperties.
                   /* do nothing */
                 } else {
                   // Transitive property methods are added by their
                   // nontransitive subproperties.
                   /* do nothing */
                 } else {
+                  // The current key does not indicate a transitive
+                  // property.
                   yield [`${key}Tags`, function* () {
                     yield* this.#yieldTags(key);
                   }];
                   if (inverseOf == null) {
                   yield [`${key}Tags`, function* () {
                     yield* this.#yieldTags(key);
                   }];
                   if (inverseOf == null) {
-                    const cased = key[0].toUpperCase() +
-                      key.substring(1);
+                    // The current key does not indicate an inverse
+                    // property, so add and delete methods are also
+                    // added.
+                    const cased = key[0].toUpperCase()
+                      + key.substring(1);
                     yield [`add${cased}Tag`, function (...tags) {
                       return this.#addTag(key, ...tags);
                     }];
                     yield [`add${cased}Tag`, function (...tags) {
                       return this.#addTag(key, ...tags);
                     }];
@@ -346,12 +362,16 @@ class Tag {
                       return this.#deleteTag(key, ...tags);
                     }];
                   } else {
                       return this.#deleteTag(key, ...tags);
                     }];
                   } else {
+                    // The current key indicates an inverse property,
+                    // so no add and delete methods are necessary.
                     /* do nothing */
                   }
                   if (
                     /* do nothing */
                   }
                   if (
-                    subPropertyOf != null &&
-                    subPropertyOf in transitiveProperties
+                    subPropertyOf != null
+                    && subPropertyOf in transitiveProperties
                   ) {
                   ) {
+                    // The current key indicates a subproperty of a
+                    // transitive property; its method is also added.
                     yield [`${subPropertyOf}Tags`, function* () {
                       yield* this.#yieldTransitiveTags(
                         subPropertyOf,
                     yield [`${subPropertyOf}Tags`, function* () {
                       yield* this.#yieldTransitiveTags(
                         subPropertyOf,
@@ -359,14 +379,19 @@ class Tag {
                       );
                     }];
                   } else {
                       );
                     }];
                   } else {
+                    // The current key does not indicate a subproperty
+                    // of a transitive property.
                     /* do nothing */
                   }
                 }
               }
               for (const key in dataProperties) {
                     /* do nothing */
                   }
                 }
               }
               for (const key in dataProperties) {
+                // Iterate over each data property and yield any
+                // necessary method definitions.
                 if (key != "prefLabel") {
                 if (key != "prefLabel") {
-                  const cased = key[0].toUpperCase() +
-                    key.substring(1);
+                  // The current key is not `"prefLabel"´.
+                  const cased = key[0].toUpperCase()
+                    + key.substring(1);
                   yield [`${key}s`, function* () {
                     yield* this.#yieldLabels(key);
                   }];
                   yield [`${key}s`, function* () {
                     yield* this.#yieldLabels(key);
                   }];
@@ -377,6 +402,8 @@ class Tag {
                     return this.#deleteLabel(key, ...labels);
                   }];
                 } else {
                     return this.#deleteLabel(key, ...labels);
                   }];
                 } else {
+                  // The current key is `"prefLabel"´. This is a
+                  // special case which is not handled by the schema.
                   /* do nothing */
                 }
               }
                   /* do nothing */
                 }
               }
@@ -394,203 +421,75 @@ class Tag {
         writable: false,
       },
     });
         writable: false,
       },
     });
-    return Object.defineProperties(
-      constructor,
-      Object.fromEntries([
-        ["name", { value: "TagSystem::Tag" }],
-        ...[
-          "all",
-          "fromIRI",
-          "fromIdentifier",
-          "fromTagURI",
-          "identifiers",
-          Storage.toInstance,
-        ].map((key) => [key, {
-          configurable: true,
-          enumerable: false,
-          value: Object.defineProperty(
-            Tag[key].bind(constructor, system, storage),
-            "name",
-            { value: String(key) },
-          ),
-          writable: true,
-        }]),
-      ]),
-    );
-  }
-
-  /**
-   * Yields the tags in the `TagSystem` associated with this
-   * constructor.
-   *
-   * ※ The first two arguments of this function are bound when
-   * generating the value of `TagSystem::Tag`. It isn’t possible to
-   * access this function in its unbound form from outside this module.
-   */
-  static *all(system, storage) {
-    for (const instance of storage.values()) {
-      // Iterate over the entries and yield the ones which are `Tag`s
-      // in this `TagSystem`.
-      if (Tag.getSystem(instance) == system) {
-        // The current instance is a `Tag` in this `TagSystem`.
-        yield instance;
-      } else {
-        // The current instance is not a `Tag` in this `TagSystem`.
-        /* do nothing */
-      }
-    }
-  }
-
-  /**
-   * Returns a new `Tag` resolved from the provided I·R·I.
-   *
-   * ※ The first two arguments of this function are bound when
-   * generating the value of `TagSystem::Tag`. It isn’t possible to
-   * access this function in its unbound form from outside this module.
-   *
-   * ☡ This function throws if the I·R·I is not in the `.iriSpace` of
-   * the `TagSystem` associated with this constructor.
-   *
-   * ※ If the I·R·I is not recognized, this function returns `null`.
-   */
-  static fromIRI(system, storage, iri) {
-    const name = `${iri}`;
-    const prefix = `${system.iriSpace}`;
-    if (!name.startsWith(prefix)) {
-      // The I·R·I does not begin with the expected prefix.
-      throw new RangeError(
-        `I·R·I did not begin with the expected prefix: ${iri}`,
-      );
-    } else {
-      // The I·R·I begins with the expected prefix.
-      const identifier = name.substring(prefix.length);
-      try {
-        // Attempt to resolve the identifier.
-        const instance = storage.get(identifier);
-        return Tag.getSystem(instance) == system ? instance : null;
-      } catch {
-        // Do not throw for bad identifiers.
-        return null;
-      }
-    }
+    return new TagConstructor(constructor, system, storage, schema);
   }
 
   /**
   }
 
   /**
-   * Returns a new `Tag` resolved from the provided identifier.
-   *
-   * ※ The first two arguments of this function are bound when
-   * generating the value of `TagSystem::Tag`. It isn’t possible to
-   * access this function in its unbound form from outside this module.
+   * Assigns the provided data and identifier to the provided tag.
    *
    *
-   * ☡ This function throws if the identifier is invalid.
+   * ☡ This function throws if the provided tag is not a `Tag´.
    *
    *
-   * ※ If the identifier is valid but not recognized, this function
-   * returns `null`.
+   * ※ This function is not exposed.
    */
    */
-  static fromIdentifier(system, storage, identifier) {
-    const instance = storage.get(identifier);
-    return Tag.getSystem(instance) == system ? instance : null;
+  static assignData(tag, data, identifier) {
+    tag.#identifier = `${identifier}`;
+    tag.#persistedData = tagData(data);
+    tag.#data = tagData(data);
+    return tag;
   }
 
   /**
   }
 
   /**
-   * Returns a new `Tag` resolved from the provided Tag U·R·I.
+   * Returns a new `Tag´ with the provided identifier, kind, and
+   * prefLabel.
    *
    *
-   * ※ The first two arguments of this function are bound when
-   * generating the value of `TagSystem::Tag`. It isn’t possible to
-   * access this function in its unbound form from outside this module.
+   * ※ This function exists to enable `TagSystem´s to replay Create
+   * activities, maintaining the identifier of the original.
    *
    *
-   * ☡ This function throws if the provided Tag U·R·I does not match
-   * the tagging entity of this constructor’s `TagSystem`.
+   * ☡ This function throws if the provided identifier is already in
+   * use.
    *
    *
-   * ※ If the specific component of the Tag U·R·I is not recognized,
-   * this function returns `null`.
+   * ※ This function is not exposed.
    */
    */
-  static fromTagURI(system, storage, tagURI) {
-    const tagName = `${tagURI}`;
-    const tagPrefix = `tag:${system.taggingEntity}:`;
-    if (!tagName.startsWith(tagPrefix)) {
-      // The Tag U·R·I does not begin with the expected prefix.
+  static new(system, identifier, kind = "Tag", prefLabel = "") {
+    const storage = (new system.Tag()).#storage;
+    if (storage.has(identifier)) {
       throw new RangeError(
       throw new RangeError(
-        `Tag U·R·I did not begin with the expected prefix: ${tagURI}`,
+        `${ÉTIQUETTE}: Cannot create Tag: Identifier already in use: ${identifier}.`,
       );
     } else {
       );
     } else {
-      // The I·R·I begins with the expected prefix.
-      const identifier = tagName.substring(tagPrefix.length);
-      try {
-        // Attempt to resolve the identifier.
-        const instance = storage.get(identifier);
-        return Tag.getSystem(instance) == system ? instance : null;
-      } catch {
-        // Do not throw for bad identifiers.
-        return null;
-      }
+      const createdTag = new system.Tag(kind, prefLabel);
+      createdTag.#identifier = identifier;
+      createdTag.persist(true);
+      return createdTag;
     }
   }
 
   /**
     }
   }
 
   /**
-   * Returns the `TagSystem` that the provided value belongs to.
+   * Returns the `TagSystem´ that the provided value belongs to.
    *
    * ※ This function can be used to check if the provided value has
    * private tag features.
    *
    *
    * ※ This function can be used to check if the provided value has
    * private tag features.
    *
+   * ※ `Tag::system´ is an overridable, publicly‐accessible means of
+   * accessing the system.
+   *
    * ※ This function is not exposed.
    */
   static getSystem($) {
     return !(#system in Object($)) ? null : $.#system;
   }
 
    * ※ This function is not exposed.
    */
   static getSystem($) {
     return !(#system in Object($)) ? null : $.#system;
   }
 
-  /**
-   * Yields the tag identifiers in the `TagSystem` associated with this
-   * constructor.
-   *
-   * ※ The first two arguments of this function are bound when
-   * generating the value of `TagSystem::Tag`. It isn’t possible to
-   * access this function in its unbound form from outside this module.
-   */
-  static *identifiers(system, storage) {
-    for (const [identifier, instance] of storage.entries()) {
-      // Iterate over the entries and yield the ones which are `Tag`s
-      // in this `TagSystem`.
-      if (Tag.getSystem(instance) == system) {
-        // The current instance is a `Tag` in this `TagSystem`.
-        yield identifier;
-      } else {
-        // The current instance is not a `Tag` in this `TagSystem`.
-        /* do nothing */
-      }
-    }
-  }
-
-  /**
-   * Returns a new `Tag` constructed from the provided data and with
-   * the provided identifier.
-   *
-   * ※ This function will not work if called directly from `Tag` (and
-   * nor is it available *to* be called as such from outside this
-   * module). It must be called from a `TagSystem::Tag` bound
-   * constructor.
-   *
-   * ※ This function is not really intended for public usage.
-   */
-  static [Storage.toInstance](_system, _storage, data, identifier) {
-    const tag = new this(data.kind);
-    tag.#identifier = `${identifier}`;
-    tag.#persistedData = tagData(data);
-    tag.#data = tagData(data);
-    return tag;
-  }
-
   static {
   static {
-    // Overwrite the default `::constructor` method to instead give the
+    // Overwrite the default `::constructor´ method to instead give the
     // actual (bound) constructor which was used to generate a given
     // actual (bound) constructor which was used to generate a given
-    // `Tag`.
+    // `Tag´.
     Object.defineProperties(this.prototype, {
       constructor: {
         configurable: true,
         enumerable: false,
         get() {
     Object.defineProperties(this.prototype, {
       constructor: {
         configurable: true,
         enumerable: false,
         get() {
-          // All `Tag`s are constructed via the `.Tag` constructor
-          // available in their `TagSystem`; return it.
+          // All `Tag´s are constructed via the `.Tag´ constructor
+          // available in their `TagSystem´; return it.
           return this.#system.Tag;
         },
         set: undefined,
           return this.#system.Tag;
         },
         set: undefined,
@@ -598,38 +497,47 @@ class Tag {
     });
   }
 
     });
   }
 
-  /** Returns the authority (domain) name for this `Tag`. */
+  /** Returns the authority (domain) name for this `Tag´. */
   get authorityName() {
     return this.#system.authorityName;
   }
 
   get authorityName() {
     return this.#system.authorityName;
   }
 
-  /** Returns the identifier of this `Tag`. */
+  /** Returns the identifier of this `Tag´. */
   get identifier() {
     return this.#identifier;
   }
 
   get identifier() {
     return this.#identifier;
   }
 
-  /** Returns the I·R·I for this `Tag`. */
+  /** Returns the I·R·I for this `Tag´. */
   get iri() {
     const { identifier, iriSpace } = this;
     return identifier == null ? null : `${iriSpace}${identifier}`;
   }
 
   get iri() {
     const { identifier, iriSpace } = this;
     return identifier == null ? null : `${iriSpace}${identifier}`;
   }
 
-  /** Returns the I·R·I space for this `Tag`. */
+  /** Returns the I·R·I space for this `Tag´. */
   get iriSpace() {
     return this.#system.iriSpace;
   }
 
   get iriSpace() {
     return this.#system.iriSpace;
   }
 
-  /** Returns the kind of this `Tag`. */
+  /** Returns the kind of this `Tag´. */
   get kind() {
     return this.#kind;
   }
 
   /**
   get kind() {
     return this.#kind;
   }
 
   /**
-   * Persist this `Tag` to storage and return an ActivityStreams
+   * Returns the `TagSystem´ for this `Tag´.
+   *
+   * ※ Internally, `Tag.getSystem´ is preferred.
+   */
+  get system() {
+    return this.#system;
+  }
+
+  /**
+   * Persist this `Tag´ to storage and return an ActivityStreams
    * serialization of a Tag Activity representing any changes, or
    * serialization of a Tag Activity representing any changes, or
-   * `null` if no changes were made.
+   * `null´ if no changes were made.
    *
    *
-   * If the second argument is `true`, the `Tag` will be persisted but
+   * If the second argument is `true´, the `Tag´ will be persisted but
    * no serialization will be made. This is somewhat more efficient.
    *
    * ※ Persistence can imply side‐effects on other objects, which are
    * no serialization will be made. This is somewhat more efficient.
    *
    * ※ Persistence can imply side‐effects on other objects, which are
@@ -655,8 +563,8 @@ class Tag {
       // Iterate over each entry of the tag data and create a diff
       // with the last persisted information.
       if (
       // Iterate over each entry of the tag data and create a diff
       // with the last persisted information.
       if (
-        objectProperties[key]?.inverseOf != null ||
-        silent && key in dataProperties
+        objectProperties[key]?.inverseOf != null
+        || silent && key in dataProperties
       ) {
         // The current property is one which is skipped in diffs.
         //
       ) {
         // The current property is one which is skipped in diffs.
         //
@@ -693,8 +601,8 @@ class Tag {
           }
           diffs[key] = { old: oldValues, new: newValues };
         } else if (
           }
           diffs[key] = { old: oldValues, new: newValues };
         } else if (
-          `${value}` != `${persisted}` ||
-          value.language != persisted.language
+          `${value}` != `${persisted}`
+          || value.language != persisted.language
         ) {
           // The current property is (optionally language‐tagged)
           // string‐valued and the value changed.
         ) {
           // The current property is (optionally language‐tagged)
           // string‐valued and the value changed.
@@ -710,11 +618,11 @@ class Tag {
     }
     const identifier = this.#identifier;
     if (identifier != null) {
     }
     const identifier = this.#identifier;
     if (identifier != null) {
-      // This `Tag` has already been persisted; use its existing
+      // This `Tag´ has already been persisted; use its existing
       // identifier and persist.
       storage.set(identifier, this);
     } else {
       // identifier and persist.
       storage.set(identifier, this);
     } else {
-      // This `Tag` has not been persisted yet; save the new
+      // This `Tag´ has not been persisted yet; save the new
       // identifier after persisting.
       this.#identifier = storage.add(this);
     }
       // identifier after persisting.
       this.#identifier = storage.add(this);
     }
@@ -732,11 +640,11 @@ class Tag {
         // The current property is the inverse of a non‐transitive
         // property.
         for (const referencedIdentifier of diffs[term].old) {
         // The current property is the inverse of a non‐transitive
         // property.
         for (const referencedIdentifier of diffs[term].old) {
-          // Iterate over the removed tags and remove this `Tag` from
+          // Iterate over the removed tags and remove this `Tag´ from
           // their inverse property.
           const referenced = storage.get(referencedIdentifier);
           try {
           // their inverse property.
           const referenced = storage.get(referencedIdentifier);
           try {
-            // Try removing this `Tag`.
+            // Try removing this `Tag´.
             referenced.#data[inverse].delete(persistedIdentifier);
             storage.set(referencedIdentifier, referenced);
           } catch {
             referenced.#data[inverse].delete(persistedIdentifier);
             storage.set(referencedIdentifier, referenced);
           } catch {
@@ -752,7 +660,8 @@ class Tag {
             referenced.#data[inverse].add(persistedIdentifier);
             storage.set(referencedIdentifier, referenced);
           } catch {
             referenced.#data[inverse].add(persistedIdentifier);
             storage.set(referencedIdentifier, referenced);
           } catch {
-            // Adding failed, possibly because the other tag was deleted.
+            // Adding failed, possibly because the other tag was
+            // deleted.
             /* do nothing */
           }
         }
             /* do nothing */
           }
         }
@@ -819,8 +728,8 @@ class Tag {
                     });
                   }
                 } catch {
                     });
                   }
                 } catch {
-                  // Value resolution failed for some reason; perhaps the
-                  // tag was deleted.
+                  // Value resolution failed for some reason; perhaps
+                  // the tag was deleted.
                   /* do nothing */
                 }
               }
                   /* do nothing */
                 }
               }
@@ -850,8 +759,8 @@ class Tag {
                     });
                   }
                 } catch {
                     });
                   }
                 } catch {
-                  // Value resolution failed for some reason; perhaps the
-                  // tag was deleted.
+                  // Value resolution failed for some reason; perhaps
+                  // the tag was deleted.
                   /* do nothing */
                 }
               }
                   /* do nothing */
                 }
               }
@@ -875,29 +784,30 @@ class Tag {
         })(),
       };
       if (
         })(),
       };
       if (
-        !Object.hasOwn(activity, "states") &&
-        !Object.hasOwn(activity, "unstates")
+        !Object.hasOwn(activity, "states")
+        && !Object.hasOwn(activity, "unstates")
       ) {
         // No meaningful changes were actually persisted.
         return null;
       } else {
       ) {
         // No meaningful changes were actually persisted.
         return null;
       } else {
-        // There were meaningful changes persisted regarding this `Tag`.
+        // There were meaningful changes persisted regarding this
+        // `Tag´.
         return activity;
       }
     }
   }
 
         return activity;
       }
     }
   }
 
-  /** Returns the preferred label for this `Tag`. */
+  /** Returns the preferred label for this `Tag´. */
   get prefLabel() {
     return this.#data.prefLabel;
   }
 
   get prefLabel() {
     return this.#data.prefLabel;
   }
 
-  /** Sets the preferred label of this `Tag` to the provided label. */
+  /** Sets the preferred label of this `Tag´ to the provided label. */
   set prefLabel($) {
     this.#data.prefLabel = langString($);
   }
 
   set prefLabel($) {
     this.#data.prefLabel = langString($);
   }
 
-  /** Returns the Tag U·R·I for this `Tag`. */
+  /** Returns the Tag U·R·I for this `Tag´. */
   get tagURI() {
     const { identifier } = this;
     return identifier == null
   get tagURI() {
     const { identifier } = this;
     return identifier == null
@@ -905,12 +815,12 @@ class Tag {
       : `tag:${this.taggingEntity}:${identifier}`;
   }
 
       : `tag:${this.taggingEntity}:${identifier}`;
   }
 
-  /** Returns the tagging entity (domain and date) for this `Tag`. */
+  /** Returns the tagging entity (domain and date) for this `Tag´. */
   get taggingEntity() {
     return this.#system.taggingEntity;
   }
 
   get taggingEntity() {
     return this.#system.taggingEntity;
   }
 
-  /** Returns the string form of the preferred label of this `Tag`. */
+  /** Returns the string form of the preferred label of this `Tag´. */
   toString() {
     return `${this.#data.prefLabel}`;
   }
   toString() {
     return `${this.#data.prefLabel}`;
   }
@@ -930,6 +840,232 @@ class Tag {
   }
 }
 
   }
 }
 
+const {
+  /**
+   * A `Tag´ constructor function.
+   *
+   * This class extends the identity function, meaning that the object
+   * provided as the constructor is used verbatim (with new private
+   * fields added).
+   *
+   * ※ The instance methods of this class are provided as static
+   * methods on the superclass which all `Tag´ constructors inherit
+   * from.
+   *
+   * ※ This class is not exposed.
+   */
+  TagConstructor,
+
+  /**
+   * The exposed constructor function from which all `Tag´ constructors
+   * inherit.
+   *
+   * ☡ This constructor always throws.
+   */
+  TagSuper,
+} = (() => {
+  const tagConstructorBehaviours = Object.create(null);
+  return {
+    TagConstructor: class extends identity {
+      /**
+       * The `TagSystem´ used for `Tag´s constructed by this
+       * constructor.
+       */
+      #system;
+
+      /** The `Storage´ managed by this constructors `TagSystem´. */
+      #storage;
+
+      /** The schema in use for this constructor. */
+      #schema;
+
+      /**
+       * Constructs a new `Tag´ constructor by adding the appropriate
+       * private fields to the provided constructor, setting its
+       * prototype, and then returning it.
+       *
+       * ※ This constructor does not modify the `name´ or `prototype´
+       * properties of the provided constructor.
+       *
+       * ※ See `Tag.For´, where this constructor is used.
+       */
+      constructor(constructor, system, storage, schema) {
+        super(constructor);
+        Object.setPrototypeOf(this, TagSuper);
+        this.#system = system;
+        this.#storage = storage;
+        this.#schema = schema;
+      }
+
+      static {
+        // Define the superclass constructor which all `Tag´
+        // constructors will inherit from.
+        const superclass = tagConstructorBehaviours.TagSuper =
+          function Tag() {
+            throw new TypeError("Tags must belong to a System.");
+          };
+        const { prototype: staticFeatures } = this;
+        delete staticFeatures.constructor;
+        Object.defineProperty(superclass, "prototype", {
+          configurable: false,
+          enumerable: false,
+          value: Tag.prototype,
+          writable: false,
+        });
+        Object.defineProperties(
+          superclass,
+          Object.getOwnPropertyDescriptors(staticFeatures),
+        );
+      }
+
+      /**
+       * Yields the tags in the `TagSystem´ associated with this
+       * constructor.
+       */
+      *all() {
+        const system = this.#system;
+        const storage = this.#storage;
+        for (const instance of storage.values()) {
+          // Iterate over the entries and yield the ones which are
+          // `Tag´s in this `TagSystem´.
+          if (Tag.getSystem(instance) == system) {
+            // The current instance is a `Tag´ in this `TagSystem´.
+            yield instance;
+          } else {
+            // The current instance is not a `Tag´ in this
+            // `TagSystem´.
+            /* do nothing */
+          }
+        }
+      }
+
+      /**
+       * Returns a new `Tag´ resolved from the provided I·R·I.
+       *
+       * ☡ This function throws if the I·R·I is not in the `.iriSpace´
+       * of the `TagSystem´ associated with this constructor.
+       *
+       * ※ If the I·R·I is not recognized, this function returns
+       * `undefined`.
+       */
+      fromIRI(iri) {
+        const system = this.#system;
+        const storage = this.#storage;
+        const name = `${iri}`;
+        const prefix = `${system.iriSpace}`;
+        if (!name.startsWith(prefix)) {
+          // The I·R·I does not begin with the expected prefix.
+          throw new RangeError(
+            `${ÉTIQUETTE}: I·R·I did not begin with the expected prefix: ${iri}`,
+          );
+        } else {
+          // The I·R·I begins with the expected prefix.
+          const identifier = name.substring(prefix.length);
+          try {
+            // Attempt to resolve the identifier.
+            const instance = storage.get(identifier);
+            return Tag.getSystem(instance) == system
+              ? instance
+              : undefined;
+          } catch {
+            // Do not throw for bad identifiers.
+            return undefined;
+          }
+        }
+      }
+
+      /**
+       * Returns a new `Tag´ resolved from the provided identifier.
+       *
+       * ☡ This function throws if the identifier is invalid.
+       *
+       * ※ If the identifier is valid but not recognized, this
+       * function returns `undefined´.
+       */
+      fromIdentifier(identifier) {
+        const system = this.#system;
+        const storage = this.#storage;
+        const instance = storage.get(identifier);
+        return Tag.getSystem(instance) == system
+          ? instance
+          : undefined;
+      }
+
+      /**
+       * Returns a new `Tag´ resolved from the provided Tag U·R·I.
+       *
+       * ☡ This function throws if the provided Tag U·R·I does not
+       * match the tagging entity of this constructors `TagSystem´.
+       *
+       * ※ If the specific component of the Tag U·R·I is not
+       * recognized, this function returns `undefined´.
+       */
+      fromTagURI(tagURI) {
+        const system = this.#system;
+        const storage = this.#storage;
+        const tagName = `${tagURI}`;
+        const tagPrefix = `tag:${system.taggingEntity}:`;
+        if (!tagName.startsWith(tagPrefix)) {
+          // The Tag U·R·I does not begin with the expected prefix.
+          throw new RangeError(
+            `${ÉTIQUETTE}: Tag U·R·I did not begin with the expected prefix: ${tagURI}`,
+          );
+        } else {
+          // The I·R·I begins with the expected prefix.
+          const identifier = tagName.substring(tagPrefix.length);
+          try {
+            // Attempt to resolve the identifier.
+            const instance = storage.get(identifier);
+            return Tag.getSystem(instance) == system
+              ? instance
+              : undefined;
+          } catch {
+            // Do not throw for bad identifiers.
+            return undefined;
+          }
+        }
+      }
+
+      /**
+       * Yields the tag identifiers in the `TagSystem´ associated with
+       * this constructor.
+       */
+      *identifiers() {
+        const system = this.#system;
+        const storage = this.#storage;
+        for (const [identifier, instance] of storage.entries()) {
+          // Iterate over the entries and yield the ones which are
+          // `Tag´s in this `TagSystem´.
+          if (Tag.getSystem(instance) == system) {
+            // The current instance is a `Tag´ in this `TagSystem´.
+            yield identifier;
+          } else {
+            // The current instance is not a `Tag´ in this `TagSystem´.
+            /* do nothing */
+          }
+        }
+      }
+
+      /** Returns the `TagSystem´ for this `Tag´ constructor. */
+      get system() {
+        return this.#system;
+      }
+
+      /**
+       * Returns a new `Tag´ constructed from the provided data and
+       * with the provided identifier.
+       *
+       * ※ This function is not really intended for public usage.
+       */
+      [Storage.toInstance](data, identifier) {
+        const tag = new this(data.kind);
+        return Tag.assignData(tag, data, identifier);
+      }
+    },
+    TagSuper: tagConstructorBehaviours.TagSuper,
+  };
+})();
+
 const {
   /**
    * Returns whether the provided schema, subject class, object
 const {
   /**
    * Returns whether the provided schema, subject class, object
@@ -1142,8 +1278,8 @@ const {
         domainUnion.some((domain) =>
           domain == "Thing" || domains.has(domain)
         )
         domainUnion.some((domain) =>
           domain == "Thing" || domains.has(domain)
         )
-      ) &&
-        rangeIntersection.every((rangeUnion) =>
+      )
+        && rangeIntersection.every((rangeUnion) =>
           rangeUnion.some((range) =>
             range == "Thing" || ranges.has(range)
           )
           rangeUnion.some((range) =>
             range == "Thing" || ranges.has(range)
           )
@@ -1154,8 +1290,8 @@ const {
 
 const {
   /**
 
 const {
   /**
-   * Returns the provided value converted into a `String` object with
-   * `.["@value"]` and `.["@language"]` properties.
+   * Returns the provided value converted into a `String´ object with
+   * `.["@value"]´ and `.["@language"]´ properties.
    *
    * The same object will be returned for every call with an equivalent
    * value.
    *
    * The same object will be returned for every call with an equivalent
    * value.
@@ -1203,7 +1339,7 @@ const {
     }
   };
 
     }
   };
 
-  /** Returns the `.["@language"]` of this object. */
+  /** Returns the `.["@language"]´ of this object. */
   const getLanguage = Object.defineProperty(
     function () {
       return this["@language"] || null;
   const getLanguage = Object.defineProperty(
     function () {
       return this["@language"] || null;
@@ -1213,9 +1349,9 @@ const {
   );
 
   /**
   );
 
   /**
-   * A `FinalizationRegistry` for language string objects.
+   * A `FinalizationRegistry´ for language string objects.
    *
    *
-   * This simply cleans up the corresponding `WeakRef` in the language
+   * This simply cleans up the corresponding `WeakRef´ in the language
    * map.
    */
   const langStringRegistry = new FinalizationRegistry(
    * map.
    */
   const langStringRegistry = new FinalizationRegistry(
@@ -1235,14 +1371,14 @@ const {
    */
   const languageMap = Object.create(null);
 
    */
   const languageMap = Object.create(null);
 
-  /** Returns the `.["@value"]` of this object. */
+  /** Returns the `.["@value"]´ of this object. */
   const toString = function () {
     return this["@value"];
   };
 
   /**
   const toString = function () {
     return this["@value"];
   };
 
   /**
-   * Returns this object if it has a `.["@language"]`; otherwise, its
-   * `.["@value"]`.
+   * Returns this object if it has a `.["@language"]´; otherwise, its
+   * `.["@value"]´.
    */
   const valueOf = function () {
     return this["@language"] ? this : this["@value"];
    */
   const valueOf = function () {
     return this["@language"] ? this : this["@value"];
@@ -1366,7 +1502,7 @@ const tagData = ($) => {
 /**
  * Returns an identifier corresponding to the provided object.
  *
 /**
  * Returns an identifier corresponding to the provided object.
  *
- * This is either the value of its `.identifier` or its string value.
+ * This is either the value of its `.identifier´ or its string value.
  *
  * ※ This function is not exposed.
  */
  *
  * ※ This function is not exposed.
  */
@@ -1380,31 +1516,34 @@ const toIdentifier = ($) =>
 /**
  * A tag system, with storage.
  *
 /**
  * A tag system, with storage.
  *
- * The `::Tag` constructor available on any `TagSystem` instance can be
- * used to create new `Tag`s within the system.
+ * The `::Tag´ constructor available on any `TagSystem´ instance can be
+ * used to create new `Tag´s within the system.
  */
 export class TagSystem {
  */
 export class TagSystem {
-  /** The cached bound `Tag` constructor for this `TagSystem`. */
+  /** The cached bound `Tag´ constructor for this `TagSystem´. */
   #Tag = null;
 
   #Tag = null;
 
-  /** The domain of this `TagSystem`. */
+  /** The domain of this `TagSystem´. */
   #domain;
 
   #domain;
 
-  /** The date of this `TagSystem`. */
+  /** The date of this `TagSystem´. */
   #date;
 
   #date;
 
-  /** The identifier of this `TagSystem`. */
+  /** The identifier of this `TagSystem´. */
   #identifier;
 
   #identifier;
 
-  /** The internal `Storage` of this `TagSystem`. */
+  /** The schema used by this `TagSystem´. */
+  #schema = schema;
+
+  /** The internal `Storage` of this `TagSystem´. */
   #storage = new Storage();
 
   /**
   #storage = new Storage();
 
   /**
-   * Constructs a new `TagSystem` with the provided domain and date.
+   * Constructs a new `TagSystem´ with the provided domain and date.
    *
    * Only actual, lowercased domain names are allowed for the domain,
    * and the date must be “full” (include month and day components).
    *
    * Only actual, lowercased domain names are allowed for the domain,
    * and the date must be “full” (include month and day components).
-   * This is for alignment with general best practices for Tag URI’s.
+   * This is for alignment with general best practices for Tag U·R·I¦s.
    *
    * ☡ This constructor throws if provided with an invalid date.
    */
    *
    * ☡ This constructor throws if provided with an invalid date.
    */
@@ -1426,8 +1565,8 @@ export class TagSystem {
       // ☡ The domain is invalid.
       throw new RangeError(`Invalid domain: ${domain}.`);
     } else if (
       // ☡ The domain is invalid.
       throw new RangeError(`Invalid domain: ${domain}.`);
     } else if (
-      !/^\d{4}-\d{2}-\d{2}$/u.test(dateString) ||
-      dateString != new Date(dateString).toISOString().split("T")[0]
+      !/^\d{4}-\d{2}-\d{2}$/u.test(dateString)
+      || dateString != new Date(dateString).toISOString().split("T")[0]
     ) {
       // ☡ The date is invalid.
       throw new RangeError(`Invalid date: ${date}.`);
     ) {
       // ☡ The date is invalid.
       throw new RangeError(`Invalid date: ${date}.`);
@@ -1439,8 +1578,8 @@ export class TagSystem {
   }
 
   /**
   }
 
   /**
-   * Returns a bound constructor for constructing `Tags` in this
-   * `TagSystem`.
+   * Returns a bound constructor for constructing `Tags´ in this
+   * `TagSystem´.
    */
   get Tag() {
     if (this.#Tag != null) {
    */
   get Tag() {
     if (this.#Tag != null) {
@@ -1449,32 +1588,191 @@ export class TagSystem {
     } else {
       // No bound constructor has been created yet.
       const storage = this.#storage;
     } else {
       // No bound constructor has been created yet.
       const storage = this.#storage;
-      return this.#Tag = Tag.For(this, storage, schema);
+      return this.#Tag = Tag.For(this, storage, this.#schema);
+    }
+  }
+
+  /**
+   * Applies the provided activity to this `TagSystem´ by replaying its
+   * statement changes.
+   *
+   * ※ This method assumes that the provided activity conforms to the
+   * assumptions made by this module; i·e that its tags use the same
+   * identifier format and its activities do not use statements with
+   * inverse property predicates. It is not intended for the generic
+   * playback of activities produced by other scripts or mechanisms,
+   * for which a more sophisticated solution is required.
+   *
+   * ☡ This method throws an error if the provided activity cannot be
+   * processed.
+   */
+  apply(activity) {
+    const { Tag: TagConstructor } = this;
+    const {
+      classes,
+      objectProperties,
+      transitiveProperties,
+      dataProperties,
+    } = this.#schema;
+    const { object, states, unstates } = activity;
+    const activityTypes = [].concat(activity["@type"]);
+    if (!object) {
+      // ☡ The provided activity has no object.
+      throw new TypeError(
+        `${ÉTIQUETTE}: Cannot apply activity: Activity lacks an object.`,
+      );
+    } else {
+      // The provided activity has an object.
+      const iri = `${object}`;
+      const iriSpace = `${this.iriSpace}`;
+      const identifier = (() => {
+        // Extract the identifier from the object I·R·I.
+        if (!iri.startsWith(iriSpace)) {
+          // ☡ The object of the provided activity is not in the I·R·I
+          // space of this `TagSystem´.
+          throw new RangeError(
+            `Cannot apply activity: Object is not in I·R·I space: ${object}`,
+          );
+        } else {
+          // ☡ The object of the provided activity is in the I·R·I
+          // space of this `TagSystem´.
+          return iri.substring(iriSpace.length);
+        }
+      })();
+      const tag = (() => {
+        // Either resolve the identifier to an existing tag or create
+        // a new one.
+        if (activityTypes.includes("Create")) {
+          // The provided activity is a Create activity.
+          const kind = states.findLast(
+            ({ predicate, object }) =>
+              predicate == "a" && `${object}` in classes,
+          )?.object;
+          if (kind == null) {
+            // ☡ There is no recognized tag class provided for the tag;
+            // it cannot be created.
+            throw new RangeError(
+              `Cannot apply activity: Tag type not recognized.`,
+            );
+          } else {
+            // There is a recognized tag class provided for the tag.
+            return Tag.new(this, identifier, kind);
+          }
+        } else {
+          // The provided activity is not a Create activity.
+          return TagConstructor.fromIdentifier(identifier);
+        }
+      })();
+      if (!tag) {
+        // ☡ Resolving the tag identifier failed.
+        throw new RangeError(
+          `${ÉTIQUETTE}: Cannot apply activity: No tag for identifier: ${identifier}.`,
+        );
+      } else {
+        // Resolving the identifier succeeded; apply the changes to the
+        // tag and then silently persist it.
+        for (
+          const [statements, mode] of [
+            [unstates ?? [], "delete"],
+            [states ?? [], "add"],
+          ]
+        ) {
+          // Delete unstatements, then add statements.
+          for (const { predicate: $p, object: $o } of statements) {
+            // Iterate over the statements and apply them.
+            const predicate = `${$p}`;
+            const term = predicate in dataProperties
+              ? langString($o)
+              : predicate in objectProperties
+                  && !(predicate in transitiveProperties
+                    || objectProperties[predicate].inverseOf != null)
+              ? `${$o}`
+              : null;
+            if (term == null) {
+              // The provided predicate is not recognized; ignore it.
+              /* do nothing */
+            } else if (predicate == "prefLabel") {
+              // Preflabels are handled specially.
+              if (mode == "delete") {
+                // Unstating a preflabel has no effect unless a new one
+                // is also stated.
+                /* do nothing */
+              } else {
+                // Update the preflabel.
+                tag.prefLabel = term;
+              }
+            } else {
+              // The predicate is not `"prefLabel"´.
+              const related = (() => {
+                // If the predicate is an object property, attempt to
+                // resolve the object.
+                if (!(predicate in objectProperties)) {
+                  // The predicate is not an object property; return
+                  // null.
+                  return null;
+                } else {
+                  // The predicate is an object property.
+                  try {
+                    // Attempt to resolve the object.
+                    return TagConstructor.fromIRI(term);
+                  } catch {
+                    // Resolving failed; return undefined.
+                    return undefined;
+                  }
+                }
+              })();
+              if (related === undefined) {
+                // The predicate is an object property, but its object
+                // was not resolvable.
+                //
+                // ☡ This is a silent error to allow for selective
+                // replay of activities while ignoring terms which are
+                // not covered.
+                /* do nothing */
+              } else {
+                // The predicate is not an object property or has a
+                // resolvable object.
+                //
+                // Apply the statement.
+                tag[
+                  mode.concat(
+                    predicate[0].toUpperCase(),
+                    predicate.substring(1),
+                    predicate in objectProperties ? "Tag" : "",
+                  )
+                ](related ?? term);
+              }
+            }
+          }
+        }
+        tag.persist(true);
+        return tag;
+      }
     }
   }
 
     }
   }
 
-  /** Returns the authority name (domain) for this `TagSystem`. */
+  /** Returns the authority name (domain) for this `TagSystem´. */
   get authorityName() {
     return this.#domain;
   }
 
   get authorityName() {
     return this.#domain;
   }
 
-  /** Returns the date of this `TagSystem`, as a string. */
+  /** Returns the date of this `TagSystem´, as a string. */
   get date() {
     return this.#date;
   }
 
   /**
   get date() {
     return this.#date;
   }
 
   /**
-   * Yields the entities in this `TagSystem`.
+   * Yields the entities in this `TagSystem´.
    *
    * ※ Entities can hypothetically be anything. If you specifically
    *
    * ※ Entities can hypothetically be anything. If you specifically
-   * want the `Tag`s, use `::Tag.all` instead.
+   * want the `Tag´s, use `::Tag.all´ instead.
    */
   *entities() {
     yield* this.#storage.values();
   }
 
   /**
    */
   *entities() {
     yield* this.#storage.values();
   }
 
   /**
-   * Returns the identifier of this `TagSystem`.
+   * Returns the identifier of this `TagSystem´.
    *
    * ※ Often this is just the empty string.
    */
    *
    * ※ Often this is just the empty string.
    */
@@ -1482,30 +1780,30 @@ export class TagSystem {
     return this.#identifier;
   }
 
     return this.#identifier;
   }
 
-  /** Yields the identifiers in use in this `TagSystem`. */
+  /** Yields the identifiers in use in this `TagSystem´. */
   *identifiers() {
     yield* this.#storage.keys();
   }
 
   *identifiers() {
     yield* this.#storage.keys();
   }
 
-  /** Returns the I·R·I for this `TagSystem`. */
+  /** Returns the I·R·I for this `TagSystem´. */
   get iri() {
     return `${this.iriSpace}${this.identifier}`;
   }
 
   /**
   get iri() {
     return `${this.iriSpace}${this.identifier}`;
   }
 
   /**
-   * Returns the prefix used for I·R·I’s of `Tag`s in this `TagSystem`.
+   * Returns the prefix used for I·R·I¦s of `Tag´s in this `TagSystem´.
    */
   get iriSpace() {
     return `https://${this.authorityName}/tag:${this.taggingEntity}:`;
   }
 
    */
   get iriSpace() {
     return `https://${this.authorityName}/tag:${this.taggingEntity}:`;
   }
 
-  /** Returns the Tag U·R·I for this `TagSystem`. */
+  /** Returns the Tag U·R·I for this `TagSystem´. */
   get tagURI() {
     return `tag:${this.taggingEntity}:${this.identifier}`;
   }
 
   /**
   get tagURI() {
     return `tag:${this.taggingEntity}:${this.identifier}`;
   }
 
   /**
-   * Returns the tagging entity (domain and date) for this `TagSystem`.
+   * Returns the tagging entity (domain and date) for this `TagSystem´.
    */
   get taggingEntity() {
     return `${this.authorityName},${this.date}`;
    */
   get taggingEntity() {
     return `${this.authorityName},${this.date}`;
This page took 0.309068 seconds and 4 git commands to generate.