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,132 @@
1
+ /**
2
+ * Async stdlib functions: then, catch*, pending?, promise-of
3
+ * EXPERIMENTAL — part of CljPending support. Deleteable.
4
+ * To revert: delete this file and remove the import from core-module.ts.
5
+ */
6
+
7
+ import { v } from '../factories'
8
+ import { CljThrownSignal, EvaluationError } from '../errors'
9
+ import { is } from '../assertions'
10
+ import { printString } from '../printer'
11
+ import { toSeq } from '../transformations'
12
+ import type { EvaluationContext, CljValue, Env } from '../types'
13
+
14
+ export const asyncFunctions: Record<string, CljValue> = {
15
+ // (then val f) — apply f when resolved, or immediately if val is not pending
16
+ then: v
17
+ .nativeFnCtx(
18
+ 'then',
19
+ (ctx: EvaluationContext, callEnv: Env, val: CljValue, f: CljValue) => {
20
+ if (!is.callable(f)) {
21
+ throw new EvaluationError(
22
+ `${printString(f)} is not a callable value`,
23
+ { fn: f, args: [] }
24
+ )
25
+ }
26
+ if (val.kind !== 'pending') {
27
+ return ctx.applyCallable(f, [val], callEnv)
28
+ }
29
+ const promise = val.promise.then((resolved) => {
30
+ try {
31
+ const result = ctx.applyCallable(f, [resolved], callEnv)
32
+ // Unwrap nested CljPending for transparent chaining
33
+ return result.kind === 'pending' ? result.promise : result
34
+ } catch (e) {
35
+ return Promise.reject(e)
36
+ }
37
+ })
38
+ return v.pending(promise)
39
+ }
40
+ )
41
+ .doc(
42
+ 'Applies f to the resolved value of a pending, or to val directly if not pending.',
43
+ [['val', 'f']]
44
+ ),
45
+
46
+ // (catch* val f) — handle rejection; named catch* to avoid collision with catch special form
47
+ 'catch*': v
48
+ .nativeFnCtx(
49
+ 'catch*',
50
+ (ctx: EvaluationContext, callEnv: Env, val: CljValue, f: CljValue) => {
51
+ if (!is.callable(f)) {
52
+ throw new EvaluationError(
53
+ `${printString(f)} is not a callable value`,
54
+ { fn: f, args: [] }
55
+ )
56
+ }
57
+ if (val.kind !== 'pending') return val // not pending — no rejection possible
58
+ const promise = val.promise.catch((err) => {
59
+ // Normalize the thrown value to a CljValue map
60
+ let errVal: CljValue
61
+ if (err instanceof CljThrownSignal) {
62
+ // (throw ...) inside async: pass the thrown value directly
63
+ errVal = err.value
64
+ } else {
65
+ errVal = {
66
+ kind: 'map',
67
+ entries: [
68
+ [
69
+ { kind: 'keyword', name: ':type' },
70
+ { kind: 'keyword', name: ':error/js' },
71
+ ],
72
+ [
73
+ { kind: 'keyword', name: ':message' },
74
+ {
75
+ kind: 'string',
76
+ value: err instanceof Error ? err.message : String(err),
77
+ },
78
+ ],
79
+ ],
80
+ }
81
+ }
82
+ try {
83
+ const result = ctx.applyCallable(f, [errVal], callEnv)
84
+ return result.kind === 'pending' ? result.promise : result
85
+ } catch (e) {
86
+ return Promise.reject(e)
87
+ }
88
+ })
89
+ return v.pending(promise)
90
+ }
91
+ )
92
+ .doc(
93
+ 'Handles rejection of a pending value by calling f with the thrown value or an error map.',
94
+ [['val', 'f']]
95
+ ),
96
+
97
+ // (pending? x) → boolean
98
+ 'pending?': v
99
+ .nativeFn('pending?', (val: CljValue) => {
100
+ return v.boolean(val.kind === 'pending')
101
+ })
102
+ .doc('Returns true if val is a pending (async) value.', [['val']]),
103
+
104
+ // (promise-of val) → CljPending that resolves immediately with val
105
+ // Primarily for testing / development before host JS interop is built.
106
+ 'promise-of': v
107
+ .nativeFn('promise-of', (val: CljValue) => {
108
+ return v.pending(Promise.resolve(val))
109
+ })
110
+ .doc(
111
+ 'Wraps val in an immediately-resolving pending value. Useful for testing async composition.',
112
+ [['val']]
113
+ ),
114
+
115
+ // (all pendings) → CljPending of a vector of all resolved values.
116
+ // Accepts any seqable (vector, list, lazy-seq, cons, nil); non-pending items resolve immediately.
117
+ // If any input rejects, the result pending rejects with that error.
118
+ all: v
119
+ .nativeFn('all', (val: CljValue) => {
120
+ const items: CljValue[] = val.kind === 'nil' ? [] : toSeq(val)
121
+ const promises = items.map((item) =>
122
+ item.kind === 'pending' ? item.promise : Promise.resolve(item)
123
+ )
124
+ return v.pending(
125
+ Promise.all(promises).then((results) => v.vector(results))
126
+ )
127
+ })
128
+ .doc(
129
+ 'Returns a pending that resolves with a vector of all results when every input resolves.',
130
+ [['pendings']]
131
+ ),
132
+ }
@@ -1,76 +1,311 @@
1
- import { isAtom, isAFunction, isReduced, isVolatile } from '../assertions'
1
+ import { is } from '../assertions'
2
2
  import { EvaluationError } from '../errors'
