Skip to content

Commit

Permalink
Simplify plug-in API
Browse files Browse the repository at this point in the history
  • Loading branch information
arnelenero committed Mar 21, 2021
1 parent 5e4ef28 commit ab143c8
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 61 deletions.
12 changes: 7 additions & 5 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export function useEntity<T, C>(
): C

export interface Entity<T> {
init: () => T
init: () => void
get: () => T
set: (
newValue: T | ((value: T, ...args: any[]) => T),
Expand Down Expand Up @@ -64,8 +64,10 @@ export function plugin<O extends object>(

export interface Plugin<M extends object = Record<any, any>> {
id: string
onInit?: (entity: Entity<any>, meta: M) => void
onSet?: (entity: Entity<any>, meta: M) => void
shouldIgnoreInit?: (meta: M) => boolean
shouldIgnoreSet?: (meta: M) => boolean
init?: (origInit: () => void, get: () => any, meta: M) => () => void
set?: (
origSet: (...args: any[]) => void,
get: () => any,
meta: M
) => (...args: any[]) => void
}
47 changes: 15 additions & 32 deletions src/__tests__/entity.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,12 @@ describe('entity', () => {
expect(() => entity(0, true)).toThrow()
})

it('applies the `onInit` plug-in tap (if any) to the entity', () => {
it('applies the `init` plug-in override (if any) to the entity', () => {
let initCalls = 0
plugins.push({
id: 'test',
onInit: (entity, meta) => {
init: (init, meta) => () => {
init()
initCalls++
}
})
Expand All @@ -131,27 +132,12 @@ describe('entity', () => {
plugins.pop()
})

it('evaluates `shouldIgnoreInit` to determine exclusion', () => {
let initCalls = 0
plugins.push({
id: 'test',
onInit: (entity, meta) => {
initCalls++
},
shouldIgnoreInit: meta => meta.skip === true
})
entity(0)
entity({ hello: 'world' }, { skip: true })
expect(initCalls).toBe(1)

plugins.pop()
})

it('applies the `onSet` plug-in tap (if any) to the entity', () => {
it('applies the `set` plug-in override (if any) to the entity', () => {
let setCalls = 0
plugins.push({
id: 'test',
onSet: (entity, meta) => {
set: (set, get, meta) => (...args) => {
set(...args)
setCalls++
}
})
Expand All @@ -165,21 +151,18 @@ describe('entity', () => {
plugins.pop()
})

it('evaluates `shouldIgnoreSet` to determine exclusion', () => {
let setCalls = 0
it('requires plug-in overrides to be specified via composer function, throws otherwise', () => {
plugins.push({
id: 'test',
onSet: (entity, meta) => {
setCalls++
},
shouldIgnoreSet: meta => meta.skip === true
set: (set, ...args) => {
set(...args)
console.log('Value changed')
}
})
const counter = entity(0)
const greeting = entity({ hello: 'world' }, { skip: true })
counter.set(1)
greeting.set('wazzup')
// note: `set` is also called automatically on init!
expect(setCalls).toBe(2)

expect(() => {
entity(0)
}).toThrow()

plugins.pop()
})
Expand Down
18 changes: 10 additions & 8 deletions src/__tests__/plugin.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,15 @@ describe('plugin', () => {
}).toThrow()
})

it('throws if plug-in (with same `id`) is being installed more than once', () => {
expect(() => {
const tester = () => ({
id: 'tester'
})
plugin(tester)
plugin(tester)
}).toThrow()
it('overwrites any prior installed plug-in with same `id`', () => {
const tester = () => ({
id: 'tester'
})
const newTester = () => ({
id: 'tester'
})
plugin(tester)
plugin(newTester)
expect(plugins).toHaveLength(1)
})
})
23 changes: 11 additions & 12 deletions src/entity.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,21 +46,20 @@ const createSetter = entity => (newValue, ...updaterArgs) => {
)
}

const applyPlugins = (entity, meta) => {
export const applyPlugins = (entity, meta) => {
plugins.forEach(plugin => {
const tapMethod = (method, tap, shouldIgnore) => {
const ignore = typeof shouldIgnore === 'function' && shouldIgnore(meta)
if (!ignore && typeof tap === 'function') {
const func = entity[method]
entity[method] = (...args) => {
func(...args)
tap(entity, meta)
}
const overrideMethod = method => {
if (typeof plugin[method] === 'function') {
const override = plugin[method](entity[method], entity.get, meta)
if (typeof override !== 'function')
throw new Error(
`Invalid override for '${method}' in plug-in '${plugin.id}'.`
)
entity[method] = override
}
}

tapMethod('init', plugin.onInit, plugin.shouldIgnoreInit)
tapMethod('set', plugin.onSet, plugin.shouldIgnoreSet)
overrideMethod('init')
overrideMethod('set')
})
}

Expand Down
8 changes: 4 additions & 4 deletions src/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ export const plugin = (pluginFn, options = {}) => {
if (typeof pluginObj.id !== 'string')
throw new Error('Plug-in should have an `id`')

if (plugins.find(installed => installed.id === pluginObj.id))
throw new Error(`Plug-in with id '${pluginObj.id}' is already installed.`)

plugins.push(pluginObj)
// Prevent installing the same plug-in more than once
const foundAt = plugins.findIndex(installed => installed.id === pluginObj.id)
if (foundAt > -1) plugins[foundAt] = pluginObj
else plugins.push(pluginObj)
}

export default plugin

0 comments on commit ab143c8

Please sign in to comment.