conjure-js 0.0.12 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist-cli/conjure-js.mjs +9360 -5298
  2. package/dist-vite-plugin/index.mjs +9463 -5185
  3. package/package.json +3 -1
  4. package/src/bin/cli.ts +2 -2
  5. package/src/bin/nrepl-symbol.ts +150 -0
  6. package/src/bin/nrepl.ts +289 -167
  7. package/src/bin/version.ts +1 -1
  8. package/src/clojure/core.clj +757 -29
  9. package/src/clojure/core.clj.d.ts +75 -131
  10. package/src/clojure/generated/builtin-namespace-registry.ts +4 -0
  11. package/src/clojure/generated/clojure-core-source.ts +758 -29
  12. package/src/clojure/generated/clojure-set-source.ts +136 -0
  13. package/src/clojure/generated/clojure-walk-source.ts +72 -0
  14. package/src/clojure/set.clj +132 -0
  15. package/src/clojure/set.clj.d.ts +20 -0
  16. package/src/clojure/string.clj.d.ts +14 -0
  17. package/src/clojure/walk.clj +68 -0
  18. package/src/clojure/walk.clj.d.ts +7 -0
  19. package/src/core/assertions.ts +114 -6
  20. package/src/core/bootstrap.ts +337 -0
  21. package/src/core/conversions.ts +48 -31
  22. package/src/core/core-module.ts +303 -0
  23. package/src/core/env.ts +20 -6
  24. package/src/core/evaluator/apply.ts +40 -25
  25. package/src/core/evaluator/arity.ts +8 -8
  26. package/src/core/evaluator/async-evaluator.ts +565 -0
  27. package/src/core/evaluator/collections.ts +28 -5
  28. package/src/core/evaluator/destructure.ts +180 -69
  29. package/src/core/evaluator/dispatch.ts +12 -14
  30. package/src/core/evaluator/evaluate.ts +22 -20
  31. package/src/core/evaluator/expand.ts +45 -15
  32. package/src/core/evaluator/form-parsers.ts +178 -0
  33. package/src/core/evaluator/index.ts +7 -9
  34. package/src/core/evaluator/js-interop.ts +189 -0
  35. package/src/core/evaluator/quasiquote.ts +14 -8
  36. package/src/core/evaluator/recur-check.ts +6 -6
  37. package/src/core/evaluator/special-forms.ts +234 -191
  38. package/src/core/factories.ts +182 -3
  39. package/src/core/index.ts +54 -4
  40. package/src/core/module.ts +136 -0
  41. package/src/core/ns-forms.ts +107 -0
  42. package/src/core/printer.ts +371 -11
  43. package/src/core/reader.ts +84 -33
  44. package/src/core/registry.ts +209 -0
  45. package/src/core/runtime.ts +376 -0
  46. package/src/core/session.ts +253 -487
  47. package/src/core/stdlib/arithmetic.ts +528 -194
  48. package/src/core/stdlib/async-fns.ts +132 -0
  49. package/src/core/stdlib/atoms.ts +291 -56
  50. package/src/core/stdlib/errors.ts +54 -50
  51. package/src/core/stdlib/hof.ts +82 -166
  52. package/src/core/stdlib/js-namespace.ts +344 -0
  53. package/src/core/stdlib/lazy.ts +34 -0
  54. package/src/core/stdlib/maps-sets.ts +322 -0
  55. package/src/core/stdlib/meta.ts +61 -30
  56. package/src/core/stdlib/predicates.ts +325 -187
  57. package/src/core/stdlib/regex.ts +126 -98
  58. package/src/core/stdlib/seq.ts +564 -0
  59. package/src/core/stdlib/strings.ts +164 -135
  60. package/src/core/stdlib/transducers.ts +95 -100
  61. package/src/core/stdlib/utils.ts +292 -130
  62. package/src/core/stdlib/vars.ts +27 -27
  63. package/src/core/stdlib/vectors.ts +122 -0
  64. package/src/core/tokenizer.ts +2 -2
  65. package/src/core/transformations.ts +117 -9
  66. package/src/core/types.ts +98 -2
  67. package/src/host/node-host-module.ts +74 -0
  68. package/src/{vite-plugin-clj/nrepl-relay.ts → nrepl/relay.ts} +72 -11
  69. package/src/vite-plugin-clj/codegen.ts +87 -95
  70. package/src/vite-plugin-clj/index.ts +178 -23
  71. package/src/vite-plugin-clj/namespace-utils.ts +39 -0
  72. package/src/vite-plugin-clj/static-analysis.ts +211 -0
  73. package/src/clojure/demo.clj +0 -72
  74. package/src/clojure/demo.clj.d.ts +0 -0
  75. package/src/core/core-env.ts +0 -61
  76. package/src/core/stdlib/collections.ts +0 -739
  77. package/src/host/node.ts +0 -55