3
- import {
4
- cljAtom,
5
- cljBoolean,
6
- cljNativeFunctionWithContext,
7
- cljNativeFunction,
8
- withDoc,
9
- } from '../factories'
10
- import type { CljValue, Env } from '../types'
3
+ import { v } from '../factories'
4
+ import { printString } from '../printer'
5
+ import { realizeDelay } from '../transformations'
6
+ import type {
7
+ CljAtom,
8
+ CljFunction,
9
+ CljNativeFunction,
10
+ CljValue,
11
+ Env,
12
+ } from '../types'
13
+
14
+ function validateAtom(
15
+ a: CljAtom,
16
+ newVal: CljValue,
17
+ ctx: import('../types').EvaluationContext,
18
+ callEnv: Env
19
+ ) {
20
+ if (a.validator && is.aFunction(a.validator)) {
21
+ const result = ctx.applyFunction(a.validator, [newVal], callEnv)
22
+ if (is.falsy(result)) {
23
+ throw new EvaluationError('Invalid reference state', { newVal })
24
+ }
25
+ }
26
+ }
27
+
28
+ function notifyWatches(a: CljAtom, oldVal: CljValue, newVal: CljValue) {
29
+ if (a.watches) {
30
+ for (const [, { key, fn, ctx, callEnv }] of a.watches) {
31
+ ctx.applyFunction(
32
+ fn as CljFunction | CljNativeFunction,
33
+ [key, { kind: 'atom', value: newVal } as CljValue, oldVal, newVal],
34
+ callEnv
35
+ )
36
+ }
37
+ }
38
+ }
11
39
 
