squint

zachcp 2025-05-05T13:03:28.471339Z

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 ?

rafaeldelboni 2025-06-23T17:48:19.778109Z

@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

zachcp 2025-06-23T21:03:30.206259Z

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

👍 2
zachcp 2025-06-23T21:04:28.697659Z

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

rafaeldelboni 2025-06-23T21:06:03.563369Z

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?

borkdude 2025-05-05T13:04:45.377669Z

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

zachcp 2025-05-05T13:08:09.607589Z

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.

borkdude 2025-05-05T13:09:59.186809Z

don't know how well it works with nested data

👍 1
zachcp 2025-05-05T13:10:43.417229Z

I'll take a look. thank you

borkdude 2025-05-05T13:15:09.507639Z

JSON schema may also work for you

👍 1
zachcp 2025-05-05T13:18:10.029049Z

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

borkdude 2025-05-05T13:21:54.642799Z

probably hard :)

zachcp 2025-05-05T13:23:16.434359Z

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.

m3tti 2025-05-05T14:21:56.538589Z

https://ajv.js.org/guide/getting-started.html#basic-data-validation is also good

👍 1
m3tti 2025-05-05T14:22:28.970539Z

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

zachcp 2025-05-05T15:32:52.051509Z

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;

borkdude 2025-05-05T15:34:51.018309Z

I think you probably need to do it like this:

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

borkdude 2025-05-05T15:34:57.434029Z

since it's a cjs module rather than ESM

borkdude 2025-05-05T15:35:17.182829Z

the error message kind of hints at that

zachcp 2025-05-05T15:36:23.805939Z

thank you.

zachcp 2025-05-05T15:36:46.156739Z

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

borkdude 2025-05-05T15:37:24.367929Z

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

borkdude 2025-05-05T15:37:37.249689Z

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

👍 1
zachcp 2025-05-05T15:38:17.854379Z

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

borkdude 2025-05-05T15:38:57.787199Z

👍

zachcp 2025-05-05T15:45:51.166289Z

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

borkdude 2025-05-05T15:46:43.052909Z

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

borkdude 2025-05-05T15:47:05.787389Z

e.g.:

["ajv-formats" :as ajv]

(js/console.log ajv)

zachcp 2025-05-05T15:47:13.257239Z

ah.

borkdude 2025-05-05T15:47:24.997749Z

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

borkdude 2025-05-05T15:47:40.159599Z

and then you should see addFormats in there somewhere hopefully

borkdude 2025-05-05T15:50:38.076739Z

oh wait you mean this?

import addFormats from "ajv-formats"

borkdude 2025-05-05T15:50:57.540389Z

this should look like this in squint:

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

👍 1
borkdude 2025-05-05T15:51:08.472219Z

so you import the default and give it the name addFormats

zachcp 2025-05-05T15:51:31.278449Z

Thank you.

zachcp 2025-05-05T15:53:36.892139Z

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

🙌 1
✅ 1
zachcp 2025-05-05T17:00:42.497499Z

FYI: https://github.com/squint-cljs/squint/pull/664

borkdude 2025-05-05T17:40:29.543769Z

Awesome thank you!

zachcp 2025-05-05T18:55:52.560419Z

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

zachcp 2025-05-05T18:59:07.382129Z

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

zachcp 2025-05-05T19:02:19.898539Z

https://squint-cljs.github.io/squint/

borkdude 2025-05-05T19:04:33.881429Z

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

borkdude 2025-05-05T19:07:26.404069Z

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

🤯 1
zachcp 2025-05-05T19:11:31.064319Z

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"} []]]])

borkdude 2025-05-05T19:18:31.898319Z

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
borkdude 2025-05-05T19:18:51.725279Z

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

zachcp 2025-05-05T20:01:21.100469Z

(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]])))

zachcp 2025-05-05T20:02:02.764699Z

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

borkdude 2025-05-05T20:02:29.978939Z

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

borkdude 2025-05-05T20:03:59.171089Z

here is a test project in the squint repo: https://github.com/squint-cljs/squint/blob/44cc9ef7fca2dac90e56a1c08de0c83a94383ee8/test-project/src/main.cljs#L2

zachcp 2025-05-05T20:06:10.036539Z

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

borkdude 2025-05-05T20:07:11.200949Z

do you have a squint.edn already?

borkdude 2025-05-05T20:07:34.576239Z

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

zachcp 2025-05-05T20:07:35.887669Z

yes.

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

borkdude 2025-05-05T20:07:48.000859Z

what does your require-macros look like?

zachcp 2025-05-05T20:09:10.808459Z

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]]))

borkdude 2025-05-05T20:09:36.145549Z

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

borkdude 2025-05-05T20:09:57.026379Z

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

borkdude 2025-05-05T20:12:52.945129Z

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
borkdude 2025-05-05T20:12:56.197459Z

makes sense?

zachcp 2025-05-05T20:15:24.412779Z

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)

zachcp 2025-05-05T20:16:23.201139Z

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!

borkdude 2025-05-05T20:16:27.616459Z

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

borkdude 2025-05-05T20:17:00.215749Z

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

zachcp 2025-05-05T20:17:24.211079Z

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

borkdude 2025-05-05T20:17:25.258759Z

oh resource vs macros

zachcp 2025-05-05T20:18:15.610209Z

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

zachcp 2025-05-05T20:18:37.906269Z

order of operations?

borkdude 2025-05-05T20:20:05.501199Z

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

borkdude 2025-05-05T20:20:23.835289Z

I'll be back later

zachcp 2025-05-05T20:20:39.444149Z

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

zachcp 2025-05-05T20:55:02.175039Z

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

git clone 
cd squint-mol
npm i
npx squint compile

👍 1