squint 2025-05-05

Are any of the clojure validation/spec libraries available for use with #squint? I saw on one thread that its possible to compile a cljs library with squint to make it consumable as a library. Has that been tried for - e.g. clojure spec // plumatic schema // malli ?

@zach.charlop.powers did you progressed on this? Just having the same requirement here, I really missing a validation input for some of my functions that I would benefit a lot from something like schema/malli

No. The data I was interested in had a JSON schema so I used that.

👍 2

I did put an example of using ajv in the squint repo

I really miss the function annotation, where you can define input / output schemas and validate in tests. I'm going to check the ajv example, how is your workflow? Define the scheme and validate inside the funcion?

currently no. perhaps there is one in the JS library ecosystem?

Thank you @borkdude! Yes. In my case I am weighing the build simplicity of squint (+ js validator) vs a true clojurescipt + spec/et.al. The data domain I am working with is relatively deeply nested would benefit from the composability of e.g. spec.

don't know how well it works with nested data

👍 1

I'll take a look. thank you

JSON schema may also work for you

👍 1

I am wondering how hard it would be to to write a Malli->joi ....

probably hard :)

lol. true. I think the JSON schema is most practical although its a bit less clj intruitive about keys etc. But I think I will try that route. Thank you.

i guess you can build stuff around it to make it nicer for clojure

I am hitting the following import issue in squint. I am aiming to us use Ajv to validate an OpenAPISpec and use that from my project. addFormats is supposedly used to extend to AJV to consume different spec dialects. Is there a way to alter/influence squint's imports?

(ns mvsj
  (:require ["fs" :as fs]
            ["url" :refer [fileURLToPath]]
            ["ajv" :refer [Ajv]]
            ["ajv-formats" :refer [addFormats]]))
file:///Users/zcpowers/Downloads/squint-mol/mvsj.mjs:5
import { addFormats } from 'ajv-formats';
         ^^^^^^^^^^
SyntaxError: Named export 'addFormats' not found. The requested module 'ajv-formats' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from 'ajv-formats';
const { addFormats } = pkg;

I think you probably need to do it like this:

["ajv-formats$default" :refer [addFormats]]

since it's a cjs module rather than ESM

the error message kind of hints at that

Now I know what this means: CommonJS modules can always be imported via the default export,

yeah sorry, it might not be clear to you what $default means. it's the standard ClojureScript notation to import a default export

Probably we need to add this to the README of squint. PR welcome :)

👍 1

Once I get this sorted I'll be happy to submit a PR

Apologies but one more continuation related to importing.

import default$1 from 'ajv-formats';
const { addFormats } = default$1;

file:///Users/zcpowers/Downloads/squint-mol/mvsj.mjs:248
const _5 = addFormats(ajv1, ({  }));
           ^

TypeError: addFormats is not a function

it's best to just console.log the ajv-formats thing and inspect it so you know what exists at runtime

e.g.:

["ajv-formats" :as ajv]

(js/console.log ajv)

if it prints something like Module with default, then add $default and try the same thing

and then you should see addFormats in there somewhere hopefully

oh wait you mean this?

import addFormats from "ajv-formats"

this should look like this in squint:

(:require ["ajv-formats$default" :as addFormats])

👍 1

so you import the default and give it the name addFormats

The last one worked. Now onto troubleshooting the openAPI call. Will post repro example as PR once worked out. TY

🙌 1
✅ 1

Awesome thank you!

Is there a gensym alternative for #squint? Any drop in alternatives?

[squint] Running test_macro.cljs
file:///Users/zcpowers/Downloads/squint-mol/test_macro.mjs:3
const name_sym1 = gensym("name");

squint doesn't have symbol, so it also doesn't have gensym

If you want to share code, you can hit the share button and paste the link here, even better than a screenshot :)

🤯 1

