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,564 @@
1
+ // Sequence abstraction: list, seq, first, rest, cons, conj, count, empty?, empty,
2
+ // nth, get, contains?, last, reverse, repeat*, range*
3
+ //
4
+ // These are the "core sequence protocol" operations — they apply uniformly across
5
+ // all collection types. conj lives here because it implements the sequence
6
+ // construction protocol (prepend for lists, append for vectors, kv-pair for maps,
7
+ // element dedup for sets).
8
+
9
+ import { is } from '../assertions'
10
+ import { EvaluationError } from '../errors'
11
+ import { v } from '../factories'
12
+ import { printString } from '../printer'
13
+ import { realizeLazySeq, toSeq } from '../transformations'
14
+ import {
15
+ valueKeywords,
16
+ type CljList,
17
+ type CljMap,
18
+ type CljNumber,
19
+ type CljSet,
20
+ type CljString,
21
+ type CljValue,
22
+ type CljVector,
23
+ } from '../types'
24
+
25
+ export const seqFunctions: Record<string, CljValue> = {
26
+ list: v
27
+ .nativeFn('list', function listImpl(...args: CljValue[]) {
28
+ if (args.length === 0) {
29
+ return v.list([])
30
+ }
31
+ return v.list(args)
32
+ })
33
+ .doc('Returns a new list containing the given values.', [['&', 'args']]),
34
+
35
+ seq: v
36
+ .nativeFn('seq', function seqImpl(coll: CljValue): CljValue {
37
+ if (coll.kind === 'nil') return v.nil()
38
+ if (is.lazySeq(coll)) {
39
+ const realized = realizeLazySeq(coll)
40
+ if (is.nil(realized)) return v.nil()
41
+ return seqImpl(realized)
42
+ }
43
+ if (is.cons(coll)) return coll
44
+ if (!is.seqable(coll)) {
45
+ throw EvaluationError.atArg(
46
+ `seq expects a collection, string, or nil, got ${printString(coll)}`,
47
+ { collection: coll },
48
+ 0
49
+ )
50
+ }
51
+ const items = toSeq(coll)
52
+ return items.length === 0 ? v.nil() : v.list(items)
53
+ })
54
+ .doc(
55
+ 'Returns a sequence of the given collection or string. Strings yield a sequence of single-character strings.',
56
+ [['coll']]
57
+ ),
58
+
59
+ first: v
60
+ .nativeFn('first', function firstImpl(collection: CljValue): CljValue {
61
+ if (collection.kind === 'nil') return v.nil()
62
+ if (is.lazySeq(collection)) {
63
+ const realized = realizeLazySeq(collection)
64
+ if (is.nil(realized)) return v.nil()
65
+ return firstImpl(realized)
66
+ }
67
+ if (is.cons(collection)) return collection.head
68
+ if (!is.seqable(collection)) {
69
+ throw EvaluationError.atArg(
70
+ 'first expects a collection or string',
71
+ { collection },
72
+ 0
73
+ )
74
+ }
75
+ const entries = toSeq(collection)
76
+ return entries.length === 0 ? v.nil() : entries[0]
77
+ })
78
+ .doc('Returns the first element of the given collection or string.', [
79
+ ['coll'],
80
+ ]),
81
+
82
+ rest: v
83
+ .nativeFn('rest', function restImpl(collection: CljValue): CljValue {
84
+ if (collection.kind === 'nil') return v.list([])
85
+ if (is.lazySeq(collection)) {
86
+ const realized = realizeLazySeq(collection)
87
+ if (is.nil(realized)) return v.list([])
88
+ return restImpl(realized)
89
+ }
90
+ if (is.cons(collection)) return collection.tail
91
+ if (!is.seqable(collection)) {
92
+ throw EvaluationError.atArg(
93
+ 'rest expects a collection or string',
94
+ { collection },
95
+ 0
96
+ )
97
+ }
98
+ if (is.list(collection)) {
99
+ if (collection.value.length === 0) {
100
+ return collection // return the empty list
101
+ }
102
+ return v.list(collection.value.slice(1))
103
+ }
104
+ if (is.vector(collection)) {
105
+ return v.vector(collection.value.slice(1))
106
+ }
107
+ if (is.map(collection)) {
108
+ if (collection.entries.length === 0) {
109
+ return collection // return the empty map
110
+ }
111
+ return v.map(collection.entries.slice(1))
112
+ }
113
+ if (collection.kind === 'string') {
114
+ const chars = toSeq(collection)
115
+ return v.list(chars.slice(1))
116
+ }
117
+ throw EvaluationError.atArg(
118
+ `rest expects a collection or string, got ${printString(collection)}`,
119
+ { collection },
120
+ 0
121
+ )
122
+ })
123
+ .doc(
124
+ 'Returns a sequence of the given collection or string excluding the first element.',
125
+ [['coll']]
126
+ ),
127
+
128
+ // conj dispatches across all collection types — it belongs here as the primary
129
+ // sequence construction operation (cons-cell prepend for lists, append for
130
+ // vectors, kv-pair insert for maps, deduplicating add for sets).
131
+ conj: v
132
+ .nativeFn(
133
+ 'conj',
134
+ function conjImpl(collection: CljValue, ...args: CljValue[]) {
135
+ if (!collection) {
136
+ throw new EvaluationError(
137
+ 'conj expects a collection as first argument',
138
+ { collection }
139
+ )
140
+ }
141
+ if (args.length === 0) {
142
+ return collection
143
+ }
144
+ if (!is.collection(collection)) {
145
+ throw EvaluationError.atArg(
146
+ `conj expects a collection, got ${printString(collection)}`,
147
+ { collection },
148
+ 0
149
+ )
150
+ }
151
+ if (is.list(collection)) {
152
+ const newItems = [] as CljValue[]
153
+ for (let i = args.length - 1; i >= 0; i--) {
154
+ newItems.push(args[i])
155
+ }
156
+ return v.list([...newItems, ...collection.value])
157
+ }
158
+ if (is.vector(collection)) {
159
+ return v.vector([...collection.value, ...args])
160
+ }
161
+ if (is.map(collection)) {
162
+ // each argument should be a vector key-pair
163
+ const newEntries: [CljValue, CljValue][] = [...collection.entries]
164
+ for (let i = 0; i < args.length; i += 1) {
165
+ const pair = args[i] as CljVector
166
+ // pair args start at index 1 in the call (collection is index 0)
167
+ const pairArgIndex = i + 1
168
+
169
+ if (pair.kind !== 'vector') {
170
+ throw EvaluationError.atArg(
171
+ `conj on maps expects each argument to be a vector key-pair for maps, got ${printString(pair)}`,
172
+ { pair },
173
+ pairArgIndex
174
+ )
175
+ }
176
+ if (pair.value.length !== 2) {
177
+ throw EvaluationError.atArg(
178
+ `conj on maps expects each argument to be a vector key-pair for maps, got ${printString(pair)}`,
179
+ { pair },
180
+ pairArgIndex
181
+ )
182
+ }
183
+ const key = pair.value[0]
184
+ const keyIdx = newEntries.findIndex(function findKeyEntry(entry) {
185
+ return is.equal(entry[0], key)
186
+ })
187
+ if (keyIdx === -1) {
188
+ newEntries.push([key, pair.value[1]])
189
+ } else {
190
+ newEntries[keyIdx] = [key, pair.value[1]]
191
+ }
192
+ }
193
+ return v.map([...newEntries])
194
+ }
195
+
196
+ if (is.set(collection)) {
197
+ const newValues = [...collection.values]
198
+ for (const v of args) {
199
+ if (!newValues.some((existing) => is.equal(existing, v))) {
200
+ newValues.push(v)
201
+ }
202
+ }
203
+ return v.set(newValues)
204
+ }
205
+
206
+ throw new EvaluationError(
207
+ `unhandled collection type, got ${printString(collection)}`,
208
+ { collection }
209
+ )
210
+ }
211
+ )
212
+ .doc(
213
+ 'Appends args to the given collection. Lists append in reverse order to the head, vectors append to the tail, sets add unique elements.',
214
+ [['collection', '&', 'args']]
215
+ ),
216
+
217
+ cons: v
218
+ .nativeFn('cons', function consImpl(x: CljValue, xs: CljValue) {
219
+ // When tail is lazy-seq or cons, create a cons cell to preserve laziness
220
+ if (is.lazySeq(xs) || is.cons(xs)) {
221
+ return v.cons(x, xs)
222
+ }
223
+ if (is.nil(xs)) {
224
+ return v.list([x])
225
+ }
226
+ if (!is.collection(xs)) {
227
+ throw EvaluationError.atArg(
228
+ `cons expects a collection as second argument, got ${printString(xs)}`,
229
+ { xs },
230
+ 1
231
+ )
232
+ }
233
+ if (is.map(xs) || is.set(xs)) {
234
+ throw EvaluationError.atArg(
235
+ 'cons on maps and sets is not supported, use vectors instead',
236
+ { xs },
237
+ 1
238
+ )
239
+ }
240
+
241
+ const wrap = is.list(xs) ? v.list : v.vector
242
+ const newItems = [x, ...xs.value]
243
+
244
+ return wrap(newItems)
245
+ })
246
+ .doc('Returns a new collection with x prepended to the head of xs.', [
247
+ ['x', 'xs'],
248
+ ]),
249
+
250
+ get: v
251
+ .nativeFn(
252
+ 'get',
253
+ function getImpl(target: CljValue, key: CljValue, notFound?: CljValue) {
254
+ const defaultValue = notFound ?? v.nil()
255
+
256
+ switch (target.kind) {
257
+ case valueKeywords.map: {
258
+ const entries = target.entries
259
+ for (const [k, v] of entries) {
260
+ if (is.equal(k, key)) {
261
+ return v
262
+ }
263
+ }
264
+ return defaultValue
265
+ }
266
+ case valueKeywords.vector: {
267
+ const values = target.value
268
+ if (key.kind !== 'number') {
269
+ throw new EvaluationError(
270
+ 'get on vectors expects a 0-based index as parameter',
271
+ { key }
272
+ )
273
+ }
274
+ if (key.value < 0 || key.value >= values.length) {
275
+ return defaultValue
276
+ }
277
+ return values[key.value]
278
+ }
279
+ default:
280
+ return defaultValue
281
+ }
282
+ }
283
+ )
284
+ .doc(
285
+ 'Returns the value associated with key in target. If target is a map, returns the value associated with key, otherwise returns the value at index key in target. If not-found is provided, it is returned if the key is not found, otherwise nil is returned.',
286
+ [
287
+ ['target', 'key'],
288
+ ['target', 'key', 'not-found'],
289
+ ]
290
+ ),
291
+
292
+ nth: v
293
+ .nativeFn(
294
+ 'nth',
295
+ function nthImpl(coll: CljValue, n: CljValue, notFound?: CljValue) {
296
+ if (coll === undefined || (!is.list(coll) && !is.vector(coll))) {
297
+ throw new EvaluationError(
298
+ `nth expects a list or vector${coll !== undefined ? `, got ${printString(coll)}` : ''}`,
299
+ { coll }
300
+ )
301
+ }
302
+ if (n === undefined || n.kind !== 'number') {
303
+ throw new EvaluationError(
304
+ `nth expects a number index${n !== undefined ? `, got ${printString(n)}` : ''}`,
305
+ { n }
306
+ )
307
+ }
308
+ const index = (n as CljNumber).value
309
+ const items = coll.value
310
+ if (index < 0 || index >= items.length) {
311
+ if (notFound !== undefined) return notFound
312
+ const err = new EvaluationError(
313
+ `nth index ${index} is out of bounds for collection of length ${items.length}`,
314
+ { coll, n }
315
+ )
316
+ err.data = { argIndex: 1 }
317
+ throw err
318
+ }
319
+ return items[index]
320
+ }
321
+ )
322
+ .doc(
323
+ 'Returns the nth element of the given collection. If not-found is provided, it is returned if the index is out of bounds, otherwise an error is thrown.',
324
+ [['coll', 'n', 'not-found']]
325
+ ),
326
+
327
+ last: v
328
+ .nativeFn('last', function lastImpl(coll: CljValue) {
329
+ if (coll === undefined || (!is.list(coll) && !is.vector(coll))) {
330
+ throw new EvaluationError(
331
+ `last expects a list or vector${coll !== undefined ? `, got ${printString(coll)}` : ''}`,
332
+ { coll }
333
+ )
334
+ }
335
+ const items = coll.value
336
+ return items.length === 0 ? v.nil() : items[items.length - 1]
337
+ })
338
+ .doc('Returns the last element of the given collection.', [['coll']]),
339
+
340
+ reverse: v
341
+ .nativeFn('reverse', function reverseImpl(coll: CljValue) {
342
+ if (coll === undefined || (!is.list(coll) && !is.vector(coll))) {
343
+ throw EvaluationError.atArg(
344
+ `reverse expects a list or vector${coll !== undefined ? `, got ${printString(coll)}` : ''}`,
345
+ { coll },
346
+ 0
347
+ )
348
+ }
349
+ return v.list([...coll.value].reverse())
350
+ })
351
+ .doc(
352
+ 'Returns a new sequence with the elements of the given collection in reverse order.',
353
+ [['coll']]
354
+ ),
355
+
356
+ 'empty?': v
357
+ .nativeFn('empty?', function emptyPredImpl(coll: CljValue) {
358
+ if (coll === undefined) {
359
+ throw EvaluationError.atArg('empty? expects one argument', {}, 0)
360
+ }
361
+ // nil and empty string count as empty, matching Clojure semantics
362
+ if (coll.kind === 'nil') return v.boolean(true)
363
+ if (!is.seqable(coll)) {
364
+ throw EvaluationError.atArg(
365
+ `empty? expects a collection, string, or nil, got ${printString(coll)}`,
366
+ { coll },
367
+ 0
368
+ )
369
+ }
370
+ return v.boolean(toSeq(coll).length === 0)
371
+ })
372
+ .doc(
373
+ 'Returns true if coll has no items. Accepts collections, strings, and nil.',
374
+ [['coll']]
375
+ ),
376
+
377
+ 'contains?': v
378
+ .nativeFn(
379
+ 'contains?',
380
+ function containsPredImpl(coll: CljValue, key: CljValue) {
381
+ if (coll === undefined) {
382
+ throw EvaluationError.atArg(
383
+ 'contains? expects a collection as first argument',
384
+ {},
385
+ 0
386
+ )
387
+ }
388
+ if (key === undefined) {
389
+ throw EvaluationError.atArg(
390
+ 'contains? expects a key as second argument',
391
+ {},
392
+ 1
393
+ )
394
+ }
395
+ if (coll.kind === 'nil') return v.boolean(false)
396
+ if (is.map(coll)) {
397
+ return v.boolean(
398
+ coll.entries.some(function checkKeyMatch([k]) {
399
+ return is.equal(k, key)
400
+ })
401
+ )
402
+ }
403
+ if (is.vector(coll)) {
404
+ if (key.kind !== 'number') return v.boolean(false)
405
+ return v.boolean(key.value >= 0 && key.value < coll.value.length)
406
+ }
407
+ if (is.set(coll)) {
408
+ return v.boolean(coll.values.some((v) => is.equal(v, key)))
409
+ }
410
+ throw EvaluationError.atArg(
411
+ `contains? expects a map, set, vector, or nil, got ${printString(coll)}`,
412
+ { coll },
413
+ 0
414
+ )
415
+ }
416
+ )
417
+ .doc(
418
+ 'Returns true if key is present in coll. For maps checks key existence (including keys with nil values). For vectors checks index bounds.',
419
+ [['coll', 'key']]
420
+ ),
421
+
422
+ 'repeat*': v
423
+ .nativeFn('repeat*', function repeatImpl(n: CljValue, x: CljValue) {
424
+ if (n === undefined || n.kind !== 'number') {
425
+ throw EvaluationError.atArg(
426
+ `repeat expects a number as first argument${n !== undefined ? `, got ${printString(n)}` : ''}`,
427
+ { n },
428
+ 0
429
+ )
430
+ }
431
+ return v.list(Array(n.value).fill(x))
432
+ })
433
+ .doc('Returns a finite sequence of n copies of x (native helper).', [
434
+ ['n', 'x'],
435
+ ]),
436
+
437
+ // ── Range ────────────────────────────────────────────────────────────────
438
+
439
+ 'range*': v
440
+ .nativeFn('range*', function rangeImpl(...args: CljValue[]) {
441
+ if (args.length === 0 || args.length > 3) {
442
+ throw new EvaluationError(
443
+ 'range expects 1, 2, or 3 arguments: (range n), (range start end), or (range start end step)',
444
+ { args }
445
+ )
446
+ }
447
+ const badIdx = args.findIndex(function checkIsNumber(a) {
448
+ return a.kind !== 'number'
449
+ })
450
+ if (badIdx !== -1) {
451
+ throw EvaluationError.atArg(
452
+ 'range expects number arguments',
453
+ { args },
454
+ badIdx
455
+ )
456
+ }
457
+ let start: number
458
+ let end: number
459
+ let step: number
460
+ if (args.length === 1) {
461
+ start = 0
462
+ end = (args[0] as CljNumber).value
463
+ step = 1
464
+ } else if (args.length === 2) {
465
+ start = (args[0] as CljNumber).value
466
+ end = (args[1] as CljNumber).value
467
+ step = 1
468
+ } else {
469
+ start = (args[0] as CljNumber).value
470
+ end = (args[1] as CljNumber).value
471
+ step = (args[2] as CljNumber).value
472
+ }
473
+ if (step === 0) {
474
+ // step is always the last arg: index args.length - 1
475
+ throw EvaluationError.atArg(
476
+ 'range step cannot be zero',
477
+ { args },
478
+ args.length - 1
479
+ )
480
+ }
481
+ const result: CljValue[] = []
482
+ if (step > 0) {
483
+ for (let i = start; i < end; i += step) {
484
+ result.push(v.number(i))
485
+ }
486
+ } else {
487
+ for (let i = start; i > end; i += step) {
488
+ result.push(v.number(i))
489
+ }
490
+ }
491
+ return v.list(result)
492
+ })
493
+ .doc('Returns a finite sequence of numbers (native helper).', [
494
+ ['n'],
495
+ ['start', 'end'],
496
+ ['start', 'end', 'step'],
497
+ ]),
498
+
499
+ count: v
500
+ .nativeFn('count', function countImpl(countable: CljValue) {
501
+ if (countable.kind === 'nil') return v.number(0)
502
+ if (is.lazySeq(countable) || is.cons(countable)) {
503
+ return v.number(toSeq(countable).length)
504
+ }
505
+ if (
506
+ !(
507
+ [
508
+ valueKeywords.list,
509
+ valueKeywords.vector,
510
+ valueKeywords.map,
511
+ valueKeywords.set,
512
+ valueKeywords.string,
513
+ ] as string[]
514
+ ).includes(countable.kind)
515
+ ) {
516
+ throw EvaluationError.atArg(
517
+ `count expects a countable value, got ${printString(countable)}`,
518
+ { countable },
519
+ 0
520
+ )
521
+ }
522
+
523
+ switch (countable.kind) {
524
+ case valueKeywords.list:
525
+ return v.number((countable as CljList).value.length)
526
+ case valueKeywords.vector:
527
+ return v.number((countable as CljVector).value.length)
528
+ case valueKeywords.map:
529
+ return v.number((countable as CljMap).entries.length)
530
+ case valueKeywords.set:
531
+ return v.number((countable as CljSet).values.length)
532
+ case valueKeywords.string:
533
+ return v.number((countable as CljString).value.length)
534
+ default:
535
+ throw new EvaluationError(
536
+ `count expects a countable value, got ${printString(countable)}`,
537
+ { countable }
538
+ )
539
+ }
540
+ })
541
+ .doc('Returns the number of elements in the given countable value.', [
542
+ ['countable'],
543
+ ]),
544
+
545
+ empty: v
546
+ .nativeFn('empty', function emptyImpl(coll: CljValue) {
547
+ if (coll === undefined || coll.kind === 'nil') return v.nil()
548
+ switch (coll.kind) {
549
+ case 'list':
550
+ return v.list([])
551
+ case 'vector':
552
+ return v.vector([])
553
+ case 'map':
554
+ return v.map([])
555
+ case 'set':
556
+ return v.set([])
557
+ default:
558
+ return v.nil()
559
+ }
560
+ })
561
+ .doc('Returns an empty collection of the same category as coll, or nil.', [
562
+ ['coll'],
563
+ ]),
564
+ }