@nxtedition/lib 25.1.7 → 26.0.1

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/app.js CHANGED
@@ -29,8 +29,7 @@ import rx from 'rxjs/operators'
29
29
  import { performance } from 'perf_hooks'
30
30
  import hashString from './hash.js'
31
31
  import { makeTrace } from './trace.js'
32
- import compose from 'koa-compose'
33
- import { createServer } from './http.js'
32
+ import { compose, createServer } from './http.js'
34
33
  import { json } from 'node:stream/consumers'
35
34
  import { monitorEventLoopDelay } from 'node:perf_hooks'
36
35
  import xuid from 'xuid'
@@ -113,7 +112,7 @@ export function makeApp(appConfig, onTerminate) {
113
112
  }
114
113
  } else {
115
114
  config = {
116
- isProduction: process.env.NODE_ENV === 'production',
115
+ isProduction,
117
116
  ...cleanAppConfig(appConfig),
118
117
  ...appConfig,
119
118
  }
package/http.js CHANGED
@@ -372,13 +372,24 @@ export class IncomingMessage extends http.IncomingMessage {
372
372
  }
373
373
 
374
374
  export class ServerResponse extends http.ServerResponse {
375
- #created = 0
376
375
  #bytesWritten = 0
376
+
377
+ #created = -1
377
378
  #connect = -1
378
379
  #headers = -1
379
380
  #data = -1
380
381
  #end = -1
381
382
 
383
+ #headersObj = undefined
384
+
385
+ /**
386
+ * @returns {{
387
+ * connect: number,
388
+ * headers: number,
389
+ * data: number,
390
+ * end: number
391
+ * }}
392
+ */
382
393
  get timing() {
383
394
  return {
384
395
  connect: this.#connect,
@@ -388,16 +399,101 @@ export class ServerResponse extends http.ServerResponse {
388
399
  }
389
400
  }
390
401
 
402
+ /**
403
+ * @returns {number}
404
+ */
391
405
  get bytesWritten() {
392
406
  return this.#bytesWritten
393
407
  }
394
408
 
409
+ /**
410
+ * @param {http.IncomingMessage} req
411
+ */
395
412
  constructor(req) {
396
413
  super(req)
397
414
 
398
415
  this.#created = performance.now()
399
416
  }
400
417
 
418
+ setHeaders() {
419
+ throw new Error('not supported')
420
+ }
421
+
422
+ appendHeader() {
423
+ throw new Error('not supported')
424
+ }
425
+
426
+ /**
427
+ * @param {string} key
428
+ * @param {string} val
429
+ */
430
+ setHeader(key, val) {
431
+ if (this.#headersObj === null) {
432
+ throw new Error('headers already sent')
433
+ } else if (this.#headersObj === undefined) {
434
+ this.#headersObj = { key: val }
435
+ } else {
436
+ this.#headersObj[key] = val
437
+ }
438
+ }
439
+
440
+ /**
441
+ * @param {string} key
442
+ * @param {string} val
443
+ */
444
+ removeHeader(key, val) {
445
+ if (this.#headersObj === null) {
446
+ throw new Error('headers already sent')
447
+ } else if (this.#headersObj === undefined) {
448
+ // Do nothing...
449
+ } else {
450
+ delete this.#headersObj[key]
451
+ }
452
+ }
453
+
454
+ /**
455
+ * @returns {string[]}
456
+ */
457
+ getHeaderNames() {
458
+ if (this.#headersObj === null) {
459
+ throw new Error('headers already sent')
460
+ } else if (this.#headersObj === undefined) {
461
+ return []
462
+ } else {
463
+ return Object.keys(this.#headersObj)
464
+ }
465
+ }
466
+
467
+ /**
468
+ * @returns {boolean}
469
+ */
470
+ get headersSent() {
471
+ return this.#headersObj === null
472
+ }
473
+
474
+ /**
475
+ * @param {number} statusCode
476
+ * @param {Record<string, string>} [headers]
477
+ * @returns
478
+ */
479
+ writeHead(statusCode, headers) {
480
+ if (this.#headersObj === null) {
481
+ throw new Error('headers already sent')
482
+ } else if (this.#headersObj === undefined) {
483
+ // Do nothing...
484
+ } else {
485
+ headers = headers ? Object.assign(this.#headersObj, headers) : this.#headersObj
486
+ }
487
+
488
+ this.#headersObj = null
489
+
490
+ return super.writeHead(statusCode, headers)
491
+ }
492
+
493
+ /**
494
+ * @param {net.Socket} socket
495
+ * @returns
496
+ */
401
497
  assignSocket(socket) {
402
498
  if (!this.destroyed) {
403
499
  if (this.#connect === -1) {
@@ -462,6 +558,11 @@ export class ServerResponse extends http.ServerResponse {
462
558
  return super.end(chunk, encoding, callback)
463
559
  }
464
560
 
561
+ /**
562
+ *
563
+ * @param {Error} [err]
564
+ * @returns
565
+ */
465
566
  destroy(err) {
466
567
  if (!this.destroyed) {
467
568
  if (this.#end === -1) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/lib",
3
- "version": "25.1.7",
3
+ "version": "26.0.1",
4
4
  "license": "MIT",
5
5
  "author": "Robert Nagy <robert.nagy@boffins.se>",
6
6
  "type": "module",
@@ -48,8 +48,6 @@
48
48
  "yield.js"
49
49
  ],
50
50
  "scripts": {
51
- "prepublishOnly": "pinst --disable",
52
- "postpublish": "pinst --enable",
53
51
  "test": "node --test-timeout 60000 --test",
54
52
  "prepare": "husky"
55
53
  },
@@ -84,7 +82,6 @@
84
82
  "mitata": "^1.0.34",
85
83
  "moment-timezone": "^0.5.48",
86
84
  "nconf": "^0.13.0",
87
- "nested-error-stacks": "^2.1.1",
88
85
  "object-hash": "^3.0.0",
89
86
  "p-queue": "^8.0.1",
90
87
  "pino": "^9.9.0",
@@ -110,11 +107,8 @@
110
107
  "eslint-plugin-promise": "^7.2.1",
111
108
  "husky": "^9.1.7",
112
109
  "lint-staged": "^16.1.5",
113
- "pinst": "^3.0.0",
114
110
  "prettier": "^3.6.2",
115
111
  "rxjs": "^7.8.2",
116
- "send": "^1.1.0",
117
- "tap": "^21.1.0",
118
112
  "typescript-eslint": "^8.40.0"
119
113
  },
120
114
  "peerDependencies": {
@@ -0,0 +1,199 @@
1
+ import { test } from 'node:test'
2
+ import combineMap from './combineMap.js'
3
+ import * as rxjs from 'rxjs'
4
+
5
+ test('combineMap sync', (t) => {
6
+ t.plan(1, { wait: true })
7
+ rxjs
8
+ .of([1, 2, 3])
9
+ .pipe(combineMap((val) => rxjs.of(val * 2)))
10
+ .subscribe((val) => {
11
+ t.assert.deepStrictEqual(val, [2, 4, 6])
12
+ })
13
+ })
14
+
15
+ test('combineMap async', (t) => {
16
+ t.plan(1, { wait: true })
17
+ rxjs
18
+ .of([1, 2, 3])
19
+ .pipe(combineMap(async (val) => val * 2))
20
+ .subscribe((val) => {
21
+ t.assert.deepStrictEqual(val, [2, 4, 6])
22
+ })
23
+ })
24
+
25
+ test('combineMap empty', (t) => {
26
+ t.plan(1, { wait: true })
27
+ rxjs
28
+ .of([])
29
+ .pipe(combineMap((val) => rxjs.of(val * 2)))
30
+ .subscribe((val) => {
31
+ t.assert.deepStrictEqual(val, [])
32
+ })
33
+ })
34
+
35
+ test('combineMap throw in resolver', (t) => {
36
+ t.plan(1, { wait: true })
37
+ const _err = new Error('asd')
38
+ rxjs
39
+ .of([1, 2, 3])
40
+ .pipe(
41
+ combineMap((val) => {
42
+ throw _err
43
+ }),
44
+ )
45
+ .subscribe({
46
+ error: (err) => {
47
+ t.assert.strictEqual(err, _err)
48
+ },
49
+ })
50
+ })
51
+
52
+ test('combineMap throw in source', (t) => {
53
+ t.plan(1, { wait: true })
54
+ const _err = new Error('asd')
55
+ rxjs
56
+ .throwError(() => _err)
57
+ .pipe(combineMap((val) => rxjs.of(val)))
58
+ .subscribe({
59
+ error: (err) => {
60
+ t.assert.strictEqual(err, _err)
61
+ },
62
+ })
63
+ })
64
+
65
+ test('combineMap bad resolve', (t) => {
66
+ t.plan(1, { wait: true })
67
+ rxjs
68
+ .of([1])
69
+ .pipe(combineMap((val) => val))
70
+ .subscribe({
71
+ error: () => {
72
+ t.assert.ok(true)
73
+ },
74
+ })
75
+ })
76
+
77
+ test('combineMap no change no tick', (t) => {
78
+ t.plan(1, { wait: true })
79
+ rxjs
80
+ .concat(
81
+ rxjs.timer(10).pipe(rxjs.map(() => [1, 2, 3])),
82
+ rxjs.timer(10).pipe(rxjs.map(() => [1, 2, 3])),
83
+ )
84
+ .pipe(combineMap((val) => rxjs.of(val * 2)))
85
+ .subscribe(() => {
86
+ t.assert.ok(true)
87
+ })
88
+ })
89
+
90
+ test('combineMap combine in single tick', (t) => {
91
+ t.plan(2, { wait: true })
92
+ rxjs
93
+ .concat(
94
+ rxjs.timer(10).pipe(rxjs.map(() => [1, 2, 3])),
95
+ rxjs.timer(10).pipe(rxjs.map(() => [4, 5, 6])),
96
+ )
97
+ .pipe(combineMap((val) => rxjs.from([val * 2, val * 2])))
98
+ .subscribe(() => {
99
+ t.assert.ok(true)
100
+ })
101
+ })
102
+
103
+ test('combineLatest completion', (t) => {
104
+ t.plan(1, { wait: true })
105
+ rxjs.combineLatest([1, 2, 3].map((x) => rxjs.of(x))).subscribe({
106
+ complete: () => {
107
+ t.assert.ok(true)
108
+ },
109
+ })
110
+ })
111
+
112
+ test('combineMap completion', (t) => {
113
+ t.plan(1, { wait: true })
114
+ rxjs
115
+ .of([1, 2, 3])
116
+ .pipe(combineMap((x) => rxjs.of(x)))
117
+ .subscribe({
118
+ complete: () => {
119
+ t.assert.ok(true)
120
+ },
121
+ })
122
+ })
123
+
124
+ test('combineLatest no completion', (t) => {
125
+ t.plan(1, { wait: true })
126
+ const subscription = rxjs
127
+ .combineLatest([1, 2, 3].map((x) => rxjs.timer(0, 1e3).pipe(rxjs.map(() => x))))
128
+ .subscribe({
129
+ next: () => {
130
+ t.assert.ok(true)
131
+ },
132
+ complete: () => {
133
+ t.assert.fail()
134
+ },
135
+ })
136
+ t.after(() => subscription.unsubscribe())
137
+ })
138
+
139
+ test('combineMap no completion', (t) => {
140
+ t.plan(1, { wait: true })
141
+ const subscription = rxjs
142
+ .of([1, 2, 3])
143
+ .pipe(combineMap((x) => rxjs.timer(0, 1e3).pipe(rxjs.map(() => x))))
144
+ .subscribe({
145
+ next: () => {
146
+ t.assert.ok(true)
147
+ },
148
+ complete: () => {
149
+ t.assert.fail()
150
+ },
151
+ })
152
+ t.after(() => subscription.unsubscribe())
153
+ })
154
+
155
+ test('combineLatest no value', (t) => {
156
+ t.plan(1, { wait: true })
157
+ rxjs.combineLatest([1, 2, 3].map((x) => rxjs.EMPTY)).subscribe({
158
+ complete: () => {
159
+ t.assert.ok(true)
160
+ },
161
+ })
162
+ })
163
+
164
+ test('combineMap no value', (t) => {
165
+ t.plan(1, { wait: true })
166
+ rxjs
167
+ .of([1, 2, 3])
168
+ .pipe(combineMap((x) => rxjs.EMPTY))
169
+ .subscribe({
170
+ complete: () => {
171
+ t.assert.ok(true)
172
+ },
173
+ })
174
+ })
175
+
176
+ test('combineMap object keys removed', (t) => {
177
+ t.plan(3, { wait: true })
178
+ const a = {}
179
+ const b = {}
180
+ const c = {}
181
+
182
+ let i = 0
183
+ rxjs
184
+ .concat(rxjs.of([a, b, c]), rxjs.of([a, b]).pipe(rxjs.delay(10)))
185
+ .pipe(combineMap((x) => rxjs.of(x)))
186
+ .subscribe({
187
+ next: (value) => {
188
+ if (i === 0) {
189
+ t.assert.deepStrictEqual(value, [a, b, c])
190
+ } else if (i === 1) {
191
+ t.assert.deepStrictEqual(value, [a, b])
192
+ }
193
+ i++
194
+ },
195
+ complete: () => {
196
+ t.assert.ok(true)
197
+ },
198
+ })
199
+ })
@@ -0,0 +1,113 @@
1
+ import { test } from 'node:test'
2
+ import assert from 'node:assert'
3
+ import compareRev from './compare-rev.js'
4
+
5
+ const cases = [
6
+ [null, null, 0],
7
+ [null, '1-00000000000000', -1],
8
+ ['1-00000000000000', null, 1],
9
+ ['INF-00000000000000', '1-00000000000000', 1],
10
+ ['1-00000000000000', 'INF-00000000000000', -1],
11
+ ['INF-00000000000000', 'INF-00000000000000', 0],
12
+ ['INF-00000000000001', 'INF-00000000000000', 1],
13
+ ['INF-00000000000001', 'INF-00000000000002', -1],
14
+ ['1-00000000000000', '1-00000000000000', 0],
15
+ ['1-00000000000000', '1-00000000000001', -1],
16
+ ['1-00000000000001', '1-00000000000000', 1],
17
+ ['1-00000000000000', '2-00000000000000', -1],
18
+ ['2-00000000000000', '1-00000000000000', 1],
19
+ ['1-00000000000000', '02-00000000000000', -1],
20
+ ['02-00000000000000', '1-00000000000000', 1],
21
+ ['01-00000000000000', '02-00000000000000', -1],
22
+ ['02-00000000000000', '01-00000000000000', 1],
23
+ ['11-00000000000000', '2-00000000000000', 1],
24
+ ['2-00000000000000', '11-00000000000000', -1],
25
+ ['837-N', '5763-/h', -1],
26
+ ['000000837-N', '5763-/h', -1],
27
+ ['1-A', '1-AA', -1],
28
+ ['4-UI7WqKrsEZJdA1-_asset', '6-UI7YZdKsENJfhH-_asset', -1],
29
+ ]
30
+
31
+ for (const [a, b, r] of cases) {
32
+ await test(`${a} ${b} ${r}`, async (t) => {
33
+ const expected = _compareRev(a, b)
34
+ if (r != null) {
35
+ assert.equal(expected, r) // sanity check
36
+ assert.equal(Math.sign(compareRev(a, b)), r)
37
+ }
38
+
39
+ assert.equal(Math.sign(compareRev(a && Buffer.from(a), b)), expected)
40
+ assert.equal(Math.sign(compareRev(a, b && Buffer.from(b))), expected)
41
+ assert.equal(Math.sign(compareRev(a && Buffer.from(a), b && Buffer.from(b))), expected)
42
+ })
43
+ }
44
+
45
+ const ascii = Array.from({ length: 128 })
46
+ .map((_, index) => (index > 27 && index < 127 ? String.fromCharCode(index) : null))
47
+ .filter(Boolean)
48
+ .join('')
49
+ const rand = (n) => Math.floor(Math.random() * n)
50
+ const randChar = () => ascii[rand(ascii.length)]
51
+ const randId = () => Array.from({ length: rand(63) + 1 }, randChar).join('')
52
+ const randRev = (other) => {
53
+ const num = other && !rand(3) ? parseInt(other) : rand(10e3)
54
+ let id
55
+ if (other && !rand(3)) {
56
+ id = other.slice(other.indexOf('-') + 1)
57
+ if (rand(3)) {
58
+ id = id.slice(0, rand(id.length - 1) + 1)
59
+ }
60
+ } else {
61
+ id = randId()
62
+ }
63
+ return `${String(num).padStart(rand(10), '0')}-${id}`
64
+ }
65
+
66
+ await test('fuzz', async (t) => {
67
+ const N = 1e4
68
+ for (let i = 0; i < N; i++) {
69
+ let a = randRev()
70
+ let b = randRev(a)
71
+ if (rand(2)) {
72
+ ;[a, b] = [b, a]
73
+ }
74
+ const r = _compareRev(a, b)
75
+
76
+ await t.test(`${a} ${b} ${r}`, (t) => {
77
+ assert.equal(Math.sign(compareRev(a, b)), r)
78
+ assert.equal(Math.sign(compareRev(a && Buffer.from(a), b)), r)
79
+ assert.equal(Math.sign(compareRev(a, b && Buffer.from(b))), r)
80
+ assert.equal(Math.sign(compareRev(a && Buffer.from(a), b && Buffer.from(b))), r)
81
+ })
82
+ }
83
+ })
84
+
85
+ function _compareRev(a, b) {
86
+ if (!a) {
87
+ return b ? -1 : 0
88
+ }
89
+
90
+ if (!b) {
91
+ return a ? 1 : 0
92
+ }
93
+
94
+ if (a === b) {
95
+ return 0
96
+ }
97
+
98
+ const av = a[0] === 'I' ? Infinity : parseInt(a)
99
+ const bv = b[0] === 'I' ? Infinity : parseInt(b)
100
+
101
+ if (av !== bv) {
102
+ return av > bv ? 1 : -1
103
+ }
104
+
105
+ const ar = a.slice(a.indexOf('-') + 1)
106
+ const br = b.slice(b.indexOf('-') + 1)
107
+
108
+ if (ar !== br) {
109
+ return ar > br ? 1 : -1
110
+ }
111
+
112
+ return 0
113
+ }
@@ -50,3 +50,32 @@ test('return function', async () => {
50
50
  'BARBAZ',
51
51
  )
52
52
  })
53
+
54
+ test('noop', async (t) => {
55
+ const { resolveTemplate } = makeTemplateCompiler({})
56
+ const x = { foo: 1, bar: {} }
57
+ const y = await resolveTemplate(x)
58
+ assert.strictEqual(x, y)
59
+ })
60
+
61
+ test('simple', async (t) => {
62
+ const { resolveTemplate } = makeTemplateCompiler({})
63
+ const x = { bar: '{{#js $.test }}' }
64
+ const y = await resolveTemplate(x, { test: 1 })
65
+ assert.deepStrictEqual(y, { bar: 1 })
66
+ })
67
+
68
+ // test('cache', async (t) => {
69
+ // const x = '{{#js $.test }}'
70
+ // t.equal(compileTemplate(x), compileTemplate(x))
71
+ // t.end()
72
+ // })
73
+
74
+ test('string concat', async (t) => {
75
+ const { resolveTemplate } = makeTemplateCompiler({})
76
+ const x = '{{#js $.pre }} {{#js $.body}} {{#js $.post}}'
77
+ assert.strictEqual(
78
+ await resolveTemplate(x, { pre: 'pre', body: 'body', post: 'post' }),
79
+ 'pre body post',
80
+ )
81
+ })
@@ -0,0 +1,165 @@
1
+ import { test } from 'node:test'
2
+ import assert from 'node:assert'
3
+ import { makeTemplateCompiler } from './index.js'
4
+ import * as rxjs from 'rxjs'
5
+
6
+ const { resolveTemplate } = makeTemplateCompiler({
7
+ ds: {
8
+ record: {
9
+ observe: () => rxjs.of({ foo: 'bar' }),
10
+ },
11
+ },
12
+ })
13
+
14
+ test('hash to int', async () => {
15
+ const val = await resolveTemplate('{{test | hashaint() | mod(128)}}', { test: { foo: '11d1' } })
16
+ assert.strictEqual(Number.isFinite(val), true)
17
+ })
18
+
19
+ test('baseValue', async () => {
20
+ assert.strictEqual(await resolveTemplate('{{test}}', { test: '11d1' }), '11d1')
21
+ assert.strictEqual(await resolveTemplate('{{test}}', { test: rxjs.of('11d1') }), '11d1')
22
+ assert.strictEqual(
23
+ await resolveTemplate('{{test.asd}}', { test: rxjs.of({ asd: '11d1' }) }),
24
+ '11d1',
25
+ )
26
+ assert.strictEqual(
27
+ await resolveTemplate('{{test.asd}}', { test: { asd: rxjs.of('11d1') } }),
28
+ '11d1',
29
+ )
30
+ })
31
+
32
+ test('integer ops', async () => {
33
+ assert.strictEqual(await resolveTemplate('{{test | div(2)}}', { test: '8' }), 4)
34
+ assert.strictEqual(await resolveTemplate('{{test | div(2)}}', { test: 8 }), 4)
35
+ assert.strictEqual(await resolveTemplate('{{test | mul(2)}}', { test: '8' }), 16)
36
+ assert.strictEqual(await resolveTemplate('{{test | mul(2)}}', { test: 8 }), 16)
37
+ assert.strictEqual(await resolveTemplate('{{test | add(2)}}', { test: '10' }), 12)
38
+ assert.strictEqual(await resolveTemplate('{{test | add(2)}}', { test: 10 }), 12)
39
+ assert.strictEqual(await resolveTemplate('{{test | sub(2)}}', { test: '10' }), 8)
40
+ assert.strictEqual(await resolveTemplate('{{test | sub(2)}}', { test: 10 }), 8)
41
+ })
42
+
43
+ test('null undefined args', async () => {
44
+ assert.strictEqual(await resolveTemplate('{{asd | default(null, true)}}', {}), null)
45
+ assert.strictEqual(await resolveTemplate('{{asd | default(undefined, true)}}', {}), undefined)
46
+ })
47
+
48
+ test('path var', async () => {
49
+ assert.strictEqual(await resolveTemplate('{{test.foo}}', { test: { foo: '111' } }), '111')
50
+ })
51
+
52
+ test('replaces strings', async () => {
53
+ assert.strictEqual(await resolveTemplate('{{test}}', { test: '111' }), '111')
54
+ assert.strictEqual(await resolveTemplate('pre{{test}}post', { test: '111' }), 'pre111post')
55
+ assert.strictEqual(
56
+ await resolveTemplate('123{{test}}456{{test}}{{test}}', { test: 'body' }),
57
+ '123body456bodybody',
58
+ )
59
+ assert.strictEqual(
60
+ await resolveTemplate('test{{test.foo}}test{{test.bar.baz}}test', {
61
+ test: { foo: '111', bar: { baz: '222' } },
62
+ }),
63
+ 'test111test222test',
64
+ )
65
+ assert.strictEqual(await resolveTemplate('{{ asd | default("te | st")}}', {}), 'te | st')
66
+ assert.strictEqual(await resolveTemplate('{{ asd | default("test\n") }}', {}), 'test\n')
67
+ assert.strictEqual(await resolveTemplate('{{ asd | default("test\n\n") }}', {}), 'test\n\n')
68
+ assert.strictEqual(await resolveTemplate('{{ asd | default("test\r\n") }}', {}), 'test\r\n')
69
+ })
70
+
71
+ test('nested', async () => {
72
+ assert.strictEqual(
73
+ await resolveTemplate('{{ asd | default("{{foo}}") }}', { foo: '"test"' }),
74
+ '"test"',
75
+ )
76
+ assert.strictEqual(await resolveTemplate('{{{{foo}}}}', { test: '111', foo: 'test' }), '111')
77
+ assert.strictEqual(
78
+ await resolveTemplate('f{{oo}}', { test: '111', foo: 'test', oo: 'oo' }),
79
+ 'foo',
80
+ )
81
+ assert.strictEqual(
82
+ await resolveTemplate('{{f{{oo}}}}', { test: '111', foo: 'test', oo: 'oo' }),
83
+ 'test',
84
+ )
85
+ assert.strictEqual(await resolveTemplate('{{{{foo}}}}', { test: '111', foo: 'test' }), '111')
86
+ assert.strictEqual(
87
+ await resolveTemplate('{{{{f{{o}}o}}}}', { test: '111', foo: 'test', o: 'o' }),
88
+ '111',
89
+ )
90
+ assert.strictEqual(
91
+ await resolveTemplate('{{ asd | default("{{test}}")}}', { test: '111', foo: 'test' }),
92
+ '111',
93
+ )
94
+ assert.strictEqual(
95
+ await resolveTemplate('{{ asd | default("{{t{{es}}t}}")}}', {
96
+ test: '111',
97
+ foo: 'test',
98
+ es: 'es',
99
+ }),
100
+ '111',
101
+ )
102
+ assert.strictEqual(
103
+ await resolveTemplate('{{ asd | default("{{test | default("test\n")}}")}}', {}),
104
+ 'test\n',
105
+ )
106
+ assert.strictEqual(
107
+ await resolveTemplate('{{ asd | default("{{test | default("test\n\n")}}")}}', {}),
108
+ 'test\n\n',
109
+ )
110
+ assert.strictEqual(
111
+ await resolveTemplate('{{ asd | default("{{test | default("test\r\n")}}")}}', {}),
112
+ 'test\r\n',
113
+ )
114
+ })
115
+
116
+ test('append', async () => {
117
+ assert.strictEqual(await resolveTemplate("{{test | append('1')}}", { test: '111' }), '1111')
118
+ })
119
+
120
+ test('object', async () => {
121
+ const obj = { foo: 1 }
122
+ assert.strictEqual(await resolveTemplate('{{test}}', { test: obj }), obj)
123
+ })
124
+
125
+ test('ds', async () => {
126
+ assert.strictEqual(
127
+ await resolveTemplate("{{test | ds() | pluck('foo')}}", { test: 'foo' }),
128
+ 'bar',
129
+ )
130
+ })
131
+
132
+ test('replace array', async () => {
133
+ assert.deepStrictEqual(
134
+ await resolveTemplate('{{test | join("#") | replace("foo", "bar") | split("#")}}', {
135
+ test: ['foo', 'bar'],
136
+ }),
137
+ ['bar', 'bar'],
138
+ )
139
+ assert.deepStrictEqual(
140
+ await resolveTemplate('{{test | join(",") | replace("foo", "bar") | split(",")}}', {
141
+ test: ['foo', 'bar'],
142
+ }),
143
+ ['bar', 'bar'],
144
+ )
145
+ })
146
+
147
+ test('You Do Not Know Me', async () => {
148
+ assert.deepStrictEqual(
149
+ await resolveTemplate('{{id | default("You Do Not Know", true)}} -', {}),
150
+ 'You Do Not Know -',
151
+ )
152
+ })
153
+
154
+ test('object 1', async () => {
155
+ assert.deepStrictEqual(await resolveTemplate({ asd: ['{{foo}}'] }, { foo: 'bar' }), {
156
+ asd: ['bar'],
157
+ })
158
+ })
159
+
160
+ test('empty arg', async () => {
161
+ assert.deepStrictEqual(
162
+ await resolveTemplate('{{source.value | includes("salami") | ternary([], )}}', {}),
163
+ undefined,
164
+ )
165
+ })