@skele/classic
Version:
Skele is an architectural framework that assists with building data-driven apps with React or React Native.
123 lines (90 loc) • 2.54 kB
JavaScript
import invariant from 'invariant'
import * as R from 'ramda'
import uuid from 'uuid'
// what is a subsystem
// required
// -- name: the name of the subsystem
export const name = R.prop('name')
// -- middleware (optional)
export const middleware = R.prop('middleware')
// -- reducer (optional)
export const reducer = R.prop('reducer')
// -- start (optional)
// -- element mixins (optional, not implemented currently)
export const elementMixins = R.pipe(
R.prop('elementMixins'),
R.defaultTo([])
)
// -- engine mixins (optional)
export const engineMixins = R.pipe(
R.prop('engineMixins'),
R.defaultTo([])
)
// default extension points
// -- updates
// -- effects
// -- ui
// -- custom methods
export const subsystemFnAttribute = '@@skele/subsystemFn'
let extensions = []
/*
Allows adding extension points for subsystems:
Subsystem.extend(sub)
This will add a property read all follwoing subsystems with the methods
defined here.
*/
export function extend(extension) {
invariant(
typeof extension === 'function',
'You must provide a function subsystem => extension'
)
extensions.push(extension)
}
export function resetExtensions() {
extensions = []
}
/*
subsystemFnAttribute: kernel => subsystemDef
allows subsystems to export an object
where calls to customized registreations can be made
e.g. file defaultSubsystem.s:
import Subsystem from 'subsystem'
export default Subsystem.create(kernel => {
name: 'default',
reducer: ...
middleware: ...
})
this object then exposes standard entrypoints for registreations:
import { ui, update } from 'defaultSubsystem'
ui.register(...)
update.register(...)
But also, if a subsystem adds an extension, other subsystems may contribute to
(see extend())
*/
export function create(subsystemFn) {
invariant(
typeof subsystemFn === 'function',
'You must provide a creator function'
)
return R.reduce(
(subsystem, ext) => ({ ...subsystem, ...ext(subsystem) }),
{
[subsystemFnAttribute]: subsystemFn,
},
extensions
)
}
export function fromMiddleware(middleware, name = undefined) {
if (name == null) name = uuid()
return create(() => ({
name,
middleware,
}))
}
export const instantiate = R.curry((kernel, instantiated, subsystem) => {
let instance = subsystem[subsystemFnAttribute](kernel, instantiated)
invariant(instance.name, 'The subsystem must have a name property')
Object.setPrototypeOf(instance, subsystem)
return instance
})