@e22m4u/js-trie-router 0.7.1 → 0.7.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.
@@ -544,9 +544,9 @@ function createRequestMock(options) {
544
544
  }
545
545
  }
546
546
  if (options.query !== void 0) {
547
- if (!options.query || typeof options.query !== "object" || Array.isArray(options.query)) {
547
+ if (options.query === null || typeof options.query !== "string" && typeof options.query !== "object" || Array.isArray(options.query)) {
548
548
  throw new import_js_format9.InvalidArgumentError(
549
- 'Option "query" must be an Object, but %v was given.',
549
+ 'Option "query" must be a String or an Object, but %v was given.',
550
550
  options.query
551
551
  );
552
552
  }
@@ -721,9 +721,9 @@ function createRequestUrl(path, query) {
721
721
  );
722
722
  }
723
723
  if (query !== void 0) {
724
- if (!query || typeof query !== "object" || Array.isArray(query)) {
724
+ if (query === null || typeof query !== "string" && typeof query !== "object" || Array.isArray(query)) {
725
725
  throw new import_js_format9.InvalidArgumentError(
726
- 'Parameter "query" must be an Object, but %v was given.',
726
+ 'Parameter "query" must be a String or an Object, but %v was given.',
727
727
  query
728
728
  );
729
729
  }
@@ -734,6 +734,8 @@ function createRequestUrl(path, query) {
734
734
  if (qs) {
735
735
  res += `?${qs}`;
736
736
  }
737
+ } else if (typeof query === "string" && query !== "" && query !== "?") {
738
+ res += `?${query.replace(/^\?/, "")}`;
737
739
  }
738
740
  return res;
739
741
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e22m4u/js-trie-router",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "description": "HTTP маршрутизатор для Node.js на основе префиксного дерева",
5
5
  "author": "Mikhail Evstropov <e22m4u@yandex.ru>",
6
6
  "license": "MIT",
@@ -1,13 +1,6 @@
1
1
  import {Readable} from 'stream';
2
2
  import {IncomingMessage} from 'http';
3
3
 
4
- /**
5
- * Request query input.
6
- */
7
- type RequestQueryInput = {
8
- [name: string]: unknown;
9
- };
10
-
11
4
  /**
12
5
  * Request headers input.
13
6
  */
@@ -24,7 +17,7 @@ type RequestOptions = {
24
17
  secure?: boolean;
25
18
  url?: string;
26
19
  path?: string;
27
- query?: RequestQueryInput;
20
+ query?: string | object;
28
21
  cookies?: object;
29
22
  headers?: RequestHeadersInput;
30
23
  body?: unknown;
@@ -116,12 +116,13 @@ export function createRequestMock(options) {
116
116
  // options.query
117
117
  if (options.query !== undefined) {
118
118
  if (
119
- !options.query ||
120
- typeof options.query !== 'object' ||
119
+ options.query === null ||
120
+ (typeof options.query !== 'string' &&
121
+ typeof options.query !== 'object') ||
121
122
  Array.isArray(options.query)
122
123
  ) {
123
124
  throw new InvalidArgumentError(
124
- 'Option "query" must be an Object, but %v was given.',
125
+ 'Option "query" must be a String or an Object, but %v was given.',
125
126
  options.query,
126
127
  );
127
128
  }
@@ -335,7 +336,7 @@ function createRequestStream(secure, body, encoding) {
335
336
  * Create request url.
336
337
  *
337
338
  * @param {string|undefined} path
338
- * @param {object|undefined} query
339
+ * @param {string|object|undefined} query
339
340
  * @returns {string}
340
341
  */
341
342
  function createRequestUrl(path, query) {
@@ -346,9 +347,13 @@ function createRequestUrl(path, query) {
346
347
  );
347
348
  }
348
349
  if (query !== undefined) {
349
- if (!query || typeof query !== 'object' || Array.isArray(query)) {
350
+ if (
351
+ query === null ||
352
+ (typeof query !== 'string' && typeof query !== 'object') ||
353
+ Array.isArray(query)
354
+ ) {
350
355
  throw new InvalidArgumentError(
351
- 'Parameter "query" must be an Object, but %v was given.',
356
+ 'Parameter "query" must be a String or an Object, but %v was given.',
352
357
  query,
353
358
  );
354
359
  }
@@ -359,6 +364,8 @@ function createRequestUrl(path, query) {
359
364
  if (qs) {
360
365
  res += `?${qs}`;
361
366
  }
367
+ } else if (typeof query === 'string' && query !== '' && query !== '?') {
368
+ res += `?${query.replace(/^\?/, '')}`;
362
369
  }
363
370
  return res;
364
371
  }
@@ -152,6 +152,26 @@ describe('createRequestMock', function () {
152
152
  mustThrowWith('');
153
153
  });
154
154
 
155
+ it('should require the option "query" to be a String or an Object', function () {
156
+ const throwable = v => () => createRequestMock({query: v});
157
+ const error = v =>
158
+ format(
159
+ 'Option "query" must be a String or an Object, but %s was given.',
160
+ v,
161
+ );
162
+ expect(throwable(10)).to.throw(error('10'));
163
+ expect(throwable(0)).to.throw(error('0'));
164
+ expect(throwable(true)).to.throw(error('true'));
165
+ expect(throwable(false)).to.throw(error('false'));
166
+ expect(throwable([])).to.throw(error('Array'));
167
+ expect(throwable(null)).to.throw(error('null'));
168
+ throwable({foo: 'bar'})();
169
+ throwable({})();
170
+ throwable('foo=bar')();
171
+ throwable('')();
172
+ throwable(undefined)();
173
+ });
174
+
155
175
  it('should require the option "cookies" to be an Object', function () {
156
176
  const throwable = v => () => createRequestMock({cookies: v});
157
177
  const error = v =>
@@ -336,17 +356,17 @@ describe('createRequestMock', function () {
336
356
  expect(req.socket).to.be.instanceof(Socket);
337
357
  });
338
358
 
339
- it('should use the default path "/" without a query string', function () {
359
+ it('should use "/" as the default value of the request url', function () {
340
360
  const req = createRequestMock();
341
361
  expect(req.url).to.be.eq('/');
342
362
  });
343
363
 
344
- it('should use "localhost" as the default "host" header', function () {
364
+ it('should use "localhost" as the default value of the "host" header', function () {
345
365
  const req = createRequestMock();
346
366
  expect(req.headers).to.be.eql({host: 'localhost'});
347
367
  });
348
368
 
349
- it('should use the "utf-8" encoding by default', async function () {
369
+ it('should use "utf-8" as the default value of the data encoding', async function () {
350
370
  const body = 'test';
351
371
  const req = createRequestMock({body: Buffer.from(body)});
352
372
  const chunks = [];
@@ -416,7 +436,43 @@ describe('createRequestMock', function () {
416
436
  expect(data).to.be.eq(body);
417
437
  });
418
438
 
419
- it('should pass an object body to the stream as JSON', async function () {
439
+ it('should pass a number from the "body" option to the stream as a string', async function () {
440
+ const body = 10;
441
+ const req = createRequestMock({body});
442
+ const chunks = [];
443
+ const data = await new Promise((resolve, reject) => {
444
+ req.on('data', chunk => chunks.push(Buffer.from(chunk)));
445
+ req.on('error', err => reject(err));
446
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
447
+ });
448
+ expect(data).to.be.eq('10');
449
+ });
450
+
451
+ it('should pass a boolean from the "body" option to the stream as a string', async function () {
452
+ const body = true;
453
+ const req = createRequestMock({body});
454
+ const chunks = [];
455
+ const data = await new Promise((resolve, reject) => {
456
+ req.on('data', chunk => chunks.push(Buffer.from(chunk)));
457
+ req.on('error', err => reject(err));
458
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
459
+ });
460
+ expect(data).to.be.eq('true');
461
+ });
462
+
463
+ it('should pass an array from the "body" option to the stream as JSON', async function () {
464
+ const body = [1, 2];
465
+ const req = createRequestMock({body});
466
+ const chunks = [];
467
+ const data = await new Promise((resolve, reject) => {
468
+ req.on('data', chunk => chunks.push(Buffer.from(chunk)));
469
+ req.on('error', err => reject(err));
470
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
471
+ });
472
+ expect(data).to.be.eq(JSON.stringify(body));
473
+ });
474
+
475
+ it('should pass an object from the "body" option to the stream as JSON', async function () {
420
476
  const body = {foo: 'bar'};
421
477
  const req = createRequestMock({body});
422
478
  const chunks = [];
@@ -428,7 +484,7 @@ describe('createRequestMock', function () {
428
484
  expect(data).to.be.eq(JSON.stringify(body));
429
485
  });
430
486
 
431
- it('should pass a Buffer body to the stream', async function () {
487
+ it('should pass a Buffer from the "body" option to the stream', async function () {
432
488
  const body = Buffer.from('test');
433
489
  const req = createRequestMock({body});
434
490
  const chunks = [];
@@ -440,27 +496,38 @@ describe('createRequestMock', function () {
440
496
  expect(data).to.be.eql(body);
441
497
  });
442
498
 
443
- it('should set the "url" option to the request url', function () {
499
+ it('should pass a value form the "url" option to the request url', function () {
444
500
  const req = createRequestMock({url: '/test'});
445
501
  expect(req.url).to.be.eq('/test');
446
502
  });
447
503
 
448
- it('should set the "path" option to the request url', function () {
504
+ it('should pass a value form the "path" option to the request url', function () {
449
505
  const req = createRequestMock({path: '/test'});
450
506
  expect(req.url).to.be.eq('/test');
451
507
  });
452
508
 
453
- it('should set the "query" option to the request url', async function () {
509
+ it('should pass a string form the "query" option to the request url', async function () {
510
+ const req1 = createRequestMock({query: 'p1=foo&p2=bar'});
511
+ const req2 = createRequestMock({query: '?p1=foo&p2=bar'});
512
+ expect(req1.url).to.be.eq('/?p1=foo&p2=bar');
513
+ expect(req2.url).to.be.eq('/?p1=foo&p2=bar');
514
+ });
515
+
516
+ it('should pass an object form the "query" option to the request url', async function () {
454
517
  const req = createRequestMock({query: {foo: 'bar', baz: 'qux'}});
455
518
  expect(req.url).to.be.eq('/?foo=bar&baz=qux');
456
519
  });
457
520
 
458
521
  it('should combine the "path" and "query" options in the request url', function () {
459
- const req = createRequestMock({path: '/test', query: {foo: 'bar'}});
460
- expect(req.url).to.be.eq('/test?foo=bar');
522
+ const req1 = createRequestMock({path: '/test', query: 'foo=bar'});
523
+ const req2 = createRequestMock({path: '/test', query: '?foo=bar'});
524
+ const req3 = createRequestMock({path: '/test', query: {foo: 'bar'}});
525
+ expect(req1.url).to.be.eq('/test?foo=bar');
526
+ expect(req2.url).to.be.eq('/test?foo=bar');
527
+ expect(req3.url).to.be.eq('/test?foo=bar');
461
528
  });
462
529
 
463
- it('should set the "method" option to the request method in upper case', async function () {
530
+ it('should set a value from the "method" option to the request method in upper case', async function () {
464
531
  const req1 = createRequestMock({method: 'get'});
465
532
  const req2 = createRequestMock({method: 'post'});
466
533
  expect(req1.method).to.be.eq('GET');
@@ -478,12 +545,12 @@ describe('createRequestMock', function () {
478
545
  expect(req.headers['x-forwarded-proto']).to.be.eq('https');
479
546
  });
480
547
 
481
- it('should set the "cookie" header from the "cookie" option', function () {
548
+ it('should serialize and set a value from the "cookies" option to the "cookie" header', function () {
482
549
  const req = createRequestMock({cookies: {p1: 'foo', p2: 'bar'}});
483
550
  expect(req.headers['cookie']).to.be.eq('p1=foo; p2=bar');
484
551
  });
485
552
 
486
- it('should merge the "cookie" header with the "cookie" option', function () {
553
+ it('should merge the "cookie" header with the "cookies" option', function () {
487
554
  const req = createRequestMock({
488
555
  headers: {cookie: 'p1=foo; p2=bar'},
489
556
  cookies: {p2: 'baz', p3: 'qux'},