@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.
@@ -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('./obj/getproperty');
9
-
3
+ const getProp = require('../obj/getproperty');
10
4
  const
11
5
  {
12
- def,F,B,S,
6
+ def,F,B,needObj,
13
7
  isObj,isArray,isConstructor,isProperty,isClassObject,
14
- needObj,needType,
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
- Trait: CoreTrait, IGNORE_STATIC,
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumjs/core",
3
- "version": "1.35.1",
3
+ "version": "1.36.0",
4
4
  "main": "lib/index.js",
5
5
  "exports":
6
6
  {