12
40
  export const atomFunctions: Record<string, CljValue> = {
13
- atom: withDoc(
14
- cljNativeFunction('atom', (value: CljValue) => {
15
- return cljAtom(value)
16
- }),
17
- 'Returns a new atom holding the given value.',
18
- [['value']]
19
- ),
41
+ atom: v
42
+ .nativeFn('atom', function atom(value: CljValue) {
43
+ return v.atom(value)
44
+ })
45
+ .doc('Returns a new atom holding the given value.', [['value']]),
20
46
 
21
- deref: withDoc(
22
- cljNativeFunction('deref', (value: CljValue) => {
23
- if (isAtom(value)) return value.value
24
- if (isVolatile(value)) return value.value
25
- if (isReduced(value)) return value.value
26
- throw EvaluationError.atArg(`deref expects an atom, volatile, or reduced value, got ${value.kind}`, { value }, 0)
27
- }),
28
- 'Returns the wrapped value from an atom, volatile, or reduced value.',
29
- [['value']]
30
- ),
47
+ deref: v
48
+ .nativeFn('deref', function deref(value: CljValue) {
49
+ if (is.atom(value)) return value.value
50
+ if (is.volatile(value)) return value.value
51
+ if (is.reduced(value)) return value.value
52
+ if (is.delay(value)) return realizeDelay(value)
53
+ // --- ASYNC (experimental) ---
54
+ if (value.kind === 'pending') {
55
+ throw EvaluationError.atArg(
56
+ '@ on a pending value requires an (async ...) context. Use (async @x) or compose with then/catch.',
57
+ { value },
58
+ 0
59
+ )
60
+ }
61
+ // --- END ASYNC ---
62
+ throw EvaluationError.atArg(
63
+ `deref expects an atom, volatile, reduced, or delay value, got ${value.kind}`,
64
+ { value },
65
+ 0
66
+ )
67
+ })
68
+ .doc(
69
+ 'Returns the wrapped value from an atom, volatile, reduced, or delay value.',
70
+ [['value']]
71
+ ),
31
72
 
32
- 'swap!': withDoc(
33
- cljNativeFunctionWithContext(
73
+ 'swap!': v
74
+ .nativeFnCtx(
34
75
  'swap!',
35
- (
76
+ function swap(
36
77
  ctx,
37
78
  callEnv: Env,
38
79
  atomVal: CljValue,
39
80
  fn: CljValue,
40
81
  ...extraArgs: CljValue[]
41
- ) => {
42
- if (!isAtom(atomVal)) {
43
- throw EvaluationError.atArg(`swap! expects an atom as its first argument, got ${atomVal.kind}`, { atomVal }, 0)
82
+ ) {
83
+ if (!is.atom(atomVal)) {
84
+ throw EvaluationError.atArg(
85
+ `swap! expects an atom as its first argument, got ${atomVal.kind}`,
86
+ { atomVal },
87
+ 0
88
+ )
44
89
  }
45
- if (!isAFunction(fn)) {
46
- throw EvaluationError.atArg(`swap! expects a function as its second argument, got ${fn.kind}`, { fn }, 1)
90
+ if (!is.aFunction(fn)) {
91
+ throw EvaluationError.atArg(
92
+ `swap! expects a function as its second argument, got ${fn.kind}`,
93
+ { fn },
94
+ 1
95
+ )
47
96
  }
48
- const newVal = ctx.applyFunction(fn, [atomVal.value, ...extraArgs], callEnv)
49
- atomVal.value = newVal
97
+ const a = atomVal as CljAtom
98
+ const oldVal = a.value
99
+ const newVal = ctx.applyFunction(fn, [oldVal, ...extraArgs], callEnv)
100
+ validateAtom(a, newVal, ctx, callEnv)
101
+ a.value = newVal
102
+ notifyWatches(a, oldVal, newVal)
103
+ return newVal
104
+ }
105
+ )
106
+ .doc(
107
+ 'Applies fn to the current value of the atom, replacing the current value with the result. Returns the new value.',
108
+ [['atomVal', 'fn', '&', 'extraArgs']]
109
+ ),
110
+
111
+ 'reset!': v
112
+ .nativeFnCtx(
113
+ 'reset!',
114
+ function reset(ctx, callEnv: Env, atomVal: CljValue, newVal: CljValue) {
115
+ if (!is.atom(atomVal)) {
116
+ throw EvaluationError.atArg(
117
+ `reset! expects an atom as its first argument, got ${atomVal.kind}`,
118
+ { atomVal },
119
+ 0
120
+ )
121
+ }
122
+ const a = atomVal as CljAtom
123
+ const oldVal = a.value
124
+ validateAtom(a, newVal, ctx, callEnv)
125
+ a.value = newVal
126
+ notifyWatches(a, oldVal, newVal)
50
127
  return newVal
51
128
  }
129
+ )
130
+ .doc('Sets the value of the atom to newVal and returns the new value.', [
131
+ ['atomVal', 'newVal'],
132
+ ]),
133
+
134
+ 'atom?': v
135
+ .nativeFn('atom?', function isAtomPredicate(value: CljValue) {
136
+ return v.boolean(is.atom(value))
137
+ })
138
+ .doc('Returns true if the value is an atom, false otherwise.', [['value']]),
139
+
140
+ 'swap-vals!': v
141
+ .nativeFnCtx(
142
+ 'swap-vals!',
143
+ function swapVals(
144
+ ctx,
145
+ callEnv: Env,
146
+ atomVal: CljValue,
147
+ fn: CljValue,
148
+ ...extraArgs: CljValue[]
149
+ ) {
150
+ if (!is.atom(atomVal)) {
151
+ throw EvaluationError.atArg(
152
+ `swap-vals! expects an atom, got ${printString(atomVal)}`,
153
+ { atomVal },
154
+ 0
155
+ )
156
+ }
157
+ if (!is.aFunction(fn)) {
158
+ throw EvaluationError.atArg(
159
+ `swap-vals! expects a function, got ${printString(fn)}`,
160
+ { fn },
161
+ 1
162
+ )
163
+ }
164
+ const oldVal = atomVal.value
165
+ const newVal = ctx.applyFunction(fn, [oldVal, ...extraArgs], callEnv)
166
+ atomVal.value = newVal
167
+ return v.vector([oldVal, newVal])
168
+ }
169
+ )
170
+ .doc(
171
+ 'Atomically swaps the value of atom to be (apply f current-value-of-atom args). Returns [old new].',
172
+ [['atom', 'f', '&', 'args']]
173
+ ),
174
+
175
+ 'reset-vals!': v
176
+ .nativeFn(
177
+ 'reset-vals!',
178
+ function resetVals(atomVal: CljValue, newVal: CljValue) {
179
+ if (!is.atom(atomVal)) {
180
+ throw EvaluationError.atArg(
181
+ `reset-vals! expects an atom, got ${printString(atomVal)}`,
182
+ { atomVal },
183
+ 0
184
+ )
185
+ }
186
+ const oldVal = atomVal.value
187
+ atomVal.value = newVal
188
+ return v.vector([oldVal, newVal])
189
+ }
190
+ )
191
+ .doc('Sets the value of atom to newVal. Returns [old new].', [
192
+ ['atom', 'newval'],
193
+ ]),
194
+
195
+ 'compare-and-set!': v
196
+ .nativeFn(
197
+ 'compare-and-set!',
198
+ function compareAndSet(
199
+ atomVal: CljValue,
200
+ oldv: CljValue,
201
+ newv: CljValue
202
+ ) {
203
+ if (!is.atom(atomVal)) {
204
+ throw EvaluationError.atArg(
205
+ `compare-and-set! expects an atom, got ${printString(atomVal)}`,
206
+ { atomVal },
207
+ 0
208
+ )
209
+ }
210
+ if (is.equal(atomVal.value, oldv)) {
211
+ atomVal.value = newv
212
+ return v.boolean(true)
213
+ }
214
+ return v.boolean(false)
215
+ }
216
+ )
217
+ .doc(
218
+ 'Atomically sets the value of atom to newval if and only if the current value of the atom is identical to oldval. Returns true if set happened, else false.',
219
+ [['atom', 'oldval', 'newval']]
220
+ ),
221
+
222
+ 'add-watch': v
223
+ .nativeFnCtx(
224
+ 'add-watch',
225
+ function addWatch(
226
+ ctx,
227
+ callEnv: Env,
228
+ atomVal: CljValue,
229
+ key: CljValue,
230
+ fn: CljValue
231
+ ) {
232
+ if (!is.atom(atomVal)) {
233
+ throw EvaluationError.atArg(
234
+ `add-watch expects an atom, got ${printString(atomVal)}`,
235
+ { atomVal },
236
+ 0
237
+ )
238
+ }
239
+ if (!is.aFunction(fn)) {
240
+ throw EvaluationError.atArg(
241
+ `add-watch expects a function, got ${printString(fn)}`,
242
+ { fn },
243
+ 2
244
+ )
245
+ }
246
+ const a = atomVal as CljAtom
247
+ if (!a.watches) a.watches = new Map()
248
+ // Store a wrapper that calls the user fn through the evaluator
249
+ a.watches.set(printString(key), { key, fn, ctx, callEnv })
250
+ return atomVal
251
+ }
252
+ )
253
+ .doc(
254
+ 'Adds a watch function to an atom. The watch fn must be a fn of 4 args: a key, the atom, its old-state, its new-state.',
255
+ [['atom', 'key', 'fn']]
52
256
  ),
53
- 'Applies fn to the current value of the atom, replacing the current value with the result. Returns the new value.',
54
- [['atomVal', 'fn', '&', 'extraArgs']]
55
- ),
56
257
 
57
- 'reset!': withDoc(
58
- cljNativeFunction('reset!', (atomVal: CljValue, newVal: CljValue) => {
59
- if (!isAtom(atomVal)) {
60
- throw EvaluationError.atArg(`reset! expects an atom as its first argument, got ${atomVal.kind}`, { atomVal }, 0)
258
+ 'remove-watch': v
259
+ .nativeFn(
260
+ 'remove-watch',
261
+ function removeWatch(atomVal: CljValue, key: CljValue) {
262
+ if (!is.atom(atomVal)) {
263
+ throw EvaluationError.atArg(
264
+ `remove-watch expects an atom, got ${printString(atomVal)}`,
265
+ { atomVal },
266
+ 0
267
+ )
268
+ }
269
+ const a = atomVal as CljAtom
270
+ if (a.watches) a.watches.delete(printString(key))
271
+ return atomVal
61
272
  }
62
- atomVal.value = newVal
63
- return newVal
64
- }),
65
- 'Sets the value of the atom to newVal and returns the new value.',
66
- [['atomVal', 'newVal']]
67
- ),
273
+ )
274
+ .doc('Removes a watch (set by add-watch) from an atom.', [['atom', 'key']]),
68
275
 
69
- 'atom?': withDoc(
70
- cljNativeFunction('atom?', (value: CljValue) => {
71
- return cljBoolean(isAtom(value))
72
- }),
73
- 'Returns true if the value is an atom, false otherwise.',
74
- [['value']]
75
- ),
276
+ 'set-validator!': v
277
+ .nativeFnCtx(
278
+ 'set-validator!',
279
+ function setValidator(
280
+ _ctx,
281
+ _callEnv: Env,
282
+ atomVal: CljValue,
283
+ fn: CljValue
284
+ ) {
285
+ if (!is.atom(atomVal)) {
286
+ throw EvaluationError.atArg(
287
+ `set-validator! expects an atom, got ${printString(atomVal)}`,
288
+ { atomVal },
289
+ 0
290
+ )
291
+ }
292
+ if (fn.kind === 'nil') {
293
+ ;(atomVal as CljAtom).validator = undefined
294
+ return v.nil()
295
+ }
296
+ if (!is.aFunction(fn)) {
297
+ throw EvaluationError.atArg(
298
+ `set-validator! expects a function or nil, got ${printString(fn)}`,
299
+ { fn },
300
+ 1
301
+ )
302
+ }
303
+ ;(atomVal as CljAtom).validator = fn
304
+ return v.nil()
305
+ }
306
+ )
307
+ .doc(
308
+ 'Sets the validator-fn for an atom. fn must be nil or a side-effect-free fn of one argument.',
309
+ [['atom', 'fn']]
310
+ ),
76
311
  }
@@ -1,11 +1,11 @@
1
1
  import { CljThrownSignal, EvaluationError } from '../errors'
2
- import { cljKeyword, cljMap, cljNativeFunction, cljNil, withDoc } from '../factories'
3
- import { isKeyword, isMap } from '../assertions'
2
+ import { v } from '../factories'
3
+ import { is } from '../assertions'
4
4
  import type { CljValue } from '../types'
5
5
 
6
6
  export const errorFunctions = {
7
- throw: withDoc(
8
- cljNativeFunction('throw', (...args: CljValue[]) => {
7
+ throw: v
8
+ .nativeFn('throw', function throwImpl(...args: CljValue[]) {
9
9
  if (args.length !== 1) {
10
10
  throw new EvaluationError(
11
11
  `throw requires exactly 1 argument, got ${args.length}`,
@@ -13,13 +13,14 @@ export const errorFunctions = {
13
13
  )
14
14
  }
15
15
  throw new CljThrownSignal(args[0])
16
- }),
17
- 'Throws a value as an exception. The value may be any CljValue; maps are idiomatic.',
18
- [['value']]
19
- ),
16
+ })
17
+ .doc(
18
+ 'Throws a value as an exception. The value may be any CljValue; maps are idiomatic.',
19
+ [['value']]
20
+ ),
20
21
 
21
- 'ex-info': withDoc(
22
- cljNativeFunction('ex-info', (...args: CljValue[]) => {
22
+ 'ex-info': v
23
+ .nativeFn('ex-info', function exInfoImpl(...args: CljValue[]) {
23
24
  if (args.length < 2) {
24
25
  throw new EvaluationError(
25
26
  `ex-info requires at least 2 arguments, got ${args.length}`,
@@ -27,55 +28,58 @@ export const errorFunctions = {
27
28
  )
28
29
  }
29
30
  const [msg, data, cause] = args
30
- if (msg.kind !== 'string') {
31
- throw new EvaluationError(
32
- 'ex-info: first argument must be a string',
33
- { msg }
34
- )
31
+ if (!is.string(msg)) {
32
+ throw new EvaluationError('ex-info: first argument must be a string', {
33
+ msg,
34
+ })
35
35
  }
36
36
  const entries: [CljValue, CljValue][] = [
37
- [cljKeyword(':message'), msg],
38
- [cljKeyword(':data'), data],
37
+ [v.keyword(':message'), msg],
38
+ [v.keyword(':data'), data],
39
39
  ]
40
40
  if (cause !== undefined) {
41
- entries.push([cljKeyword(':cause'), cause])
41
+ entries.push([v.keyword(':cause'), cause])
42
42
  }
43
- return cljMap(entries)
44
- }),
45
- 'Creates an error map with :message and :data keys. Optionally accepts a :cause.',
46
- [['msg', 'data'], ['msg', 'data', 'cause']]
47
- ),
43
+ return v.map(entries)
44
+ })
45
+ .doc(
46
+ 'Creates an error map with :message and :data keys. Optionally accepts a :cause.',
47
+ [
48
+ ['msg', 'data'],
49
+ ['msg', 'data', 'cause'],
50
+ ]
51
+ ),
48
52
 
49
- 'ex-message': withDoc(
50
- cljNativeFunction('ex-message', (...args: CljValue[]) => {
53
+ 'ex-message': v
54
+ .nativeFn('ex-message', function exMessageImpl(...args: CljValue[]) {
51
55
  const [e] = args
52
- if (!isMap(e)) return cljNil()
53
- const entry = e.entries.find(([k]) => isKeyword(k) && k.name === ':message')
54
- return entry ? entry[1] : cljNil()
55
- }),
56
- 'Returns the :message of an error map, or nil.',
57
- [['e']]
58
- ),
56
+ if (!is.map(e)) return v.nil()
57
+ const entry = e.entries.find(function findMessageKey([k]) {
58
+ return is.keyword(k) && k.name === ':message'
59
+ })
60
+ return entry ? entry[1] : v.nil()
61
+ })
62
+ .doc('Returns the :message of an error map, or nil.', [['e']]),
59
63
 
60
- 'ex-data': withDoc(
61
- cljNativeFunction('ex-data', (...args: CljValue[]) => {
64
+ 'ex-data': v
65
+ .nativeFn('ex-data', function exDataImpl(...args: CljValue[]) {
62
66
  const [e] = args
63
- if (!isMap(e)) return cljNil()
64
- const entry = e.entries.find(([k]) => isKeyword(k) && k.name === ':data')
65
- return entry ? entry[1] : cljNil()
66
- }),
67
- 'Returns the :data map of an error map, or nil.',
68
- [['e']]
69
- ),
67
+ if (!is.map(e)) return v.nil()
68
+ const entry = e.entries.find(function findDataKey([k]) {
69
+ return is.keyword(k) && k.name === ':data'
70
+ })
71
+ return entry ? entry[1] : v.nil()
72
+ })
73
+ .doc('Returns the :data map of an error map, or nil.', [['e']]),
70
74
 
71
- 'ex-cause': withDoc(
72
- cljNativeFunction('ex-cause', (...args: CljValue[]) => {
75
+ 'ex-cause': v
76
+ .nativeFn('ex-cause', function exCauseImpl(...args: CljValue[]) {
73
77
  const [e] = args
74
- if (!isMap(e)) return cljNil()
75
- const entry = e.entries.find(([k]) => isKeyword(k) && k.name === ':cause')
76
- return entry ? entry[1] : cljNil()
77
- }),
78
- 'Returns the :cause of an error map, or nil.',
79
- [['e']]
80
- ),
78
+ if (!is.map(e)) return v.nil()
79
+ const entry = e.entries.find(function findCauseKey([k]) {
80
+ return is.keyword(k) && k.name === ':cause'
81
+ })
82
+ return entry ? entry[1] : v.nil()
83
+ })
84
+ .doc('Returns the :cause of an error map, or nil.', [['e']]),
81
85
  }