# Introduction

## What is stampit

`stampit` is a JavaScript module which implements the [**stamp** specification](/essentials/specification). **Stamps** are composable factory functions.

**Think of&#x20;*****stamps*****&#x20;as classic classes but without any limits, boundaries, or rules.**

The stamps brag large amount of features and things you can do with your objects and/or stamps.

Head straight to the [Quick Start](/api/quick-start) page for code examples.

![Object instances created from classes vs stamps.](https://1681072127-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LBFDyli93b3DkmP1MWz%2F-LBFDzVCs7MXZ5zFrsca%2F-LBFE3SlonIOZYCL91vm%2Fclass_vs_stamp.png?generation=1524985778364294\&alt=media)

## Differences from classes

* Inheritance
  * Classes
    * Classes do child+parent+parent+parent... inheritance chains. See picture above.
    * When you extend a class you link class prototypes.
  * Stamps
    * Stamp are single object + single prototype. See picture above.
    * When you "extend" you separately merge [methods](/api/methods), separately merge [properties](/api/properties), separately merge [static properties](/api/static-properties), separately merge [initializers](/api/initializers) (aka constructors), etc etc etc.
    * That's why it is not just inheritance, but special type of object composition. The stamp composition algorithm is [standardized](/essentials/specification/merging-algorithm).
    * You can influence composition result with your code at runtime using the [composers](/api/composers) feature.
* Object creation
  * Classes
    * In most programming languages you execute only one constructor per class.
    * To pass data to the parent constructor you have to manually call parent constructor `this.super(data)`.
    * To create an object you need to use the `new` keyword: `const object = new MyClass()`.
  * Stamps
    * Stamp executes every initializer (aka constructor) it has.
    * All initializers receive exactly the same set of arguments, no need to manually pass data.
    * The initializer execution sequence is the same as the stamp composition sequence.
    * To create an object you [call stamp](/api/quick-start) as a function: `const object = MyStamp()`.

## History

The original idea of Stamps belongs to [Eric Elliott](https://ericelliottjs.com/). See his [first commit](https://github.com/stampit-org/stampit/commit/ac330e8537e349a9640bbe4a34c63150db445a20) from 11 Feb 2013 in the stampit repository. Since then the idea evolved to the [specification](/essentials/specification) and a whole [ecosystem](/ecosystem/ecosystem-overview) of mini modules.

## Using Stamps

Head straight to the [Quick start ](/api/quick-start)for code examples.

## Ecosystem

Stampit have a lot of helper modules. You can always find the list of official NPM packages here: <https://www.npmjs.com/~stamp>

See more information on the [Ecosystem](/ecosystem/ecosystem-overview) page.

## Quick code example

The example below introduces `GraphPoint` and `GraphLine` stamps (aka blueprints, aka factory functions, aka behaviours).

Let's start by declaring the `Point` stamp.

```javascript
const stampit = require("stampit");

const Point = stampit({
  props: { // default property values
    x: 0,
    y: 0
  },
  init({ x, y }) { // kinda constructor
    if (x != null) this.x = x;
    if (y != null) this.y = y;
  },
  methods: { // that goes to the prototype
    distance(point) {
      return Math.sqrt((this.x - point.x)**2 + (this.y - point.y)**2);
    }
  }
});
```

That's how you create instance of the above stamp.

```javascript
// Creating instance of the Point.
const point = Point({ x: 12, y: 42 });
// Calling a method.
point.distance({ x: 13, y: 42 }) === 1.0;
```

Now let's "inherit" the `Point` to create a `Circle`. We will add `radius` property to the mix.

```javascript
// kinda inheritance, but not really
const Circle = stampit(Point, {
  props: {
    radius: 1
  },
  init({ radius }) {
    if (radius != null) this.radius = radius;
  },
  methods: { // that goes to the prototype
    distance(point) {
      // Calling the "super class" by instantiating Point stamp
      return Point(point).distance(this) - this.radius;
    }
  }
});
```

When creating instance of the `Circle` you will actually call **TWO** different initialisers (aka constructors). Stamps have multiple initialisers.&#x20;

```javascript
// TWO different initializers will be executed here!!!
const circle = Circle({ x: 12, y: 42, radius: 1.5 });
circle.distance({ x: 14, y: 42 }) === 0.5;
```

Now, declaring couple of additional stamps. We'll use them to enrich JavaScript drawable objects.

```javascript
const Tagged = stampit({
  props: {
    tag: ""
  },
  init({ tag }) {
    this.tag = tag || this.tag;
  }
});

const Colored = stampit({
  props: {
    color: "#000000"
  },
  init({ color }) {
    this.color = color || this.color;
  }
});
```

The `Drawable` behaviour. We have to make sure that developers implement the `draw()` method when using this stamp.

```javascript
const Drawable = stampit(
  Tagged,
  Colored,
  init() { 
    assert(typeof this.draw === "function", "you must implement the draw() method");
  }
);
```

Now let's implement the `GraphPoint` stamp.

```javascript
const GraphPoint = stampit(Drawable, Circle, {
  methods: {
    draw(ctx) {
      ctx.setColor(this.color);
      ctx.drawFilledCircle(this.x, this.y, this.radius);
      if (this.tag) 
        ctx.drawText(this.x + this.radius, this.y + this.radius, this.tag);
    }
  }
});
```

Please, note we are executing **FOUR** intializers here.

```javascript
// FOUR different initializers will be executed here.
const graphPoint = GraphPoint({ 
  x: 12, 
  y: 42, 
  radius: 1.5, 
  color: "red", 
  tag: "start" 
});
graphPoint.draw(someDrawingContext);
```

`Line` primitive.

```javascript
const Line = stampit({
  props: {
    point1: Point({ x: 0, y: 0 }),
    point2: Point({ x: 0, y: 0 })
  },
  init({ point1, point2 }) {
    this.point1 = Point(point1);
    this.point2 = Point(point2);
  },
  methods: {
    middlePoint() {
      return Point({ 
        x: (this.point1.x + this.point2.x) / 2, 
        y: (this.point1.y + this.point2.y) / 2
      });
    }
  }
});

const line = Line({ point1: { x: 12, y: 42 }, point2: { x: 34, y: 40 } });
```

Our final destination - a drawable graph line.

```javascript
const GraphLine = stampit(Drawable, Line, {
  methods: {
    draw(ctx) {
      ctx.setColor(this.color);
      ctx.drawLine(this.point1.x, this.point1.y, this.point2.x, this.point2.y);
      if (this.tag) 
        ctx.drawText(this.middlePoint().x, this.middlePoint().y, this.tag);
    }
  }
});
```

And the usage.

```javascript
const graphLine = GraphLine({ 
  point1: { x: 12, y: 42 }, 
  point2: { x: 34, y: 40 }, 
  color: "red", 
  tag: "March" 
});
graphLine.draw(someDrawingContext);
```

The idea is - separate concerns. We split our logic into several reusable highly decoupled primitive behaviours (Point, Colored, Tagged, Circle, Line).

It's importan to distinguish the "**is**" and "**has**" composition.

The above has:

* `Point` concern and all related functionality in a *separate* stamp.
* `Circle` concern and the related functionality *separated*. `Circle` **is** an extension of the `Point`.
* `Tagged` concern in a *separate* stamp.
* `Colored` concern in a *separate* stamp.
* `GraphPoint` concern **is** `Circle`, `Tagged` and `Colored` concerns combined.
* `Line` concern - it **has** two `Points`.
* `GraphLine` - **is** the `Line` but with additional `Tagged` and `Colored` functionalities.

&#x20;You can't do anything like that with classes. And the resulting code is more readable than classes.


# What is a Stamp

Stamp is a **composable** factory function.

> *NOTE*
>
> Factory functions create and return new objects.

Go to [API Quick start](/api/quick-start) to learn how to create a Stamp.

```javascript
const object = Stamp() // creating a new object from a stamp
```

## Stamp's metadata (descriptor)

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".

```javascript
const descriptor = Stamp.compose // retrieving a stamp's metadata
```

There are 11 [standardized](/essentials/specification) types of metadata:

```typescript
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:

```javascript
console.log('Object will have these methods:', Object.keys(Stamp.compose.methods))
```

## Ducktyping a stamp

To understand if your object is a stamp you need to check its property `.compose` like this:

```javascript
function isStamp (object) {
  return typeof object === 'function' && typeof object.compose === 'function'
}
```

## Composing stamps

The main reason why stamps exist is the ability to freely compose stamps together.

```javascript
const ComposedStamp = stampit(Stamp1, Stamp2, Stamp3)
```

The line above is identical to these:

```javascript
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**](/essentials/specification).

> *NOTE*
>
> Every time you call `stampit` or `.compose` you create a **NEW** stamp.

### Naming conflict resolution

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.

```javascript
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**.

> NOTE
>
> If you really need to make sure none overwrites your method you can use [@stamp/collision](/ecosystem/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.

## Creating stamps

To create a new stamp from scratch you would need to use one of the JavaScript modules available:

* [`@stamp/compose`](https://www.npmjs.com/package/@stamp/compose) - the [**standardized compose function**](/essentials/specification)
* [`stampit`](https://www.npmjs.com/package/stampit) - the `compose()` function but with additional handy APIs

You can use `stampit` 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:

```javascript
const StampFromCompose = compose(Stamp1, Stamp2, Stamp3)
const StampFromStampit = stampit(Stamp1, Stamp2, Stamp3)
```

However, `stampit` adds few more handy APIs to your stamp (see comments):

```javascript
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):

