1+ import pluralize from 'pluralize'
12import { createRestInstanceSymbol } from './symbol'
23
34/**
@@ -256,10 +257,10 @@ export class Maker {
256257 * @throws {Error } Path should not be deep
257258 * @throws {TypeError } Maybe you forget to add listener?
258259 * @example
259- * createRest(r => {
260- * r .get('name', () => console.log('Handled get /name request'))
261- * r .get(() => console.log('Handled get / request'))
262- * r .get('create',
260+ * createRest(root => {
261+ * root .get('name', () => console.log('Handled get /name request'))
262+ * root .get(() => console.log('Handled get / request'))
263+ * root .get('create',
263264 * (req, res, next) => next(),
264265 * authorize('user'),
265266 * () => console.log('Handled get /create with middlewares')
@@ -277,10 +278,10 @@ export class Maker {
277278 * @throws {Error } Path should not be deep
278279 * @throws {TypeError } Maybe you forget to add listener?
279280 * @example
280- * createRest(r => {
281- * r .put('name', () => console.log('Handled put /name request'))
282- * r .put(() => console.log('Handled put / request'))
283- * r .put('create',
281+ * createRest(root => {
282+ * root .put('name', () => console.log('Handled put /name request'))
283+ * root .put(() => console.log('Handled put / request'))
284+ * root .put('create',
284285 * (req, res, next) => next(),
285286 * authorize('user'),
286287 * () => console.log('Handled put /create with middlewares')
@@ -298,10 +299,10 @@ export class Maker {
298299 * @throws {Error } Path should not be deep
299300 * @throws {TypeError } Maybe you forget to add listener?
300301 * @example
301- * createRest(r => {
302- * r .delete('name', () => console.log('Handled delete /name request'))
303- * r .delete(() => console.log('Handled delete / request'))
304- * r .delete('create',
302+ * createRest(root => {
303+ * root .delete('name', () => console.log('Handled delete /name request'))
304+ * root .delete(() => console.log('Handled delete / request'))
305+ * root .delete('create',
305306 * (req, res, next) => next(),
306307 * authorize('user'),
307308 * () => console.log('Handled delete /create with middlewares')
@@ -319,10 +320,10 @@ export class Maker {
319320 * @throws {Error } Path should not be deep
320321 * @throws {TypeError } Maybe you forget to add listener?
321322 * @example
322- * createRest(r => {
323- * r .patch('name', () => console.log('Handled patch /name request'))
324- * r .patch(() => console.log('Handled patch / request'))
325- * r .patch('create',
323+ * createRest(root => {
324+ * root .patch('name', () => console.log('Handled patch /name request'))
325+ * root .patch(() => console.log('Handled patch / request'))
326+ * root .patch('create',
326327 * (req, res, next) => next(),
327328 * authorize('user'),
328329 * () => console.log('Handled patch /create with middlewares')
@@ -341,13 +342,13 @@ export class Maker {
341342 * @property {object } [methodNames] Change method names
342343 *
343344 * @example <caption>Usage with `only`</caption>
344- * createRest(r => {
345- * r .resource('foo', FooController, { only: ['read'] })
345+ * createRest(root => {
346+ * root .resource('foo', FooController, { only: ['read'] })
346347 * })
347348 *
348349 * @example <caption>Usage with `except`</caption>
349- * createRest(r => {
350- * r .resource('bar', BarController, { except: ['destroy', 'update'] })
350+ * createRest(root => {
351+ * root .resource('bar', BarController, { except: ['destroy', 'update'] })
351352 * })
352353 *
353354 * @example <caption>Method names</caption>
@@ -357,15 +358,15 @@ export class Maker {
357358 * justExample() {},
358359 * youDontNeedThis() {},
359360 * }
360- * createRest(r => {
361- * r .resource('demo', Controller, { methodNames: {
361+ * createRest(root => {
362+ * root .resource('demo', Controller, { methodNames: {
362363 * read: 'justExample', create: 'createDemo', update: 'updateMe', destroy: 'youDontNeedThis',
363364 * }})
364365 * })
365366 */
366367
367368 /**
368- * Create CRUD methods for single resource.
369+ * Add CRUD methods for single resource.
369370 *
370371 * Resources not merging. Use only one resource for path.
371372 * @param {string } name Name of the resource. Create route path from
@@ -384,10 +385,10 @@ export class Maker {
384385 * read() {},
385386 * update() {},
386387 * }
387- * const routes = createRest(r => {
388- * r .resource('example', Controller)
389- * r .resource('demo', Controller, { only: ['create', 'read'] })
390- * r .resource('single', Controller, { except: ['destroy', 'create'] })
388+ * const routes = createRest(root => {
389+ * root .resource('example', Controller)
390+ * root .resource('demo', Controller, { only: ['create', 'read'] })
391+ * root .resource('single', Controller, { except: ['destroy', 'create'] })
391392 * })
392393 * printRoutes(routes, true)
393394 */
@@ -428,18 +429,146 @@ export class Maker {
428429 usedList = methodsList
429430 }
430431
431- this . scope ( name , r => {
432- r . before ( controller . beforeEach )
433- r . after ( controller . afterEach )
432+ this . scope ( name , scope => {
433+ scope . before ( controller . beforeEach )
434+ scope . after ( controller . afterEach )
434435
435436 usedList
436437 . filter ( handler => methodsList . includes ( handler ) )
437438 . map ( handler => [ handler , methods [ handler ] ] )
438439 . forEach ( ( [ handler , httpMethod ] ) => {
439- r [ httpMethod ] ( resolveMethodName ( handler , controller ) )
440+ scope [ httpMethod ] ( resolveMethodName ( handler , controller ) )
440441 } )
441442 } )
442443 }
444+
445+ /**
446+ * @desc Configure your `crud('name', controller, options)`
447+ * @typedef {object } crudOptions
448+ * @property {string[] } [only] Keep only that handlers: `[index, read, create, update, patch, destroy]`
449+ * @property {string[] } [except] Keep all except that handlers
450+ * @property {string } [memberId] Change :memberId in the URI
451+ *
452+ * @example <caption>Usage with `only`</caption>
453+ * createRest(root => {
454+ * root.crud('books', BooksController, { only: ['read', 'index] })
455+ * })
456+ * // GET /books -> index()
457+ * // GET /books/:bookId -> read()
458+ *
459+ * @example <caption>Usage with `except`</caption>
460+ * createRest(root => {
461+ * root.crud('songs', SongsController, { except: ['destroy', 'update'] })
462+ * })
463+ * // GET /songs -> index()
464+ * // POST /songs -> create()
465+ * // GET /songs/:songId -> read()
466+ * // PATCH /songs/:songId -> patch()
467+ *
468+ * @example <caption>Member ID renaming</caption>
469+ * createRest(root => {
470+ * root.crud('images', ImagesController, { memberId: 'imgid' })
471+ * })
472+ * // GET /images -> index()
473+ * // POST /images -> create()
474+ * // GET /images/:imgid -> read()
475+ * // PUT /images/:imgid -> update()
476+ * // PATCH /images/:imgid -> patch()
477+ * // DELETE /images/:imgid -> destroy()
478+ */
479+
480+ /**
481+ * Add index, create, read, update, patch, remove methods to manage resource
482+ * @param {string } name Name of the crud. Crud path created from. Example: `books`
483+ * @param {CrudController } controller Object with methods
484+ * @param {crudOptions } [options={}] Options for crud
485+ *
486+ * @example <caption>Full example</caption>
487+ * createRest(root => {
488+ * root.crud('users', UsersController)
489+ * })
490+ * // GET /users -> index()
491+ * // POST /users -> create()
492+ * // GET /users/:userId -> read()
493+ * // PUT /users/:userId -> update()
494+ * // PATCH /users/:userId -> patch()
495+ * // DELETE /users/:userId -> destroy()
496+ */
497+ crud ( name , controller , options = { } ) {
498+ /**
499+ * index : get /
500+ * create : post /
501+ * read : get /:id
502+ * update : put /:id
503+ * patch : patch /:id
504+ * remove : delete /:id
505+ */
506+ if ( ! name || name . length === 0 ) {
507+ throw new Error ( 'Crud should be named' )
508+ }
509+
510+ if ( typeof controller !== 'object' ) {
511+ return undefined
512+ }
513+
514+ if ( options . only && options . except ) {
515+ throw new Error ( `You can't use 'except' and 'only' options at the same time` )
516+ }
517+
518+ const noMethodsSlicingOption = ( ! options . only || options . only . length === 0 )
519+ && ( ! options . except || options . except . length === 0 )
520+
521+ /**
522+ * Check method existing in options `only` or `except`
523+ * @param {string } methodName
524+ * @private
525+ */
526+ const checkMethod = methodName =>
527+ noMethodsSlicingOption
528+ || ( options . only && options . only . length && options . only . includes ( methodName ) )
529+ || ( options . except && options . except . length && ! options . except . includes ( methodName ) )
530+
531+ const memberId = `:${ options . memberId } ` || `:${ pluralize . singular } Id`
532+
533+ this . scope ( name , scope => {
534+ scope . before ( controller . beforeEach )
535+ scope . after ( controller . afterEach )
536+
537+ if ( checkMethod ( 'index' ) ) {
538+ scope . get ( '/' , controller . index )
539+ }
540+
541+ if ( checkMethod ( 'create' ) ) {
542+ scope . post ( '/' , controller . create )
543+ }
544+
545+ scope . scope ( memberId , member => {
546+ if ( checkMethod ( 'read' ) ) {
547+ member . get ( '/' , controller . read )
548+ }
549+
550+ if ( checkMethod ( 'update' ) ) {
551+ member . put ( '/' , controller . update )
552+ }
553+
554+ if ( checkMethod ( 'patch' ) ) {
555+ if ( controller . patch ) {
556+ member . patch ( '/' , controller . patch )
557+ }
558+ else if ( checkMethod ( 'update' ) ) {
559+ member . patch ( '/' , controller . update )
560+ }
561+ else {
562+ // no PATCH /:id add
563+ }
564+ }
565+
566+ if ( checkMethod ( 'destroy' ) ) {
567+ member . delete ( '/' , controller . destroy )
568+ }
569+ } )
570+ } )
571+ }
443572}
444573
445574/**
0 commit comments