@bookshop/hugo-engine 3.3.3 → 3.4.0-alpha.2
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/.nyc_output/{25f8c04a-7fe3-4d10-b99e-0688e18203ec.json → 0f70a16f-6a79-48c7-8b16-3b4665e247b2.json} +0 -0
- package/.nyc_output/{2c3e7d19-6b44-48be-857a-ceba6bb9bf99.json → 6285d5fa-be3d-49e4-8f2f-82157d95dcd8.json} +0 -0
- package/.nyc_output/{5429d932-0ea0-4757-b731-0a647f4adc5f.json → 8b5e1314-6e86-4197-a3ae-3c40e4c2f39e.json} +0 -0
- package/.nyc_output/{723f5a1e-49f4-48c2-8a96-069bb758bb7f.json → c5490eb0-70c0-468f-a43f-e58c75dd34c8.json} +0 -0
- package/.nyc_output/{e4df4511-7e66-4fa6-84ed-6bd96e3027fe.json → ee1a9bec-d318-4aea-af93-7269debcf6df.json} +0 -0
- package/.nyc_output/processinfo/{25f8c04a-7fe3-4d10-b99e-0688e18203ec.json → 0f70a16f-6a79-48c7-8b16-3b4665e247b2.json} +1 -1
- package/.nyc_output/processinfo/6285d5fa-be3d-49e4-8f2f-82157d95dcd8.json +1 -0
- package/.nyc_output/processinfo/{2c3e7d19-6b44-48be-857a-ceba6bb9bf99.json → 8b5e1314-6e86-4197-a3ae-3c40e4c2f39e.json} +1 -1
- package/.nyc_output/processinfo/{5429d932-0ea0-4757-b731-0a647f4adc5f.json → c5490eb0-70c0-468f-a43f-e58c75dd34c8.json} +1 -1
- package/.nyc_output/processinfo/{723f5a1e-49f4-48c2-8a96-069bb758bb7f.json → ee1a9bec-d318-4aea-af93-7269debcf6df.json} +1 -1
- package/.nyc_output/processinfo/index.json +1 -1
- package/bookshop-hugo-templates/bookshop.html +56 -0
- package/bookshop-hugo-templates/bookshop_bindings.html +29 -0
- package/bookshop-hugo-templates/bookshop_component_browser.html +30 -0
- package/bookshop-hugo-templates/bookshop_partial.html +42 -0
- package/bookshop-hugo-templates/bookshop_scss.html +9 -0
- package/bookshop-hugo-templates/errors/bad_bookshop_tag.html +39 -0
- package/bookshop-hugo-templates/errors/err.html +6 -0
- package/bookshop-hugo-templates/helpers/component.html +25 -0
- package/bookshop-hugo-templates/helpers/component_key.html +11 -0
- package/bookshop-hugo-templates/helpers/partial.html +25 -0
- package/bookshop-hugo-templates/helpers/partial_key.html +9 -0
- package/full-hugo-renderer/build.sh +34 -0
- package/full-hugo-renderer/go.mod +87 -0
- package/{hugo-renderer → full-hugo-renderer}/go.sum +204 -12
- package/full-hugo-renderer/hugo_renderer.wasm +0 -0
- package/full-hugo-renderer/hugo_renderer.wasm.gz +0 -0
- package/full-hugo-renderer/main.go +215 -0
- package/{hugo-renderer → full-hugo-renderer}/wasm_exec.js +6 -2
- package/lib/builder.js +2 -2
- package/lib/engine.js +109 -42
- package/lib/hugoIdentifierParser.js +5 -0
- package/lib/translateTextTemplate.js +3 -0
- package/lib/translateTextTemplate.test.js +22 -16
- package/package.json +4 -4
- package/.nyc_output/processinfo/e4df4511-7e66-4fa6-84ed-6bd96e3027fe.json +0 -1
- package/hugo-renderer/build.sh +0 -66
- package/hugo-renderer/deps/bookshop_modified_deps.go +0 -6
- package/hugo-renderer/go.mod +0 -19
- package/hugo-renderer/helpers/bookshop_modified_content.go +0 -98
- package/hugo-renderer/helpers/bookshop_modified_general.go +0 -33
- package/hugo-renderer/helpers/emoji.go +0 -96
- package/hugo-renderer/hugo_renderer.wasm +0 -0
- package/hugo-renderer/hugo_renderer.wasm.gz +0 -0
- package/hugo-renderer/main.go +0 -42
- package/hugo-renderer/tpl/bookshop_engine/bookshop_func_importer.go +0 -35
- package/hugo-renderer/tpl/bookshop_engine/bookshop_render.go +0 -64
- package/hugo-renderer/tpl/bookshop_library/bookshop_components.go +0 -129
- package/hugo-renderer/tpl/bookshop_library/bookshop_data.go +0 -53
- package/hugo-renderer/tpl/cast/cast.go +0 -63
- package/hugo-renderer/tpl/cast/init.go +0 -57
- package/hugo-renderer/tpl/collections/append.go +0 -37
- package/hugo-renderer/tpl/collections/apply.go +0 -131
- package/hugo-renderer/tpl/collections/collections.go +0 -768
- package/hugo-renderer/tpl/collections/complement.go +0 -55
- package/hugo-renderer/tpl/collections/index.go +0 -133
- package/hugo-renderer/tpl/collections/init.go +0 -214
- package/hugo-renderer/tpl/collections/merge.go +0 -126
- package/hugo-renderer/tpl/collections/reflect_helpers.go +0 -216
- package/hugo-renderer/tpl/collections/sort.go +0 -183
- package/hugo-renderer/tpl/collections/symdiff.go +0 -68
- package/hugo-renderer/tpl/collections/where.go +0 -517
- package/hugo-renderer/tpl/compare/compare.go +0 -324
- package/hugo-renderer/tpl/compare/init.go +0 -85
- package/hugo-renderer/tpl/crypto/crypto.go +0 -109
- package/hugo-renderer/tpl/crypto/init.go +0 -65
- package/hugo-renderer/tpl/debug/debug.go +0 -40
- package/hugo-renderer/tpl/debug/init.go +0 -45
- package/hugo-renderer/tpl/encoding/encoding.go +0 -90
- package/hugo-renderer/tpl/encoding/init.go +0 -59
- package/hugo-renderer/tpl/fmt/fmt.go +0 -66
- package/hugo-renderer/tpl/fmt/init.go +0 -77
- package/hugo-renderer/tpl/inflect/inflect.go +0 -79
- package/hugo-renderer/tpl/inflect/init.go +0 -60
- package/hugo-renderer/tpl/internal/bookshop_modified_templatefuncsRegistry.go +0 -88
- package/hugo-renderer/tpl/math/init.go +0 -134
- package/hugo-renderer/tpl/math/math.go +0 -164
- package/hugo-renderer/tpl/math/round.go +0 -61
- package/hugo-renderer/tpl/partials/init.go +0 -55
- package/hugo-renderer/tpl/partials/partials.go +0 -88
- package/hugo-renderer/tpl/path/init.go +0 -60
- package/hugo-renderer/tpl/path/path.go +0 -159
- package/hugo-renderer/tpl/reflect/init.go +0 -51
- package/hugo-renderer/tpl/reflect/reflect.go +0 -36
- package/hugo-renderer/tpl/safe/init.go +0 -80
- package/hugo-renderer/tpl/safe/safe.go +0 -72
- package/hugo-renderer/tpl/site/bookshop_site.go +0 -67
- package/hugo-renderer/tpl/site/init.go +0 -41
- package/hugo-renderer/tpl/strings/init.go +0 -229
- package/hugo-renderer/tpl/strings/regexp.go +0 -125
- package/hugo-renderer/tpl/strings/strings.go +0 -500
- package/hugo-renderer/tpl/strings/truncate.go +0 -157
- package/hugo-renderer/tpl/transform/bookshop_unmarshal.go +0 -39
- package/hugo-renderer/tpl/transform/init.go +0 -113
- package/hugo-renderer/tpl/transform/transform.go +0 -116
- package/hugo-renderer/update-from-hugo.sh +0 -19
|
@@ -1,768 +0,0 @@
|
|
|
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
|
-
// Bookshop: Removed deep Hugo function.
|
|
384
|
-
// helpers.DistinctErrorLog.Printf("WARNING: calling IsSet with unsupported type %q (%T) will always return false.\n", av.Kind(), a)
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
return false, nil
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
// Last returns the last N items in a rangeable list.
|
|
391
|
-
func (ns *Namespace) Last(limit interface{}, seq interface{}) (interface{}, error) {
|
|
392
|
-
if limit == nil || seq == nil {
|
|
393
|
-
return nil, errors.New("both limit and seq must be provided")
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
limitv, err := cast.ToIntE(limit)
|
|
397
|
-
if err != nil {
|
|
398
|
-
return nil, err
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
if limitv < 0 {
|
|
402
|
-
return nil, errors.New("sequence length must be non-negative")
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
seqv := reflect.ValueOf(seq)
|
|
406
|
-
seqv, isNil := indirect(seqv)
|
|
407
|
-
if isNil {
|
|
408
|
-
return nil, errors.New("can't iterate over a nil value")
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
switch seqv.Kind() {
|
|
412
|
-
case reflect.Array, reflect.Slice, reflect.String:
|
|
413
|
-
// okay
|
|
414
|
-
default:
|
|
415
|
-
return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
if limitv > seqv.Len() {
|
|
419
|
-
limitv = seqv.Len()
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
return seqv.Slice(seqv.Len()-limitv, seqv.Len()).Interface(), nil
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
// Querify encodes the given parameters in URL-encoded form ("bar=baz&foo=quux") sorted by key.
|
|
426
|
-
func (ns *Namespace) Querify(params ...interface{}) (string, error) {
|
|
427
|
-
qs := url.Values{}
|
|
428
|
-
|
|
429
|
-
if len(params) == 1 {
|
|
430
|
-
switch v := params[0].(type) {
|
|
431
|
-
case []string:
|
|
432
|
-
if len(v)%2 != 0 {
|
|
433
|
-
return "", errors.New("invalid query")
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
for i := 0; i < len(v); i += 2 {
|
|
437
|
-
qs.Add(v[i], v[i+1])
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
return qs.Encode(), nil
|
|
441
|
-
|
|
442
|
-
case []interface{}:
|
|
443
|
-
params = v
|
|
444
|
-
|
|
445
|
-
default:
|
|
446
|
-
return "", errors.New("query keys must be strings")
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
if len(params)%2 != 0 {
|
|
451
|
-
return "", errors.New("invalid query")
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
for i := 0; i < len(params); i += 2 {
|
|
455
|
-
switch v := params[i].(type) {
|
|
456
|
-
case string:
|
|
457
|
-
qs.Add(v, fmt.Sprintf("%v", params[i+1]))
|
|
458
|
-
default:
|
|
459
|
-
return "", errors.New("query keys must be strings")
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
return qs.Encode(), nil
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
// Reverse creates a copy of slice and reverses it.
|
|
467
|
-
func (ns *Namespace) Reverse(slice interface{}) (interface{}, error) {
|
|
468
|
-
if slice == nil {
|
|
469
|
-
return nil, nil
|
|
470
|
-
}
|
|
471
|
-
v := reflect.ValueOf(slice)
|
|
472
|
-
|
|
473
|
-
switch v.Kind() {
|
|
474
|
-
case reflect.Slice:
|
|
475
|
-
default:
|
|
476
|
-
return nil, errors.New("argument must be a slice")
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
sliceCopy := reflect.MakeSlice(v.Type(), v.Len(), v.Len())
|
|
480
|
-
|
|
481
|
-
for i := v.Len() - 1; i >= 0; i-- {
|
|
482
|
-
element := sliceCopy.Index(i)
|
|
483
|
-
element.Set(v.Index(v.Len() - 1 - i))
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
return sliceCopy.Interface(), nil
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
// Seq creates a sequence of integers. It's named and used as GNU's seq.
|
|
490
|
-
//
|
|
491
|
-
// Examples:
|
|
492
|
-
// 3 => 1, 2, 3
|
|
493
|
-
// 1 2 4 => 1, 3
|
|
494
|
-
// -3 => -1, -2, -3
|
|
495
|
-
// 1 4 => 1, 2, 3, 4
|
|
496
|
-
// 1 -2 => 1, 0, -1, -2
|
|
497
|
-
func (ns *Namespace) Seq(args ...interface{}) ([]int, error) {
|
|
498
|
-
if len(args) < 1 || len(args) > 3 {
|
|
499
|
-
return nil, errors.New("invalid number of arguments to Seq")
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
intArgs := cast.ToIntSlice(args)
|
|
503
|
-
if len(intArgs) < 1 || len(intArgs) > 3 {
|
|
504
|
-
return nil, errors.New("invalid arguments to Seq")
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
inc := 1
|
|
508
|
-
var last int
|
|
509
|
-
first := intArgs[0]
|
|
510
|
-
|
|
511
|
-
if len(intArgs) == 1 {
|
|
512
|
-
last = first
|
|
513
|
-
if last == 0 {
|
|
514
|
-
return []int{}, nil
|
|
515
|
-
} else if last > 0 {
|
|
516
|
-
first = 1
|
|
517
|
-
} else {
|
|
518
|
-
first = -1
|
|
519
|
-
inc = -1
|
|
520
|
-
}
|
|
521
|
-
} else if len(intArgs) == 2 {
|
|
522
|
-
last = intArgs[1]
|
|
523
|
-
if last < first {
|
|
524
|
-
inc = -1
|
|
525
|
-
}
|
|
526
|
-
} else {
|
|
527
|
-
inc = intArgs[1]
|
|
528
|
-
last = intArgs[2]
|
|
529
|
-
if inc == 0 {
|
|
530
|
-
return nil, errors.New("'increment' must not be 0")
|
|
531
|
-
}
|
|
532
|
-
if first < last && inc < 0 {
|
|
533
|
-
return nil, errors.New("'increment' must be > 0")
|
|
534
|
-
}
|
|
535
|
-
if first > last && inc > 0 {
|
|
536
|
-
return nil, errors.New("'increment' must be < 0")
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
// sanity check
|
|
541
|
-
if last < -100000 {
|
|
542
|
-
return nil, errors.New("size of result exceeds limit")
|
|
543
|
-
}
|
|
544
|
-
size := ((last - first) / inc) + 1
|
|
545
|
-
|
|
546
|
-
// sanity check
|
|
547
|
-
if size <= 0 || size > 2000 {
|
|
548
|
-
return nil, errors.New("size of result exceeds limit")
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
seq := make([]int, size)
|
|
552
|
-
val := first
|
|
553
|
-
for i := 0; ; i++ {
|
|
554
|
-
seq[i] = val
|
|
555
|
-
val += inc
|
|
556
|
-
if (inc < 0 && val < last) || (inc > 0 && val > last) {
|
|
557
|
-
break
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
return seq, nil
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
// Shuffle returns the given rangeable list in a randomised order.
|
|
565
|
-
func (ns *Namespace) Shuffle(seq interface{}) (interface{}, error) {
|
|
566
|
-
if seq == nil {
|
|
567
|
-
return nil, errors.New("both count and seq must be provided")
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
seqv := reflect.ValueOf(seq)
|
|
571
|
-
seqv, isNil := indirect(seqv)
|
|
572
|
-
if isNil {
|
|
573
|
-
return nil, errors.New("can't iterate over a nil value")
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
switch seqv.Kind() {
|
|
577
|
-
case reflect.Array, reflect.Slice, reflect.String:
|
|
578
|
-
// okay
|
|
579
|
-
default:
|
|
580
|
-
return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
shuffled := reflect.MakeSlice(reflect.TypeOf(seq), seqv.Len(), seqv.Len())
|
|
584
|
-
|
|
585
|
-
randomIndices := rand.Perm(seqv.Len())
|
|
586
|
-
|
|
587
|
-
for index, value := range randomIndices {
|
|
588
|
-
shuffled.Index(value).Set(seqv.Index(index))
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
return shuffled.Interface(), nil
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
// Slice returns a slice of all passed arguments.
|
|
595
|
-
func (ns *Namespace) Slice(args ...interface{}) interface{} {
|
|
596
|
-
if len(args) == 0 {
|
|
597
|
-
return args
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
return collections.Slice(args...)
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
type intersector struct {
|
|
604
|
-
r reflect.Value
|
|
605
|
-
seen map[interface{}]bool
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
func (i *intersector) appendIfNotSeen(v reflect.Value) {
|
|
609
|
-
vi := v.Interface()
|
|
610
|
-
if !i.seen[vi] {
|
|
611
|
-
i.r = reflect.Append(i.r, v)
|
|
612
|
-
i.seen[vi] = true
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
func (i *intersector) handleValuePair(l1vv, l2vv reflect.Value) {
|
|
617
|
-
switch kind := l1vv.Kind(); {
|
|
618
|
-
case kind == reflect.String:
|
|
619
|
-
l2t, err := toString(l2vv)
|
|
620
|
-
if err == nil && l1vv.String() == l2t {
|
|
621
|
-
i.appendIfNotSeen(l1vv)
|
|
622
|
-
}
|
|
623
|
-
case isNumber(kind):
|
|
624
|
-
f1, err1 := numberToFloat(l1vv)
|
|
625
|
-
f2, err2 := numberToFloat(l2vv)
|
|
626
|
-
if err1 == nil && err2 == nil && f1 == f2 {
|
|
627
|
-
i.appendIfNotSeen(l1vv)
|
|
628
|
-
}
|
|
629
|
-
case kind == reflect.Ptr, kind == reflect.Struct:
|
|
630
|
-
if l1vv.Interface() == l2vv.Interface() {
|
|
631
|
-
i.appendIfNotSeen(l1vv)
|
|
632
|
-
}
|
|
633
|
-
case kind == reflect.Interface:
|
|
634
|
-
i.handleValuePair(reflect.ValueOf(l1vv.Interface()), l2vv)
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
// Union returns the union of the given sets, l1 and l2. l1 and
|
|
639
|
-
// l2 must be of the same type and may be either arrays or slices.
|
|
640
|
-
// If l1 and l2 aren't of the same type then l1 will be returned.
|
|
641
|
-
// If either l1 or l2 is nil then the non-nil list will be returned.
|
|
642
|
-
func (ns *Namespace) Union(l1, l2 interface{}) (interface{}, error) {
|
|
643
|
-
if l1 == nil && l2 == nil {
|
|
644
|
-
return []interface{}{}, nil
|
|
645
|
-
} else if l1 == nil && l2 != nil {
|
|
646
|
-
return l2, nil
|
|
647
|
-
} else if l1 != nil && l2 == nil {
|
|
648
|
-
return l1, nil
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
l1v := reflect.ValueOf(l1)
|
|
652
|
-
l2v := reflect.ValueOf(l2)
|
|
653
|
-
|
|
654
|
-
var ins *intersector
|
|
655
|
-
|
|
656
|
-
switch l1v.Kind() {
|
|
657
|
-
case reflect.Array, reflect.Slice:
|
|
658
|
-
switch l2v.Kind() {
|
|
659
|
-
case reflect.Array, reflect.Slice:
|
|
660
|
-
ins = &intersector{r: reflect.MakeSlice(l1v.Type(), 0, 0), seen: make(map[interface{}]bool)}
|
|
661
|
-
|
|
662
|
-
if l1v.Type() != l2v.Type() &&
|
|
663
|
-
l1v.Type().Elem().Kind() != reflect.Interface &&
|
|
664
|
-
l2v.Type().Elem().Kind() != reflect.Interface {
|
|
665
|
-
return ins.r.Interface(), nil
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
var (
|
|
669
|
-
l1vv reflect.Value
|
|
670
|
-
isNil bool
|
|
671
|
-
)
|
|
672
|
-
|
|
673
|
-
for i := 0; i < l1v.Len(); i++ {
|
|
674
|
-
l1vv, isNil = indirectInterface(l1v.Index(i))
|
|
675
|
-
|
|
676
|
-
if !l1vv.Type().Comparable() {
|
|
677
|
-
return []interface{}{}, errors.New("union does not support slices or arrays of uncomparable types")
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
if !isNil {
|
|
681
|
-
ins.appendIfNotSeen(l1vv)
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
if !l1vv.IsValid() {
|
|
686
|
-
// The first slice may be empty. Pick the first value of the second
|
|
687
|
-
// to use as a prototype.
|
|
688
|
-
if l2v.Len() > 0 {
|
|
689
|
-
l1vv = l2v.Index(0)
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
for j := 0; j < l2v.Len(); j++ {
|
|
694
|
-
l2vv := l2v.Index(j)
|
|
695
|
-
|
|
696
|
-
switch kind := l1vv.Kind(); {
|
|
697
|
-
case kind == reflect.String:
|
|
698
|
-
l2t, err := toString(l2vv)
|
|
699
|
-
if err == nil {
|
|
700
|
-
ins.appendIfNotSeen(reflect.ValueOf(l2t))
|
|
701
|
-
}
|
|
702
|
-
case isNumber(kind):
|
|
703
|
-
var err error
|
|
704
|
-
l2vv, err = convertNumber(l2vv, kind)
|
|
705
|
-
if err == nil {
|
|
706
|
-
ins.appendIfNotSeen(l2vv)
|
|
707
|
-
}
|
|
708
|
-
case kind == reflect.Interface, kind == reflect.Struct, kind == reflect.Ptr:
|
|
709
|
-
ins.appendIfNotSeen(l2vv)
|
|
710
|
-
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
return ins.r.Interface(), nil
|
|
715
|
-
default:
|
|
716
|
-
return nil, errors.New("can't iterate over " + reflect.ValueOf(l2).Type().String())
|
|
717
|
-
}
|
|
718
|
-
default:
|
|
719
|
-
return nil, errors.New("can't iterate over " + reflect.ValueOf(l1).Type().String())
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
// Uniq takes in a slice or array and returns a slice with subsequent
|
|
724
|
-
// duplicate elements removed.
|
|
725
|
-
func (ns *Namespace) Uniq(seq interface{}) (interface{}, error) {
|
|
726
|
-
if seq == nil {
|
|
727
|
-
return make([]interface{}, 0), nil
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
v := reflect.ValueOf(seq)
|
|
731
|
-
var slice reflect.Value
|
|
732
|
-
|
|
733
|
-
switch v.Kind() {
|
|
734
|
-
case reflect.Slice:
|
|
735
|
-
slice = reflect.MakeSlice(v.Type(), 0, 0)
|
|
736
|
-
|
|
737
|
-
case reflect.Array:
|
|
738
|
-
slice = reflect.MakeSlice(reflect.SliceOf(v.Type().Elem()), 0, 0)
|
|
739
|
-
default:
|
|
740
|
-
return nil, errors.Errorf("type %T not supported", seq)
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
seen := make(map[interface{}]bool)
|
|
744
|
-
|
|
745
|
-
for i := 0; i < v.Len(); i++ {
|
|
746
|
-
ev, _ := indirectInterface(v.Index(i))
|
|
747
|
-
|
|
748
|
-
key := normalize(ev)
|
|
749
|
-
|
|
750
|
-
if _, found := seen[key]; !found {
|
|
751
|
-
slice = reflect.Append(slice, ev)
|
|
752
|
-
seen[key] = true
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
return slice.Interface(), nil
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
// KeyVals creates a key and values wrapper.
|
|
760
|
-
func (ns *Namespace) KeyVals(key interface{}, vals ...interface{}) (types.KeyValues, error) {
|
|
761
|
-
return types.KeyValues{Key: key, Values: vals}, nil
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
// NewScratch creates a new Scratch which can be used to store values in a
|
|
765
|
-
// thread safe way.
|
|
766
|
-
func (ns *Namespace) NewScratch() *maps.Scratch {
|
|
767
|
-
return maps.NewScratch()
|
|
768
|
-
}
|