From f326fad9f4ee4b401ab4437076288bea026982c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Madeleine=20Sydney=20=C5=9Alaga?= Date: Thu, 12 Mar 2026 11:00:42 -0600 Subject: [PATCH] --- doerg/src/net/deertopia/doerg/element.clj | 110 +++++++++++++++--- .../test/net/deertopia/doerg/element_test.clj | 43 +++---- 2 files changed, 115 insertions(+), 38 deletions(-) diff --git a/doerg/src/net/deertopia/doerg/element.clj b/doerg/src/net/deertopia/doerg/element.clj index 75e9604..b48c387 100644 --- a/doerg/src/net/deertopia/doerg/element.clj +++ b/doerg/src/net/deertopia/doerg/element.clj @@ -1,21 +1,24 @@ (ns net.deertopia.doerg.element - (:require [babashka.process :as p] - [net.deertopia.doerg.common :as common] - [clojure.string :as str] - [clojure.zip] - [babashka.fs :as fs] - [clojure.java.io :as io] - [cheshire.core :as json] - [clojure.spec.alpha :as s] - [spec-dict.main :refer [dict]] - [net.deertopia.doerg.config :as cfg] - [com.rpl.specter :as sp] - [clojure.tools.logging.readable :as lr] - [clojure.zip :as z] - [com.rpl.specter.zipper :as sz] - [clojure.core.match :refer [match]]) - (:import (java.util UUID)) - (:refer-clojure :exclude [read-string])) + (:refer-clojure :exclude [read-string]) + (:require + [babashka.fs :as fs] + [babashka.process :as p] + [cheshire.core :as json] + [clojure.core.match :refer [match]] + [clojure.java.io :as io] + [clojure.set :as set] + [clojure.spec.alpha :as s] + [clojure.string :as str] + [clojure.tools.logging.readable :as lr] + [clojure.zip :as z] + [com.rpl.specter :as sp] + [com.rpl.specter.zipper :as sz] + [net.deertopia.doerg.common :as common] + [net.deertopia.doerg.config :as cfg] + [spec-dict.main :refer [dict]]) + (:import + (java.util UUID))) + (def ^:dynamic *uniorg-timeout-duration* @@ -37,7 +40,7 @@ (if (zero? (:exit r)) (-> r :out (json/parse-string (comp keyword camel->kebab)))))) -(declare gather-first-section gather-latex-paragraphs) +(declare gather-first-section gather-latex-paragraphs element-types) (defn read-string [s & {:keys [post-processors] @@ -65,6 +68,9 @@ (and (map? element) (contains? element :type))) +(defn type [element] + (:type element)) + (defn of-type? "Return truthy if the Org node `element` is of type `type`. In the vararg case, return truthy if `element` is of any of the types @@ -280,3 +286,71 @@ [c & rest] (recur (conj acc c) rest) [] acc)))))) + + +;;; Specs + +;; Data taken from uniorg/index.d.ts + +(comment + (defn- typescript-enum->set [s] + (as-> s + it + (str/split it #" \| ") + (map camel->kebab it) + (into #{} it)))) + +(def greater-element-types + #{"org-data" "section" "property-drawer" "drawer" "list" "list-item" + "quote-block" "verse-block" "center-block" "special-block" + "footnote-definition" "table"}) + +(def element-types + #{"list-item-tag" "src-block" "comment-block" "latex-environment" + "keyword" "paragraph" "node-property" "example-block" "clock" + "planning" "diary-sexp" "fixed-width" "export-block" + "horizontal-rule" "comment" "table-row" "headline"}) + +(def element-types + (set/union greater-element-types element-types)) + +(def object-types + #{"citation" "line-break" "citation-suffix" "footnote-reference" + "statistics-cookie" "timestamp" "superscript" "text" "table-cell" + "link" "verbatim" "italic" "citation-common-prefix" "subscript" + "citation-key" "export-snippet" "citation-prefix" + "citation-common-suffix" "latex-fragment" "strike-through" "entity" + "citation-reference" "bold" "underline" "code"}) + +(s/def ::greater-element-type + greater-element-types) + +(s/def ::element-type + element-types) + +(s/def ::object-type + object-types) + +(s/def ::contents-begin nat-int?) +(s/def ::contents-end nat-int?) + +(defmulti element-spec type) +(defmulti object-spec type) + +(s/def ::object (s/multi-spec object-spec type)) + +(s/def ::element + (s/and (dict ^:opt {:contents-begin ::contents-begin + :contents-end ::contents-end} + {:children (s/coll-of ::object :kind vector?) + :type ::element-type}) + (s/multi-spec element-spec type))) + +(defmethod object-spec "text" [_] + (dict {:value string?})) + +#_ +(s/def ::greater-element + (s/keys :req-un [::contents-begin + ::contents-end + (s/coll-of ::element-type vector?)])) diff --git a/doerg/test/net/deertopia/doerg/element_test.clj b/doerg/test/net/deertopia/doerg/element_test.clj index d1288da..08495ad 100644 --- a/doerg/test/net/deertopia/doerg/element_test.clj +++ b/doerg/test/net/deertopia/doerg/element_test.clj @@ -57,28 +57,31 @@ ()) (defn- paragraph-ends-with-latex? [doc] - (-> (sp/select-first [(walk-types "paragraph") - (sp/must :children) - sp/LAST] - doc) - (sut/of-type? "latex-environment"))) + (let [type (-> (sp/select-first [(walk-types "paragraph") + (sp/must :children) + sp/LAST] + doc) + sut/type)] + (t/is type "latex-environment"))) (defn- paragraph-has-latex? [doc] - (sp/select-first [(walk-types "paragraph") - (sp/must :children) - sp/ALL - #(sut/of-type? % "latex-environment")] - doc)) + (t/is (sp/select-first [(walk-types "paragraph") + (sp/must :children) + sp/ALL + #(sut/of-type? % "latex-environment")] + doc))) (defn- paragraph-has-multiple-latex? [doc] - (let [[interleaved fenceposted] - (sp/select [(walk-types "section") - (sp/must :children) - #(some-> % first (sut/of-type? "headline")) - (sp/subselect (sp/view #(drop 1 %)) - sp/ALL (sp/must :children) sp/ALL - (sp/must :type))] - doc)])) + (let [paragraphs (sp/select (walk-types "paragraph") doc)] + (t/is (= 2 (count paragraphs))) + (let [[p₁ p₂] paragraphs] + (t/are [p ts] (= ts + (sp/select [(sp/must :children) + sp/ALL (sp/view sut/type)] p)) + p₁ ["text" "latex-environment" + "text" "latex-environment"] + p₂ ["text" "latex-environment" + "text" "latex-environment" "text"])))) (t/deftest paragraph-separation (t/testing "paragraph ending with latex" @@ -88,5 +91,5 @@ (-> (parse-resource "paragraph-surrounding-latex.org") paragraph-has-latex?)) (t/testing "paragraph with interleaved latex" - (let [(parse-resource "paragraph-with-multiple-latex.org")]) - (t/is (-)))) + (-> (parse-resource "paragraph-with-multiple-latex.org") + paragraph-has-multiple-latex?)))