@@ -0,0 +1,136 @@
1
+ // Auto-generated from src/clojure/set.clj — do not edit directly.
2
+ // Re-generate with: npm run gen:core-source
3
+ export const clojure_setSource = `\
4
+ (ns clojure.set)
5
+
6
+ (defn union
7
+ "Return a set that is the union of the input sets."
8
+ ([] #{})
9
+ ([s] s)
10
+ ([s1 s2]
11
+ (reduce conj s1 s2))
12
+ ([s1 s2 & sets]
13
+ (reduce union (union s1 s2) sets)))
14
+
15
+ (defn intersection
16
+ "Return a set that is the intersection of the input sets."
17
+ ([s] s)
18
+ ([s1 s2]
19
+ (reduce (fn [acc x]
20
+ (if (contains? s2 x)
21
+ (conj acc x)
22
+ acc))
23
+ #{}
24
+ s1))
25
+ ([s1 s2 & sets]
26
+ (reduce intersection (intersection s1 s2) sets)))
27
+
28
+ (defn difference
29
+ "Return a set that is the first set without elements of the remaining sets."
30
+ ([s] s)
31
+ ([s1 s2]
32
+ (reduce (fn [acc x]
33
+ (if (contains? s2 x)
34
+ acc
35
+ (conj acc x)))
36
+ #{}
37
+ s1))
38
+ ([s1 s2 & sets]
39
+ (reduce difference (difference s1 s2) sets)))
40
+
41
+ (defn select
42
+ "Returns a set of the elements for which pred is true."
43
+ [pred s]
44
+ (reduce (fn [acc x]
45
+ (if (pred x)
46
+ (conj acc x)
47
+ acc))
48
+ #{}
49
+ s))
50
+
51
+ (defn project
52
+ "Returns a rel of the elements of xrel with only the keys in ks."
53
+ [xrel ks]
54
+ (reduce (fn [acc m]
55
+ (conj acc (select-keys m ks)))
56
+ #{}
57
+ xrel))
58
+
59
+ (defn rename-keys
60
+ "Returns the map with the keys in kmap renamed to the vals in kmap."
61
+ [m kmap]
62
+ (reduce (fn [acc [old-k new-k]]
63
+ (if (contains? acc old-k)
64
+ (-> acc
65
+ (assoc new-k (get acc old-k))
66
+ (dissoc old-k))
67
+ acc))
68
+ m
69
+ kmap))
70
+
71
+ (defn rename
72
+ "Returns a rel of the maps in xrel with the keys in kmap renamed to the vals in kmap."
73
+ [xrel kmap]
74
+ (reduce (fn [acc m]
75
+ (conj acc (rename-keys m kmap)))
76
+ #{}
77
+ xrel))
78
+
79
+ (defn index
80
+ "Returns a map of the distinct values of ks in the xrel mapped to a
81
+ set of the maps in xrel with the corresponding values of ks."
82
+ [xrel ks]
83
+ (reduce (fn [acc m]
84
+ (let [k (select-keys m ks)]
85
+ (assoc acc k (conj (get acc k #{}) m))))
86
+ {}
87
+ xrel))
88
+
89
+ (defn map-invert
90
+ "Returns the map with the vals mapped to the keys."
91
+ [m]
92
+ (reduce (fn [acc [k v]]
93
+ (assoc acc v k))
94
+ {}
95
+ m))
96
+
97
+ (defn join
98
+ "When passed 2 rels, returns the relation corresponding to the natural
99
+ join. When passed an additional keymap, joins on the corresponding keys."
100
+ ([xrel yrel]
101
+ (if (and (seq xrel) (seq yrel))
102
+ (let [ks (intersection (set (keys (first xrel)))
103
+ (set (keys (first yrel))))]
104
+ (if (empty? ks)
105
+ (reduce (fn [acc mx]
106
+ (reduce (fn [acc2 my]
107
+ (conj acc2 (merge mx my)))
108
+ acc
109
+ yrel))
110
+ #{}
111
+ xrel)
112
+ (join xrel yrel (zipmap ks ks))))
113
+ #{}))
114
+ ([xrel yrel km]
115
+ (let [idx (index yrel (vals km))]
116
+ (reduce (fn [acc mx]
117
+ (let [found (get idx (rename-keys (select-keys mx (keys km)) km))]
118
+ (if found
119
+ (reduce (fn [acc2 my]
120
+ (conj acc2 (merge my mx)))
121
+ acc
122
+ found)
123
+ acc)))
124
+ #{}
125
+ xrel))))
126
+
127
+ (defn subset?
128
+ "Is set1 a subset of set2?"
129
+ [s1 s2]
130
+ (every? #(contains? s2 %) s1))
131
+
132
+ (defn superset?
133
+ "Is set1 a superset of set2?"
134
+ [s1 s2]
135
+ (every? #(contains? s1 %) s2))
136
+ `
@@ -0,0 +1,72 @@
1
+ // Auto-generated from src/clojure/walk.clj — do not edit directly.
2
+ // Re-generate with: npm run gen:core-source
3
+ export const clojure_walkSource = `\
4
+ (ns clojure.walk)
5
+
6
+ (defn walk
7
+ "Traverses form, an arbitrary data structure. inner and outer are
8
+ functions. Applies inner to each element of form, building up a
9
+ data structure of the same type, then applies outer to the result."
10
+ [inner outer form]
11
+ (cond
12
+ (list? form) (outer (apply list (map inner form)))
13
+ (vector? form) (outer (into [] (map inner) form))
14
+ (map? form) (outer (into {} (map (fn [e] [(inner (first e)) (inner (second e))]) form)))
15
+ (set? form) (outer (into #{} (map inner) form))
16
+ :else (outer form)))
17
+
18
+ (defn postwalk
19
+ "Performs a depth-first, post-order traversal of form. Calls f on
20
+ each sub-form, uses f's return value in place of the original."
21
+ [f form]
22
+ (walk (fn [x] (postwalk f x)) f form))
23
+
24
+ (defn prewalk
25
+ "Like postwalk, but does pre-order traversal."
26
+ [f form]
27
+ (walk (fn [x] (prewalk f x)) identity (f form)))
28
+
29
+ (defn postwalk-replace
30
+ "Recursively transforms form by replacing keys in smap with their
31
+ values. Like clojure/replace but works on any data structure."
32
+ [smap form]
33
+ (postwalk (fn [x] (if (contains? smap x) (get smap x) x)) form))
34
+
35
+ (defn prewalk-replace
36
+ "Recursively transforms form by replacing keys in smap with their
37
+ values. Like clojure/replace but works on any data structure."
38
+ [smap form]
39
+ (prewalk (fn [x] (if (contains? smap x) (get smap x) x)) form))
40
+
41
+ (defn keywordize-keys
42
+ "Recursively transforms all map keys from strings to keywords."
43
+ [m]
44
+ (postwalk
45
+ (fn [x]
46
+ (if (map? x)
47
+ (into {} (map (fn [e]
48
+ (let [k (first e)]
49
+ (if (string? k)
50
+ [(keyword k) (second e)]
51
+ e)))
52
+ x))
53
+ x))
54
+ m))
55
+
56
+ (defn stringify-keys
57
+ "Recursively transforms all map keys from keywords to strings."
58
+ [m]
59
+ (postwalk
60
+ (fn [x]
61
+ (if (map? x)
62
+ (into {}
63
+ (map
64
+ (fn [e]
65
+ (let [k (first e)]
66
+ (if (keyword? k)
67
+ [(name k) (second e)]
68
+ e)))
69
+ x))
70
+ x))
71
+ m))
72
+ `
@@ -0,0 +1,132 @@
1
+ (ns clojure.set)
2
+
3
+ (defn union
4
+ "Return a set that is the union of the input sets."
5
+ ([] #{})
6
+ ([s] s)
7
+ ([s1 s2]
8
+ (reduce conj s1 s2))
9
+ ([s1 s2 & sets]
10
+ (reduce union (union s1 s2) sets)))
11
+
12
+ (defn intersection
13
+ "Return a set that is the intersection of the input sets."
14
+ ([s] s)
15
+ ([s1 s2]
16
+ (reduce (fn [acc x]
17
+ (if (contains? s2 x)
18
+ (conj acc x)
19
+ acc))
20
+ #{}
21
+ s1))
22
+ ([s1 s2 & sets]
23
+ (reduce intersection (intersection s1 s2) sets)))
24
+
25
+ (defn difference
26
+ "Return a set that is the first set without elements of the remaining sets."
27
+ ([s] s)
28
+ ([s1 s2]
29
+ (reduce (fn [acc x]
30
+ (if (contains? s2 x)
31
+ acc
32
+ (conj acc x)))
33
+ #{}
34
+ s1))
35
+ ([s1 s2 & sets]
36
+ (reduce difference (difference s1 s2) sets)))
37
+
38
+ (defn select
39
+ "Returns a set of the elements for which pred is true."
40
+ [pred s]
41
+ (reduce (fn [acc x]
42
+ (if (pred x)
43
+ (conj acc x)
44
+ acc))
45
+ #{}
46
+ s))
47
+
48
+ (defn project
49
+ "Returns a rel of the elements of xrel with only the keys in ks."
50
+ [xrel ks]
51
+ (reduce (fn [acc m]
52
+ (conj acc (select-keys m ks)))
53
+ #{}
54
+ xrel))
55
+
56
+ (defn rename-keys
57
+ "Returns the map with the keys in kmap renamed to the vals in kmap."
58
+ [m kmap]
59
+ (reduce (fn [acc [old-k new-k]]
60
+ (if (contains? acc old-k)
61
+ (-> acc
62
+ (assoc new-k (get acc old-k))
63
+ (dissoc old-k))
64
+ acc))
65
+ m
66
+ kmap))
67
+
68
+ (defn rename
69
+ "Returns a rel of the maps in xrel with the keys in kmap renamed to the vals in kmap."
70
+ [xrel kmap]
71
+ (reduce (fn [acc m]
72
+ (conj acc (rename-keys m kmap)))
73
+ #{}
74
+ xrel))
75
+
76
+ (defn index
77
+ "Returns a map of the distinct values of ks in the xrel mapped to a
78
+ set of the maps in xrel with the corresponding values of ks."
79
+ [xrel ks]
80
+ (reduce (fn [acc m]
81
+ (let [k (select-keys m ks)]
82
+ (assoc acc k (conj (get acc k #{}) m))))
83
+ {}
84
+ xrel))
85
+
86
+ (defn map-invert
87
+ "Returns the map with the vals mapped to the keys."
88
+ [m]
89
+ (reduce (fn [acc [k v]]
90
+ (assoc acc v k))
91
+ {}
92
+ m))
93
+
94
+ (defn join
95
+ "When passed 2 rels, returns the relation corresponding to the natural
96
+ join. When passed an additional keymap, joins on the corresponding keys."
97
+ ([xrel yrel]
98
+ (if (and (seq xrel) (seq yrel))
99
+ (let [ks (intersection (set (keys (first xrel)))
100
+ (set (keys (first yrel))))]
101
+ (if (empty? ks)
102
+ (reduce (fn [acc mx]
103
+ (reduce (fn [acc2 my]
104
+ (conj acc2 (merge mx my)))
105
+ acc
106
+ yrel))
107
+ #{}
108
+ xrel)
109
+ (join xrel yrel (zipmap ks ks))))
110
+ #{}))
111
+ ([xrel yrel km]
112
+ (let [idx (index yrel (vals km))]
113
+ (reduce (fn [acc mx]
114
+ (let [found (get idx (rename-keys (select-keys mx (keys km)) km))]
115
+ (if found
116
+ (reduce (fn [acc2 my]
117
+ (conj acc2 (merge my mx)))
118
+ acc
119
+ found)
120
+ acc)))
121
+ #{}
122
+ xrel))))
123
+
124
+ (defn subset?
125
+ "Is set1 a subset of set2?"
126
+ [s1 s2]
127
+ (every? #(contains? s2 %) s1))
128
+
129
+ (defn superset?
130
+ "Is set1 a superset of set2?"
131
+ [s1 s2]
132
+ (every? #(contains? s1 %) s2))
@@ -0,0 +1,20 @@
1
+ export function union(): unknown;
2
+ export function union(s: unknown): unknown;
3
+ export function union(s1: unknown, s2: unknown): unknown;
4
+ export function union(s1: unknown, s2: unknown, ...sets: unknown[]): unknown;
5
+ export function intersection(s: unknown): unknown;
6
+ export function intersection(s1: unknown, s2: unknown): unknown;
7
+ export function intersection(s1: unknown, s2: unknown, ...sets: unknown[]): unknown;
8
+ export function difference(s: unknown): unknown;
9
+ export function difference(s1: unknown, s2: unknown): unknown;
10
+ export function difference(s1: unknown, s2: unknown, ...sets: unknown[]): unknown;
11
+ export function select(pred: unknown, s: unknown): unknown;
12
+ export function project(xrel: unknown, ks: unknown): unknown;
13
+ export function rename_keys(m: unknown, kmap: unknown): unknown;
14
+ export function rename(xrel: unknown, kmap: unknown): unknown;
15
+ export function index(xrel: unknown, ks: unknown): unknown;
16
+ export function map_invert(m: unknown): unknown;
17
+ export function join(xrel: unknown, yrel: unknown): unknown;
18
+ export function join(xrel: unknown, yrel: unknown, km: unknown): unknown;
19
+ export function subset_QMARK_(s1: unknown, s2: unknown): unknown;
20
+ export function superset_QMARK_(s1: unknown, s2: unknown): unknown;
@@ -1,3 +1,17 @@
1
+ export const str_split_STAR_: unknown;
2
+ export const str_upper_case_STAR_: unknown;
3
+ export const str_lower_case_STAR_: unknown;
4
+ export const str_trim_STAR_: unknown;
5
+ export const str_triml_STAR_: unknown;
6
+ export const str_trimr_STAR_: unknown;
7
+ export const str_reverse_STAR_: unknown;
8
+ export const str_starts_with_STAR_: unknown;
9
+ export const str_ends_with_STAR_: unknown;
10
+ export const str_includes_STAR_: unknown;
11
+ export const str_index_of_STAR_: unknown;
12
+ export const str_last_index_of_STAR_: unknown;
13
+ export const str_replace_STAR_: unknown;
14
+ export const str_replace_first_STAR_: unknown;
1
15
  export function join(coll: unknown): unknown;
2
16
  export function join(separator: unknown, coll: unknown): unknown;
3
17
  export function split(s: unknown, sep: unknown): unknown;
@@ -0,0 +1,68 @@
1
+ (ns clojure.walk)
2
+
3
+ (defn walk
4
+ "Traverses form, an arbitrary data structure. inner and outer are
5
+ functions. Applies inner to each element of form, building up a
6
+ data structure of the same type, then applies outer to the result."
7
+ [inner outer form]
8
+ (cond
9
+ (list? form) (outer (apply list (map inner form)))
10
+ (vector? form) (outer (into [] (map inner) form))
11
+ (map? form) (outer (into {} (map (fn [e] [(inner (first e)) (inner (second e))]) form)))
12
+ (set? form) (outer (into #{} (map inner) form))
13
+ :else (outer form)))
14
+
15
+ (defn postwalk
16
+ "Performs a depth-first, post-order traversal of form. Calls f on
17
+ each sub-form, uses f's return value in place of the original."
18
+ [f form]
19
+ (walk (fn [x] (postwalk f x)) f form))
20
+
21
+ (defn prewalk
22
+ "Like postwalk, but does pre-order traversal."
23
+ [f form]
24
+ (walk (fn [x] (prewalk f x)) identity (f form)))
25
+
26
+ (defn postwalk-replace
27
+ "Recursively transforms form by replacing keys in smap with their
28
+ values. Like clojure/replace but works on any data structure."
29
+ [smap form]
30
+ (postwalk (fn [x] (if (contains? smap x) (get smap x) x)) form))
31
+
32
+ (defn prewalk-replace
33
+ "Recursively transforms form by replacing keys in smap with their
34
+ values. Like clojure/replace but works on any data structure."
35
+ [smap form]
36
+ (prewalk (fn [x] (if (contains? smap x) (get smap x) x)) form))
37
+
38
+ (defn keywordize-keys
39
+ "Recursively transforms all map keys from strings to keywords."
40
+ [m]
41
+ (postwalk
42
+ (fn [x]
43
+ (if (map? x)
44
+ (into {} (map (fn [e]
45
+ (let [k (first e)]
46
+ (if (string? k)
47
+ [(keyword k) (second e)]
48
+ e)))
49
+ x))
50
+ x))
51
+ m))
52
+
53
+ (defn stringify-keys
54
+ "Recursively transforms all map keys from keywords to strings."
55
+ [m]
56
+ (postwalk
57
+ (fn [x]
58
+ (if (map? x)
59
+ (into {}
60
+ (map
61
+ (fn [e]
62
+ (let [k (first e)]
63
+ (if (keyword? k)
64
+ [(name k) (second e)]
65
+ e)))
66
+ x))
67
+ x))
68
+ m))
@@ -0,0 +1,7 @@
1
+ export function walk(inner: unknown, outer: unknown, form: unknown): unknown;
2
+ export function postwalk(f: unknown, form: unknown): unknown;
3
+ export function prewalk(f: unknown, form: unknown): unknown;
4
+ export function postwalk_replace(smap: unknown, form: unknown): unknown;
5
+ export function prewalk_replace(smap: unknown, form: unknown): unknown;
6
+ export function keywordize_keys(m: unknown): unknown;
7
+ export function stringify_keys(m: unknown): unknown;
@@ -2,16 +2,22 @@ import {
2
2
  valueKeywords,
3
3
  type CljAtom,
4
4
  type CljBoolean,
5
+ type CljCons,
6
+ type CljDelay,
5
7
  type CljFunction,
8
+ type CljJsValue,
6
9
  type CljKeyword,
10
+ type CljLazySeq,
7
11
  type CljList,
8
12
  type CljMacro,
9
13
  type CljMap,
10
14
  type CljMultiMethod,
15
+ type CljNamespace,
11
16
  type CljNativeFunction,
12
17
  type CljNumber,
13
18
  type CljReduced,
14
19
  type CljRegex,
20
+ type CljSet,
15
21
  type CljString,
16
22
  type CljSymbol,
17
23
  type CljValue,
@@ -22,9 +28,11 @@ import {
22
28
  import { specialFormKeywords } from './evaluator/special-forms.ts'
23
29
 
24
30
  export const isNil = (value: CljValue): boolean => value.kind === 'nil'
31
+ export const isBoolean = (value: CljValue): value is CljBoolean =>
32
+ value.kind === 'boolean'
25
33
  export const isFalsy = (value: CljValue): boolean => {
26
34
  if (value.kind === 'nil') return true
27
- if (value.kind === 'boolean') return !value.value
35
+ if (isBoolean(value)) return !value.value
28
36
  return false
29
37
  }
30
38
  export const isTruthy = (value: CljValue): boolean => {
@@ -54,9 +62,13 @@ export const isAFunction = (
54
62
  ): value is CljFunction | CljNativeFunction =>
55
63
  isFunction(value) || isNativeFunction(value)
56
64
 
65
+ export const isJsValue = (value: CljValue): value is CljJsValue =>
66
+ value.kind === 'js-value'
67
+
57
68
  /** True for any value that can be invoked like a function (IFn). */
58
69
  export const isCallable = (value: CljValue): boolean =>
59
- isAFunction(value) || isKeyword(value) || isMap(value)
70
+ isAFunction(value) || isKeyword(value) || isMap(value) ||
71
+ (isJsValue(value) && typeof value.value === 'function')
60
72
  export const isMultiMethod = (value: CljValue): value is CljMultiMethod =>
61
73
  value.kind === 'multi-method'
62
74
  export const isAtom = (value: CljValue): value is CljAtom =>
@@ -68,15 +80,36 @@ export const isVolatile = (value: CljValue): value is CljVolatile =>
68
80
  export const isRegex = (value: CljValue): value is CljRegex =>
69
81
  value.kind === 'regex'
70
82
  export const isVar = (value: CljValue): value is CljVar => value.kind === 'var'
83
+ export const isSet = (value: CljValue): value is CljSet =>
84
+ value.kind === valueKeywords.set
85
+ export const isDelay = (value: CljValue): value is CljDelay =>
86
+ value.kind === 'delay'
87
+ export const isLazySeq = (value: CljValue): value is CljLazySeq =>
88
+ value.kind === 'lazy-seq'
89
+ export const isCons = (value: CljValue): value is CljCons =>
90
+ value.kind === 'cons'
91
+ export const isNamespace = (value: CljValue): value is CljNamespace =>
92
+ value.kind === 'namespace'
71
93
  export const isCollection = (
72
94
  value: CljValue
73
- ): value is CljList | CljVector | CljMap =>
74
- isVector(value) || isMap(value) || isList(value)
95
+ ): value is CljList | CljVector | CljMap | CljSet | CljCons =>
96
+ isVector(value) ||
97
+ isMap(value) ||
98
+ isList(value) ||
99
+ isSet(value) ||
100
+ isCons(value)
75
101
 
76
102
  export const isSeqable = (
77
103
  value: CljValue
78
- ): value is CljList | CljVector | CljMap | CljString =>
79
- isCollection(value) || value.kind === 'string'
104
+ ): value is
105
+ | CljList
106
+ | CljVector
107
+ | CljMap
108
+ | CljSet
109
+ | CljString
110
+ | CljLazySeq
111
+ | CljCons =>
112
+ isCollection(value) || value.kind === 'string' || isLazySeq(value)
80
113
 
81
114
  export const isCljValue = (value: any): value is CljValue => {
82
115
  return (
@@ -87,6 +120,26 @@ export const isCljValue = (value: any): value is CljValue => {
87
120
  )
88
121
  }
89
122
 
123
+ /** Realize a lazy-seq for equality comparison (trampoline to handle chains). */
124
+ function realizeLazySeqForEquality(ls: CljLazySeq): CljValue {
125
+ let current: CljValue = ls
126
+ while (current.kind === 'lazy-seq') {
127
+ const lazy = current as CljLazySeq
128
+ if (lazy.realized) {
129
+ current = lazy.value!
130
+ } else if (lazy.thunk) {
131
+ lazy.value = lazy.thunk()
132
+ lazy.thunk = null
133
+ lazy.realized = true
134
+ current = lazy.value!
135
+ } else {
136
+ // No thunk and not realized — treat as nil
137
+ return { kind: 'nil', value: null }
138
+ }
139
+ }
140
+ return current
141
+ }
142
+
90
143
  const equalityHandlers = {
91
144
  [valueKeywords.number]: (a: CljNumber, b: CljNumber) => a.value === b.value,
92
145
  [valueKeywords.string]: (a: CljString, b: CljString) => a.value === b.value,
@@ -126,8 +179,24 @@ const equalityHandlers = {
126
179
  // (= #"foo" #"foo") => false — each literal is a distinct object
127
180
  [valueKeywords.regex]: (a: CljRegex, b: CljRegex) => a === b,
128
181
  [valueKeywords.var]: (a: CljVar, b: CljVar) => a === b,
182
+ [valueKeywords.set]: (a: CljSet, b: CljSet) => {
183
+ if (a.values.length !== b.values.length) return false
184
+ return a.values.every((av) => b.values.some((bv) => isEqual(av, bv)))
185
+ },
186
+ [valueKeywords.delay]: (a: CljDelay, b: CljDelay) => a === b,
187
+ [valueKeywords.lazySeq]: (a: CljLazySeq, b: CljLazySeq) => {
188
+ // Realize both and compare structurally
189
+ const aVal = realizeLazySeqForEquality(a)
190
+ const bVal = realizeLazySeqForEquality(b)
191
+ return isEqual(aVal, bVal)
192
+ },
193
+ [valueKeywords.cons]: (a: CljCons, b: CljCons) =>
194
+ isEqual(a.head, b.head) && isEqual(a.tail, b.tail),
195
+ [valueKeywords.namespace]: (a: CljNamespace, b: CljNamespace) => a === b,
129
196
  }
130
197
 
198
+ export const isString = (value: CljValue): value is CljString =>
199
+ value.kind === 'string'
131
200
  export const isEqual = (a: CljValue, b: CljValue): boolean => {
132
201
  if (a.kind !== b.kind) return false
133
202
 
@@ -135,3 +204,42 @@ export const isEqual = (a: CljValue, b: CljValue): boolean => {
135
204
  if (!handler) return false
136
205
  return handler(a as never, b as never)
137
206
  }
207
+ export const isNumber = (value: CljValue): value is CljNumber =>
208
+ value.kind === 'number'
209
+
210
+ // Main assertion interface for the entire package
211
+ export const is = {
212
+ nil: isNil,
213
+ number: isNumber,
214
+ string: isString,
215
+ boolean: isBoolean,
216
+ falsy: isFalsy,
217
+ truthy: isTruthy,
218
+ specialForm: isSpecialForm,
219
+ symbol: isSymbol,
220
+ vector: isVector,
221
+ list: isList,
222
+ function: isFunction,
223
+ nativeFunction: isNativeFunction,
224
+ macro: isMacro,
225
+ map: isMap,
226
+ keyword: isKeyword,
227
+ aFunction: isAFunction,
228
+ callable: isCallable,
229
+ multiMethod: isMultiMethod,
230
+ atom: isAtom,
231
+ reduced: isReduced,
232
+ volatile: isVolatile,
233
+ regex: isRegex,
234
+ var: isVar,
235
+ set: isSet,
236
+ delay: isDelay,
237
+ lazySeq: isLazySeq,
238
+ cons: isCons,
239
+ namespace: isNamespace,
240
+ collection: isCollection,
241
+ seqable: isSeqable,
242
+ cljValue: isCljValue,
243
+ equal: isEqual,
244
+ jsValue: isJsValue,
245
+ }