Browse Source

refactor: makes path option required

e22m4u 3 weeks ago
parent
commit
93304d8187

+ 0 - 16
README.md

@@ -79,22 +79,6 @@ server.listen(3000, 'localhost');             // прослушивание за
 *i. Для указания метода запроса рекомендуется использовать
 константу `HttpMethod`, чтобы избежать опечаток.*
 
-#### path
-
-Параметр `path` является необязательным. Если он опущен, маршрут
-регистрируется в корне текущего контекста. Для основного экземпляра
-маршрутизатора это эквивалентно указанию пути `/` (главная страница).
-
-```js
-// добавит маршрут GET "/"
-router.defineRoute({
-  method: HttpMethod.GET,
-  handler(ctx) {
-    return 'Hello world!';
-  },
-});
-```
-
 ### Контекст запроса
 
 Первый параметр обработчика маршрута принимает экземпляр класса

+ 6 - 3
dist/cjs/index.cjs

@@ -42,6 +42,7 @@ __export(index_exports, {
   HttpMethod: () => HttpMethod,
   METHODS_WITH_BODY: () => METHODS_WITH_BODY,
   QueryParser: () => QueryParser,
+  ROOT_PATH: () => ROOT_PATH,
   RequestContext: () => RequestContext,
   RequestParser: () => RequestParser,
   Route: () => Route,
@@ -928,9 +929,9 @@ function validateRouteDefinition(routeDef) {
       routeDef.method
     );
   }
-  if (routeDef.path !== void 0 && typeof routeDef.path !== "string") {
+  if (!routeDef.path || typeof routeDef.path !== "string") {
     throw new import_js_format12.InvalidArgumentError(
-      'Option "path" must be a String, but %v was given.',
+      'Option "path" must be a non-empty String, but %v was given.',
       routeDef.path
     );
   }
@@ -993,6 +994,7 @@ var HttpMethod = {
   PATCH: "PATCH",
   DELETE: "DELETE"
 };
+var ROOT_PATH = "/";
 var _Route = class _Route extends import_js_debug.Debuggable {
   /**
    * Method.
@@ -1081,7 +1083,7 @@ var _Route = class _Route extends import_js_debug.Debuggable {
     });
     validateRouteDefinition(routeDef);
     this._method = routeDef.method.toUpperCase();
-    this._path = routeDef.path || "/";
+    this._path = routeDef.path;
     if (routeDef.meta !== void 0) {
       this._meta = cloneDeep(routeDef.meta);
     }
@@ -2017,6 +2019,7 @@ var TrieRouter = _TrieRouter;
   HttpMethod,
   METHODS_WITH_BODY,
   QueryParser,
+  ROOT_PATH,
   RequestContext,
   RequestParser,
   Route,

+ 6 - 1
src/route/route.d.ts

@@ -48,13 +48,18 @@ export type RouteMeta = {
  */
 export type RouteDefinition = {
   method: string;
-  path?: string;
+  path: string;
   handler: RouteHandler;
   preHandler?: RoutePreHandler | RoutePreHandler[];
   postHandler?: RoutePostHandler | RoutePostHandler[];
   meta?: RouteMeta;
 };
 
+/**
+ * Root path.
+ */
+export declare const ROOT_PATH: '/';
+
 /**
  * Route.
  */

+ 9 - 2
src/route/route.js

@@ -11,7 +11,7 @@ import {validateRouteDefinition} from './validate-route-definition.js';
  * @typedef {(ctx: RequestContext, data: *) => *} RoutePostHandler
  * @typedef {{
  *   method: string,
- *   path?: string,
+ *   path: string,
  *   handler: RouteHandler,
  *   preHandler?: RoutePreHandler|(RoutePreHandler[]),
  *   postHandler?: RoutePostHandler|(RoutePostHandler[]),
@@ -38,6 +38,13 @@ export const HttpMethod = {
   DELETE: 'DELETE',
 };
 
+/**
+ * Root path.
+ *
+ * @type {string}
+ */
+export const ROOT_PATH = '/';
+
 /**
  * Route.
  */
@@ -139,7 +146,7 @@ export class Route extends Debuggable {
     });
     validateRouteDefinition(routeDef);
     this._method = routeDef.method.toUpperCase();
-    this._path = routeDef.path || '/';
+    this._path = routeDef.path;
     if (routeDef.meta !== undefined) {
       this._meta = cloneDeep(routeDef.meta);
     }

+ 27 - 14
src/route/route.spec.js

@@ -1,9 +1,9 @@
 import {expect} from 'chai';
 import {format} from '@e22m4u/js-format';
-import {Route, HttpMethod} from './route.js';
 import {RouterHookType} from '../hooks/index.js';
 import {ServiceContainer} from '@e22m4u/js-service';
 import {RequestContext} from '../request-context.js';
+import {Route, HttpMethod, ROOT_PATH} from './route.js';
 import {createRequestMock, createResponseMock} from '../utils/index.js';
 
 describe('Route', function () {
@@ -24,6 +24,7 @@ describe('Route', function () {
       expect(throwable(() => undefined)).to.throw(error('Function'));
       throwable({
         method: HttpMethod.GET,
+        path: ROOT_PATH,
         handler: () => undefined,
       })();
     });
@@ -33,6 +34,7 @@ describe('Route', function () {
         const throwable = v => () =>
           new Route({
             method: v,
+            path: ROOT_PATH,
             handler: () => undefined,
           });
         const error = v =>
@@ -56,6 +58,7 @@ describe('Route', function () {
       it('should set the "method" option to the "method" property in upper case', function () {
         const route = new Route({
           method: 'post',
+          path: ROOT_PATH,
           handler: () => undefined,
         });
         expect(route.method).to.be.eq('POST');
@@ -63,7 +66,7 @@ describe('Route', function () {
     });
 
     describe('the "path" option', function () {
-      it('should require the "path" option to be a String', function () {
+      it('should require the "path" option to be a non-empty String', function () {
         const throwable = v => () =>
           new Route({
             method: HttpMethod.GET,
@@ -71,18 +74,21 @@ describe('Route', function () {
             handler: () => undefined,
           });
         const error = v =>
-          format('Option "path" must be a String, but %s was given.', v);
+          format(
+            'Option "path" must be a non-empty String, but %s was given.',
+            v,
+          );
+        expect(throwable('')).to.throw(error('""'));
         expect(throwable(10)).to.throw(error('10'));
         expect(throwable(0)).to.throw(error('0'));
         expect(throwable(true)).to.throw(error('true'));
         expect(throwable(false)).to.throw(error('false'));
-        expect(throwable(null)).to.throw(error('null'));
         expect(throwable({})).to.throw(error('Object'));
         expect(throwable([])).to.throw(error('Array'));
+        expect(throwable(undefined)).to.throw(error('undefined'));
+        expect(throwable(null)).to.throw(error('null'));
         expect(throwable(() => undefined)).to.throw(error('Function'));
         throwable('str')();
-        throwable('')();
-        throwable(undefined)();
       });
 
       it('should set the "path" option to the "path" property', function () {
@@ -94,14 +100,6 @@ describe('Route', function () {
         });
         expect(route.path).to.be.eq(value);
       });
-
-      it('should set the "path" property to "/" when the "path" option is not provided', function () {
-        const route = new Route({
-          method: HttpMethod.GET,
-          handler: () => undefined,
-        });
-        expect(route.path).to.be.eq('/');
-      });
     });
 
     describe('the "handler" option', function () {
@@ -109,6 +107,7 @@ describe('Route', function () {
         const throwable = v => () =>
           new Route({
             method: HttpMethod.GET,
+            path: ROOT_PATH,
             handler: v,
           });
         const error = v =>
@@ -130,6 +129,7 @@ describe('Route', function () {
         const value = () => undefined;
         const route = new Route({
           method: HttpMethod.GET,
+          path: ROOT_PATH,
           handler: value,
         });
         expect(route.handler).to.be.eq(value);
@@ -141,6 +141,7 @@ describe('Route', function () {
         const throwable = v => () =>
           new Route({
             method: HttpMethod.GET,
+            path: ROOT_PATH,
             preHandler: v,
             handler: () => undefined,
           });
@@ -167,6 +168,7 @@ describe('Route', function () {
         const throwable = v => () =>
           new Route({
             method: HttpMethod.GET,
+            path: ROOT_PATH,
             preHandler: [v],
             handler: () => undefined,
           });
@@ -189,6 +191,7 @@ describe('Route', function () {
         const value = () => undefined;
         const route = new Route({
           method: HttpMethod.GET,
+          path: ROOT_PATH,
           preHandler: value,
           handler: () => undefined,
         });
@@ -200,6 +203,7 @@ describe('Route', function () {
         const value = [() => undefined, () => undefined];
         const route = new Route({
           method: HttpMethod.GET,
+          path: ROOT_PATH,
           preHandler: value,
           handler: () => undefined,
         });
@@ -215,6 +219,7 @@ describe('Route', function () {
         const throwable = v => () =>
           new Route({
             method: HttpMethod.GET,
+            path: ROOT_PATH,
             postHandler: v,
             handler: () => undefined,
           });
@@ -241,6 +246,7 @@ describe('Route', function () {
         const throwable = v => () =>
           new Route({
             method: HttpMethod.GET,
+            path: ROOT_PATH,
             postHandler: [v],
             handler: () => undefined,
           });
@@ -263,6 +269,7 @@ describe('Route', function () {
         const value = () => undefined;
         const route = new Route({
           method: HttpMethod.GET,
+          path: ROOT_PATH,
           handler: () => undefined,
           postHandler: value,
         });
@@ -274,6 +281,7 @@ describe('Route', function () {
         const value = [() => undefined, () => undefined];
         const route = new Route({
           method: HttpMethod.GET,
+          path: ROOT_PATH,
           handler: () => undefined,
           postHandler: value,
         });
@@ -291,6 +299,7 @@ describe('Route', function () {
         const throwable = v => () =>
           new Route({
             method: HttpMethod.GET,
+            path: ROOT_PATH,
             handler: () => undefined,
             meta: v,
           });
@@ -314,6 +323,7 @@ describe('Route', function () {
         const metaData = {foo: {bar: {baz: 'qux'}}};
         const route = new Route({
           method: 'post',
+          path: ROOT_PATH,
           handler: () => undefined,
           meta: metaData,
         });
@@ -328,6 +338,7 @@ describe('Route', function () {
       it('should set an empty object to the "meta" property if the "meta" option is not provided', function () {
         const route = new Route({
           method: 'post',
+          path: ROOT_PATH,
           handler: () => undefined,
         });
         expect(route.meta).to.be.eql({});
@@ -336,6 +347,7 @@ describe('Route', function () {
       it('should set an empty object to the "meta" property if the "meta" option is undefined', function () {
         const route = new Route({
           method: 'post',
+          path: ROOT_PATH,
           handler: () => undefined,
           meta: undefined,
         });
@@ -348,6 +360,7 @@ describe('Route', function () {
     it('should invoke the handler with the given RequestContext and return its result', function () {
       const route = new Route({
         method: HttpMethod.GET,
+        path: ROOT_PATH,
         handler(ctx) {
           expect(ctx).to.be.instanceof(RequestContext);
           return 'OK';

+ 2 - 2
src/route/validate-route-definition.js

@@ -18,9 +18,9 @@ export function validateRouteDefinition(routeDef) {
       routeDef.method,
     );
   }
-  if (routeDef.path !== undefined && typeof routeDef.path !== 'string') {
+  if (!routeDef.path || typeof routeDef.path !== 'string') {
     throw new InvalidArgumentError(
-      'Option "path" must be a String, but %v was given.',
+      'Option "path" must be a non-empty String, but %v was given.',
       routeDef.path,
     );
   }

+ 13 - 5
src/route/validate-route-definition.spec.js

@@ -1,6 +1,6 @@
 import {expect} from 'chai';
-import {HttpMethod} from './route.js';
 import {format} from '@e22m4u/js-format';
+import {HttpMethod, ROOT_PATH} from './route.js';
 import {validateRouteDefinition} from './validate-route-definition.js';
 
 describe('validateRouteDefinition', function () {
@@ -20,6 +20,7 @@ describe('validateRouteDefinition', function () {
     expect(throwable(() => undefined)).to.throw(error('Function'));
     throwable({
       method: HttpMethod.GET,
+      path: ROOT_PATH,
       handler: () => undefined,
     })();
   });
@@ -28,6 +29,7 @@ describe('validateRouteDefinition', function () {
     const throwable = v => () =>
       validateRouteDefinition({
         method: v,
+        path: ROOT_PATH,
         handler: () => undefined,
       });
     const error = v =>
@@ -56,24 +58,25 @@ describe('validateRouteDefinition', function () {
         handler: () => undefined,
       });
     const error = v =>
-      format('Option "path" must be a String, but %s was given.', v);
+      format('Option "path" must be a non-empty String, but %s was given.', v);
+    expect(throwable('')).to.throw(error('""'));
     expect(throwable(10)).to.throw(error('10'));
     expect(throwable(0)).to.throw(error('0'));
     expect(throwable(true)).to.throw(error('true'));
     expect(throwable(false)).to.throw(error('false'));
-    expect(throwable(null)).to.throw(error('null'));
     expect(throwable({})).to.throw(error('Object'));
     expect(throwable([])).to.throw(error('Array'));
+    expect(throwable(undefined)).to.throw(error('undefined'));
+    expect(throwable(null)).to.throw(error('null'));
     expect(throwable(() => undefined)).to.throw(error('Function'));
     throwable('str')();
-    throwable('')();
-    throwable(undefined)();
   });
 
   it('should require the "handler" option to be a Function', function () {
     const throwable = v => () =>
       validateRouteDefinition({
         method: HttpMethod.GET,
+        path: ROOT_PATH,
         handler: v,
       });
     const error = v =>
@@ -95,6 +98,7 @@ describe('validateRouteDefinition', function () {
     const throwable = v => () =>
       validateRouteDefinition({
         method: HttpMethod.GET,
+        path: ROOT_PATH,
         preHandler: v,
         handler: () => undefined,
       });
@@ -121,6 +125,7 @@ describe('validateRouteDefinition', function () {
     const throwable = v => () =>
       validateRouteDefinition({
         method: HttpMethod.GET,
+        path: ROOT_PATH,
         preHandler: [v],
         handler: () => undefined,
       });
@@ -143,6 +148,7 @@ describe('validateRouteDefinition', function () {
     const throwable = v => () =>
       validateRouteDefinition({
         method: HttpMethod.GET,
+        path: ROOT_PATH,
         postHandler: v,
         handler: () => undefined,
       });
@@ -169,6 +175,7 @@ describe('validateRouteDefinition', function () {
     const throwable = v => () =>
       validateRouteDefinition({
         method: HttpMethod.GET,
+        path: ROOT_PATH,
         postHandler: [v],
         handler: () => undefined,
       });
@@ -191,6 +198,7 @@ describe('validateRouteDefinition', function () {
     const throwable = v => () =>
       validateRouteDefinition({
         method: HttpMethod.GET,
+        path: ROOT_PATH,
         handler: () => undefined,
         meta: v,
       });