```javascript
StampFromCompose.methods === undefined // THERE IS NO .methods CHAINING API
compose({ props: { myProperty: 'my value' } }) // WRONG! YOU MUST USE FULL `properties` KEY
```

> NOTE
>
> The stampit nicer API is nothing else but few additional [static methods](/api/static-properties) in your stamps. That's it.


# Installation

## Browser usage

For all JavaScript environments it is recommended to use the [`stampit`](https://github.com/stampit-org/stampit) module. It's a small (**1.5KB** gzipped), featureful and optimized. Also, it is written with TypeScript and supports both ESM and CJS modules.

### NPM

```bash
npm i -S stampit
```

### Browsers

```markup
https://npmcdn.com/stampit
```

or

```
https://unpkg.com/stampit
```

### Compatibility note

The `stampit` v5 is ESM and CJS (hybrid) module.

The detailed Release Notes are always available at the [GitHub Releases](https://github.com/stampit-org/stampit/releases) page.


# Specification

The latest version of specification can always be found here: <https://github.com/stampit-org/stamp-specification>

The history of specification releases can be found here: <https://github.com/stampit-org/stamp-specification/releases>


# Merging algorithm

When composing stamps you actually merge their [descriptors](/essentials/what-is-a-stamp) (aka metadata).

The `Object.assign` is used for these descriptor properties:

* [methods](/api/methods)
* [properties](/api/properties)
* [propertyDescriptors](/api/property-descriptors)
* [staticProperties](/api/static-properties)
* [staticPropertyDescriptors](/api/static-property-descriptors)
* [configuration](/api/configuration)

The special deep merging algorithm (see below) is used for these descriptor properties:

* [deepProperties](/api/deep-properties)
* [staticDeepProperties](/api/static-deep-properties)
* [deepConfiguration](/api/deep-configuration)

The array concatenation and deduplication (see below) is used for these descriptor properties:

* [initializers](/api/initializers)
* [composers](/api/composers)

## Array concatenation and deduplication

This is how initializers and composers metadata gets merged.

```javascript
const _ = require('lodash')

descriptor.initializers = _.uniq(_.concat(descriptor1.initializers, descriptor2.initializers))
descriptor.composers = _.uniq(_.concat(descriptor1.composers, descriptor2.composers))
```

See the [exact line](https://github.com/stampit-org/stamp-specification/blob/8a5448806da286b2f840c33cb618ddbcdb40182d/compose.js#L162) of the reference implementation source code.

## Deep merging algorithm

The [stamp specification](/essentials/specification) standardized the deep merging algorithm to, basically, this:

* Plain objects are (recursively) deep merged, including ES6 Symbol keys, ES5 getters and setters.
* **Arrays are concatenated**.
* Functions, Symbols, RegExp, etc. values are copied by reference.
* The last object type overwrites previous object type.

```javascript
const MyStamp1 = stampit()

const deepObject1 = {
  [Symbol('foo')]: { one: 'first' },                 // this plain object will be deep merged

  array: [0, 'bar', () => {}, { obj: 'my object' }], // this array will be concatenated with

  func: MyStamp1,                                    // this stamp will be replaced with another stamp

  something: [42],                                   // this array will be replaced with an object

  oldKey: 'some value'
}

const MyStamp2 = stampit()

const deepObject2 = {
  [Symbol('foo')]: { two: 'second' },

  array: [0, 'bar', { another: 'object' }],

  func: MyStamp2,

  something: { [0]: 42 },

  newKey: 'some value'
}
```

The merged result of the two objects above will be this:

```javascript
const deepResult = {
  [Symbol('foo')]: { one: 'first', two: 'second' }, // contains properties from both objects

  array: [0, 'bar', () => {}, { obj: 'my object' }, 0, 'bar', { another: 'object' }], // both arrays are here

  func: MyStamp2,                                   // Stamp2 replaced the Stamp1

  something: { [0]: 42 },                           // the array was replaced with the object

  oldKey: 'some value',                             // these two were simply carried across
  newKey: 'some value'
}
```

See the [exact line](https://github.com/stampit-org/stamp-specification/blob/8a5448806da286b2f840c33cb618ddbcdb40182d/compose.js#L70) of the reference implementation source code.


# Object creation internals

This is a plain factory function. It creates and returns a plain object.

```javascript
function myFactory () {
  return { myProperty: 'my value' }
}
```

But Stamps are a little different. They carry around the metadata about the object they are going to produce. The metadata is attached to the `Stamp.compose` object:

```javascript
function Stamp () {
  const metadata = Stamp.compose // retrieving metadata from itself

  ... SNIP ...

  return newObject
}
```

There are 11 [standardized](/essentials/specification) types of metadata, such as **properties** and **deepProperties**.

```javascript
function Stamp () {
  const metadata = Stamp.compose // retrieving metadata from itself

  const properties = metadata.properties // retrieving properties from the metadata
  let deepProperties = metadata.deepProperties // retrieving deepProperties from the metadata
  deepProperties = JSON.parse(JSON.stringify(deepProperties)) // we need to clone deepProperties
  const newObject = Object.assign({}, deepProperties, properties) // creating new object using the properties

  ... SNIP ...

  return newObject
}
```

There is also **methods** object which becomes the new object's prototype.

```javascript
function Stamp () {
  const metadata = Stamp.compose // retrieving metadata from itself

  const properties = metadata.properties // retrieving properties from the metadata
  let deepProperties = metadata.deepProperties // retrieving deepProperties from the metadata
  deepProperties = _.cloneDeep(deepProperties) // we need to clone deepProperties
  const newObject = Object.assign({}, deepProperties, properties) // creating new object using the properties

  const methods = metadata.methods // retrieving methods from the metadata
  if (methods) Object.setPrototypeOf(newObject, methods) // assigning new object's prototype

  ... SNIP ...

  return newObject
}
```

The **propertyDescriptors** metadata is an object applied to the resulting object using [`Object.defineProperties`](https://mdn.io/defineProperties) JavaScript standard function.

```javascript
function Stamp () {
  const metadata = Stamp.compose // retrieving metadata from itself

  const properties = metadata.properties // retrieving properties from the metadata
  let deepProperties = metadata.deepProperties // retrieving deepProperties from the metadata
  deepProperties = JSON.parse(JSON.stringify(deepProperties)) // we need to clone deepProperties
  const newObject = Object.assign({}, deepProperties, properties) // creating new object using the properties

  const methods = metadata.methods // retrieving methods from the metadata
  if (methods) Object.setPrototypeOf(newObject, methods) // assigning new object's prototype

  Object.defineProperties(newObject, metadata.propertyDescriptors)

  ... SNIP ...

  return newObject
}
```

Last, but not least, the **initializers** are kind of constructors. With classic classes you would execute only one constructor when creating an object. With stamps you **execute&#x20;*****all*****&#x20;the initializers** of a stamp.

```javascript
function Stamp () {
  const metadata = Stamp.compose // retrieving metadata from itself

  const properties = metadata.properties // retrieving properties from the metadata
  let deepProperties = metadata.deepProperties // retrieving deepProperties from the metadata
  deepProperties = JSON.parse(JSON.stringify(deepProperties)) // we need to clone deepProperties
  const newObject = Object.assign({}, deepProperties, properties) // creating new object using the properties

  const methods = metadata.methods // retrieving methods from the metadata
  if (methods) Object.setPrototypeOf(newObject, methods) // assigning new object's prototype

  Object.defineProperties(newObject, metadata.propertyDescriptors)

  for (const init of metadata.initializers || []) { // run every initializer one by one
    const firstArg = argument[0]
    const secondArg = { args: [...arguments], instance: newObject, stamp: Stamp }
    const returnedValue = init.call(newObject, firstArg, secondArg)
    if (returnedValue !== undefined) {
      newObject = returnedValue
    }
  }

  return newObject
}
```

If an initializer returns a non-undefined value then it becomes the new object instance.

See [Stamp Specification](/essentials/specification) for more details.

> *NOTE*
>
> The code above is not the actual stampit code. It was optimized for readability purposes.


# FAQ

## Q: What if composed stamps have same named property/method/etc?

The last composed property/method/etc wins. In other words, you can overwrite everything when composing stamps.

## Q: But what if there are names conflicts during stamp composition?

In our practice the names never collide. Because stamps tend to stay very small thanks to its absolute freedom.

But if you still need to avoid name collision or protect a method from overwriting then use [@stamp/collision](/ecosystem/stamp-collision) utility stamp.

## Q: Why stampit is ES5? Should it be ES6 or later?

* The main advantage of ES6 is the [import/export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) syntax which enables easy [treeshaking](https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking). But:
  * There is nothing to treeshake in `stampit` or `@stamp/it`.
  * `stampit` is already 1.5KB gzipped.
* Maintaining ES6->ES5 is quite hard in such a specific project.
* Most projects still transpile from ESNext to ES5.

We will rethink this policy as soon as there is a need which cannot be solved with ES5.


# Quick start

## Quick start

[Install](/essentials/installation) the JavaScript module from the NPM registry.

```bash
npm i stampit
```

Create an empty stamp.

```javascript
const stampit = require('stampit')

let Stamp = stampit() // creates new stamp
```

[Compose](/essentials/what-is-a-stamp#composing-stamps) it with another stamp.

```javascript
const HasLog = require('./HasLog')

Stamp = Stamp.compose(HasLog) // creates a new stamp composed from the two
```

Add default [properties](/api/properties) to it.

```javascript
Stamp = Stamp.props({ // creates a new derived stamp
  S3: require('aws-sdk').S3
})
```

Add an [initializer](/api/initializers) (aka constructor).

```javascript
Stamp = Stamp.init(function ({ bucket }, { stamp }) { // creates a new derived stamp
  this.s3instance = new this.S3({ 
    apiVersion: '2006-03-01', 
    params: { Bucket: bucket || stamp.compose.configuration.bucket } // using configuration.bucket, see below
  })
})
```

Add a [method](/api/methods).

```javascript
Stamp = Stamp.methods({ // creates a new derived stamp
  upload({ fileName, stream }) {
    this.log.info({ fileName }, 'Uploading file') // .log property from the HasLog stamp

    return this.s3instance.upload({ Key: fileName, Body: stream }).promise() // see above
  }
})
```

Add a [configuration](/api/configuration).

```javascript
Stamp = Stamp.conf({ // creates a new derived stamp
  bucket: process.env.UPLOAD_BUCKET
})
```

Add a [static](/api/static-properties) method.

```javascript
Stamp = Stamp.statics({ // creates a new derived stamp
  setDefaultBucket(bucket) {
    return this.conf({ bucket })
  }
})
```

Make the `.s3instance` , `.log`, and `.S3` properties [private](/ecosystem/stamp-privatize).

```javascript
const Privatize = require('@stamp/privatize')

Stamp = Stamp.compose(Privatize) // creates a new derived stamp
```

Give it a proper name.

```javascript
const FileStore = Stamp.compose({ name: 'FileStore' })
```

Create objects from your stamp.

```javascript
const store = FileStore()
```

### Shorter API

Here is the same `FileStore` stamp but written in a more concise way.

{% code title="S3FileStore.js" %}

```javascript
const HasLog = require('./HasLog')
const Privatize = require('@stamp/privatize')

const FileStore = HasLog.compose(Privatize, {
  name: 'FileStore',
  props: {
    S3: require('aws-sdk').S3
  },
  init({ bucket }, { stamp }) {
    this.s3instance = new this.S3({ 
      apiVersion: '2006-03-01', 
      params: { Bucket: bucket || stamp.compose.configuration.bucket }
    })
  },
  methods: {
    upload({ fileName, stream }) {
      this.log.info({ fileName }, 'Uploading file')
      return this.s3instance.upload({ Key: fileName, Body: stream }).promise()
    }
  },
  conf: {
    bucket: process.env.UPLOAD_BUCKET
  },
  statics: {
    setDefaultBucket(bucket) {
      return this.conf({ bucket })
    }
  }
})
```

{% endcode %}

The reusable `HasLog` stamp can be implemented in the following way.

{% code title="HasLog.js" %}

```javascript
module.exports = require('stampit')({
  init(_, { stamp }) {
    // this will reuse the stamp name "FileStore" we set above
    this.log = require('bunyan').createLogger({ name: stamp.name })
  }
})
```

{% endcode %}

### Using the stamp

Use your stamp ad-hoc.

```javascript
async function uploadTo(req, res) {
  const fileStore = FileStore({ bucket: req.params.bucket }) // create instance

  await fileStore.upload({ fileName: req.query.file, stream: req }) // use the method of the stamp

  res.sendStatus(201)
}
```

Or preconfigure it.

```javascript
const CatGifStore = FileStore.setDefaultBucket('cat-gifs') // pre-configuring the bucket name

const catGifStore = CatGifStore() // create an instance of the store

await catGifStore.upload({ fileName: 'cat.gif', stream: readableStream })
```

If you want to silence the shameful fact that you are collecting cat gifs then here is how you disable log. Just overwrite the `log` property with a silent one.

```javascript
const SilentCatGifStore = CatGifStore.props({
  log: {
    info() {} // silence!
  }
})

await SilentCatGifStore().upload({ fileName: 'cat.gif', stream: readableStream })
```

Alternatively, you can have a generic silent logger stamp. Compose with it to override the `HasLog`.

```javascript
const HasSilentLog = stampit.props({ log: { info: () => {} } })

const SilentCatGifStore = CatGifStore.compose(HasSilentLog)
```

The `new` keyword also works with any stamp.

```javascript
const catGifStore = new CatGifStore()
```

Another way to create an object is to use `.create()` static method.

```javascript
const catGifStore = CatGifStore.create()
```

## Mocking I/O in unit tests

Replacing actual `S3` with a fake one.

```javascript
const MockedFileStore = FileStore.props({
  S3() {
    return {
      upload() {
        return { promise() { return Promise.resolve() } }
      }
  }
})

// Same as above but a one-liner:

const MockedFileStore = FileStore.props({
  S3: () => ({ upload: () => ({ async promise() {} }) })
})
```

## Basic API

Head to the [Basics](/api/basics) page to view more API documentation. However, by now you already know all you need.


# Basics

## Creating Stamps

Stampit gives you several ways to create your stamps (aka factory functions).

> ***NOTE!***
>
> Any time you compose - you create a **NEW** stamp. Every function below always returns a **NEW** stamp.

### Pass plain descriptor

You can pass standard [stamp descriptor](/essentials/what-is-a-stamp#stamps-metadata-descriptor) to stampit.

```javascript
const descriptor = {
  methods: ...,
  properties: ...,
  deepProperties: ...,
  propertyDescriptors: ...,
  initializers: ...,
  staticProperties: ...,
  staticDeepProperties: ...,
  staticPropertyDescriptors: ...,
  composers: ...,
  configuration: ...,
  deepConfiguration: ...,
  name: ...
}

const MyStamp = stampit(descriptor) // passing the descriptor
```

Or you can pass *stampit-flavoured* descriptor (shorter version of the standard descriptor).

```javascript
const shorterDescriptor = {
  methods: ...,
  props: ...,
  deepProps: ...,
  propertyDescriptors: ...,
  init: ...,
  statics: ...,
  deepStatics: ...,
  staticPropertyDescriptors: ...,
  composers: ...,
  conf: ...,
  deepConf: ...,
  name: ...
}

const MyStamp = stampit(shorterDescriptor)
```

### Shortcut functions

Stampit has 18 shortcut functions attached to it. For example:

```javascript
const { props, methods, init } = stampit
```

You can create stamps from them too.

```javascript
const DefaultFoo = props({ foo: null })
const PrintFoo = methods({ printFoo() { console.log(this.foo) } })
const PassFoo = init(funciton ({ foo }) { this.foo = foo })

const Foo = DefaultFoo.compose(PrintFoo, PassFoo)
```

The full list of the shortcut functions matches the list of keys you can pass as stamp descriptor (see above).

```javascript
const {     // destructuring
  methods,

  props, properties,

  deepProps, deepProperties,

  init, initializers,

  propertyDescriptors,

  statics, staticProperties,

  deepStatics, staticDeepProperties,

  staticPropertyDescriptors,

  conf, configuration,

  deepConf, deepConfiguration,

  composers
} = stampit
```

### Creating same stamp in few ways

All the examples below create *exactly the same stamp*.

#### Classic way

```javascript
const logger = require('bunyan').createLogger({ name: 'log' })

const HasLog = stampit({
  properties: {
    log: logger
  }
})
```

#### Classic way using shorter API

```javascript
const HasLog = stampit({
  props: {
    log: logger
  }
})
```

#### Shortcut way

```javascript
const HasLog = stampit.props({
  log: logger
})

// OR

const { props } = stampit

const HasLog = props({
  log: logger
})
```

#### Composition way

```javascript
const HasLog = stampit().props({
  log: logger
})
```

### Chaining

You can chain all the shortcut functions (see the full list above).

Below is just an example of what you can do. It is a utility stamp. If you compose it to any of your stamps then it will *count the number of object instances* created from your stamp. Feel free to remove unwanted parts.

{% code title="InstanceCounter.js" %}

```javascript
const InstanceCounter = stampit()
.conf({
  instanceCounter: 0 // number of instances of a particular stamp, incremental
})
.props({
  instanceIndex: -1 // an instance number, incremental
})
.methods({
  printInstanceIndex() {
    console.log('I am instance #', this.instanceIndex)
  } 
})
.init(function (_, { stamp }) {
  this.instanceIndex = stamp.compose.configuration.instanceCounter // instance number
  stamp.compose.configuration.instanceCounter += 1 // increment the counter
})
.staticPropertyDescriptors({ // give the Stamp.name a non-default name. ES6 only.
  name: { value: 'InstanceCounter' }
})
.statics({ 
  printTotalInstanceCount() {
    console.log(this.compose.configuration.instanceCounter)
  } 
})
.composers(function ({ stamp }) {
  // We need to reset the counter each time the InstanceCounter is composed with.
  stamp.compose.configuration.instanceCounter = 0
})
```

{% endcode %}

Same `InstanceCounter` stamp but using the classic stampit way.

{% code title="InstanceCounter.js" %}

```javascript
const InstanceCounter = stampit({
  conf: {
    instanceCounter: 0 // number of instances of a particular stamp, incremental
  },
  props: {
    instanceIndex: -1 // an instance number, incremental
  },
  methods: {
    printInstanceIndex() {
      console.log('I am instance #', this.instanceIndex)
    } 
  },
  init(_, { stamp }) {
    this.instanceIndex = stamp.compose.configuration.instanceCounter // instance number
    stamp.compose.configuration.instanceCounter += 1 // increment the counter
  },
  staticPropertyDescriptors: { // give the Stamp.name a non-default name. ES6 only.
    name: { value: 'InstanceCounter' }
  },
  statics: { 
    printTotalInstanceCount() {
      console.log(this.compose.configuration.instanceCounter)
    } 
  },
  composers({ stamp }) {
    // We need to reset the counter each time the InstanceCounter is composed with.
    stamp.compose.configuration.instanceCounter = 0
  }
});
```

{% endcode %}


# Methods

You can add methods (aka *functions*) to the objects created from your stamps.

```javascript
const Logger = stampit({
  methods: {
    debug(str) {
      console.log(str)
    }
  }
})

const logger = Logger()

logger.debug('Server started')
```

All the methods are **attached to object's prototype**.

```javascript
logger.__proto__.debug === Logger.compose.methods.debug
```

Moreover, the entire `methods` [descriptor metadata](/essentials/what-is-a-stamp#stamps-metadata-descriptor) becomes the prototype.

```javascript
logger.__proto__ === Logger.compose.methods
```

If you compose the stamp above with any other stamp, then object instances created from it will also have the `.debug` method.

```javascript
const Server = Logger.compose({
  methods: {
    async start() {
      this.debug('Server started')
    }
  }
})

const server = Server()

server.debug('Starting server')
server.start()
```

## Descriptor merging algorithm

The methods are copied **by assignment**. In other words - **by reference** using `Object.assign`.

```javascript
Logger().debug === Server().debug
```

In case of conflicts the last composed method wins. To avoid method collision use the [@stamp/collision](/ecosystem/stamp-collision) stamp. To make sure a method is implemented use the [@stamp/required](/ecosystem/stamp-required) stamp.

> *NOTE*
>
> When using the [@stamp/required](/ecosystem/stamp-required) stamp it creates a proxy object and returns from the factory. This means that `logger.__proto__ === Logger.compose.methods` or `logger.__proto__.debug === Logger.compose.methods.debug` will no longer be `true`.

## Other ways to add methods

Exactly the same stamp can be created in few ways. Here they all are.

```javascript
function myDebug(str) {
  console.log(str)
}

const Logger = stampit({
  methods: {
    debug: myDebug
  }
})

const Logger = stampit.methods({
  debug: myDebug
})

const Logger = stampit().methods({
  debug: myDebug
})
```


# Properties

You can add properties to the objects created from your stamps. These are default properties of your objects.

```javascript
const HasLog = stampit({
  props: {
    log: require('bunyan').createLogger({ name: 'my logger' })
  }
})

const loggerObject = HasLog()
loggerObject.log.debug('I can log')
```

If you compose the stamp above with any other stamp, then object instances created from it will also have the `.log` property.

```javascript
const RequestHandler = stampit(HasLog) // composing with HasLog
.methods({
  handle(req, res, next) {
    this.log.info({ originalUrl: req.originalUrl }, 'handling request') // using the .log
    res.sendStatus(200)
  }
})

const handler = RequestHandler()
handler.log.debug('Created a handler')
```

## Descriptor merging algorithm

The properties are copied **by assignment**. In other words - **by reference** using `Object.assign`.

```javascript
HasLog().log === RequestHandler().log
```

In case of conflicts the last composed property wins.

## Other ways to add properties

Exactly the same stamp can be created in few ways. Here they all are.

```javascript
const myLogger = require('bunyan').createLogger({ name: 'my logger' })

const HasLog = stampit({
  props: {
    log: myLogger
  }
})

const HasLog = stampit({
  properties: {
    log: myLogger
  }
})

const HasLog = stampit.props({
  log: myLogger
})

const HasLog = stampit.properties({
  log: myLogger
})

const HasLog = stampit().props({
  log: myLogger
})

const HasLog = stampit().properties({
  log: myLogger
})
```


# Deep properties

The deep properties add properties to the objects created from your stamps. These are default properties of your objects. But unlike regular (shallow) properties these are deeply merged together by stamp [deep merging algorithm](/essentials/specification/merging-algorithm#deep-merging-algorithm).

```javascript
const AuthServiceToken = stampit.deepProps({
  Secrets: {
    authServiceToken: process.env.AUTH_SERVICE_TOKEN
  }
})

const S3KeyIdAndSecret = stampit.deepProps({
  Secrets: {
    S3: {
      keyId: process.env.AWS_ACCESS_KEY_ID,
      secret: process.env.AWS_SECRET_ACCESS_KEY
    }
  }
})

const DefaultSecrets = stampit(AuthServiceToken, S3KeyIdAndSecret) // composing them together

DefaultSecrets().Secrets.authServiceToken === process.env.AUTH_SERVICE_TOKEN
DefaultSecrets().Secrets.S3.keyId === process.env.AWS_ACCESS_KEY_ID
DefaultSecrets().Secrets.S3.secret === process.env.AWS_SECRET_ACCESS_KEY
```

## Descriptor merging algorithm

The deepProperties are **deeply merged** using stamp [deep merging algorithm](/essentials/specification/merging-algorithm#deep-merging-algorithm). See below - the `Secrets` value is always a new object.

```javascript
S3KeyIdAndSecret().Secrets !== DefaultSecrets().Secrets // NEVER EQUAL! NO MATTER WHAT!
```

Sometimes a regular (shallow) property has the same name as a deep property. While creating an object instance the shallow property wins. See [stamp internals](/essentials/specification/object-creation-internals).

```javascript
const NullSecrets = stampit.props({
  Secrets: null
})

const AuthServiceToken = stampit.deepProps({
  Secrets: {
    authServiceToken: process.env.AUTH_SERVICE_TOKEN
  }
})

const Result = NullSecrets.compose(AuthServiceToken)

Result().Secrets === null // the regular property overwrites deep property while creating an object
```

## Other ways to add deep properties

Exactly the same stamp can be created in few ways. Here they all are.

```javascript
const mySecrets = { authServiceToken: process.env.AUTH_SERVICE_TOKEN }

const AuthServiceToken = stampit({
  deepProps: {
    Secrets: mySecrets
  }
})

const HasLog = stampit({
  deepProperties: {
    Secrets: mySecrets
  }
})

const HasLog = stampit.deepProps({
  Secrets: mySecrets
})

const HasLog = stampit.deepProperties({
  Secrets: mySecrets
})

const HasLog = stampit().deepProps({
  Secrets: mySecrets
})

const HasLog = stampit().deepProperties({
  Secrets: mySecrets
})
```


# Initializers

You can add initializers (aka *constructors*) to your stamps.

```javascript
const Logger = stampit({
  init({level = 50}) {
    this.level = level
  }
})

const logger = Logger({ level: 42 })

logger.level === 42
```

**Each initializer will be executed** on object creation. *(But the list of initializers is always deduplicated.)*

```javascript
const Server = stampit(Logger, {
  init({ port = process.env.PORT }) {
    this.port = port
  }
})

const server = Server({ port: 6666 })

server.level === 50
server.port === 6666
```

If you return anything from an initializer then it becomes the object instance.

```javascript
const NullServer = Server.init(function () {
  return null
})

const server = NullServer()

server === null
```

## Descriptor merging algorithm

The initializers are concatenated into a deduplicated array. As the result, the order of composition becomes **the order of initializer execution**.

```javascript
const {init} = stampit

const Log1 = init(() => console.log(1))
const Log2 = init(() => console.log(2))
const Log3 = init(() => console.log(3))

const MultiLog = stampit(Log1, Log2, Log3)

MultiLog() // Will print three times:
// 1
// 2
// 3

// because there are 3 initializers
MultiLog.compose.initializers.length === 3
```

Stamps remove duplicate initializers.

```javascript
const {init} = stampit

const func = () => console.log(1)
const Log1 = init(func)
const Log2 = init(func)
const Log3 = init(func)

const MultiLog = stampit(Log1, Log2, Log3)

MultiLog() // Will print only once:
// 1

// because there is only one initializer
MultiLog.compose.initializers.length === 1
```

## Initializer arguments

> *NOTE*
>
> Parameter - a variable being passed to a function.
>
> Argument - a variable received by a function.

You can pass multiple parameters to your stamp while creating an object. First parameter passed as is to all initializers. But the rest of the parameters are available inside the `{args}` property of the second initializer argument.

```javascript
const MultiArg = stampit({
  init(arg1, { args }) {
    arg1 === 'foo'
    args[0] === arg1  // first argument of the initializer is passed from factory first parameter
    args[0] === 'foo'
    args[1] === 'BAR'
    args[2] === 'thing'
  }
})

MultiArg('foo', 'BAR', 'thing')
```

If there is no first parameter then an empty object is passed as the first argument.

```javascript
const NoException = stampit({
  init({ iAmUndefined }) { // won't throw exception in this line
    iAmUndefined === undefined
    console.log(arguments[0]) // will print empty object: {}
  }
})

NoException(/* nothing here! */)
```

Every initializer second argument is always this object: `{ stamp, args, instance }`. Where:

* `stamp` is the stamp which was used to create this object. Useful to retrieve stamp's metadata (aka descriptor).
* `args` the parameters passed to the stamp while creating the object.
* `instance` the object instance itself. Always equals `this` context of the initializer.

```javascript
const PrintMyArgs = stampit({
  init(_, { stamp, args, instance }) {
    console.log('Creating object from this stamp:', stamp)
    console.log('List of arguments:', args)
    console.log('Object instance:', instance)

    this === instance
  }
})
```

## Other ways to add initializers

Exactly the same stamp can be created in few ways. Here they all are.

```javascript
function myInitializer ({ level = 50 }) {
  this.level = level
}

const Logger = stampit({
  init: myInitializer
})

const Logger = stampit({
  init: [myInitializer]
})

const Logger = stampit({
  initializers: myInitializer
})

const Logger = stampit({
  initializers: [myInitializer]
})

const Logger = stampit.init(myInitializer)
const Logger = stampit.init([myInitializer])
const Logger = stampit.initializers(myInitializer)
const Logger = stampit.initializers([myInitializer])

const Logger = stampit().init(myInitializer)
const Logger = stampit().init([myInitializer])
const Logger = stampit().initializers(myInitializer)
const Logger = stampit().initializers([myInitializer])
```


# Static properties

Static properties are properties attached to the stamp itself.

```javascript
const PrintMyself = stampit({
  statics: {
    myProperty: 'foo',

    printMyself() {
      console.log(this)
    }
  }
})

PrintMyself.myProperty === 'foo'

PrintMyself.printMyself() // call the function without creating an instance of the stamp
```

If you compose the stamp above with any other stamp, then it will have the `printMyself` method too.

```javascript
const Server = stampit(PrintMyself, {
  ...
})

Server.printMyself()
```

> Fun fact
>
> Stampit's chain methods are all regular static properties: Stamp.props().methods().init().statics().conf()... etc

## Using statics to compose in your own way

Often static methods are used to tweak a stamp, to compose more metadata in a domain specific way.

```javascript
const HasFactor = stampit()
.statics({
  allowFactorSetter(allow) {
    return this.conf({ HasFactor: { allowSetter: allow } }) // tweaking the stamp. Using conf() static method
  }
})
.init(({ factor }, { instance, stamp }) => {
  let factor = factor || 1 // private (scoped) variable
  instance.getFactor = () => factor

  const { configuration } = stamp.compose
  if (configuration && configuration.HasFactor && configuration.HasFactor.addFactorSetter) {
    instance.setFactor = f => { factor = f }
  }
})
```

The example above exposes a static function which controls access to the `setFactor` method of your object instances.

```javascript
HasFactor().setFactor === undefined // there is no .setFactor() method

const HasFactorAllowed = HasFactor.allowFactorSetter(true)
const instance = HasFactor2()
instance.setFactor(5); // we have access to the setter!
instance.getFactor() === 5 // the factor was set
```

## Descriptor merging algorithm

The static properties are copied **by assignment**. In other words - **by reference** using `Object.assign`.

```javascript
HasFactor.allowFactorSetter === HasFactorAllowed.allowFactorSetter
```

In case of conflicts the last composed property wins.

## Other ways to add static properties

Exactly the same stamp can be created in few ways. Here they all are.

```javascript
function func(allow) {
  return this.conf({ HasFactor: { allowSetter: allow } })
}

const HasFactor = stampit({
  statics: {
    allowFactorSetter: func
  }
})

const HasFactor = stampit({
  staticProperties: {
    allowFactorSetter: func
  }
})

const HasFactor = stampit.statics({
  allowFactorSetter: func
})

const HasFactor = stampit.staticProperties({
  allowFactorSetter: func
})

const HasFactor = stampit().statics({
  allowFactorSetter: func
})

const HasFactor = stampit().staticProperties({
  allowFactorSetter: func
})
```


# Static deep properties

The static deep properties are properties attached to stamp itself. But unlike regular (shallow) static properties these are deeply merged together by stamp [deep merging algorithm](/essentials/specification/merging-algorithm).

```javascript
const SchemaTypes = stampit.deepStatics({
  Types: {
    String,
    Number,
    Array
  }
})

const ObjectIdSchemaType = stampit.deepStatics({
  Types: {
    ID: String,
    ObjectId: require('./object-id')
  }
})

const Schema = stampit(SchemaTypes, ObjectIdSchemaType, { // stamp deep merging kicks in this line
  init(data, { stamp }) {
    // stamp.Types.String, stamp.Types.ID, ...
  }
})

// Schema.Types.String
// Schema.Types.Number
// Schema.Types.Array
// as well as
// Schema.Types.ID
// Schema.Types.ObjectId
```

## Descriptor merging algorithm

The staticDeepProperties are **deeply merged** using stamp [deep merging algorithm](/essentials/specification/merging-algorithm). See below - the `Types` value is always a new object.

```javascript
SchemaTypes.Types !== Schema.Types // NEVER EQUAL! NO MATTER WHAT!
```

Sometimes a regular (shallow) static property has the same name as a deep static property. The shallow static property always wins.

```javascript
const NullTypes = stampit.statics({
  Types: null
})

const NoTypesSchema = Schema.compose(NullTypes)

NoTypesSchema.Types === null // the regular property overwrites deep property
```

## Other ways to add static deep properties

Exactly the same stamp can be created in few ways. Here they all are.

```javascript
const myTypes = { String, ID: String, Number, Array }

const AuthServiceToken = stampit({
  deepStatics: {
    Types: myTypes
  }
})

const HasLog = stampit({
  staticDeepProperties: {
    Types: myTypes
  }
})

const HasLog = stampit.deepStatics({
  Types: myTypes
})

const HasLog = stampit.staticDeepProperties({
  Types: myTypes
})

const HasLog = stampit().deepStatics({
  Types: myTypes
})

const HasLog = stampit().staticDeepProperties({
  Types: myTypes
})
```


# Configuration

Configuration is a storage of an arbitrary data in the `.configuration` metadata of stamp's descriptor.

```javascript
let HaveApiKey = stampit({
  conf: {
    apiKey: process.env.API_KEY
  }
})

HaveApiKey.compose.configuration.apiKey === process.env.API_KEY
```

You can set configuration in [static methods](/api/static-properties):

```javascript
HaveApiKey = HaveApiKey.statics({
  setApiKey(key) {
    return this.conf({ apiKey: key }) // create new stamp by composing parent stamp with some configuration
  }
})

HaveApiKey = HaveApiKey.setApiKey('abcd1234')

HaveApiKey.compose.configuration.apiKey === 'abcd1234'
```

You can access the configuration in stamp [initializers](/api/initializers) (aka constructors).

```javascript
const ApiKeyPrinter = HaveApiKey.init(function (opts, { stamp }) {
  const configuration = stamp.compose.configuration

  console.log(configuration.apiKey) // It is perfectly safe to log secret API keys. Right?
})

HaveApiKey() // this will execute the initializer, and will print "abcd1234" to the console
```

## Descriptor merging algorithm

The configuration properties are copied **by assignment**. In other words - **by reference** using `Object.assign`.

```javascript
HaveApiKey.compose.configuration.apiKey === ApiKeyPrinter.compose.configuration.apiKey
```

In case of conflicts the last composed property wins.

## Other ways to add configuration

Exactly the same stamp can be created in few ways. Here they all are.

```javascript
const HasLog = stampit({
  conf: {
    apiKey: process.env.API_KEY
  }
})

const HasLog = stampit({
  configuration: {
    apiKey: process.env.API_KEY
  }
})

const HasLog = stampit.conf({
  apiKey: process.env.API_KEY
})

const HasLog = stampit.configuration({
  apiKey: process.env.API_KEY
})

const HasLog = stampit().conf({
  apiKey: process.env.API_KEY
})

const HasLog = stampit().configuration({
  apiKey: process.env.API_KEY
})
```


# Deep configuration

Deep Configuration is a storage of an arbitrary data in the `.deepConfiguration` metadata of stamp's descriptor. But unlike regular (shallow) configuration these are deeply merged together by stamp [deep merging algorithm](/essentials/specification/merging-algorithm#deep-merging-algorithm).

```javascript
let Kue = stampit.deepConf({
  Kue: {
    name: 'kue',
    priority: 'normal',
    attempts: 3,
    delay: 500,
    ttl: 5,
    events: false
  }
})

const HighPriorityKue = stampit.deepConf({
  Kue: {
    priority: 'high'
  }
})

const MyKue = stampit(Kue, HighPriorityKue) // composing them together

MyKue.compose.deepConfiguration.Kue.attempts === 3
MyKue.compose.deepConfiguration.Kue.priority === 'high'
```

You can set deep configuration in [static methods](/api/static-properties):

```javascript
Kue = Kue.statics({
  configureKue(options) {
    return this.deepConf({Kue: options}) // create new stamp by composing parent stamp with some configuration
  },

  connectionString(connectionString) { return this.configureKue({connectionString} },
  priority(priority)                 { return this.configureKue({priority} },
  attempts(attempts)                 { return this.configureKue({attempts}) },
  delay(delay)                       { return this.configureKue({delay}) },
  ttl(ttl)                           { return this.configureKue({ttl}) },
  events(events)                     { return this.configureKue({events}) }
})

const MyRegularJobKue = Kue.attempts(5).delay(1000).ttl(10).events(true).priority('low')
```

You can access the configuration in stamp [initializers](/api/initializers) (aka constructors).

```javascript
Kue = Kue.init(function (payload, { stamp }) {
  const conf = stamp.compose.deepConfiguration.Kue
  this.conf = conf
  this.redisClient = require('redis').createClient(conf.connectionString)
})
.methods({
  put(data) {
    return this.redisClient.put(this.queueName, { ...this.conf, data })
  }
})

const myKue = Kue()
myKue.put({ title: 'Vasyl Boroviak', email: 'vasyl@example.com', template: 'welcome-email' })
```

## Descriptor merging algorithm

The deepConfiguration is **deeply merged** using stamp [deep merging algorithm](/essentials/specification/merging-algorithm#deep-merging-algorithm).

See below - the `Kue` value is always a new object.

```javascript
Kue.compose.deepConfiguration.Kue !== MyKue.compose.deepConfiguration.Kue
// NEVER EQUAL! NO MATTER WHAT!
```

## Other ways to add deep configuration

Exactly the same stamp can be created in few ways. Here they all are.

```javascript
const myKueConf = { Kue: { priority: 'normal' } }

const MyKue = stampit({
  deepConf: {
    Kue: myKueConf
  }
})

const MyKue = stampit({
  deepConfiguration: {
    Kue: myKueConf
  }
})

const MyKue = stampit.deepConf({
  Kue: myKueConf
})

const MyKue = stampit.deepConfiguration({
  Kue: myKueConf
})

const MyKue = stampit().deepConf({
  Kue: myKueConf
})

const MyKue = stampit().deepConfiguration({
  Kue: myKueConf
})
```


# Composers

Composers are callback functions executed each time a composition happens. There can be as many as you wish composers on each stamp.

> Composers are a very powerful feature. If you can implement something without composers then it's a good idea to avoid them.

It is highly recommended to **not create new stamps** in the composers, but **mutate the given stamp** if necessary.

```javascript
const InstanceOf = stampit.composers(({ stamp, composables }) => {
  if (!stamp.compose.methods) stamp.compose.methods = {} // mutating stamp
  stamp.compose.methods.getStamp = () => stamp           // mutating stamp

  Object.defineProperty(stamp, Symbol.hasInstance, {     // mutating stamp
    value(obj) {
      return obj && typeof obj.getStamp === 'function' && obj.getStamp() === stamp
    }
  })
})

console.log(InstanceOf() instanceof InstanceOf)     // true
console.log(InstanceOf().getStamp() === InstanceOf) // true

const Stamp = InstanceOf.props({ anything: 1 })
console.log(Stamp() instanceof Stamp)               // true
console.log(Stamp().getStamp() === Stamp)           // true

console.log(Stamp() instanceof InstanceOf)          // false
console.log(InstanceOf() instanceof Stamp)          // false
```

The above `InstanceOf` stamp overrides the default `instanceof` behavior using ES6 will-known symbol `Symbol.hasInstance`. Compose it with your stamps if you need the `instanceof` to work as expected for you.

> NOTE
>
> You can find the stamp above as the [`@stamp/instanceof`](/ecosystem/stamp-instanceof) NPM module.

## Descriptor merging algorithm

The composers are concatenated into a deduplicated array. As the result, the order of composition becomes **the order of composer execution**.

```javascript
const {composers} = stampit

const Log1 = composers(() => console.log(1))
const Log2 = composers(() => console.log(1))
const Log3 = composers(() => console.log(1))

const MultiLog = stampit(Log1, Log2, Log3)

MultiLog() // Will print three times:
// 1
// 1
// 1

// because there are 3 composers
MultiLog.compose.composers.length === 3
```

Stamps remove duplicate composers.

```javascript
const {composers} = stampit

const func = () => console.log(1)
const Log1 = composers(func)
const Log2 = composers(func)
const Log3 = composers(func)

const MultiLog = stampit(Log1, Log2, Log3)

MultiLog() // Will print only once:
// 1

// because there is only one composer
MultiLog.compose.composers.length === 1
```

## Composer arguments

Every composer always receive this object: `{ stamp, composables }`. Where:

* `stamp` is the stamp which was used to create this object. Useful to retrieve stamp's metadata (aka descriptor).
* `composables` is the array of stamps and descriptors the above stamp was composed with.

## Other ways to add composers

Exactly the same stamp can be created in few ways. Here they all are.

```javascript
function myDebugComposer ({ stamp, composables }) {
  console.log(`Stamp ${stamp} was composed of ${composables}`)
}

const Logger = stampit({
  composers: myDebugComposer
})

const Logger = stampit({
  composers: [myDebugComposer]
})

const Logger = stampit.composers(myDebugComposer)
const Logger = stampit.composers([myDebugComposer])

const Logger = stampit().composers(myDebugComposer)
const Logger = stampit().composers([myDebugComposer])
```


# Property descriptors

Property descriptors are [standard JavaScript property descriptors](https://mdn.io/defineProperties). They are applied last thing when an object instance is being created. See more info in [stamp internals](/essentials/specification/object-creation-internals).

```javascript
const Key = stampit.props({
  key: 'my secret key'
})

const auth = Key()
auth.key === 'my secret key'
auth.key = 'ha ha ha'
auth.key === 'ha ha ha' // oops :(

const FrozenKey = stampit.propertyDescriptors(Key, { // composing the two
  key: { // this is a standard JavaScript property descriptor
    configurable: false,
    writable: false,
  }
})

const auth = FrozenKey()
auth.key === 'my secret key'
auth.key = 'ha ha ha'
auth.key === 'my secret key' // OK!!! The "key" was not overwritten.
```

The code above adds some more metadata to the `Key` stamp. It protects the `key` property from overwrites

## Other ways to add property descriptors

Exactly the same stamp can be created in few ways. Here they all are.

```javascript
const keyPropertyDescriptor = {
  key: {
    configurable: false,
    writable: false,
  }
}

const FrozenKey = stampit({
  propertyDescriptors: keyPropertyDescriptor
})

const FrozenKey = stampit.propertyDescriptors(keyPropertyDescriptor)

const FrozenKey = stampit().propertyDescriptors(keyPropertyDescriptor)
```


# Static property descriptors

Static property descriptors are [standard JavaScript property descriptors](https://mdn.io/defineProperties). They are applied last thing when a stamp is being composed.

```javascript
let MyStamp = stampit() // empty stamp creates empty objects

MyStamp.name === 'Stamp' // every stamp default name is "Stamp"

MyStamp = MyStamp.staticPropertyDescriptors({
  name: { value: 'MyStamp' } // this meta data will be applied just after composition, i.e. immediately
})

MyStamp.name === 'MyStamp'
```

The code above adds some more metadata to the `MyStamp` stamp. It overwrites function name. (Property descriptors is the only way to change a function name.)

{% hint style="info" %}
NOTE

The `stampit` and `@stamp/it` modules have the ["name" feature](/api/name) built in.

```
const MyStamp = stampit({ name: 'MyStamp' })
MyStamp.name === 'MyStamp'
```

{% endhint %}

## Other ways to add static property descriptors

Exactly the same stamp can be created in few ways. Here they all are.

```javascript
const myStampName = {
  name: { value: 'MyStamp }
}

const NamedStamp = stampit({
  staticPropertyDescriptors: myStampName
})

const NamedStamp = stampit.staticPropertyDescriptors(myStampName)

const NamedStamp = stampit().staticPropertyDescriptors(myStampName)
```


# Name

By default all the stamps name is "Stamp".

```javascript
const MyStamp = stampit({})

console.log(MyStamp.name) // "Stamp"
```

But you can change it by passing the `name` property to stampit:

```javascript
const MyStamp = stampit({ name: "MyFactoryFunction" })

console.log(MyStamp.name) // "MyFactoryFunction"
```

This metadata does not have a chaining method. This is illegal: `MyStamp.name("MyFactoryFunction")`.

### **Gotchas**

* This feature is not part of the `compose` [specification](/essentials/specification). But a feature of the `stampit` pacakge.
* This code doesn’t work in JavaScript in general: `SmsGateway.name = “bla”`. Because `Function.name` is a special protected property.
* If any of the stamps you compose have a name then all the derived stamps will have it too.
* The only way to clear the name (reset to the defaults) is to set the name to *"Stamp"*.

```javascript
MyStamp = MyStamp.compose({ name: "Stamp" })
```


# Ecosystem Overview

## Main modules

Find the full list here: <https://www.npmjs.com/~stamp>

* **@stamp/compose** - The standard compose function implementation to create stamps
* **stampit** - A nice, handy API implementation of the compose standard. The original `stampit` module where it all began

## Utility stamps

* **@stamp/arg-over-prop** - Assign properties passed to the stamp factory
* [**@stamp/collision**](/ecosystem/stamp-collision) - Detect and manipulate method collisions
* **@stamp/configure** - Access configuration of your stamps anywhere
* **@stamp/eventemittable** - Node.js' EventEmitter as a stamp
* **@stamp/fp-constructor** - Adds the Functional Programming capabilities to your stamps
* **@stamp/init-property** - Replaces properties which reference stamps with objects created from the stamps
* [**@stamp/instanceof**](/ecosystem/stamp-instanceof) - Enables `obj instanceof MyStamp` in ES6 environments
* [**@stamp/named**](/ecosystem/stamp-named) - (Re)Name a stamp factory function (DEPRECATED)
* [**@stamp/privatize**](/ecosystem/stamp-privatize) - Protect private properties
* [**@stamp/required**](/ecosystem/stamp-required) - Insist on a method/property/staticProperty/configuration presence
* **@stamp/shortcut** - Adds handy shortcuts for stamp composition. Used in **@stamp/it**

## Other

* **@stamp/is** - Various validation functions used with stamps. Used in **@stamp/it**
* **@stamp/core** - Core functions for creating stamps. Used in **@stamp/it**
* **@stamp/check-compose** - Command line tool and library to test your `compose` function implementation


# @stamp/collision

*Controls collision behavior: forbid or defer*

This stamp (aka behavior) will check if there are any conflicts on every `compose` call. Throws an `Error` in case of a forbidden collision or ambiguous setup.

## Usage

```javascript
import Collision from '@stamp/collision';

const ForbidRedrawCollision = Collision.collisionSetup({forbid: ['redraw']});
```

Or if you don't want to import the stamp you can import only the method:

```javascript
import {collisionSetup} from '@stamp/collision';
const ForbidRedrawCollision = collisionSetup({forbid: ['redraw']});
```

The `defer` collects same named methods and wraps them into a single method.

```javascript
import Collision from '@stamp/collision';

import {Border, Button, Graph} from './drawable/primitives';

const UiComponent = Collision.collisionSetup({defer: ['draw']})
.compose(Border, Button, Graph);

const component = UiComponent();
const results = component.draw(); // will draw() all three primitives
console.log(results.length); // prints "3" to the console.
```

The deferred method returns the array of the values your methods returned. In the example above the `results` array will have the values the `.draw()` methods returned.

## API

### Static methods

#### collisionSetup

Forbid or Defer an exclusive method `stamp.collisionSetup({forbid: ['methodName1'], defer: ['methodName2']}) -> Stamp`

#### collisionProtectAnyMethod

Forbid any collisions, excluding those allowed `stamp.collisionProtectAnyMethod({allow: ['methoName']}) -> Stamp`

#### collisionSettingsReset

Remove any Collision settings from the stamp `stamp.collisionSettingsReset() -> Stamp`

## Example

See the comments in the code:

```javascript
import compose from '@stamp/compose';
import Collision from '@stamp/collision';
import Privatize from '@stamp/privatize';

// General purpose behavior to defer "draw()" method collisions
const DeferDraw = Collision.collisionSetup({defer: ['draw']});

const Border = compose(DeferDraw, {
  methods: {
    draw: jest.fn() // Spy function
  }
});
const Button = compose(DeferDraw, {
  methods: {
    draw: jest.fn() // Spy function
  }
});

// General purpose behavior to privatize the "draw()" method
const PrivateDraw = Privatize.privatizeMethods('draw');

// General purpose behavior to forbid the "redraw()" method collision
const ForbidRedrawCollision = Collision.collisionSetup({forbid: ['redraw']});

// The aggregating component
const ModalDialog = compose(PrivateDraw) // privatize the "draw()" method
  .compose(Border, Button) // modal will consist of Border and Button
  .compose(ForbidRedrawCollision) // there can be only one "redraw()" method
  .compose({
    methods: {
      // the public method which calls the deferred private methods
      redraw(int) {
        this.draw(int);
      }
    }
  });

// Creating an instance of the stamp
const dialog = ModalDialog();

// Check if the "draw()" method is actually privatized
expect(dialog.draw).toBeUndefined();

// Calling the public method, which calls the deferred private methods
dialog.redraw(42);

// Check if the spy "draw()" deferred functions were actually invoked
expect(Border.compose.methods.draw).toBeCalledWith(42);
expect(Button.compose.methods.draw).toBeCalledWith(42);

// Make sure the ModalDialog throws every time on the "redraw()" collisions
const HaveRedraw = compose({methods: {redraw() {}}})
expect(() => compose(ModalDialog, HaveRedraw)).toThrow();
```


# @stamp/required

*Insist on a method/property/staticProperty/configuration presence*

This stamp (aka behavior) will throw if a method (property, staticProperty, configuration, etc) is missing at object creation.

## Usage

```javascript
import Required from '@stamp/required'

const InsistOnRedrawMethod = Required.required({methods: {redraw: Required}})
```

Or if you don't want to import the stamp you can import only the method:

```javascript
import {required} from '@stamp/required'
const InsistOnRedrawMethod = required({methods: {redraw: required}})
```

## API

### Static methods

#### required

Setup which things are required `stamp.required({METATYPE: {KEY: required}}) -> Stamp`

## Example

```javascript
import stampit from '@stamp/it'
import Required, {required} from '@stamp/required'

const requiredConfigurationDifficulty = required({configuration: {difficulty: required}})
const requiredMethodMove = required({methods: {move: Required}})
const requiredPropertyGuild = Required.required({properties: {guild: required}})

let Paladin = stampit({
  props: {
    mana: 50,
    strength: 50,
    health: 100
  }
})

const paladin = Paladin() // ok

Paladin = Paladin.compose(
  requiredConfigurationDifficulty, 
  requiredMethodMove, 
  requiredPropertyGuild
)

const paladin = Paladin() // THROWS - Required: There must be difficulty in this stamp configuration

Paladin = Paladin.conf({ difficulty: 5 })

const paladin = Paladin() // THROWS - Required: There must be move in this stamp methods

Paladin = Paladin.methods({
  move(x, y) {
    // ... implementation
  }
})

const paladin = Paladin() // THROWS - Required: There must be guild in this stamp properties

Paladin = Paladin.props({ guild: 'Warriors of Light' })

const paladin = Paladin() // ok
```


# @stamp/privatize

*Makes all properties and optional methods private*

Inspired by the [`private-class`](https://github.com/parro-it/private-class) module. **NOTE!** Requires WeakMap, thus won't work in IE10.

This stamp (aka behavior) will create a proxy object. Its methods would delegate all the calls to the original object instance.

All the properties are made private. Methods privatization is optional and can be done via the `privatizeMethods` static function.

## Usage

```javascript
import Privatize from '@stamp/privatize';

import Auth from './stamps/auth';

const AuthWithPrivateProperties = Auth.compose(Privatize);

const AuthWithPrivatePropertiesAndMethod = Auth.compose(Privatize).privatizeMethods('setPassword');
```

Or if you don't want to import the stamp you can import only the method:

```javascript
import {privatizeMethods} from '@stamp/privatize';
const AuthWithPrivatePropertiesAndMethod = Auth.compose(privatizeMethods('setPassword'));
```

## Warning!

Every property you assign in the initializers will be private.

```javascript
const Original = compose({
  initializers: function () {
    this.foo = 42; // THIS WILL BE PRIVATE
    this.bar = function () {}; // THIS WILL BE PRIVATE TOO
  }
});
Original().foo === undefined; 
Original().bar === undefined;
```

This is a neat feature since you don't need to use JS closures to hide variables from external users.

## Example

```javascript
let accessPassword, accessSetPassword;
const Original = compose({
  properties: {password: '123'},
  methods: {
    setPassword(value) { this.password = value; },
    checkAccess() {
      accessPassword = this.password;
      accessSetPassword = this.setPassword;
    }
  }
});

// Add Privatize behavior, additionally protect the 'setPassword' method 
const Stamp = Original.compose(Privatize).privatizeMethods('setPassword');

// All properties and the method 'setPassword' are undefined
const instance = Stamp();
expect(instance.password).toBeUndefined();
expect(instance.setPassword).toBeUndefined();

// But the 'checkAccess' method have access to the properties and 'setPassword'
instance.checkAccess();
expect(accessPassword).toBe('123');
expect(accessSetPassword).toBe(Original.compose.methods.setPassword);
```

## Smart use of configuration

If you ever was thinking how cool if it was having `configuration` (and `deepConfiguration`) accessible in your method without explicitly exposing it through initializer, with privatize stamp you can simply do this. First make your own extension to Private stamp.

```javascript
import Privatize from '@stamp/privatize';
const ConfiguredPrivatize = Privatize.compose({
  initializers: [(_, {stamp, instance}) => {
    instance.stampConfiguration = stamp.compose.configuration;
    instance.stampDeepConfiguration = stamp.compose.deepConfiguration;
  }]
})
export default ConfiguredPrivatize;
```

Then you can use for your other stamps and being able to access configuration within any method while still have it hidden from public sight.

```javascript
compose(ConfiguredPrivatize, {
    configuration: {
        secret: 'mykey'
    },
    methods: {
        encrypt(value) {
          const { secret } = this.stampConfiguration;
          // run encryption with secret while it's still hidden from outside
        }
    }
})
```


# @stamp/named (DEPRECATED)

{% hint style="info" %}
This stamp (aka behaviour) is built into the stampit since `stampit@4.2.0` and `@stamp/it@1.1`.&#x20;
{% endhint %}

## @stamp/named (DEPRECATED)

*Changes the* `Stamp.name` *property using the* [*new ES6 feature*](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name)*.*

Supported platforms: node>=4, iOS>=10, Edge, FF, Chrome, Safari

If used in a non-supported environment (node \<v4, or IE any version) then nothing will throw. But the `Stamp.name` will always be `"Stamp"`.

## Example

Default behaviour (without this stamp):

```javascript
const MyRegularStamp = compose(...);
console.log(MyRegularStamp.name); // 'Stamp'
```

New behaviour:

```javascript
import Named from '@stamp/named';

const MyNamedStamp = MyRegularStamp.compose(Named).setName('MyNamedStamp');
```

Or if you don't want to import the stamp you can import only the method:

```javascript
import {setName} from '@stamp/named';
const MyNamedStamp = MyRegularStamp.compose(setName('MyNamedStamp'));
```

Then stamp receives a different name instead of the default "Stamp":

```javascript
console.log(MyNamedStamp.name); // 'MyNamedStamp'
```

Derived stamps behaviour:

```javascript
// All derived stamps will also be named 'MyNamedStamp' until changed:
let Stamp2 = compose(..., MyNamedStamp, ...);
console.log(Stamp2.name); // WARNING! Still 'MyNamedStamp' !!!

// Overwriting the name
Stamp2 = Stamp2.setName('Stamp2');
console.log(Stamp2.name); // 'Stamp2' :)
```


# @stamp/instanceof

*Enables* `obj instanceof MyStamp` *in ES6 environments*

```javascript
const InstanceOf = require('@stamp/instanceof');
// or
import InstanceOf from '@stamp/instanceof';
```

It uses the [well known Symbol hasInstance](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/hasInstance) to test instance.

## Example

Create a stamp:

```javascript
let MyStamp = compose({
  properties: { ... },
  initializers: [function () { ... }]
});
```

The following doesn't work:

```javascript
const obj = MyStamp();
obj instanceof MyStamp === false;
```

Compose the `InstanceOf` to your stamp:

```javascript
MyStamp = MyStamp.compose(InstanceOf);
```

Now it works:

```javascript
const myObject = MyStamp();
obj instanceof MyStamp === true;
```

## Notes

* We do not recommend to use `instanceof` in JavaScript in general.


