diff --git a/project.clj b/project.clj index d7c0230..48c4131 100644 --- a/project.clj +++ b/project.clj @@ -1,24 +1,118 @@ (defproject dog-and-duck/quack "0.1.0-SNAPSHOT" + :aliases {"test-cljs" ["with-profile" "test" "doo" "rhino" "test" "once"] + "test-all" ["do" ["test"] ["test-cljs"]]} + :cljsbuild {:builds + [{:id "dev" + :source-paths ["src"] + + ;; The presence of a :figwheel configuration here + ;; will cause figwheel to inject the figwheel client + ;; into your build + :figwheel {:on-jsload "froboz.core/on-js-reload" + ;; :open-urls will pop open your application + ;; in the default browser once Figwheel has + ;; started and compiled your application. + ;; Comment this out once it no longer serves you. + :open-urls ["http://localhost:3449/index.html"]} + + :compiler {:main froboz.core + :asset-path "js/compiled/out" + :output-to "resources/public/js/compiled/froboz.js" + :output-dir "resources/public/js/compiled/out" + :source-map-timestamp true + ;; To console.log CLJS data-structures make sure you enable devtools in Chrome + ;; https://github.com/binaryage/cljs-devtools + :preloads [devtools.preload]}} + ;; This next build is a compressed minified build for + ;; production. You can build this with: + ;; lein cljsbuild once min + {:id "min" + :source-paths ["src"] + :compiler {:output-to "resources/public/js/compiled/froboz.js" + :main froboz.core + :optimizations :advanced + :pretty-print false}}]} + :cloverage {:output "docs/cloverage" :codecov? true :emma-xml? true} -:codox {:metadata {:doc "**TODO**: write docs" - :doc/format :markdown} - :output-path "docs/codox" - :source-uri "https://github.com/simon-brooke/quack/blob/master/{filepath}#L{line}"} + :codox {:metadata {:doc "**TODO**: write docs" + :doc/format :markdown} + :output-path "docs/codox" + :source-uri "https://github.com/simon-brooke/quack/blob/master/{filepath}#L{line}"} :dependencies [[com.taoensso/timbre "6.0.4"] [hiccup "1.0.5"] [mvxcvi/clj-pgp "1.1.0"] [org.clojars.simon_brooke/internationalisation "1.0.5"] [org.clojure/clojure "1.10.3"] + [org.clojure/clojurescript "1.10.773"] + [org.clojure/core.async "0.4.500"] [org.clojure/data.json "2.4.0"] [org.clojure/tools.cli "1.0.214"] [trptr/java-wrapper "0.2.3"]] :description "A validator for ActivityStreams." + :doo {:paths {:rhino "lein run -m org.mozilla.javascript.tools.shell.Main"}} + + :figwheel {;; :http-server-root "public" ;; default and assumes "resources" + ;; :server-port 3449 ;; default + ;; :server-ip "127.0.0.1" + + :css-dirs ["resources/public/css"] ;; watch and update CSS + + ;; Start an nREPL server into the running figwheel process + ;; :nrepl-port 7888 + + ;; Server Ring Handler (optional) + ;; if you want to embed a ring handler into the figwheel http-kit + ;; server, this is for simple ring servers, if this + + ;; doesn't work for you just run your own server :) (see lein-ring) + + ;; :ring-handler hello_world.server/handler + + ;; To be able to open files in your editor from the heads up display + ;; you will need to put a script on your path. + ;; that script will have to take a file path and a line number + ;; ie. in ~/bin/myfile-opener + ;; #! /bin/sh + ;; emacsclient -n +$2 $1 + ;; + ;; :open-file-command "myfile-opener" + + ;; if you are using emacsclient you can just use + ;; :open-file-command "emacsclient" + + ;; if you want to disable the REPL + ;; :repl false + + ;; to configure a different figwheel logfile path + ;; :server-logfile "tmp/logs/figwheel-logfile.log" + + ;; to pipe all the output to the repl + ;; :server-logfile false + } :license {:name "GPL-2.0-or-later" :url "https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html"} :main ^:skip-aot dog-and-duck.quack.core - :profiles {:uberjar {:aot :all + :plugins [[lein-cljsbuild "1.1.3"] + [lein-doo "0.1.6"]] + :profiles {:dev {:dependencies [[binaryage/devtools "1.0.0"] + [figwheel-sidecar "0.5.20"]] + ;; need to add dev source path here to get user.clj loaded + :source-paths ["src/cljs" "src/cljc" "dev"] + ;; need to add the compiled assets to the :clean-targets + :clean-targets ^{:protect false} ["resources/public/js/compiled" + :target-path]} + :test {:dependencies [[org.mozilla/rhino "1.7.7"]] + :cljsbuild + {:builds + {:test + {:source-paths ["src" "test"] + :compiler {:output-to "target/main.js" + :output-dir "target" + ;; :main {{top-namespace}}.test-runner + :optimizations :simple}}}}} + :uberjar {:aot :all :jvm-opts ["-Dclojure.compiler.direct-linking=true"]}} :repl-options {:init-ns dog-and-duck.quack.core} :target-path "target/%s" diff --git a/src/dog_and_duck/quack/constants.clj b/src/clj/dog_and_duck/quack/constants.clj similarity index 100% rename from src/dog_and_duck/quack/constants.clj rename to src/clj/dog_and_duck/quack/constants.clj diff --git a/src/dog_and_duck/quack/control_variables.clj b/src/clj/dog_and_duck/quack/control_variables.clj similarity index 100% rename from src/dog_and_duck/quack/control_variables.clj rename to src/clj/dog_and_duck/quack/control_variables.clj diff --git a/src/dog_and_duck/quack/core.clj b/src/clj/dog_and_duck/quack/core.clj similarity index 100% rename from src/dog_and_duck/quack/core.clj rename to src/clj/dog_and_duck/quack/core.clj diff --git a/src/dog_and_duck/quack/objects.clj b/src/clj/dog_and_duck/quack/objects.clj similarity index 95% rename from src/dog_and_duck/quack/objects.clj rename to src/clj/dog_and_duck/quack/objects.clj index 5a4fa54..85b4a41 100644 --- a/src/dog_and_duck/quack/objects.clj +++ b/src/clj/dog_and_duck/quack/objects.clj @@ -1,6 +1,8 @@ (ns dog-and-duck.quack.objects (:require [clojure.data.json :as json] + [clojure.pprint :refer [pprint]] [clojure.set :refer [union]] + [clojure.string :refer [join]] [clojure.walk :refer [keywordize-keys]] [dog-and-duck.quack.constants :refer [actor-types noun-types @@ -20,7 +22,7 @@ object-or-uri? truthy? xsd-non-negative-integer?]] - [taoensso.timbre :refer [warn]]) + [taoensso.timbre :refer [info warn error]]) (:import [java.io FileNotFoundException] [java.net URI URISyntaxException])) @@ -138,6 +140,35 @@ :severity severity :token token})))) +(defn- percentage-value? + "Return `true` if `x` is a number between 0 and 100 inclusive, else + `false`." + [x] + (try (and (xsd-float? x) + (>= x 0) + (<= x 100)) + (catch Exception any + (error (join " " + ["Unexpected value (" + x + ") passed to `percentage-value?`:" + (-> any .getClass .getName) + ":" (.getMessage any)])) + false))) + +(defn positive? + "Return `true` if `x` is a number which is greater than 0, else `false`" + [x] + (try + (pos? x) + (catch Exception any + (error (join " " + ["Unexpected value (" + x + ") passed to `positive?`:" + (-> any .getClass .getName) + ":" (.getMessage any)])) + false))) (def object-expected-properties "Requirements of properties of object, cribbed from @@ -162,9 +193,7 @@ which will be applied to the value or values of the identified property." {:accuracy {:functional false :if-invalid [:must :invalid-number] - :validator (fn [pv] (and (xsd-float? pv) - (>= pv 0) - (<= pv 100)))} + :validator percentage-value?} :actor {:functional false :if-invalid [:must :invalid-actor] :if-missing [:must :no-actor] @@ -435,7 +464,7 @@ :invalid-replies))} :radius {:functional true :if-invalid [:must :invalid-positive-number] - :validator (fn [pv] (and (xsd-float? pv) (> pv 0)))} + :validator positive?} :rel {:functional false :if-invalid [:must :invalid-link-relation] ;; TODO: this is not really good enough. @@ -526,6 +555,11 @@ return `nil` if no faults are found, else a list of faults." [obj prop clause] ;; (info "obj" obj "prop" prop "clause" clause) + (info (join " " ["Checking validity of property" + prop "of object\n" (with-out-str + (pprint obj)) + "\nusing clause\n" + (with-out-str (pprint clause))])) (let [val (obj prop) validator (:validator clause) [severity token] (:if-invalid clause)] diff --git a/src/dog_and_duck/quack/scratch.clj b/src/clj/dog_and_duck/quack/scratch.clj similarity index 81% rename from src/dog_and_duck/quack/scratch.clj rename to src/clj/dog_and_duck/quack/scratch.clj index f40107b..20fc094 100644 --- a/src/dog_and_duck/quack/scratch.clj +++ b/src/clj/dog_and_duck/quack/scratch.clj @@ -1,6 +1,9 @@ (ns dog-and-duck.quack.scratch "Development scratchpad" - (:require [dog-and-duck.quack.objects :refer [object-expected-properties]] + (:require [clojure.data.json :refer [read-str]] + [clojure.pprint :refer [pprint]] + [clojure.walk :refer [keywordize-keys]] + [dog-and-duck.quack.objects :refer [object-expected-properties]] [dog-and-duck.quack.utils :refer [concat-non-empty]])) (defn missing-messages @@ -20,4 +23,9 @@ ;; {:@context "https://simon-brooke.github.io/dog-and-duck/codox/Validation_Faults.html", ;; :id "https://illuminator.local/fault/25785:1673378166063", :type "Fault", :severity :minor, :fault :no-id-transient, :narrative "The ActivityPub specification allows objects without `id` fields only if they are intentionally transient; even so it is preferred that the object should have an explicit null id."} ;; ({:@context "https://simon-brooke.github.io/dog-and-duck/codox/Validation_Faults.html", -;; :id "https://illuminator.local/fault/25785:1673378166069", :type "Fault", :severity :must, :fault :invalid-type, :narrative "invalid-type"})), :severity :info}}) \ No newline at end of file +;; :id "https://illuminator.local/fault/25785:1673378166069", :type "Fault", :severity :must, :fault :invalid-type, :narrative "invalid-type"})), :severity :info}}) + +(def obj (keywordize-keys + (read-str + (slurp "../dog-and-duck/resources/activitystreams-test-documents//vocabulary-ex190-jsonld.json") + ))) diff --git a/src/dog_and_duck/quack/time.clj b/src/clj/dog_and_duck/quack/time.clj similarity index 100% rename from src/dog_and_duck/quack/time.clj rename to src/clj/dog_and_duck/quack/time.clj diff --git a/src/dog_and_duck/quack/utils.clj b/src/clj/dog_and_duck/quack/utils.clj similarity index 100% rename from src/dog_and_duck/quack/utils.clj rename to src/clj/dog_and_duck/quack/utils.clj