@feathersjs/commons
Advanced tools
Comparing version 3.0.1 to 4.0.0-pre.0
@@ -6,2 +6,49 @@ # Change Log | ||
# [4.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v3.2.0-pre.1...v4.0.0-pre.0) (2019-04-21) | ||
### Bug Fixes | ||
* Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803)) | ||
* Update all dependencies to latest ([#1206](https://github.com/feathersjs/feathers/issues/1206)) ([e51e0f6](https://github.com/feathersjs/feathers/commit/e51e0f6)) | ||
* use minimal RegExp matching for better performance ([#977](https://github.com/feathersjs/feathers/issues/977)) ([3ca7e97](https://github.com/feathersjs/feathers/commit/3ca7e97)) | ||
### Features | ||
* Add TypeScript definitions ([#1275](https://github.com/feathersjs/feathers/issues/1275)) ([9dd6713](https://github.com/feathersjs/feathers/commit/9dd6713)) | ||
* Common database adapter utilities and test suite ([#1130](https://github.com/feathersjs/feathers/issues/1130)) ([17b3dc8](https://github.com/feathersjs/feathers/commit/17b3dc8)) | ||
* Remove (hook, next) signature and SKIP support ([#1269](https://github.com/feathersjs/feathers/issues/1269)) ([211c0f8](https://github.com/feathersjs/feathers/commit/211c0f8)) | ||
### BREAKING CHANGES | ||
* Move database adapter utilities from @feathersjs/commons into its own module | ||
<a name="4.0.0"></a> | ||
# [4.0.0](https://github.com/feathersjs/feathers/compare/@feathersjs/commons@3.0.1...@feathersjs/commons@4.0.0) (2018-12-16) | ||
### Bug Fixes | ||
* Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803)) | ||
### Features | ||
* Common database adapter utilities and test suite ([#1130](https://github.com/feathersjs/feathers/issues/1130)) ([17b3dc8](https://github.com/feathersjs/feathers/commit/17b3dc8)) | ||
### BREAKING CHANGES | ||
* Move database adapter utilities from @feathersjs/commons into its own module | ||
<a name="3.0.1"></a> | ||
@@ -8,0 +55,0 @@ ## [3.0.1](https://github.com/feathersjs/feathers/compare/@feathersjs/commons@3.0.0...@feathersjs/commons@3.0.1) (2018-09-17) |
345
lib/hooks.js
@@ -1,206 +0,167 @@ | ||
const { _: { each, pick }, createSymbol } = require('./utils'); | ||
// To skip further hooks | ||
const SKIP = createSymbol('__feathersSkipHooks'); | ||
exports.SKIP = SKIP; | ||
exports.ACTIVATE_HOOKS = createSymbol('__feathersActivateHooks'); | ||
exports.createHookObject = function createHookObject (method, data = {}) { | ||
const hook = {}; | ||
Object.defineProperty(hook, 'toJSON', { | ||
value () { | ||
return pick(this, 'type', 'method', 'path', | ||
'params', 'id', 'data', 'result', 'error'); | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const utils_1 = require("./utils"); | ||
const { each, pick } = utils_1._; | ||
exports.ACTIVATE_HOOKS = utils_1.createSymbol('__feathersActivateHooks'); | ||
function createHookObject(method, data = {}) { | ||
const hook = {}; | ||
Object.defineProperty(hook, 'toJSON', { | ||
value() { | ||
return pick(this, 'type', 'method', 'path', 'params', 'id', 'data', 'result', 'error'); | ||
} | ||
}); | ||
return Object.assign(hook, data, { | ||
method, | ||
// A dynamic getter that returns the path of the service | ||
get path() { | ||
const { app, service } = data; | ||
if (!service || !app || !app.services) { | ||
return null; | ||
} | ||
return Object.keys(app.services) | ||
.find(path => app.services[path] === service); | ||
} | ||
}); | ||
} | ||
exports.createHookObject = createHookObject; | ||
// Fallback used by `makeArguments` which usually won't be used | ||
function defaultMakeArguments(hook) { | ||
const result = []; | ||
if (typeof hook.id !== 'undefined') { | ||
result.push(hook.id); | ||
} | ||
}); | ||
return Object.assign(hook, data, { | ||
method, | ||
// A dynamic getter that returns the path of the service | ||
get path () { | ||
const { app, service } = data; | ||
if (!service || !app || !app.services) { | ||
return null; | ||
} | ||
return Object.keys(app.services) | ||
.find(path => app.services[path] === service); | ||
if (hook.data) { | ||
result.push(hook.data); | ||
} | ||
}); | ||
}; | ||
// Fallback used by `makeArguments` which usually won't be used | ||
exports.defaultMakeArguments = function defaultMakeArguments (hook) { | ||
const result = []; | ||
if (typeof hook.id !== 'undefined') { | ||
result.push(hook.id); | ||
} | ||
if (hook.data) { | ||
result.push(hook.data); | ||
} | ||
result.push(hook.params || {}); | ||
return result; | ||
}; | ||
result.push(hook.params || {}); | ||
return result; | ||
} | ||
exports.defaultMakeArguments = defaultMakeArguments; | ||
// Turns a hook object back into a list of arguments | ||
// to call a service method with | ||
exports.makeArguments = function makeArguments (hook) { | ||
switch (hook.method) { | ||
case 'find': | ||
return [ hook.params ]; | ||
case 'get': | ||
case 'remove': | ||
return [ hook.id, hook.params ]; | ||
case 'update': | ||
case 'patch': | ||
return [ hook.id, hook.data, hook.params ]; | ||
case 'create': | ||
return [ hook.data, hook.params ]; | ||
} | ||
return exports.defaultMakeArguments(hook); | ||
}; | ||
function makeArguments(hook) { | ||
switch (hook.method) { | ||
case 'find': | ||
return [hook.params]; | ||
case 'get': | ||
case 'remove': | ||
return [hook.id, hook.params]; | ||
case 'update': | ||
case 'patch': | ||
return [hook.id, hook.data, hook.params]; | ||
case 'create': | ||
return [hook.data, hook.params]; | ||
} | ||
return defaultMakeArguments(hook); | ||
} | ||
exports.makeArguments = makeArguments; | ||
// Converts different hook registration formats into the | ||
// same internal format | ||
exports.convertHookData = function convertHookData (obj) { | ||
let hook = {}; | ||
if (Array.isArray(obj)) { | ||
hook = { all: obj }; | ||
} else if (typeof obj !== 'object') { | ||
hook = { all: [ obj ] }; | ||
} else { | ||
each(obj, function (value, key) { | ||
hook[key] = !Array.isArray(value) ? [ value ] : value; | ||
}); | ||
} | ||
return hook; | ||
}; | ||
function convertHookData(obj) { | ||
let hook = {}; | ||
if (Array.isArray(obj)) { | ||
hook = { all: obj }; | ||
} | ||
else if (typeof obj !== 'object') { | ||
hook = { all: [obj] }; | ||
} | ||
else { | ||
each(obj, function (value, key) { | ||
hook[key] = !Array.isArray(value) ? [value] : value; | ||
}); | ||
} | ||
return hook; | ||
} | ||
exports.convertHookData = convertHookData; | ||
// Duck-checks a given object to be a hook object | ||
// A valid hook object has `type` and `method` | ||
exports.isHookObject = function isHookObject (hookObject) { | ||
return typeof hookObject === 'object' && | ||
typeof hookObject.method === 'string' && | ||
typeof hookObject.type === 'string'; | ||
}; | ||
function isHookObject(hookObject) { | ||
return typeof hookObject === 'object' && | ||
typeof hookObject.method === 'string' && | ||
typeof hookObject.type === 'string'; | ||
} | ||
exports.isHookObject = isHookObject; | ||
// Returns all service and application hooks combined | ||
// for a given method and type `appLast` sets if the hooks | ||
// from `app` should be added last (or first by default) | ||
exports.getHooks = function getHooks (app, service, type, method, appLast = false) { | ||
const appHooks = app.__hooks[type][method] || []; | ||
const serviceHooks = service.__hooks[type][method] || []; | ||
if (appLast) { | ||
// Run hooks in the order of service -> app -> finally | ||
return serviceHooks.concat(appHooks); | ||
} | ||
return appHooks.concat(serviceHooks); | ||
}; | ||
exports.processHooks = function processHooks (hooks, initialHookObject) { | ||
let hookObject = initialHookObject; | ||
let updateCurrentHook = current => { | ||
// Either use the returned hook object or the current | ||
// hook object from the chain if the hook returned undefined | ||
if (current) { | ||
if (current === SKIP) { | ||
return SKIP; | ||
} | ||
if (!exports.isHookObject(current)) { | ||
throw new Error(`${hookObject.type} hook for '${hookObject.method}' method returned invalid hook object`); | ||
} | ||
hookObject = current; | ||
function getHooks(app, service, type, method, appLast = false) { | ||
const appHooks = app.__hooks[type][method] || []; | ||
const serviceHooks = service.__hooks[type][method] || []; | ||
if (appLast) { | ||
// Run hooks in the order of service -> app -> finally | ||
return serviceHooks.concat(appHooks); | ||
} | ||
return hookObject; | ||
}; | ||
// Go through all hooks and chain them into our promise | ||
const promise = hooks.reduce((promise, fn) => { | ||
const hook = fn.bind(this); | ||
if (hook.length === 2) { // function(hook, next) | ||
promise = promise.then(hookObject => hookObject === SKIP ? SKIP : new Promise((resolve, reject) => { | ||
hook(hookObject, (error, result) => | ||
error ? reject(error) : resolve(result) | ||
); | ||
})); | ||
} else { // function(hook) | ||
promise = promise.then(hookObject => hookObject === SKIP ? SKIP : hook(hookObject)); | ||
return appHooks.concat(serviceHooks); | ||
} | ||
exports.getHooks = getHooks; | ||
function processHooks(hooks, initialHookObject) { | ||
let hookObject = initialHookObject; | ||
const updateCurrentHook = (current) => { | ||
// Either use the returned hook object or the current | ||
// hook object from the chain if the hook returned undefined | ||
if (current) { | ||
if (!isHookObject(current)) { | ||
throw new Error(`${hookObject.type} hook for '${hookObject.method}' method returned invalid hook object`); | ||
} | ||
hookObject = current; | ||
} | ||
return hookObject; | ||
}; | ||
// Go through all hooks and chain them into our promise | ||
const promise = hooks.reduce((current, fn) => { | ||
// @ts-ignore | ||
const hook = fn.bind(this); | ||
// Use the returned hook object or the old one | ||
return current.then((currentHook) => hook(currentHook)).then(updateCurrentHook); | ||
}, Promise.resolve(hookObject)); | ||
return promise.then(() => hookObject).catch(error => { | ||
// Add the hook information to any errors | ||
error.hook = hookObject; | ||
throw error; | ||
}); | ||
} | ||
exports.processHooks = processHooks; | ||
// Add `.hooks` functionality to an object | ||
function enableHooks(obj, methods, types) { | ||
if (typeof obj.hooks === 'function') { | ||
return obj; | ||
} | ||
// Use the returned hook object or the old one | ||
return promise.then(updateCurrentHook); | ||
}, Promise.resolve(hookObject)); | ||
return promise.then(() => hookObject).catch(error => { | ||
// Add the hook information to any errors | ||
error.hook = hookObject; | ||
throw error; | ||
}); | ||
}; | ||
// Add `.hooks` functionality to an object | ||
exports.enableHooks = function enableHooks (obj, methods, types) { | ||
if (typeof obj.hooks === 'function') { | ||
return obj; | ||
} | ||
const __hooks = {}; | ||
types.forEach(type => { | ||
// Initialize properties where hook functions are stored | ||
__hooks[type] = {}; | ||
}); | ||
// Add non-enumerable `__hooks` property to the object | ||
Object.defineProperty(obj, '__hooks', { | ||
value: __hooks | ||
}); | ||
return Object.assign(obj, { | ||
hooks (allHooks) { | ||
each(allHooks, (obj, type) => { | ||
if (!this.__hooks[type]) { | ||
throw new Error(`'${type}' is not a valid hook type`); | ||
const hookData = {}; | ||
types.forEach(type => { | ||
// Initialize properties where hook functions are stored | ||
hookData[type] = {}; | ||
}); | ||
// Add non-enumerable `__hooks` property to the object | ||
Object.defineProperty(obj, '__hooks', { | ||
value: hookData | ||
}); | ||
return Object.assign(obj, { | ||
hooks(allHooks) { | ||
each(allHooks, (current, type) => { | ||
// @ts-ignore | ||
if (!this.__hooks[type]) { | ||
throw new Error(`'${type}' is not a valid hook type`); | ||
} | ||
const hooks = convertHookData(current); | ||
each(hooks, (_value, method) => { | ||
if (method !== 'all' && methods.indexOf(method) === -1) { | ||
throw new Error(`'${method}' is not a valid hook method`); | ||
} | ||
}); | ||
methods.forEach(method => { | ||
// @ts-ignore | ||
const myHooks = this.__hooks[type][method] || (this.__hooks[type][method] = []); | ||
if (hooks.all) { | ||
myHooks.push.apply(myHooks, hooks.all); | ||
} | ||
if (hooks[method]) { | ||
myHooks.push.apply(myHooks, hooks[method]); | ||
} | ||
}); | ||
}); | ||
return this; | ||
} | ||
const hooks = exports.convertHookData(obj); | ||
each(hooks, (value, method) => { | ||
if (method !== 'all' && methods.indexOf(method) === -1) { | ||
throw new Error(`'${method}' is not a valid hook method`); | ||
} | ||
}); | ||
methods.forEach(method => { | ||
const myHooks = this.__hooks[type][method] || | ||
(this.__hooks[type][method] = []); | ||
if (hooks.all) { | ||
myHooks.push.apply(myHooks, hooks.all); | ||
} | ||
if (hooks[method]) { | ||
myHooks.push.apply(myHooks, hooks[method]); | ||
} | ||
}); | ||
}); | ||
return this; | ||
} | ||
}); | ||
}; | ||
}); | ||
} | ||
exports.enableHooks = enableHooks; | ||
//# sourceMappingURL=hooks.js.map |
@@ -1,88 +0,80 @@ | ||
const assert = require('assert'); | ||
module.exports = function (app, name) { | ||
const getService = () => (name && typeof app.service === 'function') | ||
? app.service(name) : app; | ||
describe('Service base tests', () => { | ||
it('.find', () => { | ||
return getService().find().then(todos => | ||
assert.deepEqual(todos, [{ | ||
text: 'some todo', | ||
complete: false, | ||
id: 0 | ||
}]) | ||
); | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const assert_1 = __importDefault(require("assert")); | ||
function setupTests(app, name) { | ||
const getService = () => (name && typeof app.service === 'function') | ||
? app.service(name) : app; | ||
describe('Service base tests', () => { | ||
it('.find', () => { | ||
return getService().find().then((todos) => assert_1.default.deepEqual(todos, [{ | ||
text: 'some todo', | ||
complete: false, | ||
id: 0 | ||
}])); | ||
}); | ||
it('.get and params passing', () => { | ||
const query = { | ||
some: 'thing', | ||
other: ['one', 'two'], | ||
nested: { a: { b: 'object' } } | ||
}; | ||
return getService().get(0, { query }) | ||
.then((todo) => assert_1.default.deepEqual(todo, { | ||
id: 0, | ||
text: 'some todo', | ||
complete: false, | ||
query | ||
})); | ||
}); | ||
it('.create and created event', done => { | ||
getService().once('created', (data) => { | ||
assert_1.default.strictEqual(data.text, 'created todo'); | ||
assert_1.default.ok(data.complete); | ||
done(); | ||
}); | ||
getService().create({ text: 'created todo', complete: true }); | ||
}); | ||
it('.update and updated event', done => { | ||
getService().once('updated', (data) => { | ||
assert_1.default.strictEqual(data.text, 'updated todo'); | ||
assert_1.default.ok(data.complete); | ||
done(); | ||
}); | ||
getService().create({ text: 'todo to update', complete: false }) | ||
.then((todo) => getService().update(todo.id, { | ||
text: 'updated todo', | ||
complete: true | ||
})); | ||
}); | ||
it('.patch and patched event', done => { | ||
getService().once('patched', (data) => { | ||
assert_1.default.strictEqual(data.text, 'todo to patch'); | ||
assert_1.default.ok(data.complete); | ||
done(); | ||
}); | ||
getService().create({ text: 'todo to patch', complete: false }) | ||
.then((todo) => getService().patch(todo.id, { complete: true })); | ||
}); | ||
it('.remove and removed event', done => { | ||
getService().once('removed', (data) => { | ||
assert_1.default.strictEqual(data.text, 'todo to remove'); | ||
assert_1.default.strictEqual(data.complete, false); | ||
done(); | ||
}); | ||
getService().create({ text: 'todo to remove', complete: false }) | ||
.then((todo) => getService().remove(todo.id)).catch(done); | ||
}); | ||
it('.get with error', () => { | ||
const query = { error: true }; | ||
return getService().get(0, { query }).catch((error) => assert_1.default.ok(error && error.message)); | ||
}); | ||
}); | ||
it('.get and params passing', () => { | ||
const query = { | ||
some: 'thing', | ||
other: ['one', 'two'], | ||
nested: {a: {b: 'object'}} | ||
}; | ||
return getService().get(0, { query }) | ||
.then(todo => assert.deepEqual(todo, { | ||
id: 0, | ||
text: 'some todo', | ||
complete: false, | ||
query: query | ||
})); | ||
}); | ||
it('.create and created event', done => { | ||
getService().once('created', function (data) { | ||
assert.equal(data.text, 'created todo'); | ||
assert.ok(data.complete); | ||
done(); | ||
}); | ||
getService().create({text: 'created todo', complete: true}); | ||
}); | ||
it('.update and updated event', done => { | ||
getService().once('updated', data => { | ||
assert.equal(data.text, 'updated todo'); | ||
assert.ok(data.complete); | ||
done(); | ||
}); | ||
getService().create({text: 'todo to update', complete: false}) | ||
.then(todo => getService().update(todo.id, { | ||
text: 'updated todo', | ||
complete: true | ||
})); | ||
}); | ||
it('.patch and patched event', done => { | ||
getService().once('patched', data => { | ||
assert.equal(data.text, 'todo to patch'); | ||
assert.ok(data.complete); | ||
done(); | ||
}); | ||
getService().create({text: 'todo to patch', complete: false}) | ||
.then(todo => getService().patch(todo.id, {complete: true})); | ||
}); | ||
it('.remove and removed event', done => { | ||
getService().once('removed', data => { | ||
assert.equal(data.text, 'todo to remove'); | ||
assert.equal(data.complete, false); | ||
done(); | ||
}); | ||
getService().create({text: 'todo to remove', complete: false}) | ||
.then(todo => getService().remove(todo.id)).catch(done); | ||
}); | ||
it('.get with error', () => { | ||
let query = {error: true}; | ||
return getService().get(0, {query}).catch(error => | ||
assert.ok(error && error.message) | ||
); | ||
}); | ||
}); | ||
}; | ||
} | ||
exports.setupTests = setupTests; | ||
if (typeof module !== 'undefined') { | ||
module.exports = Object.assign(setupTests, module.exports); | ||
} | ||
//# sourceMappingURL=client.js.map |
@@ -1,112 +0,97 @@ | ||
const assert = require('assert'); | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const assert_1 = __importDefault(require("assert")); | ||
const findAllData = [{ | ||
id: 0, | ||
description: 'You have to do something' | ||
}, { | ||
id: 1, | ||
description: 'You have to do laundry' | ||
}]; | ||
id: 0, | ||
description: 'You have to do something' | ||
}, { | ||
id: 1, | ||
description: 'You have to do laundry' | ||
}]; | ||
exports.Service = { | ||
events: [ 'log' ], | ||
find () { | ||
return Promise.resolve(findAllData); | ||
}, | ||
get (name, params) { | ||
if (params.query.error) { | ||
return Promise.reject(new Error(`Something for ${name} went wrong`)); | ||
events: ['log'], | ||
find() { | ||
return Promise.resolve(findAllData); | ||
}, | ||
get(name, params) { | ||
if (params.query.error) { | ||
return Promise.reject(new Error(`Something for ${name} went wrong`)); | ||
} | ||
if (params.query.runtimeError) { | ||
// @ts-ignore | ||
thingThatDoesNotExist(); // eslint-disable-line | ||
} | ||
return Promise.resolve({ | ||
id: name, | ||
description: `You have to do ${name}!` | ||
}); | ||
}, | ||
create(data) { | ||
const result = Object.assign({}, data, { | ||
id: 42, | ||
status: 'created' | ||
}); | ||
if (Array.isArray(data)) { | ||
result.many = true; | ||
} | ||
return Promise.resolve(result); | ||
}, | ||
update(id, data) { | ||
const result = Object.assign({}, data, { | ||
id, status: 'updated' | ||
}); | ||
if (id === null) { | ||
result.many = true; | ||
} | ||
return Promise.resolve(result); | ||
}, | ||
patch(id, data) { | ||
const result = Object.assign({}, data, { | ||
id, status: 'patched' | ||
}); | ||
if (id === null) { | ||
result.many = true; | ||
} | ||
return Promise.resolve(result); | ||
}, | ||
remove(id) { | ||
return Promise.resolve({ id }); | ||
} | ||
if (params.query.runtimeError) { | ||
thingThatDoesNotExist(); // eslint-disable-line | ||
} | ||
return Promise.resolve({ | ||
id: name, | ||
description: `You have to do ${name}!` | ||
}); | ||
}, | ||
create (data) { | ||
const result = Object.assign({}, data, { | ||
id: 42, | ||
status: 'created' | ||
}); | ||
if (Array.isArray(data)) { | ||
result.many = true; | ||
} | ||
return Promise.resolve(result); | ||
}, | ||
update (id, data) { | ||
const result = Object.assign({}, data, { | ||
id, status: 'updated' | ||
}); | ||
if (id === null) { | ||
result.many = true; | ||
} | ||
return Promise.resolve(result); | ||
}, | ||
patch (id, data) { | ||
const result = Object.assign({}, data, { | ||
id, status: 'patched' | ||
}); | ||
if (id === null) { | ||
result.many = true; | ||
} | ||
return Promise.resolve(result); | ||
}, | ||
remove (id) { | ||
return Promise.resolve({ id }); | ||
} | ||
}; | ||
exports.verify = { | ||
find (data) { | ||
assert.deepEqual(findAllData, data, 'Data as expected'); | ||
}, | ||
get (id, data) { | ||
assert.equal(data.id, id, 'Got id in data'); | ||
assert.equal(data.description, `You have to do ${id}!`, 'Got description'); | ||
}, | ||
create (original, current) { | ||
var expected = Object.assign({}, original, { | ||
id: 42, | ||
status: 'created' | ||
}); | ||
assert.deepEqual(expected, current, 'Data ran through .create as expected'); | ||
}, | ||
update (id, original, current) { | ||
var expected = Object.assign({}, original, { | ||
id: id, | ||
status: 'updated' | ||
}); | ||
assert.deepEqual(expected, current, 'Data ran through .update as expected'); | ||
}, | ||
patch (id, original, current) { | ||
var expected = Object.assign({}, original, { | ||
id: id, | ||
status: 'patched' | ||
}); | ||
assert.deepEqual(expected, current, 'Data ran through .patch as expected'); | ||
}, | ||
remove (id, data) { | ||
assert.deepEqual({ id }, data, '.remove called'); | ||
} | ||
find(data) { | ||
assert_1.default.deepStrictEqual(findAllData, data, 'Data as expected'); | ||
}, | ||
get(id, data) { | ||
assert_1.default.strictEqual(data.id, id, 'Got id in data'); | ||
assert_1.default.strictEqual(data.description, `You have to do ${id}!`, 'Got description'); | ||
}, | ||
create(original, current) { | ||
const expected = Object.assign({}, original, { | ||
id: 42, | ||
status: 'created' | ||
}); | ||
assert_1.default.deepStrictEqual(expected, current, 'Data ran through .create as expected'); | ||
}, | ||
update(id, original, current) { | ||
const expected = Object.assign({}, original, { | ||
id, | ||
status: 'updated' | ||
}); | ||
assert_1.default.deepStrictEqual(expected, current, 'Data ran through .update as expected'); | ||
}, | ||
patch(id, original, current) { | ||
const expected = Object.assign({}, original, { | ||
id, | ||
status: 'patched' | ||
}); | ||
assert_1.default.deepStrictEqual(expected, current, 'Data ran through .patch as expected'); | ||
}, | ||
remove(id, data) { | ||
assert_1.default.deepStrictEqual({ id }, data, '.remove called'); | ||
} | ||
}; | ||
//# sourceMappingURL=fixture.js.map |
321
lib/utils.js
@@ -0,232 +1,101 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
// Removes all leading and trailing slashes from a path | ||
exports.stripSlashes = function stripSlashes (name) { | ||
return name.replace(/^(\/+)|(\/+)$/g, ''); | ||
}; | ||
function stripSlashes(name) { | ||
return name.replace(/^(\/+)|(\/+)$/g, ''); | ||
} | ||
exports.stripSlashes = stripSlashes; | ||
// A set of lodash-y utility functions that use ES6 | ||
const _ = exports._ = { | ||
each (obj, callback) { | ||
if (obj && typeof obj.forEach === 'function') { | ||
obj.forEach(callback); | ||
} else if (_.isObject(obj)) { | ||
Object.keys(obj).forEach(key => callback(obj[key], key)); | ||
} | ||
}, | ||
some (value, callback) { | ||
return Object.keys(value) | ||
.map(key => [ value[key], key ]) | ||
.some(([val, key]) => callback(val, key)); | ||
}, | ||
every (value, callback) { | ||
return Object.keys(value) | ||
.map(key => [ value[key], key ]) | ||
.every(([val, key]) => callback(val, key)); | ||
}, | ||
keys (obj) { | ||
return Object.keys(obj); | ||
}, | ||
values (obj) { | ||
return _.keys(obj).map(key => obj[key]); | ||
}, | ||
isMatch (obj, item) { | ||
return _.keys(item).every(key => obj[key] === item[key]); | ||
}, | ||
isEmpty (obj) { | ||
return _.keys(obj).length === 0; | ||
}, | ||
isObject (item) { | ||
return (typeof item === 'object' && !Array.isArray(item) && item !== null); | ||
}, | ||
isObjectOrArray (value) { | ||
return typeof value === 'object' && value !== null; | ||
}, | ||
extend (...args) { | ||
return Object.assign(...args); | ||
}, | ||
omit (obj, ...keys) { | ||
const result = _.extend({}, obj); | ||
keys.forEach(key => delete result[key]); | ||
return result; | ||
}, | ||
pick (source, ...keys) { | ||
return keys.reduce((result, key) => { | ||
if (source[key] !== undefined) { | ||
result[key] = source[key]; | ||
} | ||
return result; | ||
}, {}); | ||
}, | ||
// Recursively merge the source object into the target object | ||
merge (target, source) { | ||
if (_.isObject(target) && _.isObject(source)) { | ||
Object.keys(source).forEach(key => { | ||
if (_.isObject(source[key])) { | ||
if (!target[key]) { | ||
Object.assign(target, { [key]: {} }); | ||
} | ||
_.merge(target[key], source[key]); | ||
} else { | ||
Object.assign(target, { [key]: source[key] }); | ||
exports._ = { | ||
each(obj, callback) { | ||
if (obj && typeof obj.forEach === 'function') { | ||
obj.forEach(callback); | ||
} | ||
}); | ||
else if (exports._.isObject(obj)) { | ||
Object.keys(obj).forEach(key => callback(obj[key], key)); | ||
} | ||
}, | ||
some(value, callback) { | ||
return Object.keys(value) | ||
.map(key => [value[key], key]) | ||
.some(([val, key]) => callback(val, key)); | ||
}, | ||
every(value, callback) { | ||
return Object.keys(value) | ||
.map(key => [value[key], key]) | ||
.every(([val, key]) => callback(val, key)); | ||
}, | ||
keys(obj) { | ||
return Object.keys(obj); | ||
}, | ||
values(obj) { | ||
return exports._.keys(obj).map(key => obj[key]); | ||
}, | ||
isMatch(obj, item) { | ||
return exports._.keys(item).every(key => obj[key] === item[key]); | ||
}, | ||
isEmpty(obj) { | ||
return exports._.keys(obj).length === 0; | ||
}, | ||
isObject(item) { | ||
return (typeof item === 'object' && !Array.isArray(item) && item !== null); | ||
}, | ||
isObjectOrArray(value) { | ||
return typeof value === 'object' && value !== null; | ||
}, | ||
extend(first, ...rest) { | ||
return Object.assign(first, ...rest); | ||
}, | ||
omit(obj, ...keys) { | ||
const result = exports._.extend({}, obj); | ||
keys.forEach(key => delete result[key]); | ||
return result; | ||
}, | ||
pick(source, ...keys) { | ||
return keys.reduce((result, key) => { | ||
if (source[key] !== undefined) { | ||
result[key] = source[key]; | ||
} | ||
return result; | ||
}, {}); | ||
}, | ||
// Recursively merge the source object into the target object | ||
merge(target, source) { | ||
if (exports._.isObject(target) && exports._.isObject(source)) { | ||
Object.keys(source).forEach(key => { | ||
if (exports._.isObject(source[key])) { | ||
if (!target[key]) { | ||
Object.assign(target, { [key]: {} }); | ||
} | ||
exports._.merge(target[key], source[key]); | ||
} | ||
else { | ||
Object.assign(target, { [key]: source[key] }); | ||
} | ||
}); | ||
} | ||
return target; | ||
} | ||
return target; | ||
} | ||
}; | ||
// Return a function that filters a result object or array | ||
// and picks only the fields passed as `params.query.$select` | ||
// and additional `otherFields` | ||
exports.select = function select (params, ...otherFields) { | ||
const fields = params && params.query && params.query.$select; | ||
if (Array.isArray(fields) && otherFields.length) { | ||
fields.push(...otherFields); | ||
} | ||
const convert = result => { | ||
if (!Array.isArray(fields)) { | ||
return result; | ||
} | ||
return _.pick(result, ...fields); | ||
}; | ||
return result => { | ||
if (Array.isArray(result)) { | ||
return result.map(convert); | ||
} | ||
return convert(result); | ||
}; | ||
}; | ||
// Duck-checks if an object looks like a promise | ||
exports.isPromise = function isPromise (result) { | ||
return _.isObject(result) && | ||
typeof result.then === 'function'; | ||
}; | ||
exports.makeUrl = function makeUrl (path, app = {}) { | ||
const get = typeof app.get === 'function' ? app.get.bind(app) : () => {}; | ||
const env = get('env') || process.env.NODE_ENV; | ||
const host = get('host') || process.env.HOST_NAME || 'localhost'; | ||
const protocol = (env === 'development' || env === 'test' || (env === undefined)) ? 'http' : 'https'; | ||
const PORT = get('port') || process.env.PORT || 3030; | ||
const port = (env === 'development' || env === 'test' || (env === undefined)) ? `:${PORT}` : ''; | ||
path = path || ''; | ||
return `${protocol}://${host}${port}/${exports.stripSlashes(path)}`; | ||
}; | ||
exports.createSymbol = name => { | ||
return typeof Symbol !== 'undefined' ? Symbol(name) : name; | ||
}; | ||
// Sorting algorithm taken from NeDB (https://github.com/louischatriot/nedb) | ||
// See https://github.com/louischatriot/nedb/blob/e3f0078499aa1005a59d0c2372e425ab789145c1/lib/model.js#L189 | ||
exports.compareNSB = function (a, b) { | ||
if (a < b) { return -1; } | ||
if (a > b) { return 1; } | ||
return 0; | ||
}; | ||
exports.compareArrays = function (a, b) { | ||
var i, comp; | ||
for (i = 0; i < Math.min(a.length, b.length); i += 1) { | ||
comp = exports.compare(a[i], b[i]); | ||
if (comp !== 0) { return comp; } | ||
} | ||
// Common section was identical, longest one wins | ||
return exports.compareNSB(a.length, b.length); | ||
}; | ||
exports.compare = function (a, b, compareStrings = exports.compareNSB) { | ||
const { compareNSB, compare, compareArrays } = exports; | ||
// undefined | ||
if (a === undefined) { return b === undefined ? 0 : -1; } | ||
if (b === undefined) { return a === undefined ? 0 : 1; } | ||
// null | ||
if (a === null) { return b === null ? 0 : -1; } | ||
if (b === null) { return a === null ? 0 : 1; } | ||
// Numbers | ||
if (typeof a === 'number') { return typeof b === 'number' ? compareNSB(a, b) : -1; } | ||
if (typeof b === 'number') { return typeof a === 'number' ? compareNSB(a, b) : 1; } | ||
// Strings | ||
if (typeof a === 'string') { return typeof b === 'string' ? compareStrings(a, b) : -1; } | ||
if (typeof b === 'string') { return typeof a === 'string' ? compareStrings(a, b) : 1; } | ||
// Booleans | ||
if (typeof a === 'boolean') { return typeof b === 'boolean' ? compareNSB(a, b) : -1; } | ||
if (typeof b === 'boolean') { return typeof a === 'boolean' ? compareNSB(a, b) : 1; } | ||
// Dates | ||
if (a instanceof Date) { return b instanceof Date ? compareNSB(a.getTime(), b.getTime()) : -1; } | ||
if (b instanceof Date) { return a instanceof Date ? compareNSB(a.getTime(), b.getTime()) : 1; } | ||
// Arrays (first element is most significant and so on) | ||
if (Array.isArray(a)) { return Array.isArray(b) ? compareArrays(a, b) : -1; } | ||
if (Array.isArray(b)) { return Array.isArray(a) ? compareArrays(a, b) : 1; } | ||
// Objects | ||
const aKeys = Object.keys(a).sort(); | ||
const bKeys = Object.keys(b).sort(); | ||
let comp = 0; | ||
for (let i = 0; i < Math.min(aKeys.length, bKeys.length); i += 1) { | ||
comp = compare(a[aKeys[i]], b[bKeys[i]]); | ||
if (comp !== 0) { return comp; } | ||
} | ||
return compareNSB(aKeys.length, bKeys.length); | ||
}; | ||
// An in-memory sorting function according to the | ||
// $sort special query parameter | ||
exports.sorter = function ($sort) { | ||
const criteria = Object.keys($sort).map(key => { | ||
const direction = $sort[key]; | ||
return { key, direction }; | ||
}); | ||
return function (a, b) { | ||
let compare; | ||
for (let i = 0; i < criteria.length; i++) { | ||
const criterion = criteria[i]; | ||
compare = criterion.direction * exports.compare(a[criterion.key], b[criterion.key]); | ||
if (compare !== 0) { | ||
return compare; | ||
} | ||
} | ||
return 0; | ||
}; | ||
}; | ||
function isPromise(result) { | ||
return exports._.isObject(result) && | ||
typeof result.then === 'function'; | ||
} | ||
exports.isPromise = isPromise; | ||
function makeUrl(path, app = {}) { | ||
const get = typeof app.get === 'function' ? app.get.bind(app) : () => { }; | ||
const env = get('env') || process.env.NODE_ENV; | ||
const host = get('host') || process.env.HOST_NAME || 'localhost'; | ||
const protocol = (env === 'development' || env === 'test' || (env === undefined)) ? 'http' : 'https'; | ||
const PORT = get('port') || process.env.PORT || 3030; | ||
const port = (env === 'development' || env === 'test' || (env === undefined)) ? `:${PORT}` : ''; | ||
path = path || ''; | ||
return `${protocol}://${host}${port}/${exports.stripSlashes(path)}`; | ||
} | ||
exports.makeUrl = makeUrl; | ||
function createSymbol(name) { | ||
return typeof Symbol !== 'undefined' ? Symbol(name) : name; | ||
} | ||
exports.createSymbol = createSymbol; | ||
//# sourceMappingURL=utils.js.map |
{ | ||
"name": "@feathersjs/commons", | ||
"version": "3.0.1", | ||
"version": "4.0.0-pre.0", | ||
"description": "Shared Feathers utility functions", | ||
@@ -26,5 +26,7 @@ "homepage": "https://feathersjs.com", | ||
}, | ||
"main": "lib/commons.js", | ||
"main": "lib/index.js", | ||
"scripts": { | ||
"test": "../../node_modules/.bin/mocha --opts ../../mocha.opts" | ||
"prepublish": "npm run compile", | ||
"compile": "shx rm -rf lib/ && tsc", | ||
"test": "mocha --opts ../../mocha.ts.opts --recursive test/**.test.ts test/**/*.test.ts" | ||
}, | ||
@@ -38,5 +40,12 @@ "directories": { | ||
"devDependencies": { | ||
"chai": "^4.1.2" | ||
"@types/chai": "^4.1.7", | ||
"@types/mocha": "^5.2.6", | ||
"@types/node": "^11.13.0", | ||
"chai": "^4.2.0", | ||
"mocha": "^6.0.2", | ||
"shx": "^0.3.2", | ||
"ts-node": "^8.0.3", | ||
"typescript": "^3.4.2" | ||
}, | ||
"gitHead": "da6e2732874c9c7834cb4a53526787218d62e4a3" | ||
"gitHead": "f415041c465858436a475302aabc7b8cc75adfef" | ||
} |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
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
58565
19
8
495
1
1