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.
- package/dist-cli/conjure-js.mjs +9360 -5298
- package/dist-vite-plugin/index.mjs +9463 -5185
- package/package.json +3 -1
- package/src/bin/cli.ts +2 -2
- package/src/bin/nrepl-symbol.ts +150 -0
- package/src/bin/nrepl.ts +289 -167
- package/src/bin/version.ts +1 -1
- package/src/clojure/core.clj +757 -29
- package/src/clojure/core.clj.d.ts +75 -131
- package/src/clojure/generated/builtin-namespace-registry.ts +4 -0
- package/src/clojure/generated/clojure-core-source.ts +758 -29
- package/src/clojure/generated/clojure-set-source.ts +136 -0
- package/src/clojure/generated/clojure-walk-source.ts +72 -0
- package/src/clojure/set.clj +132 -0
- package/src/clojure/set.clj.d.ts +20 -0
- package/src/clojure/string.clj.d.ts +14 -0
- package/src/clojure/walk.clj +68 -0
- package/src/clojure/walk.clj.d.ts +7 -0
- package/src/core/assertions.ts +114 -6
- package/src/core/bootstrap.ts +337 -0
- package/src/core/conversions.ts +48 -31
- package/src/core/core-module.ts +303 -0
- package/src/core/env.ts +20 -6
- package/src/core/evaluator/apply.ts +40 -25
- package/src/core/evaluator/arity.ts +8 -8
- package/src/core/evaluator/async-evaluator.ts +565 -0
- package/src/core/evaluator/collections.ts +28 -5
- package/src/core/evaluator/destructure.ts +180 -69
- package/src/core/evaluator/dispatch.ts +12 -14
- package/src/core/evaluator/evaluate.ts +22 -20
- package/src/core/evaluator/expand.ts +45 -15
- package/src/core/evaluator/form-parsers.ts +178 -0
- package/src/core/evaluator/index.ts +7 -9
- package/src/core/evaluator/js-interop.ts +189 -0
- package/src/core/evaluator/quasiquote.ts +14 -8
- package/src/core/evaluator/recur-check.ts +6 -6
- package/src/core/evaluator/special-forms.ts +234 -191
- package/src/core/factories.ts +182 -3
- package/src/core/index.ts +54 -4
- package/src/core/module.ts +136 -0
- package/src/core/ns-forms.ts +107 -0
- package/src/core/printer.ts +371 -11
- package/src/core/reader.ts +84 -33
- package/src/core/registry.ts +209 -0
- package/src/core/runtime.ts +376 -0
- package/src/core/session.ts +253 -487
- package/src/core/stdlib/arithmetic.ts +528 -194
- package/src/core/stdlib/async-fns.ts +132 -0
- package/src/core/stdlib/atoms.ts +291 -56
- package/src/core/stdlib/errors.ts +54 -50
- package/src/core/stdlib/hof.ts +82 -166
- package/src/core/stdlib/js-namespace.ts +344 -0
- package/src/core/stdlib/lazy.ts +34 -0
- package/src/core/stdlib/maps-sets.ts +322 -0
- package/src/core/stdlib/meta.ts +61 -30
- package/src/core/stdlib/predicates.ts +325 -187
- package/src/core/stdlib/regex.ts +126 -98
- package/src/core/stdlib/seq.ts +564 -0
- package/src/core/stdlib/strings.ts +164 -135
- package/src/core/stdlib/transducers.ts +95 -100
- package/src/core/stdlib/utils.ts +292 -130
- package/src/core/stdlib/vars.ts +27 -27
- package/src/core/stdlib/vectors.ts +122 -0
- package/src/core/tokenizer.ts +2 -2
- package/src/core/transformations.ts +117 -9
- package/src/core/types.ts +98 -2
- package/src/host/node-host-module.ts +74 -0
- package/src/{vite-plugin-clj/nrepl-relay.ts → nrepl/relay.ts} +72 -11
- package/src/vite-plugin-clj/codegen.ts +87 -95
- package/src/vite-plugin-clj/index.ts +178 -23
- package/src/vite-plugin-clj/namespace-utils.ts +39 -0
- package/src/vite-plugin-clj/static-analysis.ts +211 -0
- package/src/clojure/demo.clj +0 -72
- package/src/clojure/demo.clj.d.ts +0 -0
- package/src/core/core-env.ts +0 -61
- package/src/core/stdlib/collections.ts +0 -739
- 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;
|
package/src/core/assertions.ts
CHANGED
|
@@ -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
|
|
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) ||
|
|
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
|
|
79
|
-
|
|
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
|
+
}
|