]> Lady’s Gitweb - Etiquette/blobdiff - schema.js
Use configurable metadata for model
[Etiquette] / schema.js
diff --git a/schema.js b/schema.js
new file mode 100644 (file)
index 0000000..c708cfe
--- /dev/null
+++ b/schema.js
@@ -0,0 +1,114 @@
+// 📧🏷️ Étiquette ∷ schema.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/>.
+//
+// ___
+//
+// ※ The definitions in this file are minimal and only really geared
+// towards supporting the functionality that 📧🏷️ Étiquette needs.
+
+/**
+ * Supported class types.
+ *
+ * The class `"Thing"` is not defined, but is used as a generic
+ * superclass.
+ */
+const classes = {
+  Tag: { subClassOf: "Thing" },
+  CanonTag: { subClassOf: "Tag" },
+  ConceptualTag: { subClassOf: "Tag" },
+  RelationshipTag: {
+    subClassOf: ["ConceptualTag", {
+      onProperty: "involves",
+      allValuesFrom: {
+        unionOf: ["CharacterTag", "RelationshipTag"],
+      },
+    }],
+  },
+  FriendshipTag: { subClassOf: "RelationshipTag" },
+  RivalryTag: { subClassOf: "RelationshipTag" },
+  FamilialRelationshipTag: { subClassOf: "RelationshipTag" },
+  RomanticRelationshipTag: { subClassOf: "RelationshipTag" },
+  SexualRelationshipTag: { subClassOf: "RelationshipTag" },
+  EntityTag: { subClassOf: "Tag" },
+  CharacterTag: { subClassOf: "EntityTag" },
+  InanimateEntityTag: { subClassOf: "EntityTag" },
+  GenreTag: { subClassOf: "Tag" },
+  SettingTag: { subClassOf: "Tag" },
+  LocationTag: { subClassOf: "SettingTag" },
+  TimePeriodTag: { subClassOf: "SettingTag" },
+  UniverseTag: { subClassOf: "SettingTag" },
+};
+
+/** Supported transitive object properties. */
+const transitiveProperties = {
+  broaderTransitive: { domain: "Tag", range: "Tag" },
+  narrowerTransitive: { inverseOf: "broaderTransitive" },
+};
+
+/** Supported object properties. */
+const objectProperties = {
+  broader: { subPropertyOf: "broaderTransitive" },
+  narrower: {
+    inverseOf: "broader",
+    subPropertyOf: "narrowerTransitive",
+  },
+  inCanon: {
+    domain: { unionOf: ["EntityTag", "SettingTag"] },
+    range: "CanonTag",
+  },
+  hasInCanon: { inverseOf: "inCanon" },
+  involves: { domain: "ConceptualTag", range: "Tag" },
+  involvedIn: { inverseOf: "involves" },
+  ...transitiveProperties,
+};
+
+/** Supported data properties. */
+const dataProperties = {
+  prefLabel: { domain: "Thing", range: "PlainLiteral" },
+  altLabel: { domain: "Thing", range: "PlainLiteral" },
+  hiddenLabel: { domain: "Thing", range: "PlainLiteral" },
+};
+
+/**
+ * Returns an immutable, null‐prototype object deeply derived from the
+ * provided one.
+ *
+ * ※ Once records and tuples are added to Ecmascript, the schema
+ * should be defined in terms of those primitives. In the meantime,
+ * this function at least ensures the schema is Very Immutable.
+ */
+const makeRecord = ($) => {
+  return Object.preventExtensions(
+    Object.create(
+      null,
+      Object.fromEntries([...function* () {
+        for (const [key, value] of Object.entries($)) {
+          if (Object(value) === value) {
+            const recordValue = makeRecord(value);
+            yield [key, { enumerable: true, value: recordValue }];
+          } else {
+            yield [key, { enumerable: true, value }];
+          }
+        }
+        if (Array.isArray($)) {
+          yield ["length", { value: $.length }];
+        } else {
+          /* do nothing */
+        }
+      }()]),
+    ),
+  );
+};
+
+export default makeRecord({
+  classes,
+  objectProperties,
+  transitiveProperties,
+  dataProperties,
+});
This page took 0.241967 seconds and 4 git commands to generate.