├── packages ├── createrest │ ├── .npmignore │ ├── .eslintignore │ ├── .coveralls.yml │ ├── examples │ │ ├── .eslintrc │ │ ├── all-in-use.js │ │ ├── resources.js │ │ └── printers.js │ ├── lib │ │ ├── symbol.js │ │ ├── printer.js │ │ ├── flatten.js │ │ └── index.js │ ├── bin │ │ └── createrest.js │ ├── esdocs │ │ ├── handlers.md │ │ ├── index.md │ │ ├── koa.md │ │ ├── installation.md │ │ ├── express.md │ │ ├── quick-guide.md │ │ └── styles.css │ ├── .esdoc.json │ ├── test │ │ ├── printer.test.js │ │ ├── flatten.test.js │ │ └── index.test.js │ ├── package.json │ └── readme.md ├── createrest-express │ ├── .npmignore │ ├── .coveralls.yml │ ├── test │ │ ├── .eslintrc │ │ ├── utils.js │ │ ├── response.test.js │ │ └── index.test.js │ ├── lib │ │ └── index.js │ ├── readme.md │ ├── package.json │ ├── example │ │ └── index.js │ └── package-lock.json └── createrest-koa │ ├── .npmignore │ ├── .coveralls.yml │ ├── test │ ├── .eslintrc │ └── index.test.js │ ├── lib │ └── index.js │ ├── readme.md │ ├── package.json │ └── package-lock.json ├── lerna.json ├── .eslintrc ├── .babelrc ├── .travis.yml ├── .vscode └── settings.json ├── readme.md ├── .github └── ISSUE_TEMPLATE.md ├── license.md ├── .cz-config.js ├── package.json ├── .gitignore ├── CODE_OF_CONDUCT.md └── changelog.md /packages/createrest/.npmignore: -------------------------------------------------------------------------------- 1 | !dist 2 | -------------------------------------------------------------------------------- /packages/createrest-express/.npmignore: -------------------------------------------------------------------------------- 1 | !dist 2 | -------------------------------------------------------------------------------- /packages/createrest-koa/.npmignore: -------------------------------------------------------------------------------- 1 | !dist 2 | -------------------------------------------------------------------------------- /packages/createrest/.eslintignore: -------------------------------------------------------------------------------- 1 | *.test.js 2 | examples 3 | dist 4 | node_modules 5 | -------------------------------------------------------------------------------- /packages/createrest-express/.coveralls.yml: -------------------------------------------------------------------------------- 1 | repo_token: VEoX861cdATd2yDSa6XTplfeAQsFsG6zf 2 | -------------------------------------------------------------------------------- /packages/createrest-koa/.coveralls.yml: -------------------------------------------------------------------------------- 1 | repo_token: d43HpOA3ORCAkpAMXJo4fUgL7z6tqhBDj 2 | 3 | -------------------------------------------------------------------------------- /packages/createrest/.coveralls.yml: -------------------------------------------------------------------------------- 1 | repo_token: j3e2KSsnGjpZnIc7vppQgCIQfFAZGkuIr 2 | 3 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "lerna": "2.0.0-rc.5", 3 | "packages": [ 4 | "packages/*" 5 | ], 6 | "version": "0.15.0" 7 | } 8 | -------------------------------------------------------------------------------- /packages/createrest/examples/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "unicorn/no-abusive-eslint-disable": "off" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/createrest/lib/symbol.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @private 3 | */ 4 | export const createRestInstanceSymbol = Symbol('createRestInstance') 5 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@atomix/eslint-config", 3 | "parser": "babel-eslint", 4 | "parserOptions": { 5 | "ecmaVersion": 2017 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/createrest-koa/test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "import/no-extraneous-dependencies": "off", 4 | "no-magic-numbers": "off" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/createrest/bin/createrest.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /* eslint-disable no-console */ 4 | console.log('CLI is not implemented yet!') 5 | /* eslint-enable no-console */ 6 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["node8"], 3 | "env": { 4 | "test": { 5 | "presets": ["@ava/stage-4"], 6 | "ignore": "lib/*.test.js", 7 | "sourceMaps": "inline" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/createrest-express/test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "import/no-extraneous-dependencies": "off", 4 | "no-magic-numbers": "off", 5 | "no-restricted-syntax": "off", 6 | "no-await-in-loop": "off" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | 2 | language: node_js 3 | 4 | node_js: 5 | - 6 6 | - 7 7 | - 8 8 | - 9 9 | 10 | sudo: false 11 | 12 | script: 13 | - npm run build 14 | - npm test 15 | 16 | after_success: 17 | - npm run coverage 18 | - npm run report 19 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "**/.git": true, 4 | "**/.svn": true, 5 | "**/.hg": true, 6 | "**/CVS": true, 7 | "**/.DS_Store": true, 8 | "**/.nyc_output": true, 9 | "**/node_modules": true, 10 | "**/dist": true, 11 | "packages/createrest/docs": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/createrest/esdocs/handlers.md: -------------------------------------------------------------------------------- 1 | # Handlers 2 | 3 | ## [get](/class/lib/index.js~Maker.html#instance-method-get) 4 | 5 | Add handler for GET route. 6 | 7 | ```js 8 | createRest(root => { 9 | root.get('/', () => console.log('Handle GET /')) 10 | 11 | root.scope('demo', demo => { 12 | demo.get('/', () => console.log('Handle GET /demo')) 13 | }) 14 | }) 15 | ``` 16 | -------------------------------------------------------------------------------- /packages/createrest-express/test/utils.js: -------------------------------------------------------------------------------- 1 | import express from 'express' 2 | import { createRest } from 'createrest' 3 | import { createExpressMiddleware } from '../lib' 4 | 5 | 6 | let port = 6000 + Math.floor(Math.random() * 1000) 7 | 8 | export function createRawServer(routesFn) { 9 | const app = express() 10 | app.use(createExpressMiddleware(createRest(routesFn))) 11 | return app.listen(port++) 12 | } 13 | -------------------------------------------------------------------------------- /packages/createrest-koa/lib/index.js: -------------------------------------------------------------------------------- 1 | import Router from 'koa-router' 2 | import { flattenRoutes, isCreateRestInstance } from 'createrest' 3 | 4 | 5 | export function createKoaRouter(routing) { 6 | if (!isCreateRestInstance(routing)) { 7 | throw new TypeError('You can create koa middleware only from createRest routes') 8 | } 9 | 10 | const router = new Router() 11 | const flat = flattenRoutes(routing) 12 | 13 | Object.keys(flat).forEach((path) => { 14 | const methods = flat[path] 15 | 16 | Object.keys(methods).forEach((method) => { 17 | router[method.toLowerCase()](path, ...methods[method]) 18 | }) 19 | }) 20 | 21 | return router 22 | } 23 | -------------------------------------------------------------------------------- /packages/createrest-express/lib/index.js: -------------------------------------------------------------------------------- 1 | import { Router } from 'express' 2 | import { flattenRoutes, isCreateRestInstance } from 'createrest' 3 | 4 | 5 | export function createExpressMiddleware(routing) { 6 | if (!isCreateRestInstance(routing)) { 7 | throw new TypeError('You can create express middleware only for createRest routes') 8 | } 9 | const router = Router() 10 | const flat = flattenRoutes(routing) 11 | 12 | Object.keys(flat).forEach((path) => { 13 | const methods = flat[path] 14 | 15 | Object.keys(methods).forEach((method) => { 16 | router[method.toLowerCase()](path, ...methods[method]) 17 | }) 18 | }) 19 | 20 | return router 21 | } 22 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # createRest monorepo 2 | 3 | [![Travis](https://img.shields.io/travis/atomixinteractions/createrest.svg)](https://travis-ci.org/atomixinteractions/createrest) 4 | [![Coverage Status](https://coveralls.io/repos/github/atomixinteractions/createrest/badge.svg?branch=master)](https://coveralls.io/github/atomixinteractions/createrest?branch=master) 5 | ![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg) 6 | [![license](https://img.shields.io/github/license/atomixinteractions/createrest.svg)](https://github.com/atomixinteractions/createrest) 7 | 8 | 9 | Declare your routes 10 | 11 | See docs at https://createrest.js.org 12 | 13 | -------------------------------------------------------------------------------- /packages/createrest-express/readme.md: -------------------------------------------------------------------------------- 1 | # createrest-express [![npm](https://img.shields.io/npm/v/createrest-express.svg)](https://npmjs.com/createrest-express) 2 | 3 | 4 | ## Readme 5 | 6 | [createRest](/packages/createrest) generator for Express 7 | 8 | ## Usage example 9 | 10 | ```js 11 | const { createRest, printRoutes } = require('createrest') 12 | const { createExpressMiddleware } = require('createrest-express') 13 | const express = require('express') 14 | 15 | const app = express() 16 | 17 | const routes = createRest(e => { 18 | // Your routes here 19 | }) 20 | 21 | app.use(createExpressMiddlware(routes)) 22 | 23 | app.listen(3000, () => { 24 | printRoutes(routes) 25 | console.log('Listening port 3000...') 26 | }) 27 | ``` 28 | -------------------------------------------------------------------------------- /packages/createrest-koa/readme.md: -------------------------------------------------------------------------------- 1 | # createrest-koa [![npm](https://img.shields.io/npm/v/createrest-koa.svg)](https://npmjs.com/createrest-koa) 2 | 3 | ## Readme 4 | 5 | [createRest](/packages/createrest) generator for Koa2 6 | 7 | ## Usage example 8 | 9 | ```js 10 | const { createRest, printRoutes } = require('createrest') 11 | const { createKoaRouter } = require('createrest-koa') 12 | const Koa = require('koa') 13 | 14 | const app = new Koa() 15 | 16 | const routes = createRest(root => { 17 | // Your routes here 18 | }) 19 | const router = createKoaRouter(routes) 20 | 21 | 22 | app.use(router.routes(), router.allowedMethods()) 23 | 24 | app.listen(3000, () => { 25 | printRoutes(routes) 26 | console.log('Listening port 3000...') 27 | }) 28 | ``` 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | - [ ] I have verified there are no duplicate active or recent bugs, questions, or requests 2 | - [ ] I have verified that I am using the latest version of createRest 3 | - [ ] I have given my issue a non-generic title. 4 | - [ ] I have read over the documentation (before asking questions on how to do something). 5 | 6 | ###### Include the following: 7 | - createRest version: `0.x.x` 8 | - Express/Koa version: `4.x` 9 | - Node version: `v7.x.x` 10 | - NPM version: `v4.x.x` 11 | - OS Name and version: `Debian 8.x` 12 | 13 | Also, please wrap JavaScript code with correct syntax highlighting. 14 | 15 | ```javascript 16 | import { createRest } from 'createrest' 17 | 18 | // code here 19 | ``` 20 | 21 | ###### Reproduction Steps 22 | 23 | 1. 24 | 2. 25 | 3. 26 | 27 | ###### Expected Result 28 | 29 | 30 | 31 | ###### Actual Result 32 | 33 | -------------------------------------------------------------------------------- /packages/createrest/esdocs/index.md: -------------------------------------------------------------------------------- 1 | # createRest 2 | 3 | `createRest` is a node.js library for [Express](https://expressjs.com) and [koa2](http://koajs.com) designed to build REST API routing scheme. 4 | 5 | 6 | ## Routing sample 7 | 8 | > Example for express 9 | 10 | ```js 11 | // routes.js 12 | const { createExpressMiddleware } = require('createrest-express') 13 | const { createRest } = require('createrest') 14 | 15 | const routes = createRest(root => { 16 | root.get('/', handleIndexRequest) 17 | }) 18 | 19 | function handleIndexRequest(req, res) { 20 | console.log('Handled GET /') 21 | res.send('Hello!').status(200) 22 | } 23 | 24 | module.exports = createExpressMiddleware(routes) 25 | ``` 26 | 27 | ```js 28 | // app.js 29 | const Express = require('express') 30 | const routes = require('./routes') 31 | 32 | const app = Express() 33 | 34 | app.use(routes) 35 | app.listen(8000) 36 | ``` 37 | -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2018 Atomix Interactions 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.cz-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | types: [ 3 | { value: 'feat', name: 'feat: A new feature' }, 4 | { value: 'fix', name: 'fix: A bug fix' }, 5 | { value: 'docs', name: 'docs: Documentation only changes' }, 6 | { value: 'style', name: 'style: Changes that do not affect the meaning of the code\n (white-space, formatting, missing semi-colons, etc)' }, 7 | { value: 'refactor', name: 'refactor: A code change that neither fixes a bug nor adds a feature' }, 8 | { value: 'perf', name: 'perf: A code change that improves performance' }, 9 | { value: 'test', name: 'test: Adding missing tests' }, 10 | { value: 'chore', name: 'chore: Changes to the build process or auxiliary tools\n and libraries such as documentation generation' }, 11 | { value: 'revert', name: 'revert: Revert to a commit' }, 12 | { value: 'WIP', name: 'WIP: Work in progress' }, 13 | ], 14 | scopes: [ 15 | { name: 'createrest' }, 16 | { name: 'createrest-express' }, 17 | { name: 'createrest-koa' }, 18 | { name: 'documentation' }, 19 | ], 20 | allowCustomScopes: true, 21 | allowBreakingChanges: ['feat', 'fix', 'revert'], 22 | } 23 | -------------------------------------------------------------------------------- /packages/createrest/lib/printer.js: -------------------------------------------------------------------------------- 1 | import { flattenRoutes } from './flatten' 2 | 3 | /** 4 | * @namespace printer 5 | */ 6 | 7 | /** 8 | * @private 9 | * @param {string} path 10 | * @param {string} method 11 | * @param {Function[]} handlers 12 | * @return {string} 13 | */ 14 | function print(path, method, handlers) { 15 | const handlersNames = handlers.map((handler) => `${handler.displayName || handler.name || ''}()`).join(', ') 16 | 17 | return `${method.toUpperCase()} ${path} -> ${handlersNames}` 18 | } 19 | 20 | /** 21 | * Print routes to console and string 22 | * @param {RestRoutes} routes 23 | * @param {boolean} realPrint 24 | * @return {string[]} Lines of the printed routes 25 | */ 26 | export function printRoutes(routes, realPrint = true) { 27 | const flat = flattenRoutes(routes) 28 | const lines = [] 29 | 30 | Object.keys(flat) 31 | .forEach((path) => { 32 | const methods = flat[path] 33 | 34 | Object.keys(methods).forEach((method) => { 35 | lines.push(print(path, method, methods[method])) 36 | }) 37 | }) 38 | 39 | if (realPrint) { 40 | // eslint-disable-next-line no-console 41 | console.log(lines.join('\n')) 42 | } 43 | 44 | return lines 45 | } 46 | -------------------------------------------------------------------------------- /packages/createrest/esdocs/koa.md: -------------------------------------------------------------------------------- 1 | # koa example 2 | 3 | ## Installation 4 | 5 | ```shell 6 | npm install koa createrest createrest-koa 7 | ``` 8 | 9 | ## Source code 10 | 11 | ```js 12 | // routes.js 13 | const { createRest } = require('createrest') 14 | 15 | 16 | module.exports.routes = createRest(root => { 17 | root.beforeEach(beforeEachRequest) 18 | 19 | root.get('/', handleIndexRequest) 20 | 21 | root.scope('scoped', scoped => { 22 | scoped.get('/example', handleScopedRequest) 23 | }) 24 | }) 25 | 26 | function beforeEachRequest(ctx, next) { 27 | console.log('Request') 28 | next() 29 | } 30 | 31 | function handleIndexRequest(ctx) { 32 | console.log('Handled GET /') 33 | ctx.body = 'Hello!' 34 | ctx.status = 200 35 | } 36 | 37 | function handleScopedRequest(ctx) { 38 | console.log('Handled GET /scoped/example') 39 | ctx.body = 'That\'s scoped example'' 40 | } 41 | ``` 42 | 43 | ```js 44 | // app.js 45 | const Express = require('express') 46 | const { printRoutes } = require('createrest') 47 | const { createKoaRouter } = require('createrest-koa') 48 | 49 | const { routes } = require('./routes') 50 | 51 | const PORT = 8000 52 | const app = Express() 53 | const router = createKoaRouter(routes) 54 | 55 | app.use(router.routes(), router.allowedMethods()) 56 | 57 | app.listen(PORT, () => { 58 | printRoutes(routes) 59 | console.log(`Listening port ${PORT}...`) 60 | }) 61 | ``` 62 | -------------------------------------------------------------------------------- /packages/createrest/esdocs/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | ## NPM packages 4 | 5 | [createrest](https://npmjs.com/createrest) 6 | 7 | ```shell 8 | npm install --save createrest 9 | ``` 10 | 11 | ## Import functions 12 | 13 | If you use babel or latest build of node.js: 14 | 15 | ```js 16 | import { createRest, flattenRoutes, printRoutes } from 'createrest' 17 | ``` 18 | 19 | For commonjs based modules: 20 | 21 | ```js 22 | const { createRest, flattenRoutes, printRoutes } = require('createrest') 23 | ``` 24 | 25 | ## Express 26 | 27 | [createrest-express](https://npmjs.com/createrest-express) 28 | 29 | ```shell 30 | npm install --save createrest createrest-express express 31 | ``` 32 | 33 | ```js 34 | const Express = require('express') 35 | const { createExpressMiddleware } = require('createrest-express') 36 | const routes = require('./routes') 37 | 38 | const app = Express() 39 | 40 | app.use(createExpressMiddleware(routes)) 41 | 42 | app.listen(8000) 43 | ``` 44 | 45 | ## Koa2 46 | 47 | [createrest-koa](https://npmjs.com/createrest-koa) 48 | 49 | ```shell 50 | npm install --save createrest createrest-koa koa@2 51 | ``` 52 | ```js 53 | const Express = require('koa') 54 | const { createKoaRouter } = require('createrest-express') 55 | const routes = require('./routes') 56 | 57 | const app = new Koa() 58 | const router = createKoaRouter(routes) 59 | 60 | app.use(router.routes(), router.allowedMethods()) 61 | 62 | app.listen(8000) 63 | ``` 64 | 65 | -------------------------------------------------------------------------------- /packages/createrest/esdocs/express.md: -------------------------------------------------------------------------------- 1 | # Express example 2 | 3 | ## Installation 4 | 5 | ```shell 6 | npm install express createrest createrest-express 7 | ``` 8 | 9 | Installation manual for Express [here](http://expressjs.com/starter/installing.html) 10 | 11 | 12 | ## Source code 13 | 14 | ```js 15 | // routes.js 16 | const { createRest } = require('createrest') 17 | 18 | 19 | module.exports.routes = createRest(root => { 20 | root.beforeEach(beforeEachRequest) 21 | 22 | root.get('/', handleIndexRequest) 23 | 24 | root.scope('scoped', scoped => { 25 | scoped.get('/example', handleScopedRequest) 26 | }) 27 | }) 28 | 29 | function beforeEachRequest(req, res, next) { 30 | console.log('Request') 31 | next() 32 | } 33 | 34 | function handleIndexRequest(req, res) { 35 | console.log('Handled GET /') 36 | res.send('Hello!').status(200) 37 | } 38 | 39 | function handleScopedRequest(req, res) { 40 | console.log('Handled GET /scoped/example') 41 | res.send('That\'s scoped example') 42 | } 43 | ``` 44 | 45 | ```js 46 | // app.js 47 | const Express = require('express') 48 | const { printRoutes } = require('createrest') 49 | const { createExpressMiddleware } = require('createrest-express') 50 | 51 | const { routes } = require('./routes') 52 | 53 | const PORT = 8000 54 | const app = Express() 55 | 56 | app.use(createExpressMiddleware(routes)) 57 | 58 | app.listen(PORT, () => { 59 | printRoutes(routes) 60 | console.log(`Listening port ${PORT}...`) 61 | }) 62 | ``` 63 | -------------------------------------------------------------------------------- /packages/createrest-express/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "createrest-express", 3 | "version": "0.15.0", 4 | "description": "Express middleware for generate routes from createrest", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "build": "babel -d ./dist ./lib", 8 | "clean": "rimraf ./dist ./.nyc_output ./coverage", 9 | "coverage": "NODE_ENV=test nyc report --reporter=text-lcov", 10 | "dev": "nodemon -w lib -w examples -x \"npm run build && node examples/test.js\"", 11 | "report": "nyc report --reporter=text-lcov | coveralls", 12 | "report:user": "nyc report --reporter=html", 13 | "test": "npm run test:lint && npm run test:code", 14 | "test:code": "NODE_ENV=test nyc ava", 15 | "test:lint": "eslint ./lib" 16 | }, 17 | "bugs": { 18 | "url": "https://github.com/atomixinteractions/createrest/issues" 19 | }, 20 | "homepage": "https://github.com/atomixinteractions/createrest/tree/master/packages/createrest", 21 | "repository": "https://github.com/atomixinteractions/createrest/tree/master/packages/createrest-koa", 22 | "author": "Sergey Sova (https://sergeysova.com)", 23 | "license": "MIT", 24 | "files": [ 25 | "dist" 26 | ], 27 | "peerDependencies": { 28 | "createrest": "^0.14.2", 29 | "express": "4.*" 30 | }, 31 | "devDependencies": { 32 | "createrest": "^0.15.0", 33 | "express": "^4.16.2" 34 | }, 35 | "ava": { 36 | "require": "babel-register", 37 | "concurrency": 4, 38 | "files": [ 39 | "test/*.test.js" 40 | ] 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/createrest-koa/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "createrest-koa", 3 | "version": "0.15.0", 4 | "description": "Koa2 middleware to generate routes by createRest", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "build": "babel -d ./dist ./lib", 8 | "clean": "rimraf ./dist ./docs ./.nyc_output ./coverage", 9 | "coverage": "NODE_ENV=test nyc report --reporter=text-lcov", 10 | "dev": "nodemon -w lib -w examples -x \"npm run build && node examples/test.js\"", 11 | "report": "nyc report --reporter=text-lcov | coveralls", 12 | "report:user": "nyc report --reporter=html", 13 | "test": "npm run test:lint && npm run test:code", 14 | "test:code": "NODE_ENV=test nyc ava", 15 | "test:lint": "eslint ./lib" 16 | }, 17 | "keywords": [], 18 | "author": "Sergey Sova (https://sergeysova.com)", 19 | "license": "MIT", 20 | "files": [ 21 | "dist" 22 | ], 23 | "bugs": { 24 | "url": "https://github.com/atomixinteractions/createrest/issues" 25 | }, 26 | "homepage": "https://github.com/atomixinteractions/createrest/tree/master/packages/createrest", 27 | "repository": "https://github.com/atomixinteractions/createrest/tree/master/packages/createrest-koa", 28 | "dependencies": { 29 | "koa-router": "^7.4.0" 30 | }, 31 | "peerDependencies": { 32 | "createrest": "^0.14.2", 33 | "koa": "2.*" 34 | }, 35 | "devDependencies": { 36 | "createrest": "^0.15.0", 37 | "koa": "^2.4.1" 38 | }, 39 | "ava": { 40 | "require": "babel-register", 41 | "concurrency": 4, 42 | "files": [ 43 | "test/*.test.js" 44 | ] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/createrest/.esdoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "source": "./lib", 3 | "destination": "./docs", 4 | "plugins": [ 5 | { 6 | "name": "esdoc-standard-plugin", 7 | "option": { 8 | "undocumentIdentifier": { "enable": true }, 9 | "typeInference": { "enable": true }, 10 | "brand": { 11 | "title": "createRest documentation", 12 | "description": "REST routes constructor for express and koa", 13 | "site": "https://createrest.js.org", 14 | "author": "https://lestad.top" 15 | }, 16 | "manual": { 17 | "index": "./esdocs/index.md", 18 | "globalIndex": true, 19 | "files": [ 20 | "./esdocs/quick-guide.md", 21 | "./esdocs/installation.md", 22 | "./esdocs/express.md", 23 | "./esdocs/koa.md", 24 | "./esdocs/handlers.md" 25 | ] 26 | } 27 | } 28 | }, 29 | { 30 | "name": "esdoc-inject-style-plugin", 31 | "option": { 32 | "enable": true, 33 | "styles": [ 34 | "./esdocs/styles.css" 35 | ] 36 | } 37 | }, 38 | { 39 | "name": "esdoc-importpath-plugin", 40 | "option": { 41 | "stripPackageName": false, 42 | "replaces": [ 43 | { "from": ".js", "to": "" }, 44 | { "from": "/index", "to": "" } 45 | ] 46 | } 47 | }, 48 | { "name": "esdoc-ecmascript-proposal-plugin", "option": { "all": true } }, 49 | { "name": "esdoc-external-ecmascript-plugin", "option": { "enable": true } }, 50 | { "name": "esdoc-external-nodejs-plugin", "option": { "enable": true } } 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /packages/createrest/lib/flatten.js: -------------------------------------------------------------------------------- 1 | import { isCreateRestInstance } from './index' 2 | 3 | /** 4 | * Recursive flatten 5 | * @private 6 | * @param {RestRoutes} routes Routes object from `createRest()` 7 | * @param {string} prefix Add prefix to each route path 8 | * @param {RestRoutes} parent Parent routes 9 | */ 10 | function flattenize(routes, prefix, parent) { 11 | const list = {} 12 | 13 | Object.keys(routes.local).forEach((method) => { 14 | const localName = prefix === '' ? '/' : `${prefix}/` 15 | 16 | if (!list[localName]) { 17 | list[localName] = {} 18 | } 19 | list[localName][method] = [].concat( 20 | parent.before, 21 | routes.before, 22 | routes.local[method], 23 | routes.after, 24 | parent.after 25 | ) 26 | }) 27 | 28 | Object.keys(routes.scoped).forEach((scope) => { 29 | const scoped = routes.scoped[scope] 30 | const listeners = flattenize(scoped, `${prefix}/${scope}`, { 31 | before: parent.before.concat(routes.before), 32 | after: routes.after.concat(parent.after), 33 | }) 34 | 35 | Object.assign(list, listeners) 36 | }) 37 | 38 | return list 39 | } 40 | 41 | /** 42 | * Convert original deep routes to flat object 43 | * @param {RestRoutes} routes Original routes from `createRest()` 44 | * @return {object} Flattened routes object 45 | * @example 46 | * const handler = () => {} 47 | * const routes = createRest(r => { r.get('foo', handler) }) 48 | * const flatRoutes = flattenRoutes(routes) 49 | * 50 | * test.deepEqual( 51 | * flatRoutes, 52 | * { 53 | * '/foo/': { 54 | * GET: [handler], 55 | * }, 56 | * }, 57 | * ) 58 | */ 59 | export function flattenRoutes(routes) { 60 | if (!isCreateRestInstance(routes)) { 61 | throw new Error('You can flatten only createRest routes') 62 | } 63 | return flattenize(routes, '', { before: [], after: [] }) 64 | } 65 | -------------------------------------------------------------------------------- /packages/createrest/examples/all-in-use.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console, no-magic-numbers */ 2 | const { createRest, printRoutes } = require('../dist') 3 | 4 | 5 | const before1 = () => { 6 | console.log('before1()') 7 | } 8 | const before2 = () => { 9 | console.log('before2()') 10 | } 11 | const before3 = () => { 12 | console.log('before3()') 13 | } 14 | const after1 = () => { 15 | console.log('after1()') 16 | } 17 | const after2 = () => { 18 | console.log('after2()') 19 | } 20 | const after3 = () => { 21 | console.log('after3()') 22 | } 23 | const post1 = () => { 24 | console.log('post1()') 25 | } 26 | const get1 = () => { 27 | console.log('get1()') 28 | } 29 | const get2 = () => { 30 | console.log('get2()') 31 | } 32 | const put3 = () => { 33 | console.log('put3()') 34 | } 35 | 36 | const ExampleController = { 37 | beforeEach() { 38 | console.log('Call before each handler') 39 | }, 40 | afterEach() {}, 41 | read() {}, 42 | create() {}, 43 | update() {}, 44 | destroy() {}, 45 | } 46 | 47 | const BooksController = { 48 | beforeEach() { 49 | console.log('Call before each handler') 50 | }, 51 | afterEach() {}, 52 | index() {}, 53 | create() {}, 54 | read() {}, 55 | update() {}, 56 | patch() {}, 57 | destroy() {}, 58 | } 59 | 60 | const routes = createRest((root) => { 61 | root.beforeEach(before1) 62 | root.afterEach(after1) 63 | 64 | root.post('/', post1) 65 | 66 | root.scope('demo', (demoRoute) => { 67 | demoRoute.beforeEach(before2) 68 | demoRoute.afterEach(after2) 69 | 70 | demoRoute.get('/', get1) 71 | demoRoute.get('/foo', get2) 72 | 73 | demoRoute.scope('bar', (barRoute) => { 74 | barRoute.beforeEach(before3) 75 | barRoute.afterEach(after3) 76 | 77 | barRoute.put('/', put3) 78 | 79 | barRoute.crud('example', ExampleController) 80 | }) 81 | }) 82 | 83 | root.resources('books', BooksController) 84 | }) 85 | 86 | printRoutes(routes) 87 | -------------------------------------------------------------------------------- /packages/createrest-express/test/response.test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava' 2 | import supertest from 'supertest' 3 | import { createRawServer } from './utils' 4 | 5 | 6 | const newAnswer = () => ({ 7 | sampleJSON: data => (req, res) => { 8 | res.send({ data }) 9 | }, 10 | }) 11 | 12 | test('response from base methods', async (t) => { 13 | t.plan(5 * 2) 14 | const answer = newAnswer() 15 | const server = createRawServer((root) => { 16 | root.get('/', answer.sampleJSON('get')) 17 | root.post('/', answer.sampleJSON('post')) 18 | root.put('/', answer.sampleJSON('put')) 19 | root.patch('/', answer.sampleJSON('patch')) 20 | root.delete('/', answer.sampleJSON('delete')) 21 | }) 22 | 23 | for (const method of ['get', 'post', 'put', 'patch', 'delete']) { 24 | const res = await supertest(server)[method]('/') 25 | .expect('Content-Type', /json/) 26 | 27 | t.is(res.status, 200) 28 | t.is(res.body.data, method) 29 | } 30 | }) 31 | 32 | test('crud', async (t) => { 33 | const CrudCtrl = { 34 | beforeEach(req, res, next) { 35 | res.data = { mdw: 1 }; next() 36 | }, 37 | afterEach(req, res) { 38 | res.data.mdw++ 39 | res.send(res.data) 40 | }, 41 | read(req, res, next) { 42 | res.data.type = 'get' 43 | next() 44 | }, 45 | create(req, res, next) { 46 | res.data.type = 'post' 47 | next() 48 | }, 49 | update(req, res, next) { 50 | res.data.type = 'put' 51 | next() 52 | }, 53 | destroy(req, res, next) { 54 | res.data.type = 'delete' 55 | next() 56 | }, 57 | } 58 | const server = createRawServer((root) => { 59 | root.crud('demo', CrudCtrl) 60 | }) 61 | 62 | for (const method of ['get', 'post', 'put', 'delete']) { 63 | const res = await supertest(server)[method]('/demo') 64 | .expect('Content-Type', /json/) 65 | 66 | t.is(res.status, 200) 67 | t.is(res.body.mdw, 2) 68 | t.is(res.body.type, method) 69 | } 70 | }) 71 | -------------------------------------------------------------------------------- /packages/createrest-express/example/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console, no-magic-numbers */ 2 | const { 3 | createRest, 4 | printRoutes, 5 | } = require('createrest') 6 | const express = require('express') 7 | const { createExressMiddleware } = require('../dist') 8 | 9 | 10 | const app = express() 11 | 12 | function before1(req, res, next) { 13 | console.log('- before1()') 14 | next() 15 | } 16 | function before2(req, res, next) { 17 | console.log('-- before2()') 18 | next() 19 | } 20 | function before3(req, res, next) { 21 | console.log('--- before3()') 22 | next() 23 | } 24 | function after1(req, res, next) { 25 | console.log('- after1()') 26 | next() 27 | } 28 | function after2(req, res, next) { 29 | console.log('-- after2()') 30 | next() 31 | } 32 | function after3(req, res, next) { 33 | console.log('--- after3()') 34 | next() 35 | } 36 | function get1(req, res, next) { 37 | res.json({ content: 'get1()' }) 38 | console.log('- get1()') 39 | next() 40 | } 41 | function get2(req, res, next) { 42 | res.json({ content: 'get2()' }) 43 | console.log('-- get2()') 44 | next() 45 | } 46 | function get3(req, res, next) { 47 | res.json({ content: 'get3()' }) 48 | console.log('--- get3()') 49 | next() 50 | } 51 | 52 | function get4(req, res, next) { 53 | res.json({ content: 'get4()' }) 54 | console.log('---- get4()') 55 | next() 56 | } 57 | 58 | const routes = createRest((root) => { 59 | root.before(before1) 60 | root.after(after1) 61 | 62 | root.get('/', get1) 63 | 64 | root.scope('demo', (demo) => { 65 | demo.before(before2) 66 | demo.after(after2) 67 | 68 | demo.get('/', get2) 69 | demo.get('/foo', get3) 70 | 71 | demo.scope('bar', (bar) => { 72 | bar.before(before3) 73 | bar.after(after3) 74 | 75 | bar.get('/baz', get4) 76 | }) 77 | }) 78 | }) 79 | 80 | app.use(createExressMiddleware(routes)) 81 | 82 | app.listen(4001, () => { 83 | printRoutes(routes) 84 | console.log('Listening port 4001...') 85 | }) 86 | -------------------------------------------------------------------------------- /packages/createrest/test/printer.test.js: -------------------------------------------------------------------------------- 1 | import avaTest from 'ava' 2 | import { createRest } from '../lib' 3 | import { printRoutes } from '../lib/printer' 4 | 5 | 6 | const get = () => {} 7 | const post = () => {} 8 | const put = () => {} 9 | const patch = () => {} 10 | const destroy = () => {} 11 | const beforeEach = () => {} 12 | const afterEach = () => {} 13 | 14 | const make = (method, listeners = []) => ({ 15 | method, listeners, 16 | }) 17 | 18 | avaTest('Outputs beforeEach/afterEach', test => { 19 | test.deepEqual( 20 | printRoutes(createRest(root => { 21 | root.beforeEach(beforeEach) 22 | root.afterEach(afterEach) 23 | root.get(get) 24 | root.post('foo', post) 25 | }), false), 26 | [ 27 | 'GET / -> beforeEach(), get(), afterEach()', 28 | 'POST /foo/ -> beforeEach(), post(), afterEach()', 29 | ] 30 | ) 31 | }) 32 | 33 | avaTest('Outputs scoped routes with beforeEach/afterEach', test => { 34 | test.deepEqual( 35 | printRoutes(createRest(root => { 36 | root.beforeEach(beforeEach) 37 | root.afterEach(afterEach) 38 | root.get(get) 39 | root.post('foo', post) 40 | root.scope('bar', bar => { 41 | bar.beforeEach(beforeEach) 42 | bar.afterEach(afterEach) 43 | bar.put(() => {}) 44 | bar.delete('baz', destroy) 45 | }) 46 | }), false), 47 | [ 48 | 'GET / -> beforeEach(), get(), afterEach()', 49 | 'POST /foo/ -> beforeEach(), post(), afterEach()', 50 | 'PUT /bar/ -> beforeEach(), beforeEach(), (), afterEach(), afterEach()', 51 | 'DELETE /bar/baz/ -> beforeEach(), beforeEach(), destroy(), afterEach(), afterEach()' 52 | ] 53 | ) 54 | }) 55 | 56 | avaTest.todo('Real print to stdout') 57 | 58 | avaTest('Real print to output', test => { 59 | printRoutes(createRest(root => { 60 | root.beforeEach(beforeEach) 61 | root.afterEach(afterEach) 62 | root.get(get) 63 | root.post('foo', post) 64 | })) 65 | // TODO: check real print 66 | test.pass() 67 | }) 68 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "createrest-lerna", 3 | "private": true, 4 | "scripts": { 5 | "build": "lerna run build --stream", 6 | "changelog": "conventional-changelog -p atomix -i changelog.md -s -r 0 && git add changelog.md && git commit -m \"$(git describe --abbrev=0 --tags) changelog\"", 7 | "clean": "lerna run clean --stream", 8 | "coverage": "lerna run coverage --stream", 9 | "docs": "lerna run docs --scope createrest", 10 | "metapak": "metapak || exit 0", 11 | "postinstall": "lerna bootstrap; npm run metapak --silent", 12 | "postpublish": "npm run changelog && git push --all origin && git push --tags origin && lerna run docs:publish", 13 | "prepublish": "lerna run build --stream && lerna run test --stream", 14 | "publish": "lerna publish", 15 | "report": "lerna run report --stream", 16 | "test": "lerna run build && lerna run test" 17 | }, 18 | "devDependencies": { 19 | "@atomix/eslint-config": "^6.1.1", 20 | "@ava/babel-preset-stage-4": "^1.1.0", 21 | "ava": "^0.25.0", 22 | "babel-cli": "^6.26.0", 23 | "babel-core": "^6.26.0", 24 | "babel-eslint": "^8.2.1", 25 | "babel-plugin-syntax-trailing-function-commas": "^6.22.0", 26 | "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0", 27 | "babel-plugin-transform-export-extensions": "^6.22.0", 28 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 29 | "babel-preset-node8": "^1.2.0", 30 | "babel-register": "^6.26.0", 31 | "buildbranch": "^2.0.0", 32 | "conventional-changelog-atomix": "^0.3.2", 33 | "conventional-changelog-cli": "^1.3.8", 34 | "coveralls": "^3.0.0", 35 | "cz-customizable": "^5.2.0", 36 | "eslint": "^4.16.0", 37 | "lerna": "^2.8.0", 38 | "metapak": "0.0.21", 39 | "nodemon": "^1.14.11", 40 | "nyc": "^11.4.1", 41 | "rimraf": "^2.6.2", 42 | "sinon": "^4.2.2", 43 | "supertest": "^3.0.0" 44 | }, 45 | "dependencies": {}, 46 | "config": { 47 | "commitizen": { 48 | "path": "node_modules/cz-customizable" 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /packages/createrest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "createrest", 3 | "version": "0.15.0", 4 | "description": "REST routes constructor for express and koa", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "build": "babel -d ./dist ./lib", 8 | "clean": "rimraf ./dist ./docs ./.nyc_output ./coverage", 9 | "coverage": "NODE_ENV=test nyc report --reporter=text-lcov", 10 | "dev": "nodemon -w lib -w examples -x \"npm run build && node examples/resources.js\"", 11 | "docs": "esdoc", 12 | "docs:cname": "echo 'createrest.js.org' > docs/CNAME", 13 | "docs:deploy": "gh-pages -d ./docs", 14 | "docs:dev": "nodemon -w lib -w esdocs -e js,css -x 'npm run docs'", 15 | "docs:publish": "npm run docs && npm run docs:cname && npm run docs:deploy", 16 | "report": "nyc report --reporter=text-lcov | coveralls", 17 | "report:user": "nyc report --reporter=html", 18 | "test": "npm run test:lint && npm run test:code", 19 | "test:code": "NODE_ENV=test nyc ava", 20 | "test:lint": "eslint ./lib" 21 | }, 22 | "bin": { 23 | "createrest": "./bin/createrest.js", 24 | "rest": "./bin/createrest.js" 25 | }, 26 | "files": [ 27 | "dist", 28 | "bin" 29 | ], 30 | "bugs": { 31 | "url": "https://github.com/atomixinteractions/createrest/issues" 32 | }, 33 | "homepage": "https://github.com/atomixinteractions/createrest/tree/master/packages/createrest", 34 | "repository": "https://github.com/atomixinteractions/createrest/tree/master/packages/createrest-koa", 35 | "author": "Sergey Sova (https://sergeysova.com)", 36 | "license": "MIT", 37 | "dependencies": { 38 | "chalk": "^2.3.0", 39 | "pluralize": "^7.0.0" 40 | }, 41 | "devDependencies": { 42 | "esdoc": "^1.0.4", 43 | "esdoc-ecmascript-proposal-plugin": "^1.0.0", 44 | "esdoc-external-ecmascript-plugin": "^1.0.0", 45 | "esdoc-external-nodejs-plugin": "^1.0.0", 46 | "esdoc-importpath-plugin": "^1.0.1", 47 | "esdoc-inject-style-plugin": "^1.0.0", 48 | "esdoc-standard-plugin": "^1.0.0", 49 | "gh-pages": "^1.1.0", 50 | "stringify-object": "^3.2.1" 51 | }, 52 | "ava": { 53 | "require": "babel-register", 54 | "concurrency": 4, 55 | "files": [ 56 | "test/*.test.js" 57 | ] 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /packages/createrest/test/flatten.test.js: -------------------------------------------------------------------------------- 1 | import avaTest from 'ava' 2 | import { createRest, flattenRoutes } from '../lib' 3 | 4 | 5 | const get = () => {} 6 | const post = () => {} 7 | const put = () => {} 8 | const patch = () => {} 9 | const destroy = () => {} 10 | const before = () => {} 11 | const after = () => {} 12 | 13 | const make = (method, listeners = []) => ({ 14 | method, listeners, 15 | }) 16 | 17 | avaTest('Creates empty routes', test => { 18 | test.deepEqual( 19 | flattenRoutes(createRest(root => { 20 | })), 21 | {} 22 | ) 23 | }) 24 | 25 | avaTest('Creates local methods', test => { 26 | test.deepEqual( 27 | flattenRoutes(createRest(root => { 28 | root.get(get) 29 | root.post(post) 30 | root.put(put) 31 | root.patch(patch) 32 | root.delete(destroy) 33 | })), 34 | { 35 | '/': { 36 | GET: [get], 37 | POST: [post], 38 | PUT: [put], 39 | PATCH: [patch], 40 | DELETE: [destroy], 41 | } 42 | } 43 | ) 44 | }) 45 | 46 | avaTest('Creates local and scoped methods', test => { 47 | test.deepEqual( 48 | flattenRoutes(createRest(root => { 49 | root.get(get) 50 | root.post(post) 51 | root.get('/name', get) 52 | root.post('/name', post) 53 | })), 54 | { 55 | '/': { 56 | GET: [get], 57 | POST: [post], 58 | }, 59 | '/name/': { 60 | GET: [get], 61 | POST: [post], 62 | }, 63 | } 64 | ) 65 | }) 66 | 67 | avaTest('Creates local, scoped methods and methods in scope', test => { 68 | test.deepEqual( 69 | flattenRoutes(createRest(root => { 70 | root.get(get) 71 | root.post(post) 72 | root.get('/name', get) 73 | root.post('name', post) 74 | root.scope('foo', foo => { 75 | foo.get(get) 76 | foo.post('bar', post) 77 | }) 78 | root.get(get) 79 | root.post('name', post) 80 | })), 81 | { 82 | '/': { 83 | GET: [get, get], 84 | POST: [post], 85 | }, 86 | '/name/': { 87 | GET: [get], 88 | POST: [post, post], 89 | }, 90 | '/foo/': { 91 | GET: [get], 92 | }, 93 | '/foo/bar/': { 94 | POST: [post], 95 | }, 96 | } 97 | ) 98 | }) 99 | 100 | avaTest('Fail if passed not routes', test => { 101 | test.throws(() => { 102 | flattenRoutes({}) 103 | }) 104 | }) 105 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/node,windows,osx,linux 3 | 4 | ### Node ### 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # node-waf configuration 29 | .lock-wscript 30 | 31 | # Compiled binary addons (http://nodejs.org/api/addons.html) 32 | build/Release 33 | 34 | # Dependency directories 35 | node_modules 36 | jspm_packages 37 | 38 | # Optional npm cache directory 39 | .npm 40 | 41 | # Optional eslint cache 42 | .eslintcache 43 | 44 | # Optional REPL history 45 | .node_repl_history 46 | 47 | # Output of 'npm pack' 48 | *.tgz 49 | 50 | # Yarn Integrity file 51 | .yarn-integrity 52 | 53 | 54 | 55 | ### Windows ### 56 | # Windows thumbnail cache files 57 | Thumbs.db 58 | ehthumbs.db 59 | ehthumbs_vista.db 60 | 61 | # Folder config file 62 | Desktop.ini 63 | 64 | # Recycle Bin used on file shares 65 | $RECYCLE.BIN/ 66 | 67 | # Windows Installer files 68 | *.cab 69 | *.msi 70 | *.msm 71 | *.msp 72 | 73 | # Windows shortcuts 74 | *.lnk 75 | 76 | 77 | ### OSX ### 78 | *.DS_Store 79 | .AppleDouble 80 | .LSOverride 81 | 82 | # Icon must end with two \r 83 | Icon 84 | # Thumbnails 85 | ._* 86 | # Files that might appear in the root of a volume 87 | .DocumentRevisions-V100 88 | .fseventsd 89 | .Spotlight-V100 90 | .TemporaryItems 91 | .Trashes 92 | .VolumeIcon.icns 93 | .com.apple.timemachine.donotpresent 94 | # Directories potentially created on remote AFP share 95 | .AppleDB 96 | .AppleDesktop 97 | Network Trash Folder 98 | Temporary Items 99 | .apdisk 100 | 101 | 102 | ### Linux ### 103 | *~ 104 | 105 | # temporary files which can be created if a process still has a handle open of a deleted file 106 | .fuse_hidden* 107 | 108 | # KDE directory preferences 109 | .directory 110 | 111 | # Linux trash folder which might appear on any partition or disk 112 | .Trash-* 113 | 114 | # .nfs files are created when an open file is removed but is still being accessed 115 | .nfs* 116 | 117 | # End of https://www.gitignore.io/api/node,windows,osx,linux 118 | dist 119 | docs 120 | 121 | .nyc_output 122 | coverage 123 | -------------------------------------------------------------------------------- /packages/createrest/esdocs/quick-guide.md: -------------------------------------------------------------------------------- 1 | # Quick guide 2 | 3 | Let's create REST API on createRest and koa2. 4 | 5 | ### Create app package 6 | 7 | ```bash 8 | mkdir restapi 9 | cd restapi 10 | npm init --force 11 | ``` 12 | 13 | ### Install koa2, createrest and createrest-koa 14 | 15 | ```bash 16 | npm install --save koa@2 createrest createrest-koa 17 | ``` 18 | 19 | ### Create common files 20 | 21 | ```bash 22 | mkdir src 23 | 24 | touch src/app.js 25 | touch src/routes.js 26 | ``` 27 | 28 | Open `app.js` and `routes.js` in IDE/editor. 29 | 30 | #### `src/routes.js` 31 | 32 | ```js 33 | // Import createRest function 34 | const { createRest } = require('createrest') 35 | // Here you can import all of your route handlers 36 | 37 | // Let's create index and ping-pong handlers 38 | const ping = (ctx) => { 39 | ctx.body = 'pong' 40 | } 41 | 42 | const index = (ctx) => { 43 | ctx.body = 'Hello world' 44 | } 45 | 46 | // Now create routes for your handlers with createRest function 47 | const routes = createRest((root) => { 48 | // root is a instance of Maker class 49 | // with root you can define your routes, scopes, hooks 50 | 51 | // Let's create hanler for `GET /` http request 52 | root.get('/', index) // Complete! .get creates handler 53 | 54 | // Now create handler for `GET /ping` 55 | root.get('/ping', ping) 56 | }) 57 | 58 | // Okay, export routes to use in app.js 59 | module.exports = routes 60 | ``` 61 | 62 | 63 | #### `src/app.js` 64 | 65 | ```js 66 | // Import only most necessary dependencies 67 | const Koa = require('koa') 68 | const { createRest, printRoutes } = require('createrest') 69 | const { createKoaRouter } = require('createrest-koa') 70 | 71 | // Import our routes 72 | const routes = require('./routes') 73 | 74 | 75 | // Create simple Koa2 application instance 76 | const app = new Koa() 77 | 78 | // Now create router special for koa2 79 | const router = createKoaRouter(routes) 80 | 81 | // Here just pass routes to application instance 82 | app.use(router.routes()) 83 | 84 | // You can change port to listen 85 | app.listen(3000, () => { 86 | // after app created print available routes to console 87 | printRoutes(routes) 88 | console.log('Listening port 3000...') 89 | }) 90 | ``` 91 | 92 | ### Run your application 93 | 94 | ```bash 95 | node ./src/app.js 96 | ``` 97 | 98 | > You can add npm-script `start` with `node src/app` or use [nodemon](https://npmjs.com/nodemon) in `dev` task. 99 | 100 | You should see in your console: 101 | 102 | ```text 103 | GET / -> index() 104 | GET /ping/ -> ping() 105 | Listening port 3000... 106 | ``` 107 | 108 | And if you open [http://localhost:3000/](http://localhost:3000/) and [http://localhost:3000/ping](http://localhost:3000/ping), you see answers from your `index` and `ping` handlers. 109 | 110 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at i.am@lestad.net. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /packages/createrest/examples/resources.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies, no-unused-vars, no-console */ 2 | /* eslint-disable unicorn/prefer-starts-ends-with */ 3 | const stringify = require('stringify-object') 4 | const chalk = require('chalk') 5 | 6 | const { createRest, flattenRoutes, printRoutes } = require('../dist') 7 | 8 | /** 9 | * '' 10 | * '/foo' 11 | * 12 | * 'some' 13 | * '/foo/some 14 | */ 15 | 16 | const exampleAT = { 17 | demo: { 18 | before: [], 19 | after: [], 20 | methods: { 21 | POST: [() => {}], 22 | PUT: [], 23 | }, 24 | scoped: { 25 | foo: { 26 | before: [() => {}], 27 | after: [], 28 | methods: { 29 | POST: [() => {}], 30 | PUT: [], 31 | }, 32 | }, 33 | }, 34 | }, 35 | } 36 | 37 | // ========================================================================= // 38 | // ========================================================================= // 39 | 40 | const TestsController = { 41 | beforeEach() {}, 42 | afterEach() {}, 43 | index() {}, 44 | read() {}, 45 | create() {}, 46 | update() {}, 47 | patch() {}, 48 | destroy() {}, 49 | } 50 | 51 | const before1 = function before1() { 52 | console.log('before1()') 53 | } 54 | const before2 = function before2() { 55 | console.log('before2()') 56 | } 57 | const before3 = function before3() { 58 | console.log('before3()') 59 | } 60 | const after1 = function after1() { 61 | console.log('after1()') 62 | } 63 | const after2 = function after2() { 64 | console.log('after2()') 65 | } 66 | const after3 = function after3() { 67 | console.log('after3()') 68 | } 69 | const post1 = function post1() { 70 | console.log('post1()') 71 | } 72 | const get1 = function get1() { 73 | console.log('get1()') 74 | } 75 | const get2 = function get2() { 76 | console.log('get2()') 77 | } 78 | const get3 = function get3() { 79 | console.log('get3()') 80 | } 81 | const put3 = function put3() { 82 | console.log('put3()') 83 | } 84 | 85 | const routes = createRest((root) => { 86 | // root.beforeEach(before1) 87 | // root.afterEach(after1) 88 | 89 | // root.post('/', post1) 90 | 91 | // root.scope('demo', (demo) => { 92 | // demo.crud('bar', TestsController, {}, bar => { 93 | // bar.get('baz', get3) 94 | // }) 95 | // demo.get('bar', get3) 96 | // }) 97 | // root.scope('demo', (demo) => { 98 | // demo.get('baz', get2) 99 | // }) 100 | root.resources('tests', TestsController, (tests) => { 101 | tests.get('/status', get1) 102 | 103 | tests.scope(':testId', (testId) => { 104 | testId.get('description', get2) 105 | }) 106 | }) 107 | }) 108 | 109 | const strf = (data, indent = ' ') => stringify(data, { 110 | indent, 111 | transform(obj, prop, original) { 112 | if (/^function/.test(original)) { 113 | return chalk.blue(original 114 | .replace(/\n+/mg, '') 115 | .replace(/\s+/mg, ' ') 116 | .replace(/^\w+\s+(\w+)\(\).*/mg, '$1()')) 117 | } 118 | 119 | return original 120 | }, 121 | }) 122 | 123 | console.log(strf(routes)) 124 | 125 | const flat = flattenRoutes(routes) 126 | 127 | Object.keys(flat).forEach((path) => { 128 | const mt = flat[path] 129 | 130 | Object.keys(mt).forEach((method) => { 131 | console.log( 132 | chalk.green(`${method} ${path}`), 133 | ' >> ', 134 | mt[method].map((fn) => `${chalk.yellow(fn.name)}()`).join(', ') 135 | ) 136 | }) 137 | }) 138 | 139 | console.log('\n---\n') 140 | 141 | printRoutes(routes) 142 | -------------------------------------------------------------------------------- /packages/createrest/examples/printers.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console, no-magic-numbers, import/no-extraneous-dependencies */ 2 | /* eslint-disable unicorn/prefer-starts-ends-with, no-unused-vars */ 3 | const stringify = require('stringify-object') 4 | const chalk = require('chalk') 5 | 6 | const { createRest, flattenRoutes, printRoutes } = require('../dist') 7 | 8 | /** 9 | * '' 10 | * '/foo' 11 | * 12 | * 'some' 13 | * '/foo/some 14 | */ 15 | 16 | const exampleAT = { 17 | demo: { 18 | before: [], 19 | after: [], 20 | methods: { 21 | POST: [() => {}], 22 | PUT: [], 23 | }, 24 | scoped: { 25 | foo: { 26 | before: [() => {}], 27 | after: [], 28 | methods: { 29 | POST: [() => {}], 30 | PUT: [], 31 | }, 32 | }, 33 | }, 34 | }, 35 | } 36 | 37 | // ========================================================================= // 38 | // ========================================================================= // 39 | 40 | const TestsController = { 41 | beforeEach() {}, 42 | afterEach() {}, 43 | index() {}, 44 | read() {}, 45 | create() {}, 46 | update() {}, 47 | patch() {}, 48 | destroy() {}, 49 | } 50 | 51 | const before1 = function before1() { 52 | console.log('before1()') 53 | } 54 | const before2 = function before2() { 55 | console.log('before2()') 56 | } 57 | const before3 = function before3() { 58 | console.log('before3()') 59 | } 60 | const after1 = function after1() { 61 | console.log('after1()') 62 | } 63 | const after2 = function after2() { 64 | console.log('after2()') 65 | } 66 | const after3 = function after3() { 67 | console.log('after3()') 68 | } 69 | const post1 = function post1() { 70 | console.log('post1()') 71 | } 72 | const get1 = function get1() { 73 | console.log('get1()') 74 | } 75 | const get2 = function get2() { 76 | console.log('get2()') 77 | } 78 | const get3 = function get3() { 79 | console.log('get3()') 80 | } 81 | const put3 = function put3() { 82 | console.log('put3()') 83 | } 84 | 85 | const routes = createRest((root) => { 86 | root.beforeEach(before1) 87 | root.afterEach(after1) 88 | 89 | root.post('/', post1) 90 | 91 | root.scope('demo', (demo) => { 92 | demo.beforeEach(before2) 93 | demo.afterEach(after2) 94 | 95 | demo.get('/', get1) 96 | demo.get('/foo', get2) 97 | 98 | // demo.scope('bar', bar => { 99 | // bar.beforeEach(before3) 100 | // bar.afterEach(after3) 101 | 102 | // bar.put('/', put3) 103 | // }) 104 | demo.crud('bar', TestsController, {}, (bar) => { 105 | bar.get('baz', get3) 106 | }) 107 | }) 108 | root.resources('tests', TestsController) 109 | }) 110 | 111 | const strf = (data, indent = ' ') => stringify(data, { 112 | indent, 113 | transform(obj, prop, original) { 114 | if (/^function/.test(original)) { 115 | return chalk.blue(original 116 | .replace(/\n+/mg, '') 117 | .replace(/\s+/mg, ' ') 118 | .replace(/^\w+\s+(\w+)\(\).*/mg, '$1()')) 119 | } 120 | 121 | return original 122 | }, 123 | }) 124 | 125 | console.log(strf(routes)) 126 | 127 | const flat = flattenRoutes(routes) 128 | 129 | Object.keys(flat).forEach((path) => { 130 | const mt = flat[path] 131 | 132 | Object.keys(mt).forEach((method) => { 133 | console.log( 134 | chalk.green(`${method} ${path}`), 135 | ' >> ', 136 | mt[method].map((fn) => `${chalk.yellow(fn.name)}()`).join(', ') 137 | ) 138 | }) 139 | }) 140 | 141 | console.log('\n---\n') 142 | 143 | printRoutes(routes) 144 | -------------------------------------------------------------------------------- /packages/createrest/readme.md: -------------------------------------------------------------------------------- 1 | # createrest [![npm](https://img.shields.io/npm/v/createrest.svg)](https://npmjs.com/createrest) 2 | 3 | Docs at https://createrest.js.org 4 | 5 | 6 | 7 | ## Usage example 8 | 9 | ```js 10 | // routes.js 11 | const { 12 | createRest, 13 | printRoutes, 14 | } = require('createrest') 15 | 16 | const before1 = () => { console.log('before1()') } 17 | const before2 = () => { console.log('before2()') } 18 | const before3 = () => { console.log('before3()') } 19 | const after1 = () => { console.log('after1()') } 20 | const after2 = () => { console.log('after2()') } 21 | const after3 = () => { console.log('after3()') } 22 | const post1 = () => { console.log('post1()') } 23 | const get1 = () => { console.log('get1()') } 24 | const get2 = () => { console.log('get2()') } 25 | const put3 = () => { console.log('put3()') } 26 | 27 | const ExampleController = { 28 | beforeEach() { console.log('Call before each handler') }, 29 | afterEach() {}, 30 | read() {}, 31 | create() {}, 32 | update() {}, 33 | destroy () {}, 34 | } 35 | 36 | const BooksController = { 37 | beforeEach() { console.log('Call before each handler') }, 38 | afterEach() {}, 39 | index() {}, 40 | create() {}, 41 | read() {}, 42 | update() {}, 43 | patch() {}, 44 | destroy () {}, 45 | } 46 | 47 | const routes = createRest(root => { 48 | root.beforeEach(before1) 49 | root.afterEach(after1) 50 | 51 | root.post('/', post1) 52 | 53 | root.scope('demo', demoRoute => { 54 | demoRoute.beforeEach(before2) 55 | demoRoute.afterEach(after2) 56 | 57 | demoRoute.get('/', get1) 58 | demoRoute.get('/foo', get2) 59 | 60 | demoRoute.scope('bar', barRoute => { 61 | barRoute.beforeEach(before3) 62 | barRoute.afterEach(after3) 63 | 64 | barRoute.put('/', put3) 65 | 66 | barRoute.crud('example', ExampleController) 67 | }) 68 | }) 69 | 70 | root.resources('books', BooksController) 71 | }) 72 | 73 | module.exports = routes 74 | ``` 75 | 76 | ### Express 77 | 78 | More in it's repo [createrest-express](/packages/createrest-koa) 79 | 80 | ```js 81 | const { createRestExpress } = require('createrest-express') 82 | const express = require('express') 83 | const routes = require('./routes') 84 | 85 | const app = express() 86 | 87 | app.use(createRestExpress(routes)) 88 | 89 | app.listen(4001, () => { 90 | printRoutes(routes) 91 | }) 92 | ``` 93 | 94 | ### Koa 95 | 96 | More in it's repo [createrest-koa](/packages/createrest-koa) 97 | 98 | ```js 99 | const Koa = require('koa') 100 | const { createKoaRouter } = require('createrest-koa') 101 | const routes = require('./routes') 102 | 103 | const app = new Koa() 104 | const router = createKoaRouter(routes) 105 | 106 | app.use(router.routes(), router.allowedMethods()) 107 | 108 | app.listen(3000, () => { 109 | printRoutes(routes) 110 | }) 111 | ``` 112 | 113 | --- 114 | 115 | Output: 116 | 117 | ``` 118 | POST / -> before1(), post1(), after1() 119 | GET /demo/ -> before1(), before2(), get1(), after2(), after1() 120 | GET /demo/foo/ -> before1(), before2(), get2(), after2(), after1() 121 | PUT /demo/bar/ -> before1(), before2(), before3(), put3(), after3(), after2(), after1() 122 | GET /demo/bar/example/ -> before1(), before2(), before3(), beforeEach(), read(), afterEach(), after3(), after2(), after1() 123 | POST /demo/bar/example/ -> before1(), before2(), before3(), beforeEach(), create(), afterEach(), after3(), after2(), after1() 124 | PUT /demo/bar/example/ -> before1(), before2(), before3(), beforeEach(), update(), afterEach(), after3(), after2(), after1() 125 | DELETE /demo/bar/example/ -> before1(), before2(), before3(), beforeEach(), destroy(), afterEach(), after3(), after2(), after1() 126 | GET /books/ -> before1(), beforeEach(), index(), afterEach(), after1() 127 | POST /books/ -> before1(), beforeEach(), create(), afterEach(), after1() 128 | GET /books/:bookId/ -> before1(), beforeEach(), read(), afterEach(), after1() 129 | PUT /books/:bookId/ -> before1(), beforeEach(), update(), afterEach(), after1() 130 | PATCH /books/:bookId/ -> before1(), beforeEach(), patch(), afterEach(), after1() 131 | DELETE /books/:bookId/ -> before1(), beforeEach(), destroy(), afterEach(), after1() 132 | ``` 133 | -------------------------------------------------------------------------------- /packages/createrest-koa/test/index.test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava' 2 | import Koa from 'koa' 3 | import supertest from 'supertest' 4 | import sinon from 'sinon' 5 | import { createRest } from 'createrest' 6 | import { createKoaRouter } from '../lib' 7 | 8 | 9 | let port = 3000 10 | 11 | function createRawServer(routesFn) { 12 | const router = createKoaRouter(createRest(routesFn)) 13 | const app = new Koa() 14 | app.use(router.routes(), router.allowedMethods()) 15 | return app.listen(port++) 16 | } 17 | 18 | const newSpy = () => ({ 19 | get: sinon.spy(), 20 | post: sinon.spy(), 21 | patch: sinon.spy(), 22 | put: sinon.spy(), 23 | delete: sinon.spy(), 24 | before: sinon.stub().callsFake((ctx, next) => next()), 25 | before2: sinon.stub().callsFake((ctx, next) => next()), 26 | before3: sinon.stub().callsFake((ctx, next) => next()), 27 | before4: sinon.stub().callsFake((ctx, next) => next()), 28 | after: sinon.stub().callsFake((ctx, next) => next()), 29 | after2: sinon.stub().callsFake((ctx, next) => next()), 30 | after3: sinon.stub().callsFake((ctx, next) => next()), 31 | after4: sinon.stub().callsFake((ctx, next) => next()), 32 | }) 33 | 34 | 35 | test('/ get post put patch delete', async (t) => { 36 | t.plan(5) 37 | 38 | const spy = newSpy() 39 | const routes = (root) => { 40 | root.get('/', spy.get) 41 | root.post('/', spy.post) 42 | root.patch('/', spy.patch) 43 | root.put('/', spy.put) 44 | root.delete('/', spy.delete) 45 | } 46 | const server = createRawServer(routes) 47 | 48 | await supertest(server).get('/') 49 | t.true(spy.get.calledOnce) 50 | 51 | await supertest(server).post('/') 52 | t.true(spy.post.calledOnce) 53 | 54 | await supertest(server).patch('/') 55 | t.true(spy.patch.calledOnce) 56 | 57 | await supertest(server).put('/') 58 | t.true(spy.put.calledOnce) 59 | 60 | await supertest(server).delete('/') 61 | t.true(spy.delete.calledOnce) 62 | }) 63 | 64 | 65 | test('deep path in simple handlers throws', async (t) => { 66 | t.throws(() => { 67 | createRest((root) => { 68 | root.get('/so/deep/path', () => {}) 69 | }) 70 | }) 71 | }) 72 | 73 | test('throws when passed not routes', async (t) => { 74 | t.throws(() => { 75 | createKoaRouter(() => {}) 76 | }, TypeError) 77 | 78 | t.throws(() => { 79 | createKoaRouter({}) 80 | }, TypeError) 81 | }) 82 | 83 | 84 | test('deep scopes works', async (t) => { 85 | t.plan(5) 86 | 87 | const spy = newSpy() 88 | const routes = (root) => { 89 | root.scope('so', (so) => { 90 | so.scope('deep', (deep) => { 91 | deep.scope('path', (path) => { 92 | path.scope('for-you', (forYou) => { 93 | forYou.get('yea', spy.get) 94 | forYou.post('yea', spy.post) 95 | forYou.patch('yea', spy.patch) 96 | forYou.put('yea', spy.put) 97 | forYou.delete('yea', spy.delete) 98 | }) 99 | }) 100 | }) 101 | }) 102 | } 103 | const server = createRawServer(routes) 104 | 105 | await supertest(server).get('/so/deep/path/for-you/yea') 106 | t.true(spy.get.calledOnce) 107 | 108 | await supertest(server).post('/so/deep/path/for-you/yea') 109 | t.true(spy.post.calledOnce) 110 | 111 | await supertest(server).patch('/so/deep/path/for-you/yea') 112 | t.true(spy.patch.calledOnce) 113 | 114 | await supertest(server).put('/so/deep/path/for-you/yea') 115 | t.true(spy.put.calledOnce) 116 | 117 | await supertest(server).delete('/so/deep/path/for-you/yea') 118 | t.true(spy.delete.calledOnce) 119 | }) 120 | 121 | test('before|after handler on root level', async (t) => { 122 | t.plan(4) 123 | const spy = newSpy() 124 | const routes = (root) => { 125 | root.beforeEach(spy.before) 126 | root.afterEach(spy.after) 127 | root.get('/', spy.get) 128 | } 129 | const server = createRawServer(routes) 130 | 131 | await supertest(server).get('/') 132 | 133 | t.true(spy.get.calledOnce) 134 | t.true(spy.before.calledBefore(spy.get)) 135 | t.true(spy.before.calledBefore(spy.after)) 136 | t.true(spy.get.calledBefore(spy.after)) 137 | }) 138 | 139 | 140 | test('before|after for deep handlers', async (t) => { 141 | t.plan(4) 142 | const spy = newSpy() 143 | const routes = (root) => { 144 | root.beforeEach(spy.before) 145 | root.afterEach(spy.after) 146 | root.scope('foo', (foo) => { 147 | foo.scope('bar', (bar) => { 148 | bar.scope('baz', (baz) => { 149 | baz.get('/', spy.get) 150 | }) 151 | }) 152 | }) 153 | } 154 | const server = createRawServer(routes) 155 | 156 | await supertest(server).get('/foo/bar/baz') 157 | 158 | t.true(spy.get.calledOnce) 159 | t.true(spy.before.calledBefore(spy.get)) 160 | t.true(spy.before.calledBefore(spy.after)) 161 | t.true(spy.get.calledBefore(spy.after)) 162 | }) 163 | 164 | 165 | test('deep before|after for deep handlers', async (t) => { 166 | const spy = newSpy() 167 | const get = sinon.stub().callsFake((ctx, next) => next()) 168 | 169 | const routes = (root) => { 170 | root.beforeEach(spy.before) 171 | root.afterEach(spy.after) 172 | 173 | root.scope('foo', (foo) => { 174 | foo.beforeEach(spy.before2) 175 | foo.afterEach(spy.after2) 176 | 177 | foo.scope('bar', (bar) => { 178 | bar.beforeEach(spy.before3) 179 | bar.afterEach(spy.after3) 180 | 181 | bar.scope('baz', (baz) => { 182 | baz.beforeEach(spy.before4) 183 | baz.afterEach(spy.after4) 184 | 185 | baz.get('/', get) 186 | }) 187 | }) 188 | }) 189 | } 190 | const server = createRawServer(routes) 191 | 192 | await supertest(server).get('/foo/bar/baz') 193 | 194 | t.true(spy.before.calledBefore(spy.before2)) 195 | t.true(spy.before2.calledBefore(spy.before3)) 196 | t.true(spy.before3.calledBefore(spy.before4)) 197 | 198 | t.true(spy.before4.calledBefore(get)) 199 | t.true(get.calledOnce) 200 | t.true(spy.after4.calledAfter(get)) 201 | 202 | t.true(spy.after3.calledAfter(spy.after4)) 203 | t.true(spy.after2.calledAfter(spy.after3)) 204 | t.true(spy.after.calledAfter(spy.after2)) 205 | }) 206 | 207 | -------------------------------------------------------------------------------- /packages/createrest-express/test/index.test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava' 2 | import supertest from 'supertest' 3 | import sinon from 'sinon' 4 | import { createRest } from 'createrest' 5 | import { createExpressMiddleware } from '../lib' 6 | import { createRawServer } from './utils' 7 | 8 | 9 | const newSpy = () => ({ 10 | get: sinon.stub().callsFake((req, res) => res.send({})), 11 | post: sinon.stub().callsFake((req, res) => res.send({})), 12 | patch: sinon.stub().callsFake((req, res) => res.send({})), 13 | put: sinon.stub().callsFake((req, res) => res.send({})), 14 | delete: sinon.stub().callsFake((req, res) => res.send({})), 15 | before: sinon.stub().callsFake((req, res, next) => next()), 16 | before2: sinon.stub().callsFake((req, res, next) => next()), 17 | before3: sinon.stub().callsFake((req, res, next) => next()), 18 | before4: sinon.stub().callsFake((req, res, next) => next()), 19 | after: sinon.stub().callsFake((req, res, next) => next()), 20 | after2: sinon.stub().callsFake((req, res, next) => next()), 21 | after3: sinon.stub().callsFake((req, res, next) => next()), 22 | after4: sinon.stub().callsFake((req, res, next) => next()), 23 | }) 24 | 25 | 26 | test('/ get post put patch delete', async (t) => { 27 | t.plan(5) 28 | 29 | const spy = newSpy() 30 | const routes = (root) => { 31 | root.get('/', spy.get) 32 | root.post('/', spy.post) 33 | root.patch('/', spy.patch) 34 | root.put('/', spy.put) 35 | root.delete('/', spy.delete) 36 | } 37 | const server = createRawServer(routes) 38 | 39 | await supertest(server).get('/') 40 | t.true(spy.get.calledOnce) 41 | 42 | await supertest(server).post('/') 43 | t.true(spy.post.calledOnce) 44 | 45 | await supertest(server).patch('/') 46 | t.true(spy.patch.calledOnce) 47 | 48 | await supertest(server).put('/') 49 | t.true(spy.put.calledOnce) 50 | 51 | await supertest(server).delete('/') 52 | t.true(spy.delete.calledOnce) 53 | }) 54 | 55 | 56 | test('deep path in simple handlers throws', async (t) => { 57 | t.throws(() => { 58 | createRest((root) => { 59 | root.get('/so/deep/path', () => { }) 60 | }) 61 | }) 62 | }) 63 | 64 | test('throws when passed not routes', async (t) => { 65 | t.throws(() => { 66 | createExpressMiddleware(() => { }) 67 | }, TypeError) 68 | 69 | t.throws(() => { 70 | createExpressMiddleware({}) 71 | }, TypeError) 72 | }) 73 | 74 | 75 | test('deep scopes works', async (t) => { 76 | t.plan(5) 77 | 78 | const spy = newSpy() 79 | const routes = (root) => { 80 | root.scope('so', (so) => { 81 | so.scope('deep', (deep) => { 82 | deep.scope('path', (path) => { 83 | path.scope('for-you', (forYou) => { 84 | forYou.get('yea', spy.get) 85 | forYou.post('yea', spy.post) 86 | forYou.patch('yea', spy.patch) 87 | forYou.put('yea', spy.put) 88 | forYou.delete('yea', spy.delete) 89 | }) 90 | }) 91 | }) 92 | }) 93 | } 94 | const server = createRawServer(routes) 95 | 96 | await supertest(server).get('/so/deep/path/for-you/yea') 97 | t.true(spy.get.calledOnce) 98 | 99 | await supertest(server).post('/so/deep/path/for-you/yea') 100 | t.true(spy.post.calledOnce) 101 | 102 | await supertest(server).patch('/so/deep/path/for-you/yea') 103 | t.true(spy.patch.calledOnce) 104 | 105 | await supertest(server).put('/so/deep/path/for-you/yea') 106 | t.true(spy.put.calledOnce) 107 | 108 | await supertest(server).delete('/so/deep/path/for-you/yea') 109 | t.true(spy.delete.calledOnce) 110 | 111 | server.close() 112 | }) 113 | 114 | test('before|after handler on root level', async (t) => { 115 | t.plan(4) 116 | const spy = newSpy() 117 | const routes = (root) => { 118 | root.beforeEach(spy.before) 119 | root.afterEach(spy.after) 120 | root.get('/', spy.get) 121 | } 122 | const server = createRawServer(routes) 123 | 124 | await supertest(server).get('/') 125 | 126 | t.true(spy.get.calledOnce) 127 | t.true(spy.before.calledBefore(spy.get)) 128 | t.true(spy.before.calledBefore(spy.after)) 129 | t.true(spy.get.calledBefore(spy.after)) 130 | 131 | server.close() 132 | }) 133 | 134 | 135 | test('before|after for deep handlers', async (t) => { 136 | t.plan(4) 137 | const spy = newSpy() 138 | const routes = (root) => { 139 | root.beforeEach(spy.before) 140 | root.afterEach(spy.after) 141 | root.scope('foo', (foo) => { 142 | foo.scope('bar', (bar) => { 143 | bar.scope('baz', (baz) => { 144 | baz.get('/', spy.get) 145 | }) 146 | }) 147 | }) 148 | } 149 | const server = createRawServer(routes) 150 | 151 | await supertest(server).get('/foo/bar/baz') 152 | 153 | t.true(spy.get.calledOnce) 154 | t.true(spy.before.calledBefore(spy.get)) 155 | t.true(spy.before.calledBefore(spy.after)) 156 | t.true(spy.get.calledBefore(spy.after)) 157 | 158 | server.close() 159 | }) 160 | 161 | 162 | test('deep before|after for deep handlers', async (t) => { 163 | const spy = newSpy() 164 | const get = sinon.stub().callsFake((req, res, next) => next()) 165 | 166 | const routes = (root) => { 167 | root.beforeEach(spy.before) 168 | root.afterEach(spy.after) 169 | 170 | root.scope('foo', (foo) => { 171 | foo.beforeEach(spy.before2) 172 | foo.afterEach(spy.after2) 173 | 174 | foo.scope('bar', (bar) => { 175 | bar.beforeEach(spy.before3) 176 | bar.afterEach(spy.after3) 177 | 178 | bar.scope('baz', (baz) => { 179 | baz.beforeEach(spy.before4) 180 | baz.afterEach(spy.after4) 181 | 182 | baz.get('/', get) 183 | }) 184 | }) 185 | }) 186 | } 187 | const server = createRawServer(routes) 188 | 189 | await supertest(server).get('/foo/bar/baz') 190 | 191 | t.true(spy.before.calledBefore(spy.before2)) 192 | t.true(spy.before2.calledBefore(spy.before3)) 193 | t.true(spy.before3.calledBefore(spy.before4)) 194 | 195 | t.true(spy.before4.calledBefore(get)) 196 | t.true(get.calledOnce) 197 | t.true(spy.after4.calledAfter(get)) 198 | 199 | t.true(spy.after3.calledAfter(spy.after4)) 200 | t.true(spy.after2.calledAfter(spy.after3)) 201 | t.true(spy.after.calledAfter(spy.after2)) 202 | 203 | server.close() 204 | }) 205 | 206 | -------------------------------------------------------------------------------- /packages/createrest/esdocs/styles.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Source+Code+Pro'); 2 | 3 | body, html { 4 | background-color: #0f1419; 5 | /*color: #c5c5c5;*/ 6 | color: #adadad; 7 | } 8 | 9 | .layout-container > header { 10 | background-color: #0f1419; 11 | border-color: #5c6773; 12 | } 13 | 14 | .layout-container > header > a { 15 | color: #68afca; 16 | } 17 | 18 | .layout-container > header > a.repo-url-github { 19 | filter: invert(); 20 | } 21 | 22 | a { 23 | color: #68afca; 24 | } 25 | 26 | a:hover { 27 | text-decoration: underline; 28 | } 29 | 30 | code, pre { 31 | white-space: pre-wrap; 32 | } 33 | 34 | pre { 35 | background-color: #191f26; 36 | border-radius: 4px; 37 | color: #e6e1cf; 38 | } 39 | 40 | code { 41 | color: #ffb454; 42 | } 43 | 44 | pre > code { 45 | background: none; 46 | } 47 | 48 | hr { 49 | border-color: #5c6773; 50 | } 51 | 52 | pre.source-code, 53 | pre.source-code ol, 54 | pre.source-code ol li 55 | { 56 | background: none; 57 | background-color: #191f26; 58 | } 59 | 60 | pre.source-code.line-number li.active { 61 | background: rgba(255, 180, 76, 0.2); 62 | position: relative; 63 | } 64 | 65 | code, pre, 66 | .search-input, 67 | .header-notice, 68 | .version, .since, 69 | .content .detail > h3, 70 | .search-result li.search-separator, 71 | table.params tbody tr td:nth-child(1), table.params tbody tr td:nth-child(2), 72 | table.summary [data-ice="name"], table.summary [data-ice="signature"], table.summary span.access 73 | { 74 | font-family: "Source Code Pro", Menlo, Monaco, Consolas, Inconsolata, monospace; 75 | } 76 | 77 | .raw-source-code code { 78 | color: #5a5977; 79 | } 80 | 81 | .example-caption { 82 | background-color: transparent; 83 | color: #ffa0a5; 84 | font-style: italic; 85 | font-weight: 300; 86 | font-size: 14px; 87 | } 88 | 89 | .import-path pre.prettyprint, 90 | .import-path pre.prettyprint code, 91 | .source-code { 92 | background-color: #191f26; 93 | padding: 2px 4px; 94 | font-size: 13px; 95 | } 96 | .source-code { padding: 0 } 97 | .import-path .typ:before, .import-path .typ:after { 98 | content: ' ' 99 | } 100 | 101 | .kwd { color: #ffa0a5 } 102 | .pun { color: #d2abea } 103 | /*.pln { color: #e6e1cf }*/ 104 | .pln { color: #c5bb98 } 105 | .str { color: #b8cc52 } 106 | .typ { color: #99e0c9 } 107 | .com { color: #5f694f } 108 | /*.com { color: #4D4D4C }*/ 109 | 110 | .version, .since { 111 | color: #d2abea; 112 | font-size: 14px; 113 | } 114 | 115 | code, kbd, pre, samp { 116 | } 117 | 118 | h1 { 119 | border-bottom: 1px dashed #D5D5D5; 120 | font-size: 24px; 121 | } 122 | 123 | h2 { 124 | border-bottom: 1px solid #5c6773; 125 | font-size: 22px; 126 | } 127 | 128 | h1, h2 { 129 | color: white; 130 | margin: 20px 0 15px 0; 131 | padding-bottom: 6px; 132 | } 133 | 134 | h3 { 135 | font-weight: 600; 136 | font-size: 20px; 137 | background-color: transparent; 138 | color: inherit; 139 | } 140 | 141 | h3 .right-info { 142 | line-height: 24px; 143 | } 144 | 145 | .header-notice [data-ice="access"] { 146 | color: #ffa0a5; 147 | } 148 | .header-notice [data-ice="kind"] { 149 | color: #fdd687; 150 | } 151 | 152 | .content .detail > h3 { 153 | background-color: transparent; 154 | } 155 | 156 | .content .detail + .detail { 157 | margin-top: 50px; 158 | } 159 | 160 | .content .detail > h3 { 161 | color: inherit; 162 | } 163 | 164 | .content .detail > h3 .access, 165 | table.summary span.access { 166 | color: #ffa0a5; 167 | } 168 | 169 | 170 | .content .detail > h3 [data-ice="name"] { 171 | color: #fdd687; 172 | } 173 | 174 | .content .detail > h3 [data-ice="source"]::before { content: "[" } 175 | .content .detail > h3 [data-ice="source"]::after { content: "]" } 176 | 177 | .content .detail h4 { 178 | color: #6a6b75; 179 | font-size: 16px; 180 | } 181 | 182 | .inner-link-active, :target { 183 | background: rgba(255, 52, 52, 0.33) !important; 184 | border-right: 3px solid #ffb44c; 185 | } 186 | 187 | .navigation { 188 | border: none; 189 | box-shadow: none; 190 | } 191 | 192 | .navigation li { 193 | margin: 0; 194 | text-overflow: ellipsis; 195 | overflow: hidden; 196 | display: block; 197 | padding: 7px 5px; 198 | } 199 | 200 | .navigation li:hover { 201 | background-color: rgba(70, 70, 70, 0.33); 202 | } 203 | 204 | .navigation li a { 205 | display: inline-block; 206 | color: #869fb9 !important; 207 | /*color: #5c6773 !important;*/ 208 | font-size: 14px; 209 | font-weight: 400; 210 | line-height: 20px; 211 | padding: 0 5px; 212 | } 213 | 214 | .kind-class, 215 | .kind-function, 216 | .kind-interface, 217 | .kind-typedef, 218 | .kind-variable, 219 | .kind-external { 220 | margin-left: 10px; 221 | width: 20px; 222 | height: 20px; 223 | background-color: transparent !important; 224 | margin-right: 0; 225 | } 226 | .kind-function { color: #c086d4 } 227 | .kind-class { color: #5bd65b } 228 | .kind-typedef { color: #e8576b } 229 | 230 | table, 231 | table.params td, table.summary td, table.files-summary td, 232 | table.params th, table.summary th, table.files-summary th 233 | { 234 | /*border-color: #4E4C4C;*/ 235 | /*border-color: transparent;*/ 236 | border: none; 237 | } 238 | 239 | table.params thead td, table.summary thead td, table.files-summary thead td { 240 | background-color: #28282d; 241 | color: #e6e1cf; 242 | } 243 | 244 | table.files-summary tbody tr:hover, 245 | table.params tbody tr:hover td { 246 | background-color: #191f26; 247 | } 248 | 249 | table.summary tbody td { 250 | padding: 10px 5px; 251 | padding-bottom: 20px; 252 | } 253 | table.params tbody tr td:nth-child(1), table.params tbody tr td:nth-child(2) { 254 | font-size: 14px; 255 | } 256 | 257 | table.summary span.access { 258 | line-height: 24px; 259 | } 260 | 261 | .footer, .file-footer { 262 | border-top: 1px solid #5c6773; 263 | } 264 | 265 | .search-input { 266 | color: #e6e1cf; 267 | } 268 | 269 | .search-result { 270 | background-color: #141920; 271 | border: 1px solid #4E4C4C; 272 | } 273 | 274 | .search-result li.search-separator { 275 | background-color: transparent; 276 | margin-top: 10px; 277 | } 278 | 279 | .search-result li.selected { 280 | background: rgba(255, 52, 52, 0.33); 281 | } 282 | 283 | .manual-index .manual-user-index, 284 | .manual-index .manual-card { 285 | border-color: #5c6773; 286 | } 287 | 288 | .manual-toc .indent-h1 { 289 | padding: 0; 290 | } 291 | .manual-toc .indent-h1 a { 292 | padding: 5px 7px; 293 | } 294 | -------------------------------------------------------------------------------- /packages/createrest-koa/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "createrest-koa", 3 | "version": "0.14.2", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accepts": { 8 | "version": "1.3.4", 9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz", 10 | "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=", 11 | "dev": true, 12 | "requires": { 13 | "mime-types": "2.1.17", 14 | "negotiator": "0.6.1" 15 | } 16 | }, 17 | "any-promise": { 18 | "version": "1.3.0", 19 | "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", 20 | "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" 21 | }, 22 | "co": { 23 | "version": "4.6.0", 24 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", 25 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", 26 | "dev": true 27 | }, 28 | "content-disposition": { 29 | "version": "0.5.2", 30 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", 31 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", 32 | "dev": true 33 | }, 34 | "content-type": { 35 | "version": "1.0.4", 36 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 37 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", 38 | "dev": true 39 | }, 40 | "cookies": { 41 | "version": "0.7.1", 42 | "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.7.1.tgz", 43 | "integrity": "sha1-fIphX1SBxhq58WyDNzG8uPZjuZs=", 44 | "dev": true, 45 | "requires": { 46 | "depd": "1.1.1", 47 | "keygrip": "1.0.2" 48 | } 49 | }, 50 | "debug": { 51 | "version": "3.1.0", 52 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 53 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 54 | "requires": { 55 | "ms": "2.0.0" 56 | } 57 | }, 58 | "deep-equal": { 59 | "version": "1.0.1", 60 | "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", 61 | "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", 62 | "dev": true 63 | }, 64 | "delegates": { 65 | "version": "1.0.0", 66 | "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", 67 | "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", 68 | "dev": true 69 | }, 70 | "depd": { 71 | "version": "1.1.1", 72 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", 73 | "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" 74 | }, 75 | "destroy": { 76 | "version": "1.0.4", 77 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 78 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", 79 | "dev": true 80 | }, 81 | "ee-first": { 82 | "version": "1.1.1", 83 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 84 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", 85 | "dev": true 86 | }, 87 | "error-inject": { 88 | "version": "1.0.0", 89 | "resolved": "https://registry.npmjs.org/error-inject/-/error-inject-1.0.0.tgz", 90 | "integrity": "sha1-4rPZG1Su1nLzCdlQ0VSFD6EdTzc=", 91 | "dev": true 92 | }, 93 | "escape-html": { 94 | "version": "1.0.3", 95 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 96 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", 97 | "dev": true 98 | }, 99 | "fresh": { 100 | "version": "0.5.2", 101 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 102 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", 103 | "dev": true 104 | }, 105 | "http-assert": { 106 | "version": "1.3.0", 107 | "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.3.0.tgz", 108 | "integrity": "sha1-oxpc+IyHPsu1eWkH1NbxMujAHko=", 109 | "dev": true, 110 | "requires": { 111 | "deep-equal": "1.0.1", 112 | "http-errors": "1.6.2" 113 | } 114 | }, 115 | "http-errors": { 116 | "version": "1.6.2", 117 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", 118 | "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", 119 | "requires": { 120 | "depd": "1.1.1", 121 | "inherits": "2.0.3", 122 | "setprototypeof": "1.0.3", 123 | "statuses": "1.4.0" 124 | } 125 | }, 126 | "inherits": { 127 | "version": "2.0.3", 128 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 129 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 130 | }, 131 | "is-generator-function": { 132 | "version": "1.0.6", 133 | "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.6.tgz", 134 | "integrity": "sha1-nnFlPNFf/zQcecQVFGChMdMen8Q=", 135 | "dev": true 136 | }, 137 | "isarray": { 138 | "version": "0.0.1", 139 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 140 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" 141 | }, 142 | "keygrip": { 143 | "version": "1.0.2", 144 | "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.0.2.tgz", 145 | "integrity": "sha1-rTKXxVcGneqLz+ek+kkbdcXd65E=", 146 | "dev": true 147 | }, 148 | "koa": { 149 | "version": "2.4.1", 150 | "resolved": "https://registry.npmjs.org/koa/-/koa-2.4.1.tgz", 151 | "integrity": "sha512-3caQ9OyLDYSL3wAhVfv2s9k3tLNgW18QxnKIPaRjzG9uXyDhp4tOo+U+XtbY+xbzEiCW5smjxMCegpZqCjmjMw==", 152 | "dev": true, 153 | "requires": { 154 | "accepts": "1.3.4", 155 | "content-disposition": "0.5.2", 156 | "content-type": "1.0.4", 157 | "cookies": "0.7.1", 158 | "debug": "3.1.0", 159 | "delegates": "1.0.0", 160 | "depd": "1.1.1", 161 | "destroy": "1.0.4", 162 | "error-inject": "1.0.0", 163 | "escape-html": "1.0.3", 164 | "fresh": "0.5.2", 165 | "http-assert": "1.3.0", 166 | "http-errors": "1.6.2", 167 | "is-generator-function": "1.0.6", 168 | "koa-compose": "4.0.0", 169 | "koa-convert": "1.2.0", 170 | "koa-is-json": "1.0.0", 171 | "mime-types": "2.1.17", 172 | "on-finished": "2.3.0", 173 | "only": "0.0.2", 174 | "parseurl": "1.3.2", 175 | "statuses": "1.4.0", 176 | "type-is": "1.6.15", 177 | "vary": "1.1.2" 178 | } 179 | }, 180 | "koa-compose": { 181 | "version": "4.0.0", 182 | "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.0.0.tgz", 183 | "integrity": "sha1-KAClE9nDYe8NY4UrA45Pby1adzw=", 184 | "dev": true 185 | }, 186 | "koa-convert": { 187 | "version": "1.2.0", 188 | "resolved": "https://registry.npmjs.org/koa-convert/-/koa-convert-1.2.0.tgz", 189 | "integrity": "sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA=", 190 | "dev": true, 191 | "requires": { 192 | "co": "4.6.0", 193 | "koa-compose": "3.2.1" 194 | }, 195 | "dependencies": { 196 | "koa-compose": { 197 | "version": "3.2.1", 198 | "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-3.2.1.tgz", 199 | "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=", 200 | "dev": true, 201 | "requires": { 202 | "any-promise": "1.3.0" 203 | } 204 | } 205 | } 206 | }, 207 | "koa-is-json": { 208 | "version": "1.0.0", 209 | "resolved": "https://registry.npmjs.org/koa-is-json/-/koa-is-json-1.0.0.tgz", 210 | "integrity": "sha1-JzwH7c3Ljfaiwat9We52SRRR7BQ=", 211 | "dev": true 212 | }, 213 | "koa-router": { 214 | "version": "7.4.0", 215 | "resolved": "https://registry.npmjs.org/koa-router/-/koa-router-7.4.0.tgz", 216 | "integrity": "sha512-IWhaDXeAnfDBEpWS6hkGdZ1ablgr6Q6pGdXCyK38RbzuH4LkUOpPqPw+3f8l8aTDrQmBQ7xJc0bs2yV4dzcO+g==", 217 | "requires": { 218 | "debug": "3.1.0", 219 | "http-errors": "1.6.2", 220 | "koa-compose": "3.2.1", 221 | "methods": "1.1.2", 222 | "path-to-regexp": "1.7.0", 223 | "urijs": "1.19.0" 224 | }, 225 | "dependencies": { 226 | "koa-compose": { 227 | "version": "3.2.1", 228 | "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-3.2.1.tgz", 229 | "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=", 230 | "requires": { 231 | "any-promise": "1.3.0" 232 | } 233 | } 234 | } 235 | }, 236 | "media-typer": { 237 | "version": "0.3.0", 238 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 239 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", 240 | "dev": true 241 | }, 242 | "methods": { 243 | "version": "1.1.2", 244 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 245 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 246 | }, 247 | "mime-db": { 248 | "version": "1.30.0", 249 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", 250 | "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", 251 | "dev": true 252 | }, 253 | "mime-types": { 254 | "version": "2.1.17", 255 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", 256 | "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", 257 | "dev": true, 258 | "requires": { 259 | "mime-db": "1.30.0" 260 | } 261 | }, 262 | "ms": { 263 | "version": "2.0.0", 264 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 265 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 266 | }, 267 | "negotiator": { 268 | "version": "0.6.1", 269 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", 270 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", 271 | "dev": true 272 | }, 273 | "on-finished": { 274 | "version": "2.3.0", 275 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 276 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 277 | "dev": true, 278 | "requires": { 279 | "ee-first": "1.1.1" 280 | } 281 | }, 282 | "only": { 283 | "version": "0.0.2", 284 | "resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz", 285 | "integrity": "sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q=", 286 | "dev": true 287 | }, 288 | "parseurl": { 289 | "version": "1.3.2", 290 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", 291 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", 292 | "dev": true 293 | }, 294 | "path-to-regexp": { 295 | "version": "1.7.0", 296 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", 297 | "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", 298 | "requires": { 299 | "isarray": "0.0.1" 300 | } 301 | }, 302 | "setprototypeof": { 303 | "version": "1.0.3", 304 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", 305 | "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" 306 | }, 307 | "statuses": { 308 | "version": "1.4.0", 309 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 310 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 311 | }, 312 | "type-is": { 313 | "version": "1.6.15", 314 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", 315 | "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", 316 | "dev": true, 317 | "requires": { 318 | "media-typer": "0.3.0", 319 | "mime-types": "2.1.17" 320 | } 321 | }, 322 | "urijs": { 323 | "version": "1.19.0", 324 | "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.0.tgz", 325 | "integrity": "sha512-Qs2odXn0hST5VSPVjpi73CMqtbAoanahaqWBujGU+IyMrMqpWcIhDewxQRhCkmqYxuyvICDcSuLdv2O7ncWBGw==" 326 | }, 327 | "vary": { 328 | "version": "1.1.2", 329 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 330 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", 331 | "dev": true 332 | } 333 | } 334 | } 335 | -------------------------------------------------------------------------------- /packages/createrest-express/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "accepts": { 6 | "version": "1.3.4", 7 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz", 8 | "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=", 9 | "requires": { 10 | "mime-types": "2.1.17", 11 | "negotiator": "0.6.1" 12 | } 13 | }, 14 | "array-flatten": { 15 | "version": "1.1.1", 16 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 17 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 18 | }, 19 | "body-parser": { 20 | "version": "1.18.2", 21 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", 22 | "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", 23 | "requires": { 24 | "bytes": "3.0.0", 25 | "content-type": "1.0.4", 26 | "debug": "2.6.9", 27 | "depd": "1.1.1", 28 | "http-errors": "1.6.2", 29 | "iconv-lite": "0.4.19", 30 | "on-finished": "2.3.0", 31 | "qs": "6.5.1", 32 | "raw-body": "2.3.2", 33 | "type-is": "1.6.15" 34 | } 35 | }, 36 | "bytes": { 37 | "version": "3.0.0", 38 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", 39 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" 40 | }, 41 | "content-disposition": { 42 | "version": "0.5.2", 43 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", 44 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" 45 | }, 46 | "content-type": { 47 | "version": "1.0.4", 48 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 49 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 50 | }, 51 | "cookie": { 52 | "version": "0.3.1", 53 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 54 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 55 | }, 56 | "cookie-signature": { 57 | "version": "1.0.6", 58 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 59 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 60 | }, 61 | "debug": { 62 | "version": "2.6.9", 63 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 64 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 65 | "requires": { 66 | "ms": "2.0.0" 67 | } 68 | }, 69 | "depd": { 70 | "version": "1.1.1", 71 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", 72 | "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" 73 | }, 74 | "destroy": { 75 | "version": "1.0.4", 76 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 77 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 78 | }, 79 | "ee-first": { 80 | "version": "1.1.1", 81 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 82 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 83 | }, 84 | "encodeurl": { 85 | "version": "1.0.1", 86 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz", 87 | "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=" 88 | }, 89 | "escape-html": { 90 | "version": "1.0.3", 91 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 92 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 93 | }, 94 | "etag": { 95 | "version": "1.8.1", 96 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 97 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 98 | }, 99 | "express": { 100 | "version": "4.16.2", 101 | "resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz", 102 | "integrity": "sha1-41xt/i1kt9ygpc1PIXgb4ymeB2w=", 103 | "requires": { 104 | "accepts": "1.3.4", 105 | "array-flatten": "1.1.1", 106 | "body-parser": "1.18.2", 107 | "content-disposition": "0.5.2", 108 | "content-type": "1.0.4", 109 | "cookie": "0.3.1", 110 | "cookie-signature": "1.0.6", 111 | "debug": "2.6.9", 112 | "depd": "1.1.1", 113 | "encodeurl": "1.0.1", 114 | "escape-html": "1.0.3", 115 | "etag": "1.8.1", 116 | "finalhandler": "1.1.0", 117 | "fresh": "0.5.2", 118 | "merge-descriptors": "1.0.1", 119 | "methods": "1.1.2", 120 | "on-finished": "2.3.0", 121 | "parseurl": "1.3.2", 122 | "path-to-regexp": "0.1.7", 123 | "proxy-addr": "2.0.2", 124 | "qs": "6.5.1", 125 | "range-parser": "1.2.0", 126 | "safe-buffer": "5.1.1", 127 | "send": "0.16.1", 128 | "serve-static": "1.13.1", 129 | "setprototypeof": "1.1.0", 130 | "statuses": "1.3.1", 131 | "type-is": "1.6.15", 132 | "utils-merge": "1.0.1", 133 | "vary": "1.1.2" 134 | } 135 | }, 136 | "finalhandler": { 137 | "version": "1.1.0", 138 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", 139 | "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", 140 | "requires": { 141 | "debug": "2.6.9", 142 | "encodeurl": "1.0.1", 143 | "escape-html": "1.0.3", 144 | "on-finished": "2.3.0", 145 | "parseurl": "1.3.2", 146 | "statuses": "1.3.1", 147 | "unpipe": "1.0.0" 148 | } 149 | }, 150 | "forwarded": { 151 | "version": "0.1.2", 152 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 153 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 154 | }, 155 | "fresh": { 156 | "version": "0.5.2", 157 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 158 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 159 | }, 160 | "http-errors": { 161 | "version": "1.6.2", 162 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", 163 | "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", 164 | "requires": { 165 | "depd": "1.1.1", 166 | "inherits": "2.0.3", 167 | "setprototypeof": "1.0.3", 168 | "statuses": "1.3.1" 169 | }, 170 | "dependencies": { 171 | "setprototypeof": { 172 | "version": "1.0.3", 173 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", 174 | "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" 175 | } 176 | } 177 | }, 178 | "iconv-lite": { 179 | "version": "0.4.19", 180 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", 181 | "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" 182 | }, 183 | "inherits": { 184 | "version": "2.0.3", 185 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 186 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 187 | }, 188 | "ipaddr.js": { 189 | "version": "1.5.2", 190 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz", 191 | "integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A=" 192 | }, 193 | "media-typer": { 194 | "version": "0.3.0", 195 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 196 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 197 | }, 198 | "merge-descriptors": { 199 | "version": "1.0.1", 200 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 201 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 202 | }, 203 | "methods": { 204 | "version": "1.1.2", 205 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 206 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 207 | }, 208 | "mime": { 209 | "version": "1.4.1", 210 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", 211 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" 212 | }, 213 | "mime-db": { 214 | "version": "1.30.0", 215 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", 216 | "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" 217 | }, 218 | "mime-types": { 219 | "version": "2.1.17", 220 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", 221 | "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", 222 | "requires": { 223 | "mime-db": "1.30.0" 224 | } 225 | }, 226 | "ms": { 227 | "version": "2.0.0", 228 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 229 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 230 | }, 231 | "negotiator": { 232 | "version": "0.6.1", 233 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", 234 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" 235 | }, 236 | "on-finished": { 237 | "version": "2.3.0", 238 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 239 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 240 | "requires": { 241 | "ee-first": "1.1.1" 242 | } 243 | }, 244 | "parseurl": { 245 | "version": "1.3.2", 246 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", 247 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" 248 | }, 249 | "path-to-regexp": { 250 | "version": "0.1.7", 251 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 252 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 253 | }, 254 | "proxy-addr": { 255 | "version": "2.0.2", 256 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz", 257 | "integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=", 258 | "requires": { 259 | "forwarded": "0.1.2", 260 | "ipaddr.js": "1.5.2" 261 | } 262 | }, 263 | "qs": { 264 | "version": "6.5.1", 265 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", 266 | "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" 267 | }, 268 | "range-parser": { 269 | "version": "1.2.0", 270 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", 271 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" 272 | }, 273 | "raw-body": { 274 | "version": "2.3.2", 275 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", 276 | "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", 277 | "requires": { 278 | "bytes": "3.0.0", 279 | "http-errors": "1.6.2", 280 | "iconv-lite": "0.4.19", 281 | "unpipe": "1.0.0" 282 | } 283 | }, 284 | "safe-buffer": { 285 | "version": "5.1.1", 286 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 287 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 288 | }, 289 | "send": { 290 | "version": "0.16.1", 291 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz", 292 | "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==", 293 | "requires": { 294 | "debug": "2.6.9", 295 | "depd": "1.1.1", 296 | "destroy": "1.0.4", 297 | "encodeurl": "1.0.1", 298 | "escape-html": "1.0.3", 299 | "etag": "1.8.1", 300 | "fresh": "0.5.2", 301 | "http-errors": "1.6.2", 302 | "mime": "1.4.1", 303 | "ms": "2.0.0", 304 | "on-finished": "2.3.0", 305 | "range-parser": "1.2.0", 306 | "statuses": "1.3.1" 307 | } 308 | }, 309 | "serve-static": { 310 | "version": "1.13.1", 311 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz", 312 | "integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==", 313 | "requires": { 314 | "encodeurl": "1.0.1", 315 | "escape-html": "1.0.3", 316 | "parseurl": "1.3.2", 317 | "send": "0.16.1" 318 | } 319 | }, 320 | "setprototypeof": { 321 | "version": "1.1.0", 322 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", 323 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" 324 | }, 325 | "statuses": { 326 | "version": "1.3.1", 327 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", 328 | "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" 329 | }, 330 | "type-is": { 331 | "version": "1.6.15", 332 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", 333 | "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", 334 | "requires": { 335 | "media-typer": "0.3.0", 336 | "mime-types": "2.1.17" 337 | } 338 | }, 339 | "unpipe": { 340 | "version": "1.0.0", 341 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 342 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 343 | }, 344 | "utils-merge": { 345 | "version": "1.0.1", 346 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 347 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 348 | }, 349 | "vary": { 350 | "version": "1.1.2", 351 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 352 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 353 | } 354 | } 355 | } 356 | -------------------------------------------------------------------------------- /packages/createrest/test/index.test.js: -------------------------------------------------------------------------------- 1 | import avaTest from 'ava' 2 | import { createRest } from '../lib' 3 | import { createRestInstanceSymbol } from '../lib/symbol' 4 | 5 | 6 | const get = () => {} 7 | const post = () => {} 8 | const put = () => {} 9 | const patch = () => {} 10 | const destroy = () => {} 11 | const before = () => {} 12 | const after = () => {} 13 | 14 | const ObjectController = { 15 | create() {}, 16 | read() {}, 17 | update() {}, 18 | destroy() {}, 19 | } 20 | 21 | const make = (before = [], after = [], local = {}, scoped = {}) => ({ 22 | before, 23 | after, 24 | local, 25 | scoped, 26 | [createRestInstanceSymbol]: true, 27 | }) 28 | 29 | avaTest('Creates base structure', (test) => { 30 | test.deepEqual( 31 | createRest((r) => {}), 32 | make() 33 | ) 34 | }) 35 | 36 | avaTest('createRest fails if a function is not passed', (test) => { 37 | test.throws(() => { 38 | createRest(null) 39 | }) 40 | test.throws(() => { 41 | createRest({}) 42 | }) 43 | test.throws(() => { 44 | createRest([]) 45 | }) 46 | test.throws(() => { 47 | createRest(true) 48 | }) 49 | test.throws(() => { 50 | createRest(1) 51 | }) 52 | test.throws(() => { 53 | createRest('') 54 | }) 55 | test.throws(() => { 56 | createRest() 57 | }) 58 | }) 59 | 60 | avaTest('Creates before', (test) => { 61 | test.deepEqual( 62 | createRest((root) => { 63 | root.beforeEach(before) 64 | }), 65 | make([before]) 66 | ) 67 | }) 68 | 69 | avaTest('Creates after', (test) => { 70 | test.deepEqual( 71 | createRest((root) => { 72 | root.afterEach(after) 73 | }), 74 | make([], [after]) 75 | ) 76 | }) 77 | 78 | avaTest('Creates methods', (test) => { 79 | test.deepEqual( 80 | createRest((root) => { 81 | root.get(get) 82 | root.post(post) 83 | root.put(put) 84 | root.patch('/', patch) 85 | root.delete('/', destroy) 86 | }), 87 | make([], [], { 88 | POST: [post], 89 | GET: [get], 90 | PUT: [put], 91 | PATCH: [patch], 92 | DELETE: [destroy], 93 | }) 94 | ) 95 | }) 96 | 97 | avaTest('Creates methods with before/after', (test) => { 98 | test.deepEqual( 99 | createRest((root) => { 100 | root.beforeEach(before) 101 | root.afterEach(after) 102 | root.get('/', get) 103 | root.post('/', post) 104 | root.put('/', put) 105 | root.patch('/', patch) 106 | root.delete('/', destroy) 107 | }), 108 | make([before], [after], { 109 | POST: [post], 110 | GET: [get], 111 | PUT: [put], 112 | PATCH: [patch], 113 | DELETE: [destroy], 114 | }) 115 | ) 116 | }) 117 | 118 | avaTest('Creates simple scoping', (test) => { 119 | test.deepEqual( 120 | createRest((root) => { 121 | root.scope('demo', (demo) => { 122 | }) 123 | }), 124 | make([], [], {}, { 125 | demo: make(), 126 | }) 127 | ) 128 | }) 129 | 130 | avaTest('Creates scoped methods', (test) => { 131 | test.deepEqual( 132 | createRest((root) => { 133 | root.scope('demo', (demo) => { 134 | demo.get('/', get) 135 | demo.post('/', post) 136 | demo.put('/', put) 137 | demo.patch('/', patch) 138 | demo.delete('/', destroy) 139 | }) 140 | }), 141 | make([], [], {}, { 142 | demo: make([], [], { 143 | POST: [post], 144 | GET: [get], 145 | PUT: [put], 146 | PATCH: [patch], 147 | DELETE: [destroy], 148 | }), 149 | }) 150 | ) 151 | }) 152 | 153 | avaTest('Creates before/after in a scope', (test) => { 154 | test.deepEqual( 155 | createRest((root) => { 156 | root.beforeEach(before) 157 | root.afterEach(after) 158 | root.scope('demo', (demo) => { 159 | demo.beforeEach(before) 160 | demo.afterEach(after) 161 | demo.get('/', get) 162 | demo.post('/', post) 163 | demo.put('/', put) 164 | }) 165 | root.patch('/', patch) 166 | root.delete('/', destroy) 167 | }), 168 | make( 169 | [before], [after], 170 | { 171 | PATCH: [patch], 172 | DELETE: [destroy], 173 | }, 174 | { 175 | demo: make([before], [after], { 176 | POST: [post], 177 | GET: [get], 178 | PUT: [put], 179 | }), 180 | } 181 | ) 182 | ) 183 | }) 184 | 185 | avaTest('Creates deep scope', (test) => { 186 | test.deepEqual( 187 | createRest((root) => { 188 | root.scope('foo', (foo) => { 189 | foo.scope('bar', (bar) => { 190 | bar.get('/', get) 191 | }) 192 | }) 193 | }), 194 | make([], [], {}, 195 | { 196 | foo: make([], [], {}, { 197 | bar: make([], [], { 198 | GET: [get], 199 | }), 200 | }), 201 | } 202 | ) 203 | ) 204 | }) 205 | 206 | avaTest('Creates scoped by methods', (test) => { 207 | test.deepEqual( 208 | createRest((root) => { 209 | root.post('/foo', post, post) 210 | root.get('bar', get, get) 211 | }), 212 | make([], [], {}, { 213 | foo: make([], [], { POST: [post, post] }), 214 | bar: make([], [], { GET: [get, get] }), 215 | }) 216 | ) 217 | }) 218 | 219 | avaTest('Attaches local methods', (test) => { 220 | test.deepEqual( 221 | createRest((root) => { 222 | root.get('/bar', get) 223 | root.get('bar', get, get) 224 | }), 225 | make([], [], {}, { 226 | bar: make([], [], { GET: [get, get, get] }), 227 | }) 228 | ) 229 | }) 230 | 231 | avaTest('Fails for wrong scope name', (test) => { 232 | test.throws(() => { 233 | createRest((root) => { 234 | root.scope('', () => {}) 235 | }) 236 | }) 237 | test.throws(() => { 238 | createRest((root) => { 239 | root.scope(null, () => {}) 240 | }) 241 | }) 242 | test.throws(() => { 243 | createRest((root) => { 244 | root.scope('/', () => {}) 245 | }) 246 | }) 247 | }) 248 | 249 | avaTest('Fails if deep path to a method is passed', (test) => { 250 | test.throws(() => { 251 | createRest((root) => { 252 | root.post('foo/bar', post) 253 | }) 254 | }) 255 | }) 256 | 257 | avaTest('Fails if no listeners are passed to a method', (test) => { 258 | test.throws(() => { 259 | createRest((root) => { 260 | root.put('demo') 261 | }) 262 | }) 263 | }) 264 | 265 | avaTest('Creates simple crud with default options', (test) => { 266 | test.deepEqual( 267 | createRest((root) => { 268 | root.crud('unicorn', ObjectController) 269 | }), 270 | make([], [], {}, { 271 | unicorn: make([], [], { 272 | GET: [ObjectController.read], 273 | POST: [ObjectController.create], 274 | PUT: [ObjectController.update], 275 | DELETE: [ObjectController.destroy], 276 | }), 277 | }) 278 | ) 279 | }) 280 | 281 | avaTest('Creates crud with partial controller and before/after', (test) => { 282 | const Controller = Object.assign({}, ObjectController, { 283 | beforeEach: before, 284 | afterEach: after, 285 | create: undefined, 286 | }) 287 | test.deepEqual( 288 | createRest((root) => { 289 | root.crud('unicorn', Controller) 290 | }), 291 | make([], [], {}, { 292 | unicorn: make([before], [after], { 293 | GET: [ObjectController.read], 294 | PUT: [ObjectController.update], 295 | DELETE: [ObjectController.destroy], 296 | }), 297 | }) 298 | ) 299 | }) 300 | 301 | 302 | avaTest('Fails for crud with default options', (test) => { 303 | test.deepEqual( 304 | createRest((root) => { 305 | root.crud('unicorn') 306 | }), 307 | make() 308 | ) 309 | 310 | test.throws(() => { 311 | createRest((root) => { 312 | root.crud() 313 | }) 314 | }) 315 | }) 316 | 317 | avaTest('Creaets crud with options.only', (test) => { 318 | test.deepEqual( 319 | createRest((root) => { 320 | root.crud('unicorn', ObjectController, { only: ['create'] }) 321 | }), 322 | make([], [], {}, { 323 | unicorn: make([], [], { 324 | POST: [ObjectController.create], 325 | }), 326 | }) 327 | ) 328 | }) 329 | 330 | avaTest('Creates crud with options.except', (test) => { 331 | test.deepEqual( 332 | createRest((root) => { 333 | root.crud('unicorn', ObjectController, { except: ['create'] }) 334 | }), 335 | make([], [], {}, { 336 | unicorn: make([], [], { 337 | GET: [ObjectController.read], 338 | PUT: [ObjectController.update], 339 | DELETE: [ObjectController.destroy], 340 | }), 341 | }) 342 | ) 343 | }) 344 | 345 | avaTest('Creates crud with options.methodNames', (test) => { 346 | const RenamedController = { 347 | first() {}, 348 | second() {}, 349 | third() {}, 350 | fourth() {}, 351 | } 352 | test.deepEqual( 353 | createRest((root) => { 354 | root.crud('unicorn', RenamedController, { 355 | methodNames: { read: 'first', create: 'second', update: 'third', destroy: 'fourth' }, 356 | }) 357 | }), 358 | make([], [], {}, { 359 | unicorn: make([], [], { 360 | GET: [RenamedController.first], 361 | POST: [RenamedController.second], 362 | PUT: [RenamedController.third], 363 | DELETE: [RenamedController.fourth], 364 | }), 365 | }) 366 | ) 367 | }) 368 | 369 | avaTest('Creates crud in scope', (test) => { 370 | test.deepEqual( 371 | createRest((root) => { 372 | root.scope('rainbow', (rainbow) => { 373 | rainbow.crud('unicorn', ObjectController, { except: ['create'] }) 374 | }) 375 | }), 376 | make([], [], {}, { 377 | rainbow: make([], [], {}, { 378 | unicorn: make([], [], { 379 | GET: [ObjectController.read], 380 | PUT: [ObjectController.update], 381 | DELETE: [ObjectController.destroy], 382 | }), 383 | }), 384 | }) 385 | ) 386 | }) 387 | 388 | avaTest('Merge scopes with the same name', (test) => { 389 | test.deepEqual( 390 | createRest((root) => { 391 | root.scope('foo', (foo) => { 392 | foo.get('bar', get) 393 | }) 394 | root.scope('foo', (foo) => { 395 | foo.post('baz', post) 396 | }) 397 | }), 398 | make([], [], {}, { 399 | foo: make([], [], {}, { 400 | baz: make([], [], { POST: [post] }), 401 | bar: make([], [], { GET: [get] }), 402 | }), 403 | }) 404 | ) 405 | }) 406 | 407 | avaTest('Crud with child scope', (test) => { 408 | const spy = () => {} 409 | test.deepEqual( 410 | createRest((root) => { 411 | root.scope('rainbow', (rainbow) => { 412 | rainbow.crud('unicorn', ObjectController, {}, (unicorn) => { 413 | unicorn.get('excellent', spy) 414 | }) 415 | }) 416 | }), 417 | make([], [], {}, { 418 | rainbow: make([], [], {}, { 419 | unicorn: make([], [], { 420 | POST: [ObjectController.create], 421 | GET: [ObjectController.read], 422 | PUT: [ObjectController.update], 423 | DELETE: [ObjectController.destroy], 424 | }, { 425 | excellent: make([], [], { 426 | GET: [spy], 427 | }), 428 | }), 429 | }), 430 | }) 431 | ) 432 | }) 433 | 434 | const DefaultController = { 435 | beforeEach() {}, 436 | afterEach() {}, 437 | index() {}, 438 | create() {}, 439 | read() {}, 440 | update() {}, 441 | patch() {}, 442 | destroy() {}, 443 | } 444 | 445 | avaTest('Resources with default', (test) => { 446 | test.deepEqual( 447 | createRest((root) => { 448 | root.resources('books', DefaultController) 449 | }), 450 | make([], [], {}, { 451 | books: make( 452 | [DefaultController.beforeEach], 453 | [DefaultController.afterEach], 454 | { 455 | GET: [DefaultController.index], POST: [DefaultController.create], 456 | }, 457 | { 458 | ':bookId': make([], [], { 459 | GET: [DefaultController.read], 460 | PUT: [DefaultController.update], 461 | PATCH: [DefaultController.patch], 462 | DELETE: [DefaultController.destroy], 463 | }), 464 | } 465 | ), 466 | }) 467 | ) 468 | }) 469 | 470 | avaTest('Resource with empty controller', (test) => { 471 | test.deepEqual( 472 | createRest((root) => { 473 | root.resources('books', {}) 474 | }), 475 | make([], [], {}, { 476 | books: make([], [], {}, { 477 | ':bookId': make(), 478 | }), 479 | }) 480 | ) 481 | }) 482 | 483 | avaTest('Resources with only', (test) => { 484 | test.deepEqual( 485 | createRest((root) => { 486 | root.resources('books', DefaultController, { only: ['index', 'read'] }) 487 | }), 488 | make([], [], {}, { 489 | books: make( 490 | [DefaultController.beforeEach], 491 | [DefaultController.afterEach], 492 | { 493 | GET: [DefaultController.index], 494 | }, 495 | { 496 | ':bookId': make([], [], { 497 | GET: [DefaultController.read], 498 | }), 499 | } 500 | ), 501 | }) 502 | ) 503 | }) 504 | 505 | avaTest('Resources with except', (test) => { 506 | test.deepEqual( 507 | createRest((root) => { 508 | root.resources('books', DefaultController, { except: ['index', 'read', 'update'] }) 509 | }), 510 | make([], [], {}, { 511 | books: make( 512 | [DefaultController.beforeEach], 513 | [DefaultController.afterEach], 514 | { 515 | POST: [DefaultController.create], 516 | }, 517 | { 518 | ':bookId': make([], [], { 519 | PATCH: [DefaultController.patch], 520 | DELETE: [DefaultController.destroy], 521 | }), 522 | } 523 | ), 524 | }) 525 | ) 526 | }) 527 | 528 | avaTest('Resources with patch/update case', (test) => { 529 | test.deepEqual( 530 | createRest((root) => { 531 | root.resources('books', Object.assign({}, DefaultController, { patch: undefined })) 532 | }), 533 | make([], [], {}, { 534 | books: make( 535 | [DefaultController.beforeEach], 536 | [DefaultController.afterEach], 537 | { 538 | GET: [DefaultController.index], POST: [DefaultController.create], 539 | }, 540 | { 541 | ':bookId': make([], [], { 542 | GET: [DefaultController.read], 543 | PUT: [DefaultController.update], 544 | PATCH: [DefaultController.update], 545 | DELETE: [DefaultController.destroy], 546 | }), 547 | } 548 | ), 549 | }) 550 | ) 551 | }) 552 | 553 | avaTest('Resources with patch/update case w/o update()', (test) => { 554 | test.deepEqual( 555 | createRest((root) => { 556 | root.resources('books', Object.assign({}, DefaultController, { patch: undefined, update: undefined })) 557 | }), 558 | make([], [], {}, { 559 | books: make( 560 | [DefaultController.beforeEach], 561 | [DefaultController.afterEach], 562 | { 563 | GET: [DefaultController.index], POST: [DefaultController.create], 564 | }, 565 | { 566 | ':bookId': make([], [], { 567 | GET: [DefaultController.read], 568 | DELETE: [DefaultController.destroy], 569 | }), 570 | } 571 | ), 572 | }) 573 | ) 574 | }) 575 | 576 | avaTest('Resources with memberId option', (test) => { 577 | test.deepEqual( 578 | createRest((root) => { 579 | root.resources('books', DefaultController, { memberId: 'demoId' }) 580 | }), 581 | make([], [], {}, { 582 | books: make( 583 | [DefaultController.beforeEach], 584 | [DefaultController.afterEach], 585 | { 586 | GET: [DefaultController.index], POST: [DefaultController.create], 587 | }, 588 | { 589 | ':demoId': make([], [], { 590 | GET: [DefaultController.read], 591 | PUT: [DefaultController.update], 592 | PATCH: [DefaultController.patch], 593 | DELETE: [DefaultController.destroy], 594 | }), 595 | } 596 | ), 597 | }) 598 | ) 599 | }) 600 | 601 | 602 | avaTest('Resources with patch in only and w/o patch(), update() methods', (test) => { 603 | test.deepEqual( 604 | createRest((root) => { 605 | root.resources( 606 | 'books', 607 | Object.assign({}, DefaultController, { patch: undefined, update: undefined }), 608 | { only: ['patch'] } 609 | ) 610 | }), 611 | make([], [], {}, { 612 | books: make( 613 | [DefaultController.beforeEach], 614 | [DefaultController.afterEach], 615 | { 616 | }, 617 | { 618 | ':bookId': make([], [], { 619 | }), 620 | } 621 | ), 622 | }) 623 | ) 624 | }) 625 | 626 | avaTest('Resources should be named', (test) => { 627 | test.throws(() => { 628 | createRest((root) => { 629 | root.resources() 630 | }, /Resources should be named/, 'unnamed resources not throws') 631 | }) 632 | }) 633 | 634 | avaTest('Resources controller should be object', (test) => { 635 | test.throws(() => { 636 | createRest((root) => { 637 | root.resources('ex', null) 638 | }) 639 | }, /Controller should be object/, 'null not throws') 640 | test.throws(() => { 641 | createRest((root) => { 642 | root.resources('ex', () => {}) 643 | }) 644 | }, /Controller should be object/, 'function not throws') 645 | test.throws(() => { 646 | createRest((root) => { 647 | root.resources('ex', 1) 648 | }) 649 | }, /Controller should be object/, 'number not throws') 650 | }) 651 | 652 | avaTest('Resources cannot use only and expect at the same time', (test) => { 653 | test.throws(() => { 654 | createRest((root) => { 655 | root.resources('demo', {}, { only: [], except: [] }) 656 | }) 657 | }, /You can't use/, 'except and only not throws') 658 | }) 659 | 660 | avaTest('Resources with shallow creator with empty options', (test) => { 661 | test.deepEqual( 662 | createRest((root) => { 663 | root.resources('books', DefaultController, {}, (books) => { 664 | books.get('status', get) 665 | }) 666 | }), 667 | make([], [], {}, { 668 | books: make( 669 | [DefaultController.beforeEach], 670 | [DefaultController.afterEach], 671 | { 672 | GET: [DefaultController.index], POST: [DefaultController.create], 673 | }, 674 | { 675 | ':bookId': make([], [], { 676 | GET: [DefaultController.read], 677 | PUT: [DefaultController.update], 678 | PATCH: [DefaultController.patch], 679 | DELETE: [DefaultController.destroy], 680 | }), 681 | status: make([], [], { 682 | GET: [get], 683 | }), 684 | } 685 | ), 686 | }) 687 | ) 688 | }) 689 | 690 | avaTest('Resources with shallow creator instead of options', (test) => { 691 | test.deepEqual( 692 | createRest((root) => { 693 | root.resources('books', DefaultController, (books) => { 694 | books.get('status', get) 695 | }) 696 | }), 697 | make([], [], {}, { 698 | books: make( 699 | [DefaultController.beforeEach], 700 | [DefaultController.afterEach], 701 | { 702 | GET: [DefaultController.index], POST: [DefaultController.create], 703 | }, 704 | { 705 | ':bookId': make([], [], { 706 | GET: [DefaultController.read], 707 | PUT: [DefaultController.update], 708 | PATCH: [DefaultController.patch], 709 | DELETE: [DefaultController.destroy], 710 | }), 711 | status: make([], [], { 712 | GET: [get], 713 | }), 714 | } 715 | ), 716 | }) 717 | ) 718 | }) 719 | 720 | avaTest('Resources with scope:memberId creator', (test) => { 721 | test.deepEqual( 722 | createRest((root) => { 723 | root.resources('books', DefaultController, {}, (books) => { 724 | books.get('status', get) 725 | books.scope(':bookId', (bookId) => { 726 | bookId.get('details', get) 727 | }) 728 | }) 729 | }), 730 | make([], [], {}, { 731 | books: make( 732 | [DefaultController.beforeEach], 733 | [DefaultController.afterEach], 734 | { 735 | GET: [DefaultController.index], POST: [DefaultController.create], 736 | }, 737 | { 738 | ':bookId': make([], [], 739 | { 740 | GET: [DefaultController.read], 741 | PUT: [DefaultController.update], 742 | PATCH: [DefaultController.patch], 743 | DELETE: [DefaultController.destroy], 744 | }, 745 | { 746 | details: make([], [], { GET: [get] }), 747 | } 748 | ), 749 | status: make([], [], { 750 | GET: [get], 751 | }), 752 | } 753 | ), 754 | }) 755 | ) 756 | }) 757 | 758 | avaTest('Resources with memberId creator with renamed memberId', (test) => { 759 | test.deepEqual( 760 | createRest((root) => { 761 | root.resources('books', DefaultController, { memberId: 'demoId' }, (books) => { 762 | books.get('status', get) 763 | books.scope(':demoId', (bookId) => { 764 | bookId.get('details', get) 765 | }) 766 | }) 767 | }), 768 | make([], [], {}, { 769 | books: make( 770 | [DefaultController.beforeEach], 771 | [DefaultController.afterEach], 772 | { 773 | GET: [DefaultController.index], POST: [DefaultController.create], 774 | }, 775 | { 776 | ':demoId': make([], [], 777 | { 778 | GET: [DefaultController.read], 779 | PUT: [DefaultController.update], 780 | PATCH: [DefaultController.patch], 781 | DELETE: [DefaultController.destroy], 782 | }, 783 | { 784 | details: make([], [], { GET: [get] }), 785 | } 786 | ), 787 | status: make([], [], { 788 | GET: [get], 789 | }), 790 | } 791 | ), 792 | }) 793 | ) 794 | }) 795 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | 2 | # [](https://github.com/atomixinteractions/createrest/compare/v0.15.0...v) (2018-01-30) 3 | 4 | 5 | 6 | 7 | # [0.15.0](https://github.com/atomixinteractions/createrest/compare/v0.14.2...v0.15.0) (2018-01-30) 8 | 9 | 10 | ### Build system 11 | 12 | * Refactor changelog building ([79e114f](https://github.com/atomixinteractions/createrest/commit/79e114f)) 13 | 14 | 15 | ### Code Refactoring 16 | 17 | * fix linter issues ([fb9e68e](https://github.com/atomixinteractions/createrest/commit/fb9e68e)) 18 | 19 | 20 | ### Documentation 21 | 22 | * update versions and links in packages ([70a0555](https://github.com/atomixinteractions/createrest/commit/70a0555)) 23 | 24 | 25 | ### Features 26 | 27 | * add conventional-changelog and cz-customizable ([d8bcd18](https://github.com/atomixinteractions/createrest/commit/d8bcd18)) 28 | * upgrade root dependencies ([3b79eb7](https://github.com/atomixinteractions/createrest/commit/3b79eb7)) 29 | * **createrest-koa:** update koa-router version ([dfbeaf6](https://github.com/atomixinteractions/createrest/commit/dfbeaf6)) 30 | 31 | 32 | 33 | 34 | ## [0.14.2](https://github.com/atomixinteractions/createrest/compare/v0.14.1...v0.14.2) (2017-12-26) 35 | 36 | 37 | ### Build system 38 | 39 | * Update dependencies and add changelog ([79432a4](https://github.com/atomixinteractions/createrest/commit/79432a4)) 40 | 41 | 42 | ### Chores 43 | 44 | * Add conventional changelog ([4dccd7c](https://github.com/atomixinteractions/createrest/commit/4dccd7c)) 45 | 46 | 47 | ### Documentation 48 | 49 | * **quick-guide:** Add quick guide page ([7410d03](https://github.com/atomixinteractions/createrest/commit/7410d03)) 50 | 51 | 52 | 53 | 54 | ## [0.14.1](https://github.com/atomixinteractions/createrest/compare/v0.14.0...v0.14.1) (2017-11-27) 55 | 56 | 57 | ### Chores 58 | 59 | * Regenerate package-lock files ([398f1f2](https://github.com/atomixinteractions/createrest/commit/398f1f2)) 60 | 61 | 62 | ### Tests 63 | 64 | * **createrest-express:** Add real tests with supertest ([ae871e7](https://github.com/atomixinteractions/createrest/commit/ae871e7)) 65 | * **createrest-express:** Add tests for server answer ([edd082f](https://github.com/atomixinteractions/createrest/commit/edd082f)) 66 | * **createrest-koa:** Add tests for scope, beforeEach, afterEach ([50a72e2](https://github.com/atomixinteractions/createrest/commit/50a72e2)) 67 | * **createrest-koa:** Test createKoaRouter ([22b9f74](https://github.com/atomixinteractions/createrest/commit/22b9f74)) 68 | 69 | 70 | 71 | 72 | # [0.14.0](https://github.com/atomixinteractions/createrest/compare/v0.13.0...v0.14.0) (2017-11-24) 73 | 74 | 75 | ### Chores 76 | 77 | * Update dependencies ([4584915](https://github.com/atomixinteractions/createrest/commit/4584915)) 78 | 79 | 80 | ### Documentation 81 | 82 | * **esdoc:** Update configuration ([d26f19d](https://github.com/atomixinteractions/createrest/commit/d26f19d)) 83 | * Add manual pages ([8242539](https://github.com/atomixinteractions/createrest/commit/8242539)) 84 | * **manual:** Add more manual pages (handlers, installation) ([20e7007](https://github.com/atomixinteractions/createrest/commit/20e7007)) 85 | 86 | 87 | 88 | 89 | # [0.13.0](https://github.com/atomixinteractions/createrest/compare/v0.12.0...v0.13.0) (2017-10-13) 90 | 91 | 92 | * Update linter ([53ea1b2](https://github.com/atomixinteractions/createrest/commit/53ea1b2)) 93 | * Update dependencies ([de52e7d](https://github.com/atomixinteractions/createrest/commit/de52e7d)) 94 | 95 | 96 | ### Bug Fixes 97 | 98 | * Fix building ([f4879ec](https://github.com/atomixinteractions/createrest/commit/f4879ec)) 99 | 100 | 101 | ### Build system 102 | 103 | * Refactor dependencies tree ([7b15ff5](https://github.com/atomixinteractions/createrest/commit/7b15ff5)) 104 | 105 | 106 | ### Styles 107 | 108 | * **createrest:** Update dependencies and linter ([5b2c10e](https://github.com/atomixinteractions/createrest/commit/5b2c10e)) 109 | * **createrest-express:** Update dependencies ([ba5169d](https://github.com/atomixinteractions/createrest/commit/ba5169d)) 110 | * **createrest-koa:** Update dependencies ([d22b078](https://github.com/atomixinteractions/createrest/commit/d22b078)) 111 | 112 | 113 | 114 | 115 | # [0.12.0](https://github.com/atomixinteractions/createrest/compare/v0.11.0...v0.12.0) (2017-07-19) 116 | 117 | 118 | * Add coveralls file for createrest-koa ([15cb5ca](https://github.com/atomixinteractions/createrest/commit/15cb5ca)) 119 | * Add creator for resources. #11 ([3fecc44](https://github.com/atomixinteractions/createrest/commit/3fecc44)), closes [#11](https://github.com/atomixinteractions/createrest/issues/11) 120 | 121 | 122 | 123 | 124 | # [0.11.0](https://github.com/atomixinteractions/createrest/compare/v0.10.6...v0.11.0) (2017-07-19) 125 | 126 | 127 | * Merge scopes with the same name. #11 ([03fbd74](https://github.com/atomixinteractions/createrest/commit/03fbd74)), closes [#11](https://github.com/atomixinteractions/createrest/issues/11) 128 | 129 | 130 | 131 | 132 | ## [0.10.6](https://github.com/atomixinteractions/createrest/compare/v0.10.2...v0.10.6) (2017-07-12) 133 | 134 | 135 | * Replace buildbranch to gh-pages ([c4b0ce7](https://github.com/atomixinteractions/createrest/commit/c4b0ce7)) 136 | * Run test in travis on node@8 ([cad3d42](https://github.com/atomixinteractions/createrest/commit/cad3d42)) 137 | * Finalize lockfile ([2a557be](https://github.com/atomixinteractions/createrest/commit/2a557be)) 138 | * Update npm script to fix install ([3c671e9](https://github.com/atomixinteractions/createrest/commit/3c671e9)) 139 | * Move package dep to peerDeps ([1d8da8b](https://github.com/atomixinteractions/createrest/commit/1d8da8b)) 140 | * Fix deps ([21dc251](https://github.com/atomixinteractions/createrest/commit/21dc251)) 141 | * Fix koa peer deps ([b64b72c](https://github.com/atomixinteractions/createrest/commit/b64b72c)) 142 | * [BROKEN] package crossdeps ([7bbefe4](https://github.com/atomixinteractions/createrest/commit/7bbefe4)) 143 | * Change dependent versions ([752421a](https://github.com/atomixinteractions/createrest/commit/752421a)) 144 | * Fix <hr> color for esdocs ([b358a0a](https://github.com/atomixinteractions/createrest/commit/b358a0a)) 145 | * Fix readme for packages ([4b9b78f](https://github.com/atomixinteractions/createrest/commit/4b9b78f)) 146 | * Come back to single version of all ([205ee5c](https://github.com/atomixinteractions/createrest/commit/205ee5c)) 147 | * Publish ([4c3037e](https://github.com/atomixinteractions/createrest/commit/4c3037e)) 148 | * Update readme.md ([b1af8cf](https://github.com/atomixinteractions/createrest/commit/b1af8cf)) 149 | * Fix readme ([0b8f304](https://github.com/atomixinteractions/createrest/commit/0b8f304)) 150 | * Publish ([48b3f00](https://github.com/atomixinteractions/createrest/commit/48b3f00)) 151 | * Fix ignore files ([668ff65](https://github.com/atomixinteractions/createrest/commit/668ff65)) 152 | * Publish ([96fd409](https://github.com/atomixinteractions/createrest/commit/96fd409)) 153 | * Move to independent versioning ([af90f80](https://github.com/atomixinteractions/createrest/commit/af90f80)) 154 | * Import createrest-koa ([ab50e15](https://github.com/atomixinteractions/createrest/commit/ab50e15)) 155 | * Import createrest-koa ([b72f460](https://github.com/atomixinteractions/createrest/commit/b72f460)) 156 | * Add forgotten files ([e55f774](https://github.com/atomixinteractions/createrest/commit/e55f774)) 157 | 158 | 159 | 160 | 161 | ## [0.10.2](https://github.com/atomixinteractions/createrest/compare/v0.10.1...v0.10.2) (2017-07-04) 162 | 163 | 164 | * Imported createrest-express ([83de9b1](https://github.com/atomixinteractions/createrest/commit/83de9b1)) 165 | 166 | 167 | 168 | 169 | ## [0.10.1](https://github.com/atomixinteractions/createrest/compare/v0.10.0...v0.10.1) (2017-07-04) 170 | 171 | 172 | * Update publish scripts ([0e544b1](https://github.com/atomixinteractions/createrest/commit/0e544b1)) 173 | * Fix comment typo ([1da3f9c](https://github.com/atomixinteractions/createrest/commit/1da3f9c)) 174 | * Fix run script ([035e725](https://github.com/atomixinteractions/createrest/commit/035e725)) 175 | * Publish in one command ([b7362f6](https://github.com/atomixinteractions/createrest/commit/b7362f6)) 176 | * vundefined ([a207aa0](https://github.com/atomixinteractions/createrest/commit/a207aa0)) 177 | * Update publish scripts ([d9aedd1](https://github.com/atomixinteractions/createrest/commit/d9aedd1)) 178 | * Move to lerna ([694fd2f](https://github.com/atomixinteractions/createrest/commit/694fd2f)) 179 | * Move createrest to packages ([de1cc50](https://github.com/atomixinteractions/createrest/commit/de1cc50)) 180 | * Resources small example file ([7fb7f05](https://github.com/atomixinteractions/createrest/commit/7fb7f05)) 181 | * Add more examples for resour ([21e5e20](https://github.com/atomixinteractions/createrest/commit/21e5e20)) 182 | 183 | 184 | 185 | 186 | # [0.10.0](https://github.com/atomixinteractions/createrest/compare/v0.9.0...v0.10.0) (2017-07-03) 187 | 188 | 189 | * Improve docs and tests ([a4b6e8d](https://github.com/atomixinteractions/createrest/commit/a4b6e8d)) 190 | * Test resources exceptions ([e21a55a](https://github.com/atomixinteractions/createrest/commit/e21a55a)) 191 | * Add creator to .crud(). Add more docs ([d3f5f81](https://github.com/atomixinteractions/createrest/commit/d3f5f81)) 192 | * Latest esdoc stylesheet fixes ([e87128e](https://github.com/atomixinteractions/createrest/commit/e87128e)) 193 | * Ignore private method ([5657d03](https://github.com/atomixinteractions/createrest/commit/5657d03)) 194 | * Improve jsdoc docs ([a1235fa](https://github.com/atomixinteractions/createrest/commit/a1235fa)) 195 | * Improve esdoc styles ([3672698](https://github.com/atomixinteractions/createrest/commit/3672698)) 196 | * Refactor examples ([dcddef7](https://github.com/atomixinteractions/createrest/commit/dcddef7)) 197 | 198 | 199 | 200 | 201 | # [0.9.0](https://github.com/atomixinteractions/createrest/compare/v0.8.3...v0.9.0) (2017-07-01) 202 | 203 | 204 | * Add tests for resources() ([abc17bc](https://github.com/atomixinteractions/createrest/commit/abc17bc)) 205 | * Fix resoures creation of memberId ([125ff86](https://github.com/atomixinteractions/createrest/commit/125ff86)) 206 | * Update dependencies ([74746c4](https://github.com/atomixinteractions/createrest/commit/74746c4)) 207 | * Remove `before`/`after` aliases ([c3af94e](https://github.com/atomixinteractions/createrest/commit/c3af94e)) 208 | * Rename `resource()` to `crud()` ([83e6256](https://github.com/atomixinteractions/createrest/commit/83e6256)) 209 | * Rename `crud()` to `resources()` ([e2bc6d9](https://github.com/atomixinteractions/createrest/commit/e2bc6d9)) 210 | * Fix styles for esdocs ([63727ad](https://github.com/atomixinteractions/createrest/commit/63727ad)) 211 | * Add base `crud()` method ([19eeb74](https://github.com/atomixinteractions/createrest/commit/19eeb74)) 212 | * Create CODE_OF_CONDUCT.md (#9) ([d7275df](https://github.com/atomixinteractions/createrest/commit/d7275df)), closes [#9](https://github.com/atomixinteractions/createrest/issues/9) 213 | * Fix type in readme ([5f4fdce](https://github.com/atomixinteractions/createrest/commit/5f4fdce)) 214 | 215 | 216 | 217 | 218 | ## [0.8.3](https://github.com/atomixinteractions/createrest/compare/v0.8.0...v0.8.3) (2017-06-11) 219 | 220 | 221 | * Add *each aliases for before/after ([c48bc7a](https://github.com/atomixinteractions/createrest/commit/c48bc7a)) 222 | * Add docs for isCreateRestInstance function ([834a595](https://github.com/atomixinteractions/createrest/commit/834a595)) 223 | * Update readme ([315b7be](https://github.com/atomixinteractions/createrest/commit/315b7be)) 224 | 225 | 226 | 227 | 228 | # [0.8.0](https://github.com/atomixinteractions/createrest/compare/v0.7.0...v0.8.0) (2017-06-11) 229 | 230 | 231 | * Refactor check for routes instance ([0177d09](https://github.com/atomixinteractions/createrest/commit/0177d09)) 232 | 233 | 234 | 235 | 236 | # [0.7.0](https://github.com/atomixinteractions/createrest/compare/v0.6.2...v0.7.0) (2017-06-11) 237 | 238 | 239 | * Add symbol property to routes to check instance ([7e82ee2](https://github.com/atomixinteractions/createrest/commit/7e82ee2)) 240 | 241 | 242 | 243 | 244 | ## [0.6.2](https://github.com/atomixinteractions/createrest/compare/v0.6.1...v0.6.2) (2017-06-05) 245 | 246 | 247 | * Source code styles patches ([8246d6c](https://github.com/atomixinteractions/createrest/commit/8246d6c)) 248 | * Add dark theme ([702b6e4](https://github.com/atomixinteractions/createrest/commit/702b6e4)) 249 | * - improve test names (#7) ([4b09891](https://github.com/atomixinteractions/createrest/commit/4b09891)), closes [#7](https://github.com/atomixinteractions/createrest/issues/7) 250 | * Refactor names in tests ([ad183be](https://github.com/atomixinteractions/createrest/commit/ad183be)) 251 | 252 | 253 | 254 | 255 | ## [0.6.1](https://github.com/atomixinteractions/createrest/compare/v0.6.0...v0.6.1) (2017-06-03) 256 | 257 | 258 | * Handle displayName for printRoutes ([a6a2a2b](https://github.com/atomixinteractions/createrest/commit/a6a2a2b)) 259 | * Change callback parameter names to be more explicit (#6) ([542fce6](https://github.com/atomixinteractions/createrest/commit/542fce6)), closes [#6](https://github.com/atomixinteractions/createrest/issues/6) 260 | * Update docs ([7a82c26](https://github.com/atomixinteractions/createrest/commit/7a82c26)) 261 | * Update readme ([4e57dba](https://github.com/atomixinteractions/createrest/commit/4e57dba)) 262 | * Move to npm:files from npmignore ([61f6d2c](https://github.com/atomixinteractions/createrest/commit/61f6d2c)) 263 | * Add not merging scopes ([c93306a](https://github.com/atomixinteractions/createrest/commit/c93306a)) 264 | 265 | 266 | 267 | 268 | # [0.6.0](https://github.com/atomixinteractions/createrest/compare/v0.5.2...v0.6.0) (2017-06-01) 269 | 270 | 271 | * Add methods renaming for resource ([e6738ce](https://github.com/atomixinteractions/createrest/commit/e6738ce)) 272 | * Scope not merging ([df48540](https://github.com/atomixinteractions/createrest/commit/df48540)) 273 | 274 | 275 | 276 | 277 | ## [0.5.2](https://github.com/atomixinteractions/createrest/compare/v0.5.1...v0.5.2) (2017-06-01) 278 | 279 | 280 | * Fix documentation ([1498908](https://github.com/atomixinteractions/createrest/commit/1498908)) 281 | * Add semantic release badge ([4a0dd39](https://github.com/atomixinteractions/createrest/commit/4a0dd39)) 282 | 283 | 284 | 285 | 286 | ## [0.5.1](https://github.com/atomixinteractions/createrest/compare/v0.5.0...v0.5.1) (2017-05-31) 287 | 288 | 289 | * Add esdoc ([4110b0a](https://github.com/atomixinteractions/createrest/commit/4110b0a)) 290 | 291 | 292 | 293 | 294 | # [0.5.0](https://github.com/atomixinteractions/createrest/compare/v0.4.0...v0.5.0) (2017-05-29) 295 | 296 | 297 | * Add engines to config ([473e8b6](https://github.com/atomixinteractions/createrest/commit/473e8b6)) 298 | * Add npm5 lock. Change babel plugins. Add check for creator ([7c55bc8](https://github.com/atomixinteractions/createrest/commit/7c55bc8)) 299 | * Refactor make() in tests ([6f09323](https://github.com/atomixinteractions/createrest/commit/6f09323)) 300 | 301 | 302 | 303 | 304 | # [0.4.0](https://github.com/atomixinteractions/createrest/compare/v0.3.0...v0.4.0) (2017-05-26) 305 | 306 | 307 | * Remove unused variable :idName ([3ab420d](https://github.com/atomixinteractions/createrest/commit/3ab420d)) 308 | * Safe npm scripts ([098364e](https://github.com/atomixinteractions/createrest/commit/098364e)) 309 | * Drop :nameId scope for resource. Add readme for resource ([7909853](https://github.com/atomixinteractions/createrest/commit/7909853)) 310 | * Add base readme ([0cd16ba](https://github.com/atomixinteractions/createrest/commit/0cd16ba)) 311 | * More tests for resource ([067335a](https://github.com/atomixinteractions/createrest/commit/067335a)) 312 | * Add simple resource ([5889355](https://github.com/atomixinteractions/createrest/commit/5889355)) 313 | * Full coverage ([f3ec18b](https://github.com/atomixinteractions/createrest/commit/f3ec18b)) 314 | 315 | 316 | 317 | 318 | # [0.3.0](https://github.com/atomixinteractions/createrest/compare/v0.2.0...v0.3.0) (2017-05-24) 319 | 320 | 321 | * Improve default scripts ([1d86d31](https://github.com/atomixinteractions/createrest/commit/1d86d31)) 322 | * Print to console ([f9e07e5](https://github.com/atomixinteractions/createrest/commit/f9e07e5)) 323 | * Improve testings ([c2cb0a7](https://github.com/atomixinteractions/createrest/commit/c2cb0a7)) 324 | * Add merging listeners to test ([d19fe25](https://github.com/atomixinteractions/createrest/commit/d19fe25)) 325 | * Fix flatten init prefix ([ed49a78](https://github.com/atomixinteractions/createrest/commit/ed49a78)) 326 | * Clean more ([b387dbe](https://github.com/atomixinteractions/createrest/commit/b387dbe)) 327 | * Refactered flattening ([b2cd0bd](https://github.com/atomixinteractions/createrest/commit/b2cd0bd)) 328 | * Cover scope name ([46f6271](https://github.com/atomixinteractions/createrest/commit/46f6271)) 329 | * More ERRORS! ([03d4ca3](https://github.com/atomixinteractions/createrest/commit/03d4ca3)) 330 | * Show <function> if listener without name ([98bf79a](https://github.com/atomixinteractions/createrest/commit/98bf79a)) 331 | * More tests for methods ([9294c1f](https://github.com/atomixinteractions/createrest/commit/9294c1f)) 332 | * Fix check for deep path in methods ([952d0b9](https://github.com/atomixinteractions/createrest/commit/952d0b9)) 333 | * Try to test with nyc ([863dfd0](https://github.com/atomixinteractions/createrest/commit/863dfd0)) 334 | * Send coverage in travis ([7446c2b](https://github.com/atomixinteractions/createrest/commit/7446c2b)) 335 | * Setup out services ([b7e6ce1](https://github.com/atomixinteractions/createrest/commit/b7e6ce1)) 336 | * Full tests ([652eb93](https://github.com/atomixinteractions/createrest/commit/652eb93)) 337 | * Temp drop pub ([27ea7b8](https://github.com/atomixinteractions/createrest/commit/27ea7b8)) 338 | * Ignore tests from linting ([203ff3a](https://github.com/atomixinteractions/createrest/commit/203ff3a)) 339 | * Improve ava config ([c0da303](https://github.com/atomixinteractions/createrest/commit/c0da303)) 340 | 341 | 342 | 343 | 344 | # [0.2.0](https://github.com/atomixinteractions/createrest/compare/v0.1.1...v0.2.0) (2017-05-24) 345 | 346 | 347 | * Add support comments ([752d4b9](https://github.com/atomixinteractions/createrest/commit/752d4b9)) 348 | * Refactor methods, name for methods no required ([eb74f0d](https://github.com/atomixinteractions/createrest/commit/eb74f0d)) 349 | * Add more test ([82dd23d](https://github.com/atomixinteractions/createrest/commit/82dd23d)) 350 | * Add simple test ([9e0d98a](https://github.com/atomixinteractions/createrest/commit/9e0d98a)) 351 | 352 | 353 | 354 | 355 | ## [0.1.1](https://github.com/atomixinteractions/createrest/compare/v0.0.1...v0.1.1) (2017-05-23) 356 | 357 | 358 | * Add check ([ca11182](https://github.com/atomixinteractions/createrest/commit/ca11182)) 359 | * Simple rest ([eb5bb82](https://github.com/atomixinteractions/createrest/commit/eb5bb82)) 360 | * New way examples/another ([0e03603](https://github.com/atomixinteractions/createrest/commit/0e03603)) 361 | * Add next ([46e53c4](https://github.com/atomixinteractions/createrest/commit/46e53c4)) 362 | * Half ready `flattenRoutes` ([4252c1a](https://github.com/atomixinteractions/createrest/commit/4252c1a)) 363 | 364 | 365 | 366 | 367 | ## [0.0.1](https://github.com/atomixinteractions/createrest/compare/v0.0.1-dev.4...v0.0.1) (2017-03-07) 368 | 369 | 370 | * Add link to docs to README ([301246c](https://github.com/atomixinteractions/createrest/commit/301246c)) 371 | 372 | 373 | 374 | 375 | ## [0.0.1-dev.4](https://github.com/atomixinteractions/createrest/compare/v0.0.1-dev.3...v0.0.1-dev.4) (2017-03-07) 376 | 377 | 378 | * Add dummy bin ([a6e730c](https://github.com/atomixinteractions/createrest/commit/a6e730c)) 379 | * Drop express from devDeps ([0c44ec7](https://github.com/atomixinteractions/createrest/commit/0c44ec7)) 380 | 381 | 382 | 383 | 384 | ## [0.0.1-dev.3](https://github.com/atomixinteractions/createrest/compare/v0.0.1-dev.2...v0.0.1-dev.3) (2017-03-07) 385 | 386 | 387 | * Fix lint issues ([1db4561](https://github.com/atomixinteractions/createrest/commit/1db4561)) 388 | * Fix printer ([a57e011](https://github.com/atomixinteractions/createrest/commit/a57e011)) 389 | 390 | 391 | 392 | 393 | ## [0.0.1-dev.2](https://github.com/atomixinteractions/createrest/compare/v0.0.1-dev.1...v0.0.1-dev.2) (2017-03-07) 394 | 395 | 396 | * Add clean script ([d279f8e](https://github.com/atomixinteractions/createrest/commit/d279f8e)) 397 | * Fix codestyle ([52d5e1f](https://github.com/atomixinteractions/createrest/commit/52d5e1f)) 398 | * Add `resource` creator ([84efff6](https://github.com/atomixinteractions/createrest/commit/84efff6)) 399 | 400 | 401 | 402 | 403 | ## [0.0.1-dev.1](https://github.com/atomixinteractions/createrest/compare/7b8f498...v0.0.1-dev.1) (2017-03-07) 404 | 405 | 406 | * Add simple printer ([f915bdd](https://github.com/atomixinteractions/createrest/commit/f915bdd)) 407 | * Add docs for `createRest` ([8085a00](https://github.com/atomixinteractions/createrest/commit/8085a00)) 408 | * Drop docs ([e00ab07](https://github.com/atomixinteractions/createrest/commit/e00ab07)) 409 | * Add buildbranch ([c1e0b81](https://github.com/atomixinteractions/createrest/commit/c1e0b81)) 410 | * Remove namespace `createrest` from docs ([7f60928](https://github.com/atomixinteractions/createrest/commit/7f60928)) 411 | * Build docs ([360a855](https://github.com/atomixinteractions/createrest/commit/360a855)) 412 | * Add documentation ([9afea45](https://github.com/atomixinteractions/createrest/commit/9afea45)) 413 | * Patch readme ([5d6a30c](https://github.com/atomixinteractions/createrest/commit/5d6a30c)) 414 | * Drop unused files ([4c1b0b9](https://github.com/atomixinteractions/createrest/commit/4c1b0b9)) 415 | * Add forgotten filess ([29ec64e](https://github.com/atomixinteractions/createrest/commit/29ec64e)) 416 | * Add `member` creator ([8dc05b0](https://github.com/atomixinteractions/createrest/commit/8dc05b0)) 417 | * Add `resources` ([279c889](https://github.com/atomixinteractions/createrest/commit/279c889)) 418 | * Ignore docs ([f65e0eb](https://github.com/atomixinteractions/createrest/commit/f65e0eb)) 419 | * Drop `root` creator ([6394089](https://github.com/atomixinteractions/createrest/commit/6394089)) 420 | * Add simple creators ([3c6515d](https://github.com/atomixinteractions/createrest/commit/3c6515d)) 421 | * Rename restified to createrest ([bd6a71b](https://github.com/atomixinteractions/createrest/commit/bd6a71b)) 422 | * Update ([73bc033](https://github.com/atomixinteractions/createrest/commit/73bc033)) 423 | * Update ([0e8a4fa](https://github.com/atomixinteractions/createrest/commit/0e8a4fa)) 424 | * Update README.md ([38c98ce](https://github.com/atomixinteractions/createrest/commit/38c98ce)) 425 | * Create ISSUE_TEMPLATE.md ([962f06f](https://github.com/atomixinteractions/createrest/commit/962f06f)) 426 | * Add CLI example ([834e52d](https://github.com/atomixinteractions/createrest/commit/834e52d)) 427 | * Add pluralize and gitignore ([bf9f31c](https://github.com/atomixinteractions/createrest/commit/bf9f31c)) 428 | * Update LICENSE.md ([bdc2ad6](https://github.com/atomixinteractions/createrest/commit/bdc2ad6)) 429 | * Initial commit ([7b8f498](https://github.com/atomixinteractions/createrest/commit/7b8f498)) 430 | 431 | 432 | 433 | -------------------------------------------------------------------------------- /packages/createrest/lib/index.js: -------------------------------------------------------------------------------- 1 | import pluralize from 'pluralize' 2 | import { createRestInstanceSymbol } from './symbol' 3 | 4 | /** 5 | * @desc Controller object for `crud()` method {@link RestRoutes} 6 | * @since 0.9.0 7 | * @typedef {object} CrudController 8 | * @property {function} [beforeEach] Called before each request 9 | * @property {function} [afterEach] Called after each request 10 | * @property {function} [read] Handle GET /name 11 | * @property {function} [create] Handle POST /name 12 | * @property {function} [update] Handle PUT /name 13 | * @property {function} [destroy] handle DELETE /name 14 | * @example 15 | * const DemoController = { 16 | * beforeEach(req, res, next) { 17 | * // any checks here 18 | * next() 19 | * }, 20 | * create(req, res, next) { 21 | * context.makeDemo.create(req.params) 22 | * res.json({ complete: true }) 23 | * next() 24 | * }, 25 | * afterEach(req, res, next) { 26 | * // close your resources here 27 | * context.db.close() 28 | * } 29 | * } 30 | */ 31 | 32 | /** 33 | * @desc Controller object for `resources()` method. See {@link Maker.resources} 34 | * @since 0.9.0 35 | * @typedef {object} ResourcesController 36 | * @property {function} [beforeEach] Hook will invoke before each handler in controller 37 | * @property {function} [afterEach] Hook will invoke before after handler in controller 38 | * @property {function} [index] 39 | * @property {function} [create] 40 | * @property {function} [read] 41 | * @property {function} [update] 42 | * @property {function} [patch] 43 | * @property {function} [destroy] 44 | */ 45 | 46 | /** 47 | * Check is correct routes passed 48 | * @public 49 | * @since 0.7.0 50 | * @function 51 | * @param {RestRoutes} routes 52 | * @return {boolean} 53 | */ 54 | export const isCreateRestInstance = (routes) => routes[createRestInstanceSymbol] === true 55 | 56 | /** 57 | * @desc Routes object 58 | * @protected 59 | * @typedef {object} RestRoutes 60 | * @property {Symbol} Symbol(createRestInstanceSymbol) 61 | * @property {object[]} before 62 | * @property {object[]} after 63 | * @property {object} scoped 64 | * @property {object} local 65 | */ 66 | 67 | /** 68 | * @class Maker 69 | * @protected 70 | */ 71 | export class Maker { 72 | /** 73 | * @private 74 | */ 75 | constructor() { 76 | /** 77 | * @ignore 78 | */ 79 | this.ctx = { 80 | before: [], 81 | after: [], 82 | scoped: {}, 83 | local: {}, 84 | } 85 | } 86 | 87 | /** 88 | * @private 89 | * Build routes ast 90 | */ 91 | build() { 92 | const scoped = {} 93 | 94 | Object.keys(this.ctx.scoped).forEach((name) => { 95 | scoped[name] = this.ctx.scoped[name].build() 96 | }) 97 | return Object.assign({}, this.ctx, { scoped, [createRestInstanceSymbol]: true }) 98 | } 99 | 100 | /** 101 | * Add middlewares before request handler to current scope and all child scope 102 | * @param {...function} list List of the middlewares 103 | * 104 | * @example 105 | * const beforeHandler = () => console.log('before') 106 | * const getHandler = () => console.log('get') 107 | * 108 | * createRest(root => { 109 | * root.beforeEach(beforeHandler) 110 | * // GET /demo beforeHandler(); getHandler() 111 | * root.get('/demo', getHandler) 112 | * }) 113 | * // Output: 114 | * // > before 115 | * // > get 116 | * @example With variable count 117 | * const handle1 = () => console.log('handle1') 118 | * const handle2 = () => console.log('handle2') 119 | * 120 | * createRest(root => { 121 | * root.beforeEach(handle1, handle2) 122 | * // same as 123 | * root.beforeEach(handle1) 124 | * root.beforeEach(handle2) 125 | * }) 126 | */ 127 | beforeEach(...list) { 128 | this.ctx.before = this.ctx.before.concat(list.filter((ln) => !!ln)) 129 | } 130 | 131 | /** 132 | * Add middlewares after request handler to current scope and all child scope 133 | * @param {...function} list List of the middlewares 134 | * @example 135 | * const getHandler = () => console.log('get') 136 | * const afterHandler = () => console.log('after') 137 | * 138 | * createRest(root => { 139 | * root.afterEach(afterHandler) 140 | * // GET /demo getHandler(); afterHandler() 141 | * root.get('/demo', getHandler) 142 | * }) 143 | * // Output: 144 | * // > get 145 | * // > after 146 | * @example You can combine beforeEach and afterEach 147 | * const getHandler = () => console.log('get foo') 148 | * const deleteHandler = () => console.log('DELETE requested') 149 | * const before1 = () => console.log('That is before 1') 150 | * const before2 = () => console.log('Second before') 151 | * const after = () => console.log('Just after request') 152 | * 153 | * const routes = createRest(root => { 154 | * root.beforeEach(before1, before2) 155 | * root.afterEach(after) 156 | * 157 | * // GET /foo before1(); before2(); getHandler(); after() 158 | * root.get('/foo', getHandler) 159 | * 160 | * root.scope('bar', bar => { 161 | * // DELETE /bar/baz before1(); before2(); deleteHandler(); after() 162 | * bar.delete('/baz', deleteHandler) 163 | * }) 164 | * }) 165 | * // Output on GET /foo request: 166 | * // > That is before 1 167 | * // > Second before 168 | * // > get foo 169 | * // > Just after request 170 | * 171 | * // Output on DELETE /bar/baz 172 | * // > That is before 1 173 | * // > Second before 174 | * // > DELETE requested 175 | * // > Just after request 176 | */ 177 | afterEach(...list) { 178 | this.ctx.after = this.ctx.after.concat(list.filter((ln) => !!ln)) 179 | } 180 | 181 | /** 182 | * Add scoped address, before/after handlers and simple handlers.
183 | * Before/After handlers is inherits from parent scope.
184 | * Scopes with the same name will be merged 185 | * 186 | * @param {string} name Name of the scope 187 | * @param {function(scope: Maker): void} creator 188 | * @throws {Error} "Name of the scope should be a word" 189 | * @throws {TypeError} "Name of the scope should be string!" 190 | * @return {void} 191 | * @since 0.2.0 192 | * @example 193 | * const before1 = () => console.log('before1') 194 | * const before2 = () => console.log('before2') 195 | * const after1 = () => console.log('after1') 196 | * const after2 = () => console.log('after2') 197 | * const bazHandler = () => console.log('baz') 198 | * const barHandler = () => console.log('bar') 199 | * 200 | * createRest(root => { 201 | * root.beforeEach(before1) 202 | * root.afterEach(after1) 203 | * 204 | * // POST /baz before1(); bazHandler(); after1() 205 | * root.post('baz', bazHandler) 206 | * 207 | * root.scope('foo', foo => { 208 | * foo.beforeEach(before2) 209 | * foo.afterEach(after2) 210 | * 211 | * // GET /foo/bar before1(); before2(); barHandler(); after2(); after1() 212 | * foo.get('bar', barHandler) 213 | * }) 214 | * }) 215 | */ 216 | scope(name, creator) { 217 | if (typeof name !== 'string') { 218 | throw new TypeError('Name of the scope should be string!') 219 | } 220 | if (name.length === 0 || name.indexOf('/') !== -1) { 221 | throw new Error('Name of the scope should be a word') 222 | } 223 | 224 | const scopedCtx = this.ctx.scoped[name] || new Maker() 225 | 226 | creator(scopedCtx) 227 | this.ctx.scoped[name] = scopedCtx 228 | } 229 | 230 | /** 231 | * Add HTTP method listeners to local 232 | * 233 | * @private 234 | * @param {string} method 235 | * @param {function[]} listeners 236 | */ 237 | local(method, listeners) { 238 | // if listeners for that methods exists, simple merge 239 | if (this.ctx.local[method]) { 240 | this.ctx.local[method] = this.ctx.local[method].concat(listeners) 241 | } 242 | else { 243 | this.ctx.local[method] = listeners 244 | } 245 | } 246 | 247 | /** 248 | * Handle method creator 249 | * 250 | * @ignore 251 | * @param {string} name 252 | * @param {string} method 253 | * @param {Function[]} listeners 254 | */ 255 | method(method, listenersRaw) { 256 | let name = '' 257 | let listeners = listenersRaw 258 | 259 | if (typeof listeners[0] === 'string') { 260 | [name] = listeners.splice(0, 1) 261 | } 262 | name = name.replace(/^\//gm, '') 263 | 264 | if (name.indexOf('/') !== -1) { 265 | throw new Error('Path should not be deep') 266 | } 267 | if (listeners.length === 0) { 268 | throw new TypeError('Maybe you forget to add listener?') 269 | } 270 | 271 | listeners = listeners.filter((e) => typeof e === 'function') 272 | 273 | // if added undefined listeners 274 | if (listeners.length === 0) return 275 | 276 | if (name !== '') { 277 | let scoped = this.ctx.scoped[name] 278 | 279 | if (!scoped) { 280 | scoped = new Maker() 281 | this.ctx.scoped[name] = scoped 282 | } 283 | 284 | scoped.local(method, listeners) 285 | } 286 | else { 287 | this.local(method, listeners) 288 | } 289 | } 290 | 291 | /** 292 | * Handle POST HTTP method with single or many handlers 293 | * @param {string} [name] Route path. Default is current scope 294 | * @param {...function} handlers List of http-handlers 295 | * @throws {Error} Path should not be deep 296 | * @throws {TypeError} Maybe you forget to add listener? 297 | * @example 298 | * createRest(root => { 299 | * root.post('name', () => console.log('Handled post /name request')) 300 | * root.post(() => console.log('Handled post / request')) 301 | * root.post('create', 302 | * (req, res, next) => next(), 303 | * authorize('user'), 304 | * () => console.log('Handled post /create with middlewares') 305 | * ) 306 | * }) 307 | */ 308 | post(name, ...handlers) { 309 | this.method('POST', [name, ...handlers]) 310 | } 311 | 312 | /** 313 | * Handle GET HTTP method with single or many handlers 314 | * @param {string} [name] Route path. Default is current scope 315 | * @param {...function} handlers List of http-handlers 316 | * @throws {Error} Path should not be deep 317 | * @throws {TypeError} Maybe you forget to add listener? 318 | * @example 319 | * createRest(root => { 320 | * root.get('name', () => console.log('Handled get /name request')) 321 | * root.get(() => console.log('Handled get / request')) 322 | * root.get('create', 323 | * (req, res, next) => next(), 324 | * authorize('user'), 325 | * () => console.log('Handled get /create with middlewares') 326 | * ) 327 | * }) 328 | */ 329 | get(name, ...handlers) { 330 | this.method('GET', [name, ...handlers]) 331 | } 332 | 333 | /** 334 | * Handle PUT HTTP method with single or many handlers 335 | * @param {string} [name] Route path. Default is current scope 336 | * @param {...function} handlers List of http-handlers 337 | * @throws {Error} Path should not be deep 338 | * @throws {TypeError} Maybe you forget to add listener? 339 | * @example 340 | * createRest(root => { 341 | * root.put('name', () => console.log('Handled put /name request')) 342 | * root.put(() => console.log('Handled put / request')) 343 | * root.put('create', 344 | * (req, res, next) => next(), 345 | * authorize('user'), 346 | * () => console.log('Handled put /create with middlewares') 347 | * ) 348 | * }) 349 | */ 350 | put(name, ...handlers) { 351 | this.method('PUT', [name, ...handlers]) 352 | } 353 | 354 | /** 355 | * Handle DELETE HTTP method with single or many handlers 356 | * @param {string} [name] Route path. Default is current scope 357 | * @param {...function} handlers List of http-handlers 358 | * @throws {Error} Path should not be deep 359 | * @throws {TypeError} Maybe you forget to add listener? 360 | * @example 361 | * createRest(root => { 362 | * root.delete('name', () => console.log('Handled delete /name request')) 363 | * root.delete(() => console.log('Handled delete / request')) 364 | * root.delete('create', 365 | * (req, res, next) => next(), 366 | * authorize('user'), 367 | * () => console.log('Handled delete /create with middlewares') 368 | * ) 369 | * }) 370 | */ 371 | delete(name, ...handlers) { 372 | this.method('DELETE', [name, ...handlers]) 373 | } 374 | 375 | /** 376 | * Handle PATCH HTTP method with single or many handlers 377 | * @param {string} [name] Route path. Default is current scope 378 | * @param {...function} handlers List of http-handlers 379 | * @throws {Error} Path should not be deep 380 | * @throws {TypeError} Maybe you forget to add listener? 381 | * @example 382 | * createRest(root => { 383 | * root.patch('name', () => console.log('Handled patch /name request')) 384 | * root.patch(() => console.log('Handled patch / request')) 385 | * root.patch('create', 386 | * (req, res, next) => next(), 387 | * authorize('user'), 388 | * () => console.log('Handled patch /create with middlewares') 389 | * ) 390 | * }) 391 | */ 392 | patch(name, ...handlers) { 393 | this.method('PATCH', [name, ...handlers]) 394 | } 395 | 396 | /** 397 | * @desc Configure your `crud('name', controller, options)`
See {@link Maker.crud} 398 | * @typedef {object} crudOptions 399 | * @property {string[]} [only] Keep only that handlers: `read`, `create`, `update`, `destroy` 400 | * @property {string[]} [except] Keep all except that handlers 401 | * @property {object} [methodNames] Change method names 402 | * @since 0.9.0 403 | * 404 | * @example Usage with `only` 405 | * createRest(root => { 406 | * root.crud('foo', FooController, { only: ['read'] }) 407 | * }) 408 | * 409 | * @example Usage with `except` 410 | * createRest(root => { 411 | * root.crud('bar', BarController, { except: ['destroy', 'update'] }) 412 | * }) 413 | * 414 | * @example Method names 415 | * const Controller = { 416 | * createDemo() {}, 417 | * updateMe() {}, 418 | * justExample() {}, 419 | * youDontNeedThis() {}, 420 | * } 421 | * createRest(root => { 422 | * root.crud('demo', Controller, { methodNames: { 423 | * read: 'justExample', create: 'createDemo', update: 'updateMe', destroy: 'youDontNeedThis', 424 | * }}) 425 | * }) 426 | */ 427 | 428 | /** 429 | * Add CRUD methods for single resource.
430 | * CRUD methods not merging. __Use only one crud for path.__ 431 | * @param {string} name Name of the resource. Create route path from 432 | * @param {CrudController} controller Object with methods 433 | * @param {crudOptions} [options={}] Options object 434 | * @param {function(scope: Maker): void} [creator=null] Scoped creator function 435 | * @since 0.9.0 436 | * @example Simple 437 | * const Controller = { 438 | * read() {}, 439 | * create() {}, 440 | * update() {}, 441 | * destroy() {}, 442 | * beforeEach() {}, 443 | * afterEach() {}, 444 | * } 445 | * const routes = createRest(root => { 446 | * // GET /example read() 447 | * // POST /example create() 448 | * // PUT /example update() 449 | * // DELETE /example destroy() 450 | * root.crud('example', Controller) 451 | * }) 452 | * @example Only/Except option 453 | * const Controller = { 454 | * read() {}, 455 | * create() {}, 456 | * update() {}, 457 | * destroy() {}, 458 | * beforeEach() {}, 459 | * afterEach() {}, 460 | * } 461 | * const routes = createRest(root => { 462 | * // GET /demo read() 463 | * // POST /demo create() 464 | * root.crud('demo', Controller, { only: ['create', 'read'] }) 465 | * 466 | * // GET /single read() 467 | * // PUT /single update() 468 | * root.crud('single', Controller, { except: ['destroy', 'create'] }) 469 | * }) 470 | * @example With scope 471 | * const routes = createRest(root => { 472 | * // GET /example 473 | * // POST /example 474 | * // PUT /example 475 | * // DELETE /example 476 | * root.crud('example', Controller, {}, example => { 477 | * // GET /example/demo 478 | * example.get('/demo', () => {}) 479 | * }) 480 | * }) 481 | */ 482 | crud(name, controller, options = {}, creator = null) { 483 | if (!name || name.length === 0) { 484 | throw new Error('Resource should be named') 485 | } 486 | 487 | if (typeof controller === 'undefined') { 488 | return 489 | } 490 | 491 | const methods = { 492 | read: 'get', 493 | create: 'post', 494 | update: 'put', 495 | destroy: 'delete', 496 | } 497 | const methodsList = Object.keys(methods) 498 | 499 | const resolveMethodName = (handler, currentController) => ( 500 | options.methodNames && options.methodNames[handler] 501 | ? currentController[options.methodNames[handler]] 502 | : currentController[handler] 503 | ) 504 | 505 | /** 506 | * @var {Array<[string, string]>} usedList [[handlerName, httpMethod], ...] 507 | */ 508 | let usedList = [] 509 | 510 | if (Array.isArray(options.only)) { 511 | usedList = options.only 512 | } 513 | else if (Array.isArray(options.except)) { 514 | usedList = methodsList 515 | .filter((handlerName) => !options.except.includes(handlerName)) 516 | } 517 | else { 518 | usedList = methodsList 519 | } 520 | 521 | this.scope(name, (scope) => { 522 | scope.beforeEach(controller.beforeEach) 523 | scope.afterEach(controller.afterEach) 524 | 525 | usedList 526 | .filter((handler) => methodsList.includes(handler)) 527 | .map((handler) => [handler, methods[handler]]) 528 | .forEach(([handler, httpMethod]) => { 529 | scope[httpMethod](resolveMethodName(handler, controller)) 530 | }) 531 | 532 | if (creator) { 533 | creator(scope) 534 | } 535 | }) 536 | } 537 | 538 | /** 539 | * Configure your `resources('name', controller, options)` 540 | *
You can't use `except` and `only` at the same time 541 | *
Available handlers: `index`, `read`, `create`, `update`, `patch`, `destroy` 542 | * @typedef {object} resourcesOptions 543 | * @property {string[]} [only] Keep only that handlers 544 | * @property {string[]} [except] Keep all except that handlers 545 | * @property {string} [memberId] Change :memberId in the URI 546 | * @since 0.9.0 547 | * 548 | * @example Usage with `only` 549 | * createRest(root => { 550 | * // GET /books -> index() 551 | * // GET /books/:bookId -> read() 552 | * root.resources('books', BooksController, { only: ['read', 'index'] }) 553 | * }) 554 | * 555 | * @example Usage with `except` 556 | * createRest(root => { 557 | * // GET /songs -> index() 558 | * // POST /songs -> create() 559 | * // GET /songs/:songId -> read() 560 | * // PATCH /songs/:songId -> patch() 561 | * root.resources('songs', SongsController, { except: ['destroy', 'update'] }) 562 | * }) 563 | * 564 | * @example With beforeEach afterEach methods 565 | * const Controller = { 566 | * beforeEach() {}, 567 | * afterEach() {}, 568 | * create() {}, 569 | * read() {}, 570 | * } 571 | * // If controller no methods, no handlers creates 572 | * 573 | * createRest(root => { 574 | * // GET /demo beforeEach(); read(); afterEach() 575 | * // POST /demo beforeEach(); create(); afterEach() 576 | * root.crud('demo', Controller) 577 | * }) 578 | * 579 | * @example Member ID renaming 580 | * createRest(root => { 581 | * // GET /images -> index() 582 | * // POST /images -> create() 583 | * // GET /images/:imgid -> read() 584 | * // PUT /images/:imgid -> update() 585 | * // PATCH /images/:imgid -> patch() 586 | * // DELETE /images/:imgid -> destroy() 587 | * root.resources('images', ImagesController, { memberId: 'imgid' }) 588 | * }) 589 | */ 590 | 591 | /** 592 | * Add index, create, read, update, patch, remove methods to manage resource
593 | * See {@link ResourcesController} and {@link resourcesOptions} 594 | * @param {string} name Name of the resources. Path created from. Example: `books` 595 | * @param {ResourcesController} controller Object with methods 596 | * @param {resourcesOptions} [options={}] Options for resources 597 | * @param {function(scope: Maker): void} [creator=null] Scoped creator function 598 | * @return {void} 599 | * @throws {Error} "Resources should be named" 600 | * @throws {Error} "You can't use 'except' and 'only' options at the same time" 601 | * @throws {TypeError} "Controller should be object" 602 | * 603 | * @example Full example 604 | * createRest(root => { 605 | * // GET /users -> index() 606 | * // POST /users -> create() 607 | * // GET /users/:userId -> read() 608 | * // PUT /users/:userId -> update() 609 | * // PATCH /users/:userId -> patch() 610 | * // DELETE /users/:userId -> destroy() 611 | * root.resources('users', UsersController) 612 | * }) 613 | */ 614 | resources(name, controller, options = {}, creator = null) { 615 | /** 616 | * index : get / 617 | * create : post / 618 | * read : get /:id 619 | * update : put /:id 620 | * patch : patch /:id 621 | * remove : delete /:id 622 | */ 623 | if (!name || name.length === 0) { 624 | throw new Error('Resources should be named') 625 | } 626 | 627 | if (!controller || typeof controller !== 'object') { 628 | throw new TypeError('Controller should be object') 629 | } 630 | 631 | if (typeof options === 'function') { 632 | /* eslint-disable no-param-reassign */ 633 | creator = options 634 | options = {} 635 | /* eslint-enable no-param-reassign */ 636 | } 637 | 638 | if (options.only && options.except) { 639 | throw new Error('You can\'t use \'except\' and \'only\' options at the same time') 640 | } 641 | 642 | const noMethodsSlicingOption = (!options.only || options.only.length === 0) 643 | && (!options.except || options.except.length === 0) 644 | 645 | /** 646 | * Check method existing in options `only` or `except` 647 | * @param {string} methodName 648 | * @private 649 | */ 650 | const checkMethod = (methodName) => noMethodsSlicingOption 651 | || (options.only && options.only.length && options.only.includes(methodName)) 652 | || (options.except && options.except.length && !options.except.includes(methodName)) 653 | 654 | const memberId = options.memberId || `${pluralize.singular(name)}Id` 655 | 656 | this.scope(name, (scope) => { 657 | scope.beforeEach(controller.beforeEach) 658 | scope.afterEach(controller.afterEach) 659 | 660 | if (checkMethod('index')) { 661 | scope.get('/', controller.index) 662 | } 663 | 664 | if (checkMethod('create')) { 665 | scope.post('/', controller.create) 666 | } 667 | 668 | scope.scope(`:${memberId}`, (member) => { 669 | if (checkMethod('read')) { 670 | member.get('/', controller.read) 671 | } 672 | 673 | if (checkMethod('update')) { 674 | member.put('/', controller.update) 675 | } 676 | 677 | if (checkMethod('patch')) { 678 | if (controller.patch) { 679 | member.patch('/', controller.patch) 680 | } 681 | else if (checkMethod('update')) { 682 | member.patch('/', controller.update) 683 | } 684 | else { 685 | // no PATCH /:id add 686 | } 687 | } 688 | 689 | if (checkMethod('destroy')) { 690 | member.delete('/', controller.destroy) 691 | } 692 | }) 693 | 694 | if (creator) { 695 | creator(scope) 696 | } 697 | }) 698 | } 699 | } 700 | 701 | /** 702 | * Create routes by sync callback 703 | * @param {function(r: Maker): null} creator Callback 704 | * @return {RestRoutes} Routes object 705 | */ 706 | export function createRest(creator) { 707 | if (typeof creator !== 'function') { 708 | throw new TypeError('Creator should be a function') 709 | } 710 | 711 | const ctx = new Maker('') 712 | 713 | creator(ctx) 714 | return ctx.build() 715 | } 716 | 717 | export { flattenRoutes } from './flatten' 718 | export { printRoutes } from './printer' 719 | --------------------------------------------------------------------------------