@bookshop/hugo-engine 2.4.0-hugo.0

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 (75) hide show
  1. package/.nyc_output/50eb2ebd-c797-4d3f-8df7-a707c1b211eb.json +1 -0
  2. package/.nyc_output/86f85916-4f58-43da-8c32-c1ec29ca783e.json +1 -0
  3. package/.nyc_output/a27680c8-8858-4ede-921d-6e6617f42a0b.json +1 -0
  4. package/.nyc_output/b5f86652-cbe8-44f9-a36c-d5721dfe5bbe.json +1 -0
  5. package/.nyc_output/ecca87c1-5774-4962-864a-2e4537aa9915.json +1 -0
  6. package/.nyc_output/processinfo/50eb2ebd-c797-4d3f-8df7-a707c1b211eb.json +1 -0
  7. package/.nyc_output/processinfo/86f85916-4f58-43da-8c32-c1ec29ca783e.json +1 -0
  8. package/.nyc_output/processinfo/a27680c8-8858-4ede-921d-6e6617f42a0b.json +1 -0
  9. package/.nyc_output/processinfo/b5f86652-cbe8-44f9-a36c-d5721dfe5bbe.json +1 -0
  10. package/.nyc_output/processinfo/ecca87c1-5774-4962-864a-2e4537aa9915.json +1 -0
  11. package/.nyc_output/processinfo/index.json +1 -0
  12. package/build.js +1 -0
  13. package/hugo-renderer/build.sh +16 -0
  14. package/hugo-renderer/deps/bookshop_modified_deps.go +6 -0
  15. package/hugo-renderer/go.mod +55 -0
  16. package/hugo-renderer/go.sum +886 -0
  17. package/hugo-renderer/helpers/bookshop_modified_content.go +64 -0
  18. package/hugo-renderer/helpers/bookshop_modified_general.go +33 -0
  19. package/hugo-renderer/hugo_renderer.wasm +0 -0
  20. package/hugo-renderer/main.go +28 -0
  21. package/hugo-renderer/tpl/bookshop_engine/bookshop_func_importer.go +34 -0
  22. package/hugo-renderer/tpl/bookshop_engine/bookshop_render.go +64 -0
  23. package/hugo-renderer/tpl/bookshop_library/bookshop_components.go +107 -0
  24. package/hugo-renderer/tpl/cast/cast.go +63 -0
  25. package/hugo-renderer/tpl/cast/init.go +57 -0
  26. package/hugo-renderer/tpl/collections/append.go +37 -0
  27. package/hugo-renderer/tpl/collections/apply.go +131 -0
  28. package/hugo-renderer/tpl/collections/collections.go +767 -0
  29. package/hugo-renderer/tpl/collections/complement.go +55 -0
  30. package/hugo-renderer/tpl/collections/index.go +133 -0
  31. package/hugo-renderer/tpl/collections/init.go +214 -0
  32. package/hugo-renderer/tpl/collections/merge.go +126 -0
  33. package/hugo-renderer/tpl/collections/reflect_helpers.go +216 -0
  34. package/hugo-renderer/tpl/collections/sort.go +183 -0
  35. package/hugo-renderer/tpl/collections/symdiff.go +68 -0
  36. package/hugo-renderer/tpl/collections/where.go +517 -0
  37. package/hugo-renderer/tpl/compare/compare.go +324 -0
  38. package/hugo-renderer/tpl/compare/init.go +85 -0
  39. package/hugo-renderer/tpl/crypto/crypto.go +109 -0
  40. package/hugo-renderer/tpl/crypto/init.go +65 -0
  41. package/hugo-renderer/tpl/debug/debug.go +40 -0
  42. package/hugo-renderer/tpl/debug/init.go +45 -0
  43. package/hugo-renderer/tpl/encoding/encoding.go +90 -0
  44. package/hugo-renderer/tpl/encoding/init.go +59 -0
  45. package/hugo-renderer/tpl/fmt/fmt.go +64 -0
  46. package/hugo-renderer/tpl/fmt/init.go +77 -0
  47. package/hugo-renderer/tpl/inflect/inflect.go +79 -0
  48. package/hugo-renderer/tpl/inflect/init.go +60 -0
  49. package/hugo-renderer/tpl/internal/bookshop_modified_templatefuncsRegistry.go +88 -0
  50. package/hugo-renderer/tpl/math/init.go +134 -0
  51. package/hugo-renderer/tpl/math/math.go +164 -0
  52. package/hugo-renderer/tpl/math/round.go +61 -0
  53. package/hugo-renderer/tpl/partials/init.go +55 -0
  54. package/hugo-renderer/tpl/partials/partials.go +86 -0
  55. package/hugo-renderer/tpl/path/init.go +60 -0
  56. package/hugo-renderer/tpl/path/path.go +159 -0
  57. package/hugo-renderer/tpl/reflect/init.go +51 -0
  58. package/hugo-renderer/tpl/reflect/reflect.go +36 -0
  59. package/hugo-renderer/tpl/safe/init.go +80 -0
  60. package/hugo-renderer/tpl/safe/safe.go +72 -0
  61. package/hugo-renderer/tpl/strings/init.go +229 -0
  62. package/hugo-renderer/tpl/strings/regexp.go +125 -0
  63. package/hugo-renderer/tpl/strings/strings.go +500 -0
  64. package/hugo-renderer/tpl/strings/truncate.go +157 -0
  65. package/hugo-renderer/wasm_exec.js +636 -0
  66. package/lib/builder.js +21 -0
  67. package/lib/engine.js +134 -0
  68. package/lib/engine.test.js +5 -0
  69. package/lib/hugoIdentifierParser.js +324 -0
  70. package/lib/hugoIdentifierParser.test.js +72 -0
  71. package/lib/translateTextTemplate.js +58 -0
  72. package/lib/translateTextTemplate.test.js +39 -0
  73. package/main.js +1 -0
  74. package/main.test.js +5 -0
  75. package/package.json +32 -0
