@apicase/core
Advanced tools
Comparing version 0.7.0-beta.1 to 0.7.0-beta.2
@@ -5,2 +5,3 @@ module.exports = { | ||
'env': { | ||
'jest': true, | ||
'node': true, | ||
@@ -12,3 +13,3 @@ 'browser': true | ||
/* It's better to have indent for call expr with multi-lines */ | ||
'indent': ['error', 2, { 'CallExpression': { 'arguments': 1 } }] | ||
'indent': ['error', 2, { 'CallExpression': { 'arguments': 1 } }], | ||
/* Prettier doesn't support space before paren */ | ||
@@ -15,0 +16,0 @@ 'space-before-function-paren': 0 |
@@ -8,17 +8,13 @@ import _default3 from 'nanoutils/lib/mapObjIndexed'; | ||
function compose(hooks, createData) { | ||
return function (payload, changePayload) { | ||
if (!hooks.length) return Promise.resolve(payload); | ||
return new Promise(function (resolve) { | ||
var data = createData(payload); | ||
var merged = _default(data, { | ||
next: function (payload) { | ||
changePayload(payload); | ||
return compose(hooks.slice(1), createData)(payload, changePayload).then(resolve); | ||
} | ||
}); | ||
hooks[0](merged); | ||
}); | ||
const compose = (hooks, createData) => (payload, changePayload) => new Promise(resolve => { | ||
if (!hooks.length) return resolve(payload); | ||
const data = createData(payload); | ||
const next = payload => { | ||
changePayload(payload); | ||
const callNextHooks = compose(hooks.slice(1), createData); | ||
return callNextHooks(payload, changePayload).then(resolve); | ||
}; | ||
} | ||
const merged = _default(data, { next }); | ||
hooks[0](merged); | ||
}); | ||
@@ -41,3 +37,3 @@ /** | ||
/** | ||
* State of querty | ||
* State of query | ||
* | ||
@@ -82,148 +78,146 @@ * @typedef {Object} State | ||
*/ | ||
export function apicase(adapter) { | ||
return function (req, opts) { | ||
// Prepare | ||
opts = opts || {}; | ||
req = req._isNormalized ? req : normalizeOptions(req); | ||
const apicase = adapter => (req, opts) => { | ||
// Prepare | ||
opts = opts || {}; | ||
req = req._isNormalized ? req : normalizeOptions(adapter, req); | ||
// All data | ||
var bus = new EventBus(); | ||
var res = { | ||
state: { | ||
success: false, | ||
pending: false, | ||
started: false, | ||
payload: req.payload, | ||
result: adapter.createState() | ||
}, | ||
on: function (evt, cb) { | ||
bus.on(evt, cb); | ||
return res; | ||
}, | ||
cancel: function () { | ||
return Promise.resolve().then(function () { | ||
return cancelCallback(); | ||
}).then(function (res) { | ||
bus.emit('cancel', res.state); | ||
}); | ||
} | ||
}; | ||
var cancelCallback = function () {}; | ||
/* TODO: reduce boilerplate for sets */ | ||
function setState(change) { | ||
var prev = _default2(res.state); | ||
var next = _default(prev, change); | ||
res.state = next; | ||
bus.emit('change:state', { | ||
prev: prev, | ||
next: next, | ||
change: change | ||
// All data | ||
const bus = new EventBus(); | ||
const res = { | ||
state: { | ||
success: false, | ||
pending: false, | ||
started: false, | ||
cancelled: false, | ||
payload: req.payload, | ||
result: adapter.createState ? adapter.createState() : {} | ||
}, | ||
on: (evt, cb) => { | ||
bus.on(evt, cb); | ||
return res; | ||
}, | ||
cancel: () => { | ||
return Promise.resolve().then(() => cancelCallback()).then(() => { | ||
setState({ success: false, pending: false, cancelled: true }); | ||
bus.emit('cancel', res.state); | ||
}); | ||
} | ||
}; | ||
let cancelCallback = () => {}; | ||
function setPayload(change) { | ||
var prev = _default2(res.state.payload); | ||
var next = _default(prev, change); | ||
res.state.payload = next; | ||
bus.emit('change:payload', { | ||
prev: prev, | ||
next: next, | ||
change: change | ||
}); | ||
} | ||
/* TODO: reduce boilerplate for sets */ | ||
const setState = change => { | ||
const prev = _default2(res.state); | ||
const next = _default(prev, change); | ||
res.state = next; | ||
bus.emit('change:state', { | ||
prev: prev, | ||
next: next, | ||
change: change | ||
}); | ||
}; | ||
function setResult(change) { | ||
var prev = _default2(res.state.result); | ||
var next = _default(prev, change); | ||
res.state.result = next; | ||
bus.emit('change:result', { | ||
prev: prev, | ||
next: next, | ||
change: change | ||
const setPayload = change => { | ||
const prev = _default2(res.state.payload); | ||
const next = _default(prev, change); | ||
res.state.payload = next; | ||
bus.emit('change:payload', { | ||
prev: prev, | ||
next: next, | ||
change: change | ||
}); | ||
}; | ||
const setResult = change => { | ||
const prev = _default2(res.state.result); | ||
const next = _default(prev, change); | ||
res.state.result = next; | ||
bus.emit('change:result', { | ||
prev: prev, | ||
next: next, | ||
change: change | ||
}); | ||
}; | ||
// Adapter + hooks | ||
const doRequest = function (payload) { | ||
return new Promise(resolve => { | ||
const resolveCb = result => setResult(result) || composedHooks.resolve(res.state.result).then(() => resolve(res.state)); | ||
const rejectCb = result => setResult(result) || composedHooks.reject(res.state.result).then(() => resolve(res.state)); | ||
adapter.callback({ | ||
payload: res.state.payload, | ||
result: res.state.result, | ||
setResult: setResult, | ||
resolve: resolveCb, | ||
reject: rejectCb, | ||
emit: bus.emit, | ||
setCancelCallback: cb => { | ||
cancelCallback = cb; | ||
} | ||
}); | ||
} | ||
}); | ||
}; | ||
var hooks = { | ||
before: { | ||
state: { started: true, pending: true }, | ||
update: setPayload, | ||
payload: function (payload) { | ||
return { | ||
payload: payload, | ||
resolve: composedHooks.resolve, | ||
reject: composedHooks.reject | ||
}; | ||
}, | ||
finalCb: callAdapter | ||
}, | ||
resolve: { | ||
state: { success: true }, | ||
update: setResult, | ||
payload: function (result) { | ||
return { | ||
result: result, | ||
reject: composedHooks.reject | ||
}; | ||
}, | ||
finalCb: function (result) { | ||
setState({ pending: false }); | ||
bus.emit('resolve', result, res.state); | ||
bus.emit('finish', result, res.state); | ||
} | ||
}, | ||
reject: { | ||
state: { success: true }, | ||
update: setResult, | ||
payload: function (result) { | ||
return { | ||
result: result, | ||
resolve: composedHooks.resolve | ||
}; | ||
}, | ||
finalCb: function (result) { | ||
setState({ pending: false }); | ||
bus.emit('resolve', result, res.state); | ||
bus.emit('finish', result, res.state); | ||
} | ||
// Options for hooks queues | ||
const hooks = { | ||
before: { | ||
state: { started: true, pending: true }, | ||
update: setPayload, | ||
payload: payload => ({ | ||
payload: payload, | ||
resolve: composedHooks.resolve, | ||
reject: composedHooks.reject | ||
}), | ||
finalCb: doRequest | ||
}, | ||
resolve: { | ||
state: { success: true }, | ||
update: setResult, | ||
payload: result => ({ | ||
retry: doRequest, | ||
result: result, | ||
reject: composedHooks.reject | ||
}), | ||
finalCb: result => { | ||
setState({ pending: false }); | ||
bus.emit('resolve', result, res.state); | ||
bus.emit('finish', result, res.state); | ||
} | ||
}; | ||
}, | ||
reject: { | ||
state: { success: false }, | ||
update: setResult, | ||
payload: result => ({ | ||
retry: doRequest, | ||
result: result, | ||
resolve: composedHooks.resolve | ||
}), | ||
finalCb: result => { | ||
setState({ pending: false }); | ||
bus.emit('reject', result, res.state); | ||
bus.emit('finish', result, res.state); | ||
} | ||
} | ||
var composedHooks = _default3(function (params, k) { | ||
return function (payload) { | ||
setState(params.state); | ||
return compose(req.hooks[k], params.payload)(payload, params.update).then(params.finalCb); | ||
}; | ||
}, hooks); | ||
// Object with callbacks that start hooks queue | ||
};const composedHooks = _default3((params, k) => payload => { | ||
setState(params.state); | ||
if (res.state.cancelled) return res; | ||
return compose(req.hooks[k], params.payload)(payload, params.update).then(params.finalCb); | ||
}, hooks); | ||
// Adapter + hooks | ||
var callAdapter = function (payload) { | ||
return new Promise(function (done) { | ||
adapter.callback({ | ||
payload: res.state.payload, | ||
resolve: function (result) { | ||
composedHooks.resolve(result).then(function () { | ||
done(res.state); | ||
}); | ||
}, | ||
reject: function (res) { | ||
composedHooks.reject(result).then(function () { | ||
done(res.state); | ||
}); | ||
}, | ||
emit: bus.emit, | ||
setCancelCallback(cb) { | ||
cancelCallback = cb; | ||
} | ||
}); | ||
}); | ||
}; | ||
// Start queue and add to res | ||
res.promise = composedHooks.before(req.payload); | ||
res.promise.catch(function (err) { | ||
bus.emit('error', err); | ||
return Promise.reject(err); | ||
}); | ||
res.then = cb => res.promise.then(cb); | ||
res.catch = cb => res.promise.catch(cb); | ||
// Start queue and add to res | ||
res.promise = composedHooks.before(req.payload); | ||
res.then = res.promise.then; | ||
res.catch = res.promise.catch; | ||
return res; | ||
}; | ||
return res; | ||
}; | ||
} | ||
export { apicase }; |
@@ -1,2 +0,5 @@ | ||
import _default2 from 'nanoutils/lib/clone'; | ||
import _default5 from 'nanoutils/lib/map'; | ||
import _default4 from 'nanoutils/lib/clone'; | ||
import _default3 from 'nanoutils/lib/mapObjIndexed'; | ||
import _default2 from 'nanoutils/lib/merge'; | ||
import _default from 'nanoutils/lib/mergeWith'; | ||
@@ -7,34 +10,24 @@ import defaults from './defaults'; | ||
var mergers = { | ||
adapter(from, to) { | ||
return from || to; | ||
}, | ||
hooks(from, to) { | ||
return _default(function (from, to) { | ||
return (from || []).concat(to); | ||
}, from, to); | ||
}, | ||
meta(from, to) { | ||
return _default(function (from, to) { | ||
return to; | ||
}, from, to); | ||
}, | ||
payload(from, to, res) { | ||
return res.adapter && res.adapter.merge ? res.adapter.merge(from, to) : _default(function (from, to) { | ||
return to !== undefined ? to : from; | ||
}, from, to); | ||
} | ||
const mergers = { | ||
adapter: adapter => (from, to) => from || to, | ||
hooks: adapter => _default((from, to) => (from || []).concat(to)), | ||
meta: adapter => _default((from, to) => to), | ||
payload: adapter => adapter && adapter.merge ? adapter.merge : _default2 | ||
}; | ||
export function mergeOptions(adapter, opts) { | ||
opts = opts.map(function (opt) { | ||
return normalizeOptions(adapter, _default2(typeof opt === 'function' ? opt() : opt)); | ||
}); | ||
var def = _default2(defaults); | ||
return Object.keys(mergers).reduce(function (res, key) { | ||
res[key] = opts.reduce(function (opt, next, index, opts) { | ||
return mergers[key](opt, next[key], res, index, opts); | ||
}, def[key]); | ||
return res; | ||
}, def); | ||
} | ||
const createMergeReducer = cbs => (res, cur) => Object.assign(res, _default3((val, key) => cbs[key] ? cbs[key](res[key], val) : val, cur)); | ||
// TODO: refactor it | ||
const mergeOptions = (adapter, opts) => { | ||
opts = opts.map(opt => normalizeOptions(adapter, _default4(typeof opt === 'function' ? opt() : opt))); | ||
const cbs = _default5(cb => cb(adapter), mergers); | ||
const def = _default4(defaults); | ||
const reducer = createMergeReducer(cbs); | ||
return opts.reduce(reducer, def); | ||
}; | ||
export { mergeOptions }; |
@@ -9,17 +9,14 @@ import _default5 from 'nanoutils/lib/omit'; | ||
function normalize(callbacks, obj) { | ||
return Object.keys(obj).reduce(function (res, key) { | ||
res[key] = callbacks[key] ? callbacks[key](obj[key], res, obj) : obj[key]; | ||
return res; | ||
}, { _isNormalized: true }); | ||
} | ||
const normalize = (callbacks, obj) => Object.keys(obj).reduce((res, key) => { | ||
res[key] = callbacks[key] ? callbacks[key](obj[key], res, obj) : obj[key]; | ||
return res; | ||
}, { _isNormalized: true }); | ||
var defaults = _default(function (a, b) { | ||
return b === undefined ? a : b; | ||
}); | ||
const defaults = _default((a, b) => b === undefined ? a : b); | ||
var normalizers = { | ||
adapter(adapter) { | ||
return adapter || null; | ||
}, | ||
const normalizers = { | ||
// Return adapter or null | ||
adapter: adapter => adapter || null, | ||
// Convert payload with | ||
payload(payload, res, prev) { | ||
@@ -35,7 +32,9 @@ if (process.env.NODE_ENV !== 'production') { | ||
}, | ||
hooks(hooks) { | ||
hooks: hooks => { | ||
if (!hooks) return {}; | ||
return _default2(function (hooks, k) { | ||
return _default2((hooks, k) => { | ||
const hooksArr = Array.isArray(hooks) ? hooks : [hooks]; | ||
if (process.env.NODE_ENV !== 'production') { | ||
;(Array.isArray(hooks) ? hooks : [hooks]).forEach(function (hook, idx) { | ||
hooksArr.forEach((hook, idx) => { | ||
if (typeof hook !== 'function') { | ||
@@ -46,3 +45,3 @@ throw new TypeError('[Apicase] ' + k + ' hook #' + idx + ' is not a function'); | ||
} | ||
return Array.isArray(hooks) ? hooks : [hooks]; | ||
return hooksArr; | ||
}, _default3(_default4(defaultOptions.hooks), hooks)); | ||
@@ -52,13 +51,11 @@ } | ||
function format(adapter, opts) { | ||
return { | ||
adapter: adapter, | ||
meta: opts.meta, | ||
hooks: opts.hooks, | ||
payload: _default5(['adapter', 'meta', 'hooks'], opts) | ||
}; | ||
} | ||
const format = (adapter, opts) => ({ | ||
adapter: adapter, | ||
meta: opts.meta, | ||
hooks: opts.hooks, | ||
payload: _default5(['adapter', 'meta', 'hooks'], opts) | ||
}); | ||
export function normalizeOptions(adapter, opts) { | ||
return opts._isNormalized ? opts : normalize(normalizers, defaults(_default4(defaultOptions), format(adapter, opts || {}))); | ||
} | ||
const normalizeOptions = (adapter, opts) => opts._isNormalized ? opts : normalize(normalizers, defaults(_default4(defaultOptions), format(adapter, opts || {}))); | ||
export { normalizeOptions }; |
@@ -7,13 +7,18 @@ import { apiCall } from './call'; | ||
*/ | ||
export function apiQueue(optsArray, prev) { | ||
if (!optsArray.length) return Promise.resolve(prev); | ||
var opt = typeof optsArray[0] === 'function' ? optsArray[0](prev) : optsArray[0]; | ||
if (process.env.NODE_ENV !== 'production') { | ||
if (typeof opt !== 'object') { | ||
throw new TypeError('[apicase.apiQueue] Expected options to be an Object but some of them are not'); | ||
} | ||
} | ||
return apiCall(opt).then(function (res) { | ||
return apiQueue(optsArray.slice(1), res); | ||
}); | ||
} | ||
export function ApiQueue() {} | ||
// export function apiQueue(optsArray, prev) { | ||
// if (!optsArray.length) return Promise.resolve(prev) | ||
// var opt = | ||
// typeof optsArray[0] === 'function' ? optsArray[0](prev) : optsArray[0] | ||
// if (process.env.NODE_ENV !== 'production') { | ||
// if (typeof opt !== 'object') { | ||
// throw new TypeError( | ||
// '[apicase.apiQueue] Expected options to be an Object but some of them are not' | ||
// ) | ||
// } | ||
// } | ||
// return apiCall(opt).then(function(res) { | ||
// return apiQueue(optsArray.slice(1), res) | ||
// }) | ||
// } |
@@ -19,4 +19,4 @@ import _default from 'nanoutils/lib/equals'; | ||
function addCall(payload) { | ||
var call = apicase(this.adapter)(payload).on('finish', function () { | ||
const addCall = payload => { | ||
const call = apicase(this.adapter)(payload).on('finish', () => { | ||
this.queue.splice(this.queue.indexOf(call), 1); | ||
@@ -26,4 +26,6 @@ }); | ||
return call; | ||
} | ||
}; | ||
const getOpts = opts => mergeOptions(this.adapter, this._opts.concat(opts)); | ||
/** | ||
@@ -42,3 +44,3 @@ * Create a new extended service | ||
this.doRequest = function (opts) { | ||
return addCall(mergeOptions(this.adapter, this._opts.concat(opts))); | ||
return addCall(getOpts(opts)); | ||
}; | ||
@@ -51,8 +53,12 @@ | ||
this.pushRequest = function (opts) { | ||
var s = this; | ||
if (this.queue.length > 0) { | ||
this.queue[this.queue.length - 1].on('finish', function () { | ||
return s.doRequest(opts); | ||
}); | ||
} | ||
if (!this.queue.length) return addCall(opts); | ||
const withHook = { | ||
hooks: { | ||
before: ({ payload, next }) => { | ||
this.queue[this.queue.length - 1].on('finish', () => next(payload)); | ||
} | ||
} | ||
}; | ||
const mergedOpts = mergeOptions(withHook, opts); | ||
return addCall(getOpts(mergedOpts)); | ||
}; | ||
@@ -75,12 +81,6 @@ | ||
this.doUniqueRequest = function (opts) { | ||
var req = mergeOptions(this.adapter, this._opts.concat(opts)); | ||
var idx = -1; | ||
for (var i in this.queue) { | ||
if (_default(this.queue[i].state.payload, req.payload)) { | ||
idx = i; | ||
break; | ||
} | ||
} | ||
const req = getOpts(opts); | ||
const idx = this.queue.findIndex(i => _default(i.state.payload, req.payload)); | ||
return idx > -1 ? this.queue[idx] : addCall(req); | ||
}; | ||
} |
{ | ||
"name": "@apicase/core", | ||
"version": "0.7.0-beta.1", | ||
"version": "0.7.0-beta.2", | ||
"description": "Core library to make API calls with any adapter", | ||
@@ -11,6 +11,13 @@ "main": "es/index.js", | ||
"license": "MIT", | ||
"config": { | ||
"ghooks": { | ||
"pre-commit": "npm run lint" | ||
} | ||
}, | ||
"scripts": { | ||
"lint": "eslint --fix *.js", | ||
"size": "size-limit", | ||
"test": "jest" | ||
"test": "jest", | ||
"build": "node build.js && npm run test && npm run size", | ||
"prepublish": "npm run build" | ||
}, | ||
@@ -24,7 +31,7 @@ "size-limit": [ | ||
"path": "es/all.js", | ||
"limit": "1.5 KB" | ||
"limit": "2 KB" | ||
}, | ||
{ | ||
"path": "es/queue.js", | ||
"limit": "1.5 KB" | ||
"limit": "2 KB" | ||
}, | ||
@@ -41,3 +48,3 @@ { | ||
"path": "es/service.js", | ||
"limit": "2 KB" | ||
"limit": "3 KB" | ||
}, | ||
@@ -51,8 +58,10 @@ { | ||
"nanoevents": "^1.0.2", | ||
"nanoutils": "^0.0.13" | ||
"nanoutils": "^0.0.15" | ||
}, | ||
"devDependencies": { | ||
"babel-core": "^6.26.0", | ||
"babel-jest": "^22.4.0", | ||
"babel-plugin-nanoutils": "^0.1.1", | ||
"babel-plugin-transform-es2015-modules-simple-commonjs": "^0.3.0", | ||
"babel-preset-env": "^1.6.1", | ||
"eslint": "^4.16.0", | ||
@@ -64,3 +73,5 @@ "eslint-config-standard": "^11.0.0-beta.0", | ||
"eslint-plugin-standard": "^3.0.1", | ||
"ghooks": "^2.0.2", | ||
"jest": "^22.1.4", | ||
"regenerator-runtime": "^0.11.1", | ||
"rimraf": "^2.6.2", | ||
@@ -67,0 +78,0 @@ "rollup": "^0.55.1", |
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
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
30302
19
850
3
19
1
+ Addednanoutils@0.0.15(transitive)
- Removednanoutils@0.0.13(transitive)
Updatednanoutils@^0.0.15