Comparing version 0.1.0 to 0.1.1
@@ -1,12 +0,21 @@ | ||
import ZSchema from 'z-schema'; | ||
"use strict"; | ||
import SchemaValidationError from './SchemaValidationError'; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.default = createDefaultValidator; | ||
ZSchema.registerFormat('binary', () => true); | ||
var _zSchema = _interopRequireDefault(require("z-schema")); | ||
export default function createDefaultValidator() { | ||
const validator = new ZSchema({ | ||
var _SchemaValidationError = _interopRequireDefault(require("./SchemaValidationError")); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
_zSchema.default.registerFormat('binary', () => true); | ||
function createDefaultValidator() { | ||
const validator = new _zSchema.default({ | ||
assumeAdditional: true, | ||
breakOnFirstError: false, | ||
reportPathAsArray: true, | ||
reportPathAsArray: true | ||
}); | ||
@@ -19,3 +28,3 @@ return (data, schema) => { | ||
} else { | ||
reject(new SchemaValidationError('JSON schema validation failed', errors)); | ||
reject(new _SchemaValidationError.default('JSON schema validation failed', errors)); | ||
} | ||
@@ -25,2 +34,2 @@ }); | ||
}; | ||
} | ||
} |
@@ -1,19 +0,26 @@ | ||
export default function createMatcher(pathTemplate, pathParameters = []) { | ||
const arrayNames = pathParameters | ||
.filter(({ schema = {} }) => schema.type === 'array') | ||
.map(({ name }) => name); | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.default = createMatcher; | ||
function createMatcher(pathTemplate, pathParameters = []) { | ||
const arrayNames = pathParameters.filter(({ | ||
schema = {} | ||
}) => schema.type === 'array').map(({ | ||
name | ||
}) => name); | ||
const names = []; | ||
const pathRegex = new RegExp( | ||
`^${pathTemplate.replace(/{(\w+)}/gi, (match, name) => { | ||
names.push(name); | ||
return arrayNames.includes(name) ? '(.*)' : '([^/]+)'; | ||
})}$`, | ||
'i', | ||
); | ||
const pathRegex = new RegExp(`^${pathTemplate.replace(/{(\w+)}/gi, (match, name) => { | ||
names.push(name); | ||
return arrayNames.includes(name) ? '(.*)' : '([^/]+)'; | ||
})}$`, 'i'); | ||
return url => { | ||
const urlMatch = url.match(pathRegex); | ||
if (!urlMatch) { | ||
return null; | ||
} | ||
return names.reduce((acc, name, index) => { | ||
@@ -24,2 +31,2 @@ acc[name] = decodeURI(urlMatch[index + 1]); | ||
}; | ||
} | ||
} |
@@ -1,15 +0,19 @@ | ||
import createMatcher from './createMatcher'; | ||
"use strict"; | ||
it.each([ | ||
['/', '/', {}], | ||
['/{foo}', '/bar', { foo: 'bar' }], | ||
['/a/{a}/b/{b}/c/{c}', '/a/x/b/y/c/z', { a: 'x', b: 'y', c: 'z' }], | ||
['/', '/todeep', null], | ||
['/{foo}', '/', null], | ||
])('%s should transform %s into %o', (template, url, params) => { | ||
const matcher = createMatcher(template); | ||
const result = matcher(url); | ||
// Test twice, because some RegExp functions hold a global state. | ||
var _createMatcher = _interopRequireDefault(require("./createMatcher")); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
it.each([['/', '/', {}], ['/{foo}', '/bar', { | ||
foo: 'bar' | ||
}], ['/a/{a}/b/{b}/c/{c}', '/a/x/b/y/c/z', { | ||
a: 'x', | ||
b: 'y', | ||
c: 'z' | ||
}], ['/', '/todeep', null], ['/{foo}', '/', null]])('%s should transform %s into %o', (template, url, params) => { | ||
const matcher = (0, _createMatcher.default)(template); | ||
const result = matcher(url); // Test twice, because some RegExp functions hold a global state. | ||
expect(result).toStrictEqual(params); | ||
expect(result).toStrictEqual(params); | ||
}); | ||
}); |
82
koas.js
@@ -1,16 +0,34 @@ | ||
import compose from 'koa-compose'; | ||
import { cloneDeep } from 'lodash'; | ||
import RefParser from 'json-schema-ref-parser'; | ||
"use strict"; | ||
import createMatcher from './createMatcher'; | ||
import createDefaultValidator from './createDefaultValidator'; | ||
import SchemaValidationError from './SchemaValidationError'; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.default = koas; | ||
Object.defineProperty(exports, "SchemaValidationError", { | ||
enumerable: true, | ||
get: function () { | ||
return _SchemaValidationError.default; | ||
} | ||
}); | ||
var _koaCompose = _interopRequireDefault(require("koa-compose")); | ||
var _lodash = require("lodash"); | ||
var _jsonSchemaRefParser = _interopRequireDefault(require("json-schema-ref-parser")); | ||
var _createMatcher = _interopRequireDefault(require("./createMatcher")); | ||
var _createDefaultValidator = _interopRequireDefault(require("./createDefaultValidator")); | ||
var _SchemaValidationError = _interopRequireDefault(require("./SchemaValidationError")); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
const methods = new Set(['delete', 'get', 'head', 'options', 'patch', 'post', 'put', 'trace']); | ||
/** | ||
* This symbol is used internally to specify a middleware should always be run. | ||
*/ | ||
const RUN_ALWAYS = Symbol('This middleware is always run'); | ||
/** | ||
@@ -22,2 +40,3 @@ * Mark that middleware always needs to run, even if there is no matching OpenAPI operation. | ||
*/ | ||
function markRunAlways(middleware) { | ||
@@ -29,27 +48,19 @@ // eslint-disable-next-line no-param-reassign | ||
export { SchemaValidationError }; | ||
export default async function koas( | ||
spec, | ||
middlewares = [], | ||
{ createValidator = createDefaultValidator } = {}, | ||
) { | ||
const dereferencedSpec = await RefParser.dereference(cloneDeep(spec)); | ||
async function koas(spec, middlewares = [], { | ||
createValidator = _createDefaultValidator.default | ||
} = {}) { | ||
const dereferencedSpec = await _jsonSchemaRefParser.default.dereference((0, _lodash.cloneDeep)(spec)); | ||
const matchers = Object.entries(dereferencedSpec.paths).map(([pathTemplate, pathItemObject]) => { | ||
const matcher = createMatcher(pathTemplate, pathItemObject.parameters); | ||
const matcher = (0, _createMatcher.default)(pathTemplate, pathItemObject.parameters); | ||
return [matcher, pathItemObject]; | ||
}); | ||
const validate = await createValidator(spec); | ||
const injected = middlewares.map(middleware => | ||
middleware({ | ||
rawSpec: spec, | ||
runAlways: markRunAlways, | ||
spec: dereferencedSpec, | ||
validate, | ||
}), | ||
); | ||
const composed = compose(injected); | ||
const runAlways = compose(injected.filter(middleware => middleware[RUN_ALWAYS])); | ||
const injected = middlewares.map(middleware => middleware({ | ||
rawSpec: spec, | ||
runAlways: markRunAlways, | ||
spec: dereferencedSpec, | ||
validate | ||
})); | ||
const composed = (0, _koaCompose.default)(injected); | ||
const runAlways = (0, _koaCompose.default)(injected.filter(middleware => middleware[RUN_ALWAYS])); | ||
return (ctx, next) => { | ||
@@ -61,6 +72,11 @@ let params; | ||
}); | ||
ctx.openApi = { openApiObject: spec, validate }; | ||
ctx.openApi = { | ||
openApiObject: spec, | ||
validate | ||
}; | ||
if (!match) { | ||
return runAlways(ctx, next); | ||
} | ||
const [, pathItemObject] = match; | ||
@@ -70,12 +86,16 @@ ctx.openApi.pathItemObject = pathItemObject; | ||
const method = ctx.method.toLowerCase(); | ||
if (!methods.has(method)) { | ||
return runAlways(ctx, next); | ||
} | ||
const operationObject = pathItemObject[method]; | ||
if (!operationObject) { | ||
return runAlways(ctx, next); | ||
} | ||
ctx.openApi.operationObject = operationObject; | ||
return composed(ctx, next); | ||
}; | ||
} | ||
} |
@@ -1,3 +0,7 @@ | ||
import createServer from 'koas-supertest'; | ||
"use strict"; | ||
var _koasSupertest = _interopRequireDefault(require("koas-supertest")); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function noop(ctx, next) { | ||
@@ -11,5 +15,9 @@ return next(); | ||
schemas: { | ||
foo: { type: 'string' }, | ||
bar: { $ref: '#/components/schemas/foo' }, | ||
}, | ||
foo: { | ||
type: 'string' | ||
}, | ||
bar: { | ||
$ref: '#/components/schemas/foo' | ||
} | ||
} | ||
}, | ||
@@ -19,6 +27,6 @@ paths: { | ||
get: { | ||
responses: {}, | ||
}, | ||
}, | ||
}, | ||
responses: {} | ||
} | ||
} | ||
} | ||
}; | ||
@@ -29,15 +37,10 @@ let api; | ||
let middlewares; | ||
beforeEach(async () => { | ||
middlewares = [jest.fn(noop), jest.fn(noop)]; | ||
api = await createServer(spec, [ | ||
args => async (ctx, next) => { | ||
injectedArgs = args; | ||
context = ctx; | ||
await next(); | ||
}, | ||
...middlewares.map(m => () => m), | ||
]); | ||
api = await (0, _koasSupertest.default)(spec, [args => async (ctx, next) => { | ||
injectedArgs = args; | ||
context = ctx; | ||
await next(); | ||
}, ...middlewares.map(m => () => m)]); | ||
}); | ||
it('should call middleware', async () => { | ||
@@ -48,3 +51,2 @@ await api.get('/'); | ||
}); | ||
it('should inject the raw and dereferenced OpenAPI spec', async () => { | ||
@@ -57,9 +59,13 @@ await api.get('/'); | ||
title: 'Test server', | ||
version: 'test', | ||
version: 'test' | ||
}, | ||
components: { | ||
schemas: { | ||
foo: { type: 'string' }, | ||
bar: { type: 'string' }, | ||
}, | ||
foo: { | ||
type: 'string' | ||
}, | ||
bar: { | ||
type: 'string' | ||
} | ||
} | ||
}, | ||
@@ -69,6 +75,6 @@ paths: { | ||
get: { | ||
responses: {}, | ||
}, | ||
}, | ||
}, | ||
responses: {} | ||
} | ||
} | ||
} | ||
}, | ||
@@ -79,9 +85,13 @@ rawSpec: { | ||
title: 'Test server', | ||
version: 'test', | ||
version: 'test' | ||
}, | ||
components: { | ||
schemas: { | ||
foo: { type: 'string' }, | ||
bar: { $ref: '#/components/schemas/foo' }, | ||
}, | ||
foo: { | ||
type: 'string' | ||
}, | ||
bar: { | ||
$ref: '#/components/schemas/foo' | ||
} | ||
} | ||
}, | ||
@@ -91,11 +101,10 @@ paths: { | ||
get: { | ||
responses: {}, | ||
}, | ||
}, | ||
}, | ||
responses: {} | ||
} | ||
} | ||
} | ||
}, | ||
runAlways: expect.any(Function), | ||
runAlways: expect.any(Function) | ||
}); | ||
}); | ||
it('should configure openApi related fields for middleware', async () => { | ||
@@ -106,2 +115,2 @@ await api.get('/'); | ||
}); | ||
}); | ||
}); |
{ | ||
"name": "koas-core", | ||
"version": "0.1.0", | ||
"version": "0.1.1", | ||
"author": "Remco Haszing <remcohaszing@gmail.com>", | ||
@@ -23,4 +23,4 @@ "license": "MIT", | ||
"devDependencies": { | ||
"koas-supertest": "^0.1.0" | ||
"koas-supertest": "^0.1.1" | ||
} | ||
} |
@@ -1,2 +0,9 @@ | ||
export default class SchemaValidationError extends Error { | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.default = void 0; | ||
class SchemaValidationError extends Error { | ||
constructor(message, errors) { | ||
@@ -8,2 +15,5 @@ super(message); | ||
} | ||
} | ||
exports.default = SchemaValidationError; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
8700
259