Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

_Mono repository for stamp related packages._

Documentation: https://stampit.js.org
Documentation: https://stampit.js.org/ecosystem

* `@stamp/arg-over-prop` - Assign properties passed to the stamp factory
* `@stamp/check-compose` - Command line tool to test your 'compose' function implementation
Expand Down
54 changes: 28 additions & 26 deletions __tests__/privatize-plus-collision.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
var compose = require('../packages/compose');
var Collision = require('../packages/collision');
var Privatize = require('../packages/privatize');
var compose = require("../packages/compose");
var Collision = require("../packages/collision");
var Privatize = require("../packages/privatize");

describe('Collision + Privatize', function () {
it('work together', function () {
describe("Collision + Privatize", function () {
it("work together", function () {
var Stamp = compose(
Collision,
Privatize,
Expand All @@ -13,47 +13,49 @@ describe('Collision + Privatize', function () {
}
}
)
.collisionProtectAnyMethod()
.privatizeMethods('privateMethod');
.collisionSetup({ methods: "forbid" })
.privatizeMethods("privateMethod");

var obj = Stamp();

expect(obj.privateMethod).toBeUndefined();
});

it('privatizes deferred methods', function () {
it("privatizes deferred methods", function () {
// General purpose behavior to defer "draw()" method collisions
var DeferDraw = Collision.collisionSetup({defer: ['draw']});
var DeferDraw = Collision.collisionSetup({ methods: { draw: "defer" } });

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

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

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

// The aggregating component
var 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: function (int) {
this.draw(int);
}
.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: function (int) {
this.draw(int);
}
});
}
});

// Creating an instance of the stamp
var dialog = ModalDialog();
Expand All @@ -65,11 +67,11 @@ describe('Collision + Privatize', function () {
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);
expect(draw1).toBeCalledWith(42);
expect(draw2).toBeCalledWith(42);

// Make sure the ModalDialog throws every time on the "redraw()" collisions
var HaveRedraw = compose({methods: {redraw: jest.fn()}});
expect(function () {compose(ModalDialog, HaveRedraw)}).toThrow();
var HaveRedraw = compose({ methods: { redraw: jest.fn() } });
expect(function () {compose(ModalDialog, HaveRedraw);}).toThrow();
});
});
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
}
},
"jest": {
"testEnvironment": "node",
"coverageReporters": [
"html",
"text"
Expand Down
115 changes: 92 additions & 23 deletions packages/collision/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# @stamp/collision

_Controls collision behavior: forbid or defer_
_Controls collision behavior: forbid, defer or pipe_

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.
Expand All @@ -10,44 +10,111 @@ Throws an `Error` in case of a forbidden collision or ambiguous setup.
```js
import Collision from '@stamp/collision';

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

Or if you don't want to import the stamp you can import only the method:
```js
import {collisionSetup} from '@stamp/collision';
const ForbidRedrawCollision = collisionSetup({forbid: ['redraw']});
const ForbidRedrawCollision = collisionSetup({methods: {redraw: "forbid" }});
```


The `defer` collects same named methods and wraps them into a single method.
The `defer` collects same named methods and wraps them into a single method which returns an array of returned values.
```js
import Collision from '@stamp/collision';

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

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

const component = UiComponent();
component.draw(); // will draw() all three primitives
const array = component.draw(42); // will draw() all three primitives
```


The `pipe` collects same named methods and wraps them into a single method which pipes method returned values one into another
```js
import Collision from '@stamp/collision';

const UserDetails = stampit({
props: {
firstName: "John",
lastName: "Smith"
},
methods: {
toJSON(previous) {
return {...previous, firstName: this.firstName, lastName: this.lastName};
}
}
});
const UserAuth = stampit({
props: {
email: "john@example.com",
password: "hashedpassword"
},
methods: {
toJSON(previous) {
return {...previous, email: this.email, password: this.password};
}
}
});

const User = Collision.collisionSetup({methods: {toJSON: "pipe" }})
.compose(UserDetails, UserAuth);

const user = User();
const json = user.toJSON();
/*
{ email: 'john@example.com',
password: 'hashedpassword',
firstName: 'John',
lastName: 'Smith' }
*/
```

## API

### Static methods
### Forbid, Defer or Pipe an exclusive method
`stamp.collisionSetup({ [META]: { [NAME]: TYPE } }) -> Stamp`
Where:
* `META` - String, one of "methods", "properties", "deepProperties", "propertyDescriptors", "staticProperties", "staticDeepProperties", "staticPropertyDescriptors", "configuration", "deepConfiguration".
* `NAME` - String, the name of your method, property, etc.
* `TYPE` - String, one of "forbid", "defer", "pipe".

#### collisionSetup
Forbid or Defer an exclusive method
`stamp.collisionSetup({forbid: ['methodName1'], defer: ['methodName2']}) -> Stamp`
Example:
```js
MyStamp = MyStamp.collisionSetup({ methods: { setPassword: "forbid" }});
```

### Forbid, Defer or Pipe an all the methods
`stamp.collisionSetup({ [META]: TYPE }) -> Stamp`

Example:
```js
MyStamp = MyStamp.collisionSetup({ methods: "forbid" });
```

### Forbid, Defer or Pipe everything (NOT RECOMMENDED TO USE)
`stamp.collisionSetup(TYPE) -> Stamp`

Example - effectively disables any further composition:
```js
MyStamp = MyStamp.collisionSetup("forbid");
```

### Remove (reset) all the collision settings
```js
MyStamp = MyStamp.setupCollision(null);
```

### Remove (reset) some collision settings
```js
MyStamp = MyStamp.setupCollision({ methods: null });
```

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

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

## Example

Expand All @@ -58,24 +125,26 @@ 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 DeferDraw = Collision.collisionSetup({methods: {draw: "defer"}});

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

// 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']});
const ForbidRedrawCollision = Collision.collisionSetup({methods: {redraw: "forbid"}});

// The aggregating component
const ModalDialog = compose(PrivateDraw) // privatize the "draw()" method
Expand All @@ -100,10 +169,10 @@ expect(dialog.draw).toBeUndefined();
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);
expect(draw1).toBeCalledWith(42);
expect(draw2).toBeCalledWith(42);

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