-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtrait.js
112 lines (99 loc) · 2.14 KB
/
trait.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import { rename, setTag } from "./utils/index.js";
/**
* Creates traits.
*
* @param {String} name trait name
*/
export default function Trait( name )
{
if( ! ( this instanceof Trait ))
{
return new Trait( name );
}
/**
* Trait name.
*
* @type {String}
*/
this.name = setTag( this, name );
/**
* It keeps the traits list that this trait has, including itself.
*
* @type {Array}
*/
this.traits = [ this.name ];
/**
* Methods and properties in the trait's own and inherited traits.
*
* @type {Object}
*/
this.properties = {}
/**
* Dependencies list to inject method closure.
*
* @type {Object}
*/
this.dependencies = {}
/**
* It copies the properties of the given parent trait(s) into
* the properties of this trait. Inherits it.
*
* @param {Trait} ...parents traits to use
* @return {this}
*/
this.uses = function( trait, renameMap )
{
this.body(
renameMap
? rename( trait.properties, renameMap, true )
: trait.properties
);
this.traits = [ ...this.traits, ...trait.traits ];
Object.assign( this.dependencies, trait.dependencies );
return this;
}
/**
* Adds properties from the given object to the trait's
* properties stack.
*
* @param {Object} context an object containing methods and properties
* @return {this}
*/
this.body = function( context )
{
Object.assign( this.properties, context );
return this;
}
/**
* Appends to the dependencies list.
*
* @param {Object} dependencies dependencies to add dependencies list
* @return {Trait}
*/
this.inject = function( dependencies )
{
Object.assign( this.dependencies, dependencies );
return this;
}
/**
* Tells whether the represented trait extends a given trait.
*
* @param {Trait} target a trait to check if it is extended
* @return {Boolean}
*/
this.behave = function( target )
{
return this.traits.includes( target.name );
}
/**
* Tests given target trait is used by this trait. It's
* also a trap for instanceof scenarios.
*
* @param {Trait} target
* @returns {Boolean}
*/
this[ Symbol.hasInstance ] = function( target )
{
return target.behave( this );
}
}