@@ -0,0 +1,767 @@
1
+ // Copyright 2019 The Hugo Authors. All rights reserved.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ // http://www.apache.org/licenses/LICENSE-2.0
7
+ //
8
+ // Unless required by applicable law or agreed to in writing, software
9
+ // distributed under the License is distributed on an "AS IS" BASIS,
10
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ // See the License for the specific language governing permissions and
12
+ // limitations under the License.
13
+
14
+ // Package collections provides template functions for manipulating collections
15
+ // such as arrays, maps, and slices.
16
+ package collections
17
+
18
+ import (
19
+ "fmt"
20
+ "html/template"
21
+ "math/rand"
22
+ "net/url"
23
+ "reflect"
24
+ "strings"
25
+ "time"
26
+
27
+ "hugo-renderer/deps"
28
+
29
+ "github.com/gohugoio/hugo/common/collections"
30
+ "github.com/gohugoio/hugo/common/maps"
31
+ "github.com/gohugoio/hugo/common/types"
32
+ "github.com/pkg/errors"
33
+ "github.com/spf13/cast"
34
+ )
35
+
36
+ func init() {
37
+ rand.Seed(time.Now().UTC().UnixNano())
38
+ }
39
+
40
+ // New returns a new instance of the collections-namespaced template functions.
41
+ func New(deps *deps.Deps) *Namespace {
42
+ return &Namespace{
43
+ deps: deps,
44
+ }
45
+ }
46
+
47
+ // Namespace provides template functions for the "collections" namespace.
48
+ type Namespace struct {
49
+ deps *deps.Deps
50
+ }
51
+
52
+ // After returns all the items after the first N in a rangeable list.
53
+ func (ns *Namespace) After(index interface{}, seq interface{}) (interface{}, error) {
54
+ if index == nil || seq == nil {
55
+ return nil, errors.New("both limit and seq must be provided")
56
+ }
57
+
58
+ indexv, err := cast.ToIntE(index)
59
+ if err != nil {
60
+ return nil, err
61
+ }
62
+
63
+ if indexv < 0 {
64
+ return nil, errors.New("sequence bounds out of range [" + cast.ToString(indexv) + ":]")
65
+ }
66
+
67
+ seqv := reflect.ValueOf(seq)
68
+ seqv, isNil := indirect(seqv)
69
+ if isNil {
70
+ return nil, errors.New("can't iterate over a nil value")
71
+ }
72
+
73
+ switch seqv.Kind() {
74
+ case reflect.Array, reflect.Slice, reflect.String:
75
+ // okay
76
+ default:
77
+ return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
78
+ }
79
+
80
+ if indexv >= seqv.Len() {
81
+ return seqv.Slice(0, 0).Interface(), nil
82
+ }
83
+
84
+ return seqv.Slice(indexv, seqv.Len()).Interface(), nil
85
+ }
86
+
87
+ // Delimit takes a given sequence and returns a delimited HTML string.
88
+ // If last is passed to the function, it will be used as the final delimiter.
89
+ func (ns *Namespace) Delimit(seq, delimiter interface{}, last ...interface{}) (template.HTML, error) {
90
+ d, err := cast.ToStringE(delimiter)
91
+ if err != nil {
92
+ return "", err
93
+ }
94
+
95
+ var dLast *string
96
+ if len(last) > 0 {
97
+ l := last[0]
98
+ dStr, err := cast.ToStringE(l)
99
+ if err != nil {
100
+ dLast = nil
101
+ } else {
102
+ dLast = &dStr
103
+ }
104
+ }
105
+
106
+ seqv := reflect.ValueOf(seq)
107
+ seqv, isNil := indirect(seqv)
108
+ if isNil {
109
+ return "", errors.New("can't iterate over a nil value")
110
+ }
111
+
112
+ var str string
113
+ switch seqv.Kind() {
114
+ case reflect.Map:
115
+ sortSeq, err := ns.Sort(seq)
116
+ if err != nil {
117
+ return "", err
118
+ }
119
+ seqv = reflect.ValueOf(sortSeq)
120
+ fallthrough
121
+ case reflect.Array, reflect.Slice, reflect.String:
122
+ for i := 0; i < seqv.Len(); i++ {
123
+ val := seqv.Index(i).Interface()
124
+ valStr, err := cast.ToStringE(val)
125
+ if err != nil {
126
+ continue
127
+ }
128
+ switch {
129
+ case i == seqv.Len()-2 && dLast != nil:
130
+ str += valStr + *dLast
131
+ case i == seqv.Len()-1:
132
+ str += valStr
133
+ default:
134
+ str += valStr + d
135
+ }
136
+ }
137
+
138
+ default:
139
+ return "", fmt.Errorf("can't iterate over %v", seq)
140
+ }
141
+
142
+ return template.HTML(str), nil
143
+ }
144
+
145
+ // Dictionary creates a map[string]interface{} from the given parameters by
146
+ // walking the parameters and treating them as key-value pairs. The number
147
+ // of parameters must be even.
148
+ // The keys can be string slices, which will create the needed nested structure.
149
+ func (ns *Namespace) Dictionary(values ...interface{}) (map[string]interface{}, error) {
150
+ if len(values)%2 != 0 {
151
+ return nil, errors.New("invalid dictionary call")
152
+ }
153
+
154
+ root := make(map[string]interface{})
155
+
156
+ for i := 0; i < len(values); i += 2 {
157
+ dict := root
158
+ var key string
159
+ switch v := values[i].(type) {
160
+ case string:
161
+ key = v
162
+ case []string:
163
+ for i := 0; i < len(v)-1; i++ {
164
+ key = v[i]
165
+ var m map[string]interface{}
166
+ v, found := dict[key]
167
+ if found {
168
+ m = v.(map[string]interface{})
169
+ } else {
170
+ m = make(map[string]interface{})
171
+ dict[key] = m
172
+ }
173
+ dict = m
174
+ }
175
+ key = v[len(v)-1]
176
+ default:
177
+ return nil, errors.New("invalid dictionary key")
178
+ }
179
+ dict[key] = values[i+1]
180
+ }
181
+
182
+ return root, nil
183
+ }
184
+
185
+ // EchoParam returns a given value if it is set; otherwise, it returns an
186
+ // empty string.
187
+ func (ns *Namespace) EchoParam(a, key interface{}) interface{} {
188
+ av, isNil := indirect(reflect.ValueOf(a))
189
+ if isNil {
190
+ return ""
191
+ }
192
+
193
+ var avv reflect.Value
194
+ switch av.Kind() {
195
+ case reflect.Array, reflect.Slice:
196
+ index, ok := key.(int)
197
+ if ok && av.Len() > index {
198
+ avv = av.Index(index)
199
+ }
200
+ case reflect.Map:
201
+ kv := reflect.ValueOf(key)
202
+ if kv.Type().AssignableTo(av.Type().Key()) {
203
+ avv = av.MapIndex(kv)
204
+ }
205
+ }
206
+
207
+ avv, isNil = indirect(avv)
208
+
209
+ if isNil {
210
+ return ""
211
+ }
212
+
213
+ if avv.IsValid() {
214
+ switch avv.Kind() {
215
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
216
+ return avv.Int()
217
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
218
+ return avv.Uint()
219
+ case reflect.Float32, reflect.Float64:
220
+ return avv.Float()
221
+ case reflect.String:
222
+ return avv.String()
223
+ }
224
+ }
225
+
226
+ return ""
227
+ }
228
+
229
+ // First returns the first N items in a rangeable list.
230
+ func (ns *Namespace) First(limit interface{}, seq interface{}) (interface{}, error) {
231
+ if limit == nil || seq == nil {
232
+ return nil, errors.New("both limit and seq must be provided")
233
+ }
234
+
235
+ limitv, err := cast.ToIntE(limit)
236
+ if err != nil {
237
+ return nil, err
238
+ }
239
+
240
+ if limitv < 0 {
241
+ return nil, errors.New("sequence length must be non-negative")
242
+ }
243
+
244
+ seqv := reflect.ValueOf(seq)
245
+ seqv, isNil := indirect(seqv)
246
+ if isNil {
247
+ return nil, errors.New("can't iterate over a nil value")
248
+ }
249
+
250
+ switch seqv.Kind() {
251
+ case reflect.Array, reflect.Slice, reflect.String:
252
+ // okay
253
+ default:
254
+ return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
255
+ }
256
+
257
+ if limitv > seqv.Len() {
258
+ limitv = seqv.Len()
259
+ }
260
+
261
+ return seqv.Slice(0, limitv).Interface(), nil
262
+ }
263
+
264
+ // In returns whether v is in the set l. l may be an array or slice.
265
+ func (ns *Namespace) In(l interface{}, v interface{}) (bool, error) {
266
+ if l == nil || v == nil {
267
+ return false, nil
268
+ }
269
+
270
+ lv := reflect.ValueOf(l)
271
+ vv := reflect.ValueOf(v)
272
+
273
+ vvk := normalize(vv)
274
+
275
+ switch lv.Kind() {
276
+ case reflect.Array, reflect.Slice:
277
+ for i := 0; i < lv.Len(); i++ {
278
+ lvv, isNil := indirectInterface(lv.Index(i))
279
+ if isNil {
280
+ continue
281
+ }
282
+
283
+ lvvk := normalize(lvv)
284
+
285
+ if lvvk == vvk {
286
+ return true, nil
287
+ }
288
+ }
289
+ }
290
+ ss, err := cast.ToStringE(l)
291
+ if err != nil {
292
+ return false, nil
293
+ }
294
+
295
+ su, err := cast.ToStringE(v)
296
+ if err != nil {
297
+ return false, nil
298
+ }
299
+ return strings.Contains(ss, su), nil
300
+ }
301
+
302
+ // Intersect returns the common elements in the given sets, l1 and l2. l1 and
303
+ // l2 must be of the same type and may be either arrays or slices.
304
+ func (ns *Namespace) Intersect(l1, l2 interface{}) (interface{}, error) {
305
+ if l1 == nil || l2 == nil {
306
+ return make([]interface{}, 0), nil
307
+ }
308
+
309
+ var ins *intersector
310
+
311
+ l1v := reflect.ValueOf(l1)
312
+ l2v := reflect.ValueOf(l2)
313
+
314
+ switch l1v.Kind() {
315
+ case reflect.Array, reflect.Slice:
316
+ ins = &intersector{r: reflect.MakeSlice(l1v.Type(), 0, 0), seen: make(map[interface{}]bool)}
317
+ switch l2v.Kind() {
318
+ case reflect.Array, reflect.Slice:
319
+ for i := 0; i < l1v.Len(); i++ {
320
+ l1vv := l1v.Index(i)
321
+ if !l1vv.Type().Comparable() {
322
+ return make([]interface{}, 0), errors.New("intersect does not support slices or arrays of uncomparable types")
323
+ }
324
+
325
+ for j := 0; j < l2v.Len(); j++ {
326
+ l2vv := l2v.Index(j)
327
+ if !l2vv.Type().Comparable() {
328
+ return make([]interface{}, 0), errors.New("intersect does not support slices or arrays of uncomparable types")
329
+ }
330
+
331
+ ins.handleValuePair(l1vv, l2vv)
332
+ }
333
+ }
334
+ return ins.r.Interface(), nil
335
+ default:
336
+ return nil, errors.New("can't iterate over " + reflect.ValueOf(l2).Type().String())
337
+ }
338
+ default:
339
+ return nil, errors.New("can't iterate over " + reflect.ValueOf(l1).Type().String())
340
+ }
341
+ }
342
+
343
+ // Group groups a set of elements by the given key.
344
+ // This is currently only supported for Pages.
345
+ func (ns *Namespace) Group(key interface{}, items interface{}) (interface{}, error) {
346
+ if key == nil {
347
+ return nil, errors.New("nil is not a valid key to group by")
348
+ }
349
+
350
+ if g, ok := items.(collections.Grouper); ok {
351
+ return g.Group(key, items)
352
+ }
353
+
354
+ in := newSliceElement(items)
355
+
356
+ if g, ok := in.(collections.Grouper); ok {
357
+ return g.Group(key, items)
358
+ }
359
+
360
+ return nil, fmt.Errorf("grouping not supported for type %T %T", items, in)
361
+ }
362
+
363
+ // IsSet returns whether a given array, channel, slice, or map has a key
364
+ // defined.
365
+ func (ns *Namespace) IsSet(a interface{}, key interface{}) (bool, error) {
366
+ av := reflect.ValueOf(a)
367
+ kv := reflect.ValueOf(key)
368
+
369
+ switch av.Kind() {
370
+ case reflect.Array, reflect.Chan, reflect.Slice:
371
+ k, err := cast.ToIntE(key)
372
+ if err != nil {
373
+ return false, fmt.Errorf("isset unable to use key of type %T as index", key)
374
+ }
375
+ if av.Len() > k {
376
+ return true, nil
377
+ }
378
+ case reflect.Map:
379
+ if kv.Type() == av.Type().Key() {
380
+ return av.MapIndex(kv).IsValid(), nil
381
+ }
382
+ default:
383
+ // helpers.DistinctErrorLog.Printf("WARNING: calling IsSet with unsupported type %q (%T) will always return false.\n", av.Kind(), a)
384
+ }
385
+
386
+ return false, nil
387
+ }
388
+
389
+ // Last returns the last N items in a rangeable list.
390
+ func (ns *Namespace) Last(limit interface{}, seq interface{}) (interface{}, error) {
391
+ if limit == nil || seq == nil {
392
+ return nil, errors.New("both limit and seq must be provided")
393
+ }
394
+
395
+ limitv, err := cast.ToIntE(limit)
396
+ if err != nil {
397
+ return nil, err
398
+ }
399
+
400
+ if limitv < 0 {
401
+ return nil, errors.New("sequence length must be non-negative")
402
+ }
403
+
404
+ seqv := reflect.ValueOf(seq)
405
+ seqv, isNil := indirect(seqv)
406
+ if isNil {
407
+ return nil, errors.New("can't iterate over a nil value")
408
+ }
409
+
410
+ switch seqv.Kind() {
411
+ case reflect.Array, reflect.Slice, reflect.String:
412
+ // okay
413
+ default:
414
+ return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
415
+ }
416
+
417
+ if limitv > seqv.Len() {
418
+ limitv = seqv.Len()
419
+ }
420
+
421
+ return seqv.Slice(seqv.Len()-limitv, seqv.Len()).Interface(), nil
422
+ }
423
+
424
+ // Querify encodes the given parameters in URL-encoded form ("bar=baz&foo=quux") sorted by key.
425
+ func (ns *Namespace) Querify(params ...interface{}) (string, error) {
426
+ qs := url.Values{}
427
+
428
+ if len(params) == 1 {
429
+ switch v := params[0].(type) {
430
+ case []string:
431
+ if len(v)%2 != 0 {
432
+ return "", errors.New("invalid query")
433
+ }
434
+
435
+ for i := 0; i < len(v); i += 2 {
436
+ qs.Add(v[i], v[i+1])
437
+ }
438
+
439
+ return qs.Encode(), nil
440
+
441
+ case []interface{}:
442
+ params = v
443
+
444
+ default:
445
+ return "", errors.New("query keys must be strings")
446
+ }
447
+ }
448
+
449
+ if len(params)%2 != 0 {
450
+ return "", errors.New("invalid query")
451
+ }
452
+
453
+ for i := 0; i < len(params); i += 2 {
454
+ switch v := params[i].(type) {
455
+ case string:
456
+ qs.Add(v, fmt.Sprintf("%v", params[i+1]))
457
+ default:
458
+ return "", errors.New("query keys must be strings")
459
+ }
460
+ }
461
+
462
+ return qs.Encode(), nil
463
+ }
464
+
465
+ // Reverse creates a copy of slice and reverses it.
466
+ func (ns *Namespace) Reverse(slice interface{}) (interface{}, error) {
467
+ if slice == nil {
468
+ return nil, nil
469
+ }
470
+ v := reflect.ValueOf(slice)
471
+
472
+ switch v.Kind() {
473
+ case reflect.Slice:
474
+ default:
475
+ return nil, errors.New("argument must be a slice")
476
+ }
477
+
478
+ sliceCopy := reflect.MakeSlice(v.Type(), v.Len(), v.Len())
479
+
480
+ for i := v.Len() - 1; i >= 0; i-- {
481
+ element := sliceCopy.Index(i)
482
+ element.Set(v.Index(v.Len() - 1 - i))
483
+ }
484
+
485
+ return sliceCopy.Interface(), nil
486
+ }
487
+
488
+ // Seq creates a sequence of integers. It's named and used as GNU's seq.
489
+ //
490
+ // Examples:
491
+ // 3 => 1, 2, 3
492
+ // 1 2 4 => 1, 3
493
+ // -3 => -1, -2, -3
494
+ // 1 4 => 1, 2, 3, 4
495
+ // 1 -2 => 1, 0, -1, -2
496
+ func (ns *Namespace) Seq(args ...interface{}) ([]int, error) {
497
+ if len(args) < 1 || len(args) > 3 {
498
+ return nil, errors.New("invalid number of arguments to Seq")
499
+ }
500
+
501
+ intArgs := cast.ToIntSlice(args)
502
+ if len(intArgs) < 1 || len(intArgs) > 3 {
503
+ return nil, errors.New("invalid arguments to Seq")
504
+ }
505
+
506
+ inc := 1
507
+ var last int
508
+ first := intArgs[0]
509
+
510
+ if len(intArgs) == 1 {
511
+ last = first
512
+ if last == 0 {
513
+ return []int{}, nil
514
+ } else if last > 0 {
515
+ first = 1
516
+ } else {
517
+ first = -1
518
+ inc = -1
519
+ }
520
+ } else if len(intArgs) == 2 {
521
+ last = intArgs[1]
522
+ if last < first {
523
+ inc = -1
524
+ }
525
+ } else {
526
+ inc = intArgs[1]
527
+ last = intArgs[2]
528
+ if inc == 0 {
529
+ return nil, errors.New("'increment' must not be 0")
530
+ }
531
+ if first < last && inc < 0 {
532
+ return nil, errors.New("'increment' must be > 0")
533
+ }
534
+ if first > last && inc > 0 {
535
+ return nil, errors.New("'increment' must be < 0")
536
+ }
537
+ }
538
+
539
+ // sanity check
540
+ if last < -100000 {
541
+ return nil, errors.New("size of result exceeds limit")
542
+ }
543
+ size := ((last - first) / inc) + 1
544
+
545
+ // sanity check
546
+ if size <= 0 || size > 2000 {
547
+ return nil, errors.New("size of result exceeds limit")
548
+ }
549
+
550
+ seq := make([]int, size)
551
+ val := first
552
+ for i := 0; ; i++ {
553
+ seq[i] = val
554
+ val += inc
555
+ if (inc < 0 && val < last) || (inc > 0 && val > last) {
556
+ break
557
+ }
558
+ }
559
+
560
+ return seq, nil
561
+ }
562
+
563
+ // Shuffle returns the given rangeable list in a randomised order.
564
+ func (ns *Namespace) Shuffle(seq interface{}) (interface{}, error) {
565
+ if seq == nil {
566
+ return nil, errors.New("both count and seq must be provided")
567
+ }
568
+
569
+ seqv := reflect.ValueOf(seq)
570
+ seqv, isNil := indirect(seqv)
571
+ if isNil {
572
+ return nil, errors.New("can't iterate over a nil value")
573
+ }
574
+
575
+ switch seqv.Kind() {
576
+ case reflect.Array, reflect.Slice, reflect.String:
577
+ // okay
578
+ default:
579
+ return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
580
+ }
581
+
582
+ shuffled := reflect.MakeSlice(reflect.TypeOf(seq), seqv.Len(), seqv.Len())
583
+
584
+ randomIndices := rand.Perm(seqv.Len())
585
+
586
+ for index, value := range randomIndices {
587
+ shuffled.Index(value).Set(seqv.Index(index))
588
+ }
589
+
590
+ return shuffled.Interface(), nil
591
+ }
592
+
593
+ // Slice returns a slice of all passed arguments.
594
+ func (ns *Namespace) Slice(args ...interface{}) interface{} {
595
+ if len(args) == 0 {
596
+ return args
597
+ }
598
+
599
+ return collections.Slice(args...)
600
+ }
601
+
602
+ type intersector struct {
603
+ r reflect.Value
604
+ seen map[interface{}]bool
605
+ }
606
+
607
+ func (i *intersector) appendIfNotSeen(v reflect.Value) {
608
+ vi := v.Interface()
609
+ if !i.seen[vi] {
610
+ i.r = reflect.Append(i.r, v)
611
+ i.seen[vi] = true
612
+ }
613
+ }
614
+
615
+ func (i *intersector) handleValuePair(l1vv, l2vv reflect.Value) {
616
+ switch kind := l1vv.Kind(); {
617
+ case kind == reflect.String:
618
+ l2t, err := toString(l2vv)
619
+ if err == nil && l1vv.String() == l2t {
620
+ i.appendIfNotSeen(l1vv)
621
+ }
622
+ case isNumber(kind):
623
+ f1, err1 := numberToFloat(l1vv)
624
+ f2, err2 := numberToFloat(l2vv)
625
+ if err1 == nil && err2 == nil && f1 == f2 {
626
+ i.appendIfNotSeen(l1vv)
627
+ }
628
+ case kind == reflect.Ptr, kind == reflect.Struct:
629
+ if l1vv.Interface() == l2vv.Interface() {
630
+ i.appendIfNotSeen(l1vv)
631
+ }
632
+ case kind == reflect.Interface:
633
+ i.handleValuePair(reflect.ValueOf(l1vv.Interface()), l2vv)
634
+ }
635
+ }
636
+
637
+ // Union returns the union of the given sets, l1 and l2. l1 and
638
+ // l2 must be of the same type and may be either arrays or slices.
639
+ // If l1 and l2 aren't of the same type then l1 will be returned.
640
+ // If either l1 or l2 is nil then the non-nil list will be returned.
641
+ func (ns *Namespace) Union(l1, l2 interface{}) (interface{}, error) {
642
+ if l1 == nil && l2 == nil {
643
+ return []interface{}{}, nil
644
+ } else if l1 == nil && l2 != nil {
645
+ return l2, nil
646
+ } else if l1 != nil && l2 == nil {
647
+ return l1, nil
648
+ }
649
+
650
+ l1v := reflect.ValueOf(l1)
651
+ l2v := reflect.ValueOf(l2)
652
+
653
+ var ins *intersector
654
+
655
+ switch l1v.Kind() {
656
+ case reflect.Array, reflect.Slice:
657
+ switch l2v.Kind() {
658
+ case reflect.Array, reflect.Slice:
659
+ ins = &intersector{r: reflect.MakeSlice(l1v.Type(), 0, 0), seen: make(map[interface{}]bool)}
660
+
661
+ if l1v.Type() != l2v.Type() &&
662
+ l1v.Type().Elem().Kind() != reflect.Interface &&
663
+ l2v.Type().Elem().Kind() != reflect.Interface {
664
+ return ins.r.Interface(), nil
665
+ }
666
+
667
+ var (
668
+ l1vv reflect.Value
669
+ isNil bool
670
+ )
671
+
672
+ for i := 0; i < l1v.Len(); i++ {
673
+ l1vv, isNil = indirectInterface(l1v.Index(i))
674
+
675
+ if !l1vv.Type().Comparable() {
676
+ return []interface{}{}, errors.New("union does not support slices or arrays of uncomparable types")
677
+ }
678
+
679
+ if !isNil {
680
+ ins.appendIfNotSeen(l1vv)
681
+ }
682
+ }
683
+
684
+ if !l1vv.IsValid() {
685
+ // The first slice may be empty. Pick the first value of the second
686
+ // to use as a prototype.
687
+ if l2v.Len() > 0 {
688
+ l1vv = l2v.Index(0)
689
+ }
690
+ }
691
+
692
+ for j := 0; j < l2v.Len(); j++ {
693
+ l2vv := l2v.Index(j)
694
+
695
+ switch kind := l1vv.Kind(); {
696
+ case kind == reflect.String:
697
+ l2t, err := toString(l2vv)
698
+ if err == nil {
699
+ ins.appendIfNotSeen(reflect.ValueOf(l2t))
700
+ }
701
+ case isNumber(kind):
702
+ var err error
703
+ l2vv, err = convertNumber(l2vv, kind)
704
+ if err == nil {
705
+ ins.appendIfNotSeen(l2vv)
706
+ }
707
+ case kind == reflect.Interface, kind == reflect.Struct, kind == reflect.Ptr:
708
+ ins.appendIfNotSeen(l2vv)
709
+
710
+ }
711
+ }
712
+
713
+ return ins.r.Interface(), nil
714
+ default:
715
+ return nil, errors.New("can't iterate over " + reflect.ValueOf(l2).Type().String())
716
+ }
717
+ default:
718
+ return nil, errors.New("can't iterate over " + reflect.ValueOf(l1).Type().String())
719
+ }
720
+ }
721
+
722
+ // Uniq takes in a slice or array and returns a slice with subsequent
723
+ // duplicate elements removed.
724
+ func (ns *Namespace) Uniq(seq interface{}) (interface{}, error) {
725
+ if seq == nil {
726
+ return make([]interface{}, 0), nil
727
+ }
728
+
729
+ v := reflect.ValueOf(seq)
730
+ var slice reflect.Value
731
+
732
+ switch v.Kind() {
733
+ case reflect.Slice:
734
+ slice = reflect.MakeSlice(v.Type(), 0, 0)
735
+
736
+ case reflect.Array:
737
+ slice = reflect.MakeSlice(reflect.SliceOf(v.Type().Elem()), 0, 0)
738
+ default:
739
+ return nil, errors.Errorf("type %T not supported", seq)
740
+ }
741
+
742
+ seen := make(map[interface{}]bool)
743
+
744
+ for i := 0; i < v.Len(); i++ {
745
+ ev, _ := indirectInterface(v.Index(i))
746
+
747
+ key := normalize(ev)
748
+
749
+ if _, found := seen[key]; !found {
750
+ slice = reflect.Append(slice, ev)
751
+ seen[key] = true
752
+ }
753
+ }
754
+
755
+ return slice.Interface(), nil
756
+ }
757
+
758
+ // KeyVals creates a key and values wrapper.
759
+ func (ns *Namespace) KeyVals(key interface{}, vals ...interface{}) (types.KeyValues, error) {
760
+ return types.KeyValues{Key: key, Values: vals}, nil
761
+ }
762
+
763
+ // NewScratch creates a new Scratch which can be used to store values in a
764
+ // thread safe way.
765
+ func (ns *Namespace) NewScratch() *maps.Scratch {
766
+ return maps.NewScratch()
767
+ }