@lumjs/core 1.35.1 → 1.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/{traits.js → traits/funcs.js} +4 -255
- package/lib/traits/index.js +13 -0
- package/lib/traits/registry.js +166 -0
- package/lib/traits/trait.js +194 -0
- package/package.json +1 -1
|
@@ -1,18 +1,11 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A very simplistic Trait system.
|
|
3
|
-
* @module @lumjs/core/traits
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
1
|
"use strict";
|
|
7
2
|
|
|
8
|
-
const getProp = require('
|
|
9
|
-
|
|
3
|
+
const getProp = require('../obj/getproperty');
|
|
10
4
|
const
|
|
11
5
|
{
|
|
12
|
-
def,F,B,
|
|
6
|
+
def,F,B,needObj,
|
|
13
7
|
isObj,isArray,isConstructor,isProperty,isClassObject,
|
|
14
|
-
|
|
15
|
-
} = require('./types');
|
|
8
|
+
} = require('../types');
|
|
16
9
|
|
|
17
10
|
// Symbol for private storage of composed traits.
|
|
18
11
|
const COMPOSED_TRAITS = Symbol.for('@lumjs/core/traits~ComposedTraits');
|
|
@@ -568,254 +561,10 @@ function decompose(specTarget, specSource, opts={})
|
|
|
568
561
|
return c;
|
|
569
562
|
}
|
|
570
563
|
|
|
571
|
-
/**
|
|
572
|
-
* An abstract class for Traits.
|
|
573
|
-
*
|
|
574
|
-
* Simply offers a couple static methods and APIs that
|
|
575
|
-
* wrap the `compose()` and `composeFully()` functions,
|
|
576
|
-
* and makes it fairly simple to create Trait classes.
|
|
577
|
-
*
|
|
578
|
-
* @alias module:@lumjs/core/traits.Trait
|
|
579
|
-
*/
|
|
580
|
-
class CoreTrait
|
|
581
|
-
{
|
|
582
|
-
/**
|
|
583
|
-
* Extend another class or object instance with the methods and
|
|
584
|
-
* getter/setter properties from a Trait.
|
|
585
|
-
*
|
|
586
|
-
* The sub-class of Trait this static method is called on will always
|
|
587
|
-
* be the `source` argument.
|
|
588
|
-
*
|
|
589
|
-
* @param {(function|object)} target - Target class or instance.
|
|
590
|
-
*
|
|
591
|
-
* @param {object} [protoOpts] Options for `compose()` function.
|
|
592
|
-
*
|
|
593
|
-
* If this is not specified, or is any value other than an `object`,
|
|
594
|
-
* we will look for defaults in a `composeOptions` static property:
|
|
595
|
-
*
|
|
596
|
-
* ```js
|
|
597
|
-
* static get composeOptions() { return {your: default, options: here}; }
|
|
598
|
-
* ```
|
|
599
|
-
*
|
|
600
|
-
* @param {(object|true)} [staticOpts] Static options.
|
|
601
|
-
*
|
|
602
|
-
* If this is set we'll use `composeFully()` instead of using `compose()`.
|
|
603
|
-
*
|
|
604
|
-
* If this value is an `object` it will be used as the `staticOpts`.
|
|
605
|
-
*
|
|
606
|
-
* If this is the special value `true`, then we will look for the options
|
|
607
|
-
* in a `staticOptions` static property:
|
|
608
|
-
*
|
|
609
|
-
* ```js
|
|
610
|
-
* static get staticOptions() { return {your: static, options: here}; }
|
|
611
|
-
* ```
|
|
612
|
-
*
|
|
613
|
-
* If this any value other than an `object` or `true`, it will be ignored
|
|
614
|
-
* entirely, and the regular `compose()` call will be used.
|
|
615
|
-
*
|
|
616
|
-
* @returns {object} Return value from the `setupTrait()` static method.
|
|
617
|
-
*
|
|
618
|
-
*/
|
|
619
|
-
static composeInto(target, protoOpts, staticOpts)
|
|
620
|
-
{
|
|
621
|
-
if (!isObj(protoOpts))
|
|
622
|
-
{
|
|
623
|
-
protoOpts = this.composeOptions ?? {};
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
if (staticOpts === true)
|
|
627
|
-
{
|
|
628
|
-
staticOpts = this.staticOptions ?? {};
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
let composed;
|
|
632
|
-
|
|
633
|
-
if (isObj(staticOpts))
|
|
634
|
-
{
|
|
635
|
-
composed = composeFully(target, this, protoOpts, staticOpts);
|
|
636
|
-
}
|
|
637
|
-
else
|
|
638
|
-
{
|
|
639
|
-
composed = compose(target, this, protoOpts);
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
return this.setupTrait({target, protoOpts, staticOpts, composed});
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
/**
|
|
646
|
-
* A static method called by `composeInto()`
|
|
647
|
-
* _after_ composing the trait properties into the target.
|
|
648
|
-
*
|
|
649
|
-
* @param {object} info - Metadata from `composeInto()`
|
|
650
|
-
* @param {(function|object)} info.target - The `target` argument
|
|
651
|
-
* @param {object} info.protoOpts - The `protoOpts` used
|
|
652
|
-
* @param {object} [info.staticOpts] The `staticOpts` if used
|
|
653
|
-
* @param {module:@lumjs/core/traits~Composed} info.composed
|
|
654
|
-
* The return value from `compose()` or `composeFully()`.
|
|
655
|
-
*
|
|
656
|
-
* @returns {object} The `info` object, with any changes made
|
|
657
|
-
* by an overridden `setupTrait()` method in the sub-class.
|
|
658
|
-
*
|
|
659
|
-
* The default implementation is a placeholder that returns the
|
|
660
|
-
* `info` object without making any changes.
|
|
661
|
-
*
|
|
662
|
-
*/
|
|
663
|
-
static setupTrait(info)
|
|
664
|
-
{
|
|
665
|
-
if (this.debug)
|
|
666
|
-
{
|
|
667
|
-
console.debug(this.name, "setupTrait()", info, this);
|
|
668
|
-
}
|
|
669
|
-
return info;
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
/**
|
|
673
|
-
* A method wrapping {@link module:@lumjs/core/traits.decompose}
|
|
674
|
-
* where the `source` is always the Trait sub-class constructor.
|
|
675
|
-
*
|
|
676
|
-
* See the `decompose()` docs for descriptions of the other arguments.
|
|
677
|
-
*
|
|
678
|
-
* @param {(function|object)} target
|
|
679
|
-
* @param {object} [opts]
|
|
680
|
-
* @returns {object} Return value from the `removedTrait()` static method.
|
|
681
|
-
*/
|
|
682
|
-
static decomposeFrom(target, opts)
|
|
683
|
-
{
|
|
684
|
-
const info = {target, ok:true};
|
|
685
|
-
info.composed = this.getComposed(target);
|
|
686
|
-
this.removeTrait(info);
|
|
687
|
-
|
|
688
|
-
if (info.ok)
|
|
689
|
-
{
|
|
690
|
-
info.count = decompose(target, this, opts);
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
return this.removedTrait(info);
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
/**
|
|
697
|
-
* A static method called by `decomposeFrom()`
|
|
698
|
-
* _before_ decomposing the trait properties from the target.
|
|
699
|
-
*
|
|
700
|
-
* @param {object} info - Metadata from `decomposeFrom()`
|
|
701
|
-
* @param {(function|object)} info.target - The `target` argument
|
|
702
|
-
* @param {module:@lumjs/core/traits~Composed} info.composed
|
|
703
|
-
* The property map that was previously composed.
|
|
704
|
-
* @param {boolean} info.ok - Will always be `true` initially.
|
|
705
|
-
*
|
|
706
|
-
* If an overridden `removeTrait()` method sets this to `false`,
|
|
707
|
-
* then the decomposeFrom() operation will skip the step of
|
|
708
|
-
* actually decomposing the trait.
|
|
709
|
-
*
|
|
710
|
-
* @returns {*} Return value is not used.
|
|
711
|
-
*/
|
|
712
|
-
static removeTrait(info)
|
|
713
|
-
{
|
|
714
|
-
if (this.debug)
|
|
715
|
-
{
|
|
716
|
-
console.debug(this.name, "removeTrait()", info, this);
|
|
717
|
-
}
|
|
718
|
-
return info;
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
/**
|
|
722
|
-
* A static method called by `decomposeFrom()`
|
|
723
|
-
* _after_ decomposing the trait properties from the target.
|
|
724
|
-
*
|
|
725
|
-
* @param {object} info - The same as `removeTrait()`, plus:
|
|
726
|
-
* @param {number} info.count - The number of properties decomposed;
|
|
727
|
-
*
|
|
728
|
-
* @returns {object} The `info` object, with any changes made
|
|
729
|
-
* by `removeTrait()` and `removedTrait()` methods in the
|
|
730
|
-
* sub-class.
|
|
731
|
-
*
|
|
732
|
-
* The default implementation is a placeholder that returns the
|
|
733
|
-
* `info` object without making any changes.
|
|
734
|
-
*
|
|
735
|
-
*/
|
|
736
|
-
static removedTrait(info)
|
|
737
|
-
{
|
|
738
|
-
if (this.debug)
|
|
739
|
-
{
|
|
740
|
-
console.debug(this.name, "removedTrait()", info, this);
|
|
741
|
-
}
|
|
742
|
-
return info;
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
/**
|
|
746
|
-
* A method wrapping {@link module:@lumjs/core/traits.getComposed}
|
|
747
|
-
* where the `source` is always the Trait sub-class constructor.
|
|
748
|
-
*
|
|
749
|
-
* @param {(function|object)} target
|
|
750
|
-
* @returns {mixed} Return value from `getComposed()`
|
|
751
|
-
*/
|
|
752
|
-
static getComposed(target)
|
|
753
|
-
{
|
|
754
|
-
return getComposed(target, this);
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
} // CoreTrait class
|
|
758
|
-
|
|
759
|
-
/**
|
|
760
|
-
* Build a Trait registry.
|
|
761
|
-
*
|
|
762
|
-
* @param {object} registry - Object for the registry.
|
|
763
|
-
*
|
|
764
|
-
* Generally the `exports` from a Node.js module would be good here.
|
|
765
|
-
*
|
|
766
|
-
* It will have a `Trait` property added, which is an alias to
|
|
767
|
-
* the `Trait` class constructor.
|
|
768
|
-
*
|
|
769
|
-
* It will also have a `registerTrait(name, value)` function added.
|
|
770
|
-
* This function will add new traits to the registry, using
|
|
771
|
-
* the `name` as its property key. The `value` is either the
|
|
772
|
-
* Trait sub-class constructor `function` itself, or a _lazy-loading_
|
|
773
|
-
* closure `function` that must load and return the actual sub-class
|
|
774
|
-
* constructor when executed. The registry DOES NOT support `object`
|
|
775
|
-
* type traits, or any class that doesn't extend the `Trait` class.
|
|
776
|
-
*
|
|
777
|
-
* @returns {function} The `registerTrait()` function created above.
|
|
778
|
-
* @alias module:@lumjs/core/traits.makeRegistry
|
|
779
|
-
*/
|
|
780
|
-
function makeTraitRegistry(registry={})
|
|
781
|
-
{
|
|
782
|
-
needObj(registry, false, 'invalid trait registry object');
|
|
783
|
-
|
|
784
|
-
def(registry, 'Trait', CoreTrait);
|
|
785
|
-
|
|
786
|
-
function registerTrait(name, value)
|
|
787
|
-
{
|
|
788
|
-
needType(S, name, 'invalid trait name');
|
|
789
|
-
needType(F, value, 'invalid trait loader value');
|
|
790
|
-
|
|
791
|
-
if (registry[name] !== undefined)
|
|
792
|
-
{
|
|
793
|
-
console.error("trait already registered", {name,value,registry});
|
|
794
|
-
return;
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
if (CoreTrait.isPrototypeOf(value))
|
|
798
|
-
{ // Make it available directly.
|
|
799
|
-
def(registry, name, value, def.e);
|
|
800
|
-
}
|
|
801
|
-
else
|
|
802
|
-
{ // Lazy-loading engaged.
|
|
803
|
-
def.lazy(registry, name, value, def.e);
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
def(registry, 'registerTrait', registerTrait);
|
|
808
|
-
|
|
809
|
-
return registerTrait;
|
|
810
|
-
}
|
|
811
|
-
|
|
812
564
|
module.exports =
|
|
813
565
|
{
|
|
814
566
|
compose, composeFully, getComposed, decompose,
|
|
815
|
-
|
|
816
|
-
ensureProto, ensureConstructor,
|
|
817
|
-
makeRegistry: makeTraitRegistry,
|
|
818
|
-
|
|
567
|
+
IGNORE_STATIC, ensureProto, ensureConstructor,
|
|
819
568
|
// Undocumented:
|
|
820
569
|
hasOwn,
|
|
821
570
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A very simplistic Trait system.
|
|
3
|
+
* @module @lumjs/core/traits
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
"use strict";
|
|
7
|
+
|
|
8
|
+
const funcs = require('./funcs');
|
|
9
|
+
const Trait = require('./trait');
|
|
10
|
+
const regfns = require('./registry');
|
|
11
|
+
|
|
12
|
+
// Export all the things
|
|
13
|
+
Object.assign(exports, funcs, regfns, {Trait});
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const {def,F,S,needObj,needType} = require('../types');
|
|
4
|
+
const Trait = require('./trait');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Get a trait from the specified registry
|
|
8
|
+
*
|
|
9
|
+
* The exported function version of this is not generally called directly.
|
|
10
|
+
* Instead use the bound `getTrait()` method of a registry object.
|
|
11
|
+
*
|
|
12
|
+
* @alias module:@lumjs/core/traits.getTrait
|
|
13
|
+
*
|
|
14
|
+
* @param {module:@lumjs/core/traits~Registry} registry
|
|
15
|
+
* @param {(string|function)} trait - Trait to get
|
|
16
|
+
*
|
|
17
|
+
* This should almost always be the name of the trait you want
|
|
18
|
+
* to get out of this registry.
|
|
19
|
+
*
|
|
20
|
+
* If this happens to be a Trait class constructor already,
|
|
21
|
+
* it will be returned as is.
|
|
22
|
+
*
|
|
23
|
+
* @returns {?function} A trait class constructor, or `null` if the
|
|
24
|
+
* specified trait name does not exist in the registry.
|
|
25
|
+
*/
|
|
26
|
+
function getTrait(registry,trait)
|
|
27
|
+
{
|
|
28
|
+
if (typeof trait === S)
|
|
29
|
+
{ // Assume a string is the name of a trait in this registry
|
|
30
|
+
trait = registry[trait];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (typeof trait === F && Trait.isPrototypeOf(trait))
|
|
34
|
+
{
|
|
35
|
+
return trait;
|
|
36
|
+
}
|
|
37
|
+
else
|
|
38
|
+
{
|
|
39
|
+
console.error("invalid trait", {trait});
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get a bunch of traits from the specified registry
|
|
46
|
+
*
|
|
47
|
+
* The exported function version of this is not generally called directly.
|
|
48
|
+
* Instead use the bound `getTraits()` method from a registry object.
|
|
49
|
+
*
|
|
50
|
+
* @alias module:@lumjs/core/traits.getTraits
|
|
51
|
+
*
|
|
52
|
+
* @param {module:@lumjs/core/traits~Registry} registry
|
|
53
|
+
* @param {Iterable<(string|function)>} inList - List of traits to get
|
|
54
|
+
*
|
|
55
|
+
* Every item from this list will be passed to `getTrait()` to get
|
|
56
|
+
* the Trait class constructors for the returned set.
|
|
57
|
+
*
|
|
58
|
+
* @param {Set} [outSet=new Set] Will be populated with requested traits
|
|
59
|
+
*
|
|
60
|
+
* @returns {Set} The `outSet` with all traits added to it
|
|
61
|
+
*/
|
|
62
|
+
function getTraits(registry, inList, outSet)
|
|
63
|
+
{
|
|
64
|
+
if (!outSet)
|
|
65
|
+
{
|
|
66
|
+
outSet=new Set();
|
|
67
|
+
}
|
|
68
|
+
else if (!(outSet instanceof Set))
|
|
69
|
+
{
|
|
70
|
+
console.error({inList, outSet});
|
|
71
|
+
throw new TypeError("Invalid Set object");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
for (const ti of inList)
|
|
75
|
+
{
|
|
76
|
+
const tc = getTrait(registry, ti);
|
|
77
|
+
if (tc)
|
|
78
|
+
{
|
|
79
|
+
outSet.add(tc);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return outSet;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Register a trait class in a registry
|
|
88
|
+
*
|
|
89
|
+
* The exported function version of this is not generally called directly.
|
|
90
|
+
* Instead use the bound `registerTrait()` method from a registry object.
|
|
91
|
+
*
|
|
92
|
+
* @function module:@lumjs/core/traits.registerTrait
|
|
93
|
+
*
|
|
94
|
+
* @param {module:@lumjs/core/traits~Registry} registry
|
|
95
|
+
* @param {string} name - Name to use for the trait in the registry
|
|
96
|
+
* @param {function} getTrait
|
|
97
|
+
*
|
|
98
|
+
* If the function passed is a class constructor with the `Trait`
|
|
99
|
+
* class in its prototype chain, it will be used as the trait itself.
|
|
100
|
+
*
|
|
101
|
+
* If it is just a regular function or closure, it will be used as
|
|
102
|
+
* a lazy-loader that must return the actual class constructor.
|
|
103
|
+
*
|
|
104
|
+
* @param {boolean} [overwrite=false]
|
|
105
|
+
*
|
|
106
|
+
* @returns {module:@lumjs/core/traits~Registry} The registry object
|
|
107
|
+
*
|
|
108
|
+
* As a special exception to the argument type checking, if you omit both
|
|
109
|
+
* arguments, then the registry object will be returned immediately.
|
|
110
|
+
*
|
|
111
|
+
* @throws {TypeError} If `name` or `getTrait` were not valid values
|
|
112
|
+
*/
|
|
113
|
+
|
|
114
|
+
function registerTrait(registry, name, getTrait, overwrite=false)
|
|
115
|
+
{
|
|
116
|
+
if (name === undefined && getTrait === undefined)
|
|
117
|
+
{ // A special case, return the registry object
|
|
118
|
+
return registry;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
needType(S, name, 'invalid trait name');
|
|
122
|
+
needType(F, getTrait, 'invalid trait loader value');
|
|
123
|
+
|
|
124
|
+
if (!overwrite && registry[name] !== undefined)
|
|
125
|
+
{
|
|
126
|
+
console.error("trait already registered", {name,getTrait,registry});
|
|
127
|
+
return registry;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (Trait.isPrototypeOf(getTrait))
|
|
131
|
+
{ // Make it available directly.
|
|
132
|
+
def(registry, name, getTrait, def.e);
|
|
133
|
+
}
|
|
134
|
+
else
|
|
135
|
+
{ // Lazy-loading engaged.
|
|
136
|
+
def.lazy(registry, name, getTrait, def.e);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return registry;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Build a Trait registry.
|
|
144
|
+
*
|
|
145
|
+
* @param {object} [registry={}] Object for the registry
|
|
146
|
+
*
|
|
147
|
+
* Generally the `exports` from a Node.js module would be good here.
|
|
148
|
+
* The object will have several properties and methods assigned to it
|
|
149
|
+
* see {@link module:@lumjs/core/traits~Registry} for details.
|
|
150
|
+
*
|
|
151
|
+
* @returns {function} A
|
|
152
|
+
* @alias module:@lumjs/core/traits.makeRegistry
|
|
153
|
+
*/
|
|
154
|
+
function makeTraitRegistry(registry={})
|
|
155
|
+
{
|
|
156
|
+
needObj(registry, false, 'invalid trait registry object');
|
|
157
|
+
|
|
158
|
+
def(registry, 'Trait', Trait);
|
|
159
|
+
def(registry, 'getTrait', getTrait.bind(registry, registry));
|
|
160
|
+
def(registry, 'getTraits', getTraits.bind(registry, registry));
|
|
161
|
+
def(registry, 'registerTrait', registerTrait.bind(registry, registry));
|
|
162
|
+
|
|
163
|
+
return registerTrait;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
module.exports = makeTraitRegistry;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const {isObj} = require('../types');
|
|
4
|
+
const {getComposed,decompose,compose,composeFully} = require('./funcs');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* An abstract class for Traits.
|
|
8
|
+
*
|
|
9
|
+
* Simply offers a couple static methods and APIs that
|
|
10
|
+
* wrap the `compose()` and `composeFully()` functions,
|
|
11
|
+
* and makes it fairly simple to create Trait classes.
|
|
12
|
+
*
|
|
13
|
+
* @alias module:@lumjs/core/traits.Trait
|
|
14
|
+
*/
|
|
15
|
+
class CoreTrait
|
|
16
|
+
{
|
|
17
|
+
/**
|
|
18
|
+
* Extend another class or object instance with the methods and
|
|
19
|
+
* getter/setter properties from a Trait.
|
|
20
|
+
*
|
|
21
|
+
* The sub-class of Trait this static method is called on will always
|
|
22
|
+
* be the `source` argument.
|
|
23
|
+
*
|
|
24
|
+
* @param {(function|object)} target - Target class or instance.
|
|
25
|
+
*
|
|
26
|
+
* @param {object} [protoOpts] Options for `compose()` function.
|
|
27
|
+
*
|
|
28
|
+
* If this is not specified, or is any value other than an `object`,
|
|
29
|
+
* we will look for defaults in a `composeOptions` static property:
|
|
30
|
+
*
|
|
31
|
+
* ```js
|
|
32
|
+
* static get composeOptions() { return {your: default, options: here}; }
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* @param {(object|true)} [staticOpts] Static options.
|
|
36
|
+
*
|
|
37
|
+
* If this is set we'll use `composeFully()` instead of using `compose()`.
|
|
38
|
+
*
|
|
39
|
+
* If this value is an `object` it will be used as the `staticOpts`.
|
|
40
|
+
*
|
|
41
|
+
* If this is the special value `true`, then we will look for the options
|
|
42
|
+
* in a `staticOptions` static property:
|
|
43
|
+
*
|
|
44
|
+
* ```js
|
|
45
|
+
* static get staticOptions() { return {your: static, options: here}; }
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* If this any value other than an `object` or `true`, it will be ignored
|
|
49
|
+
* entirely, and the regular `compose()` call will be used.
|
|
50
|
+
*
|
|
51
|
+
* @returns {object} Return value from the `setupTrait()` static method.
|
|
52
|
+
*
|
|
53
|
+
*/
|
|
54
|
+
static composeInto(target, protoOpts, staticOpts)
|
|
55
|
+
{
|
|
56
|
+
if (!isObj(protoOpts))
|
|
57
|
+
{
|
|
58
|
+
protoOpts = this.composeOptions ?? {};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (staticOpts === true)
|
|
62
|
+
{
|
|
63
|
+
staticOpts = this.staticOptions ?? {};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let composed;
|
|
67
|
+
|
|
68
|
+
if (isObj(staticOpts))
|
|
69
|
+
{
|
|
70
|
+
composed = composeFully(target, this, protoOpts, staticOpts);
|
|
71
|
+
}
|
|
72
|
+
else
|
|
73
|
+
{
|
|
74
|
+
composed = compose(target, this, protoOpts);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return this.setupTrait({target, protoOpts, staticOpts, composed});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* A static method called by `composeInto()`
|
|
82
|
+
* _after_ composing the trait properties into the target.
|
|
83
|
+
*
|
|
84
|
+
* @param {object} info - Metadata from `composeInto()`
|
|
85
|
+
* @param {(function|object)} info.target - The `target` argument
|
|
86
|
+
* @param {object} info.protoOpts - The `protoOpts` used
|
|
87
|
+
* @param {object} [info.staticOpts] The `staticOpts` if used
|
|
88
|
+
* @param {module:@lumjs/core/traits~Composed} info.composed
|
|
89
|
+
* The return value from `compose()` or `composeFully()`.
|
|
90
|
+
*
|
|
91
|
+
* @returns {object} The `info` object, with any changes made
|
|
92
|
+
* by an overridden `setupTrait()` method in the sub-class.
|
|
93
|
+
*
|
|
94
|
+
* The default implementation is a placeholder that returns the
|
|
95
|
+
* `info` object without making any changes.
|
|
96
|
+
*
|
|
97
|
+
*/
|
|
98
|
+
static setupTrait(info)
|
|
99
|
+
{
|
|
100
|
+
if (this.debug)
|
|
101
|
+
{
|
|
102
|
+
console.debug(this.name, "setupTrait()", info, this);
|
|
103
|
+
}
|
|
104
|
+
return info;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* A method wrapping {@link module:@lumjs/core/traits.decompose}
|
|
109
|
+
* where the `source` is always the Trait sub-class constructor.
|
|
110
|
+
*
|
|
111
|
+
* See the `decompose()` docs for descriptions of the other arguments.
|
|
112
|
+
*
|
|
113
|
+
* @param {(function|object)} target
|
|
114
|
+
* @param {object} [opts]
|
|
115
|
+
* @returns {object} Return value from the `removedTrait()` static method.
|
|
116
|
+
*/
|
|
117
|
+
static decomposeFrom(target, opts)
|
|
118
|
+
{
|
|
119
|
+
const info = {target, ok:true};
|
|
120
|
+
info.composed = this.getComposed(target);
|
|
121
|
+
this.removeTrait(info);
|
|
122
|
+
|
|
123
|
+
if (info.ok)
|
|
124
|
+
{
|
|
125
|
+
info.count = decompose(target, this, opts);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return this.removedTrait(info);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* A static method called by `decomposeFrom()`
|
|
133
|
+
* _before_ decomposing the trait properties from the target.
|
|
134
|
+
*
|
|
135
|
+
* @param {object} info - Metadata from `decomposeFrom()`
|
|
136
|
+
* @param {(function|object)} info.target - The `target` argument
|
|
137
|
+
* @param {module:@lumjs/core/traits~Composed} info.composed
|
|
138
|
+
* The property map that was previously composed.
|
|
139
|
+
* @param {boolean} info.ok - Will always be `true` initially.
|
|
140
|
+
*
|
|
141
|
+
* If an overridden `removeTrait()` method sets this to `false`,
|
|
142
|
+
* then the decomposeFrom() operation will skip the step of
|
|
143
|
+
* actually decomposing the trait.
|
|
144
|
+
*
|
|
145
|
+
* @returns {*} Return value is not used.
|
|
146
|
+
*/
|
|
147
|
+
static removeTrait(info)
|
|
148
|
+
{
|
|
149
|
+
if (this.debug)
|
|
150
|
+
{
|
|
151
|
+
console.debug(this.name, "removeTrait()", info, this);
|
|
152
|
+
}
|
|
153
|
+
return info;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* A static method called by `decomposeFrom()`
|
|
158
|
+
* _after_ decomposing the trait properties from the target.
|
|
159
|
+
*
|
|
160
|
+
* @param {object} info - The same as `removeTrait()`, plus:
|
|
161
|
+
* @param {number} info.count - The number of properties decomposed;
|
|
162
|
+
*
|
|
163
|
+
* @returns {object} The `info` object, with any changes made
|
|
164
|
+
* by `removeTrait()` and `removedTrait()` methods in the
|
|
165
|
+
* sub-class.
|
|
166
|
+
*
|
|
167
|
+
* The default implementation is a placeholder that returns the
|
|
168
|
+
* `info` object without making any changes.
|
|
169
|
+
*
|
|
170
|
+
*/
|
|
171
|
+
static removedTrait(info)
|
|
172
|
+
{
|
|
173
|
+
if (this.debug)
|
|
174
|
+
{
|
|
175
|
+
console.debug(this.name, "removedTrait()", info, this);
|
|
176
|
+
}
|
|
177
|
+
return info;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* A method wrapping {@link module:@lumjs/core/traits.getComposed}
|
|
182
|
+
* where the `source` is always the Trait sub-class constructor.
|
|
183
|
+
*
|
|
184
|
+
* @param {(function|object)} target
|
|
185
|
+
* @returns {mixed} Return value from `getComposed()`
|
|
186
|
+
*/
|
|
187
|
+
static getComposed(target)
|
|
188
|
+
{
|
|
189
|
+
return getComposed(target, this);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
} // CoreTrait class
|
|
193
|
+
|
|
194
|
+
module.exports = CoreTrait;
|