ah! this is what I'm working on. little macro to condense JSON creation. (def gen (let [counter (atom 0)] (fn [prefix] (swap! counter inc) (str prefix @counter)))) (defmacro nodize "Transforms a hiccup-like vector [:name props children] into a node map." [form] (let [name-sym (gen "name") props-sym (gen "props") children-sym (gen "children")] `(let [[name-sym props-sym children-sym] form] (cond-> {"kind" (name ~name-sym)} (not (empty? props-sym)) (assoc "params" props-sym) (seq children-sym) (assoc "children" (mapv nodize children-sym)))))) (nodize [:thing1 {:prop1 "container"} [[:thing2 {} []] [:thing3 {:prop2 "awesome"} []]]])

That's cool, but macros don't work in the playground unfortunately (yet). Macros have to live in a separate file and have to be loaded with :require-macros

👍 1

You can use gensym in macros since they are executed in SCI, not in the target runtime

(ns nextjournal.clojure-mode-tests
  (:require #?@(:squint []
                :cljs [[cljs.test :refer [are testing deftest is]]])
            [nextjournal.clojure-mode :as cm-clojure]
            [nextjournal.clojure-mode.util :as util]
            [nextjournal.clojure-mode.test-utils :as test-utils]
            [nextjournal.clojure-mode.extensions.close-brackets :as close-brackets]
            [nextjournal.clojure-mode.commands :as commands]
            [nextjournal.clojure-mode.extensions.formatting :as format]
            [nextjournal.clojure-mode.extensions.eval-region :as eval-region]
            [nextjournal.scratch]
            #?@(:squint []
                :cljs [[nextjournal.livedoc :as livedoc]])
            #?(:squint ["assert" :as assert]))
  #?(:squint (:require-macros [nextjournal.clojure-mode-tests.macros :refer [deftest are testing is]])))

^ I was running into require-macro problems and looking up how youv'e done it elsewhere. Looks like a :squint key is required.

no that is only in .cljc files where you use a reader conditional

Thanks I'll work off of that I kept running into errors like this but didn't have a minimal working example to work from.

[squint] Compiling CLJS file: /Users/zcpowers/Downloads/squint-mol/src/mvsj/core.cljs
node:fs:441
      path = getValidatedPath(path);
             ^

TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string or an instance of Buffer or URL. Received null

do you have a squint.edn already?

the macro needs to be somewhere in a directory that is mentioned in :source-paths

yes.

{:paths ["resources", "src/mvsj"]
 :output-dir "dist"}

what does your require-macros look like?

tree  src/
src/
└── mvsj
    ├── core.cljs
    ├── macros.cljc
    └── mvsj.cljs
(ns mvsj.core
  (:require
   [mvsj.mvsj :as mvsj]
   ["fs" :as fs]
   ["ajv$default" :as Ajv]
   ["ajv-formats$default" :as addFormats])
  ;; (:require-macros [resources.macros :refer [nodize]])
  (:require-macros [msvj.macros :refer [nodize]]))

you need to change :paths to ["resources" "src"]

you have one mvsj nested too many when you say "src/mvjs"

if you say (:require-macros [msvj.macros]) squint tries to look in all the paths mentioned in squint.edn + /msvj/macros.cljc added to that.

👍 1

makes sense?

Note:

; works: different tree
(:require-macros [mvsj.resource :refer [nodize]])

; triggers and issue....
(:require-macros [mvsj.macros :refer [nodize]])

; [squint] Compiling CLJS file: /Users/zcpowers/Downloads/squint-: 
; mol/src/mvsj/core.cljs
; node:fs:441
;       path = getValidatedPath(path);
;
; TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type ;
; string or an instance of Buffer or URL. Received null
;    at Module.readFileSync (node:fs:441:14)

Yes. The path is much clearer now. I also see how the compiled MJS files look in the output. I put the issue about but as the first one works I am def unblocked!

I think the error just means that it can't find the macro file on the path (is my guess)

I see two times the same :require-macros in your previous post, but maybe I'm misreading

Updated the words. The first one uses resources/ the second users src/mvsj/macros

oh resource vs macros

The first is how you structures you macros in the squint repo; the second in the test-project

order of operations?

sorry I don't follow and I don't see any difference between how it's described in the README and in the test-project. If you want to make sure I get, post your project on github so I can clone it

I'll be back later

Yes. I will troubleshoot. Thank you for your time.

Macros import correctly and they compile . Now I need to try using them

git clone 
cd squint-mol
npm i
npx squint compile

👍 1