What is a Stamp
Stamp is a composable factory function.
NOTEFactory functions create and return new objects.
const object = Stamp() // creating a new object from a stamp
But unlike plain functions, Stamps carry around the metadata about the object they are going to produce. The metadata is attached to the
Stamp.compose
object. Another name for that metadata is "stamp descriptor" or just "descriptor".const descriptor = Stamp.compose // retrieving a stamp's metadata
interface Descriptor {
methods: Object,
properties: Object,
deepProperties: Object,
propertyDescriptors: Object,
initializers: Function[],
staticProperties: Object,
staticDeepProperties: Object,
staticPropertyDescriptors: Object,
composers: Function[],
configuration: Object,
deepConfiguration: Object
}
You, the developer, is allowed and encouraged to operate that metadata manually if needed.
For example, you can always check which methods an object instance will have:
console.log('Object will have these methods:', Object.keys(Stamp.compose.methods))
To understand if your object is a stamp you need to check its property
.compose
like this:function isStamp (object) {
return typeof object === 'function' && typeof object.compose === 'function'
}
The main reason why stamps exist is the ability to freely compose stamps together.
const ComposedStamp = stampit(Stamp1, Stamp2, Stamp3)
The line above is identical to these:
const ComposedStamp = Stamp1.compose(Stamp2, Stamp3)
const ComposedStamp = Stamp1.compose(Stamp2).compose(Stamp3)
const ComposedStamp = Stamp1.compose(Stamp2.compose(Stamp3))
const ComposedStamp = stampit().compose(Stamp1, Stamp2, Stamp3)
The
stampit
and .compose
functions are doing only one thing: merge stamp descriptors according to the stamp specification.NOTEEvery time you callstampit
or.compose
you create a NEW stamp.
There is no naming conflict resolution in stamps by default. This means that in case of conflicting properties/methods the last composed overwrites all previous.
const Stamp1 = stampit({ prop: { conflicting: 'foo' } })
const Stamp2 = stampit({ prop: { conflicting: 'oops!!!' } })
const ComposedStamp = compose(Stamp1, Stamp2)
ComposedStamp.compose.properties.conflicting === 'oops!!!'
const ReverseComposedStamp = compose(Stamp2, Stamp1)
ReverseComposedStamp.compose.properties.conflicting === 'foo'
This behaviour is by design.
NOTEIf you really need to make sure none overwrites your method you can use @stamp/collision stamp. Compose it into your stamp. However, in our practice stamps tend to stay quite small, so that conflict resolution is never needed.
To create a new stamp from scratch you would need to use one of the JavaScript modules available:
You can use both
stampit
s same way as if it was the compose
function. But you cannot use compose
function same way as stampit
. For example, these lines generate same stamp:const StampFromCompose = compose(Stamp1, Stamp2, Stamp3)
const StampFromStampit = stampit(Stamp1, Stamp2, Stamp3)
However,
stampit
adds few more handy APIs to your stamp (see comments):const NewStamp1 = StampFromStampit.methods({ myMethod () {} }) // add a method metadata using chaining API
const NewStamp2 = stampit({ props: { myProperty: 'my value' } }) // using "props" metadata shortcut
// etc
Whereas
compose
does not have the handy API (see comments):StampFromCompose.methods === undefined // THERE IS NO .methods CHAINING API
compose({ props: { myProperty: 'my value' } }) // WRONG! YOU MUST USE FULL `properties` KEY
NOTE
Last modified 4yr ago