@lumjs/core 1.0.0-beta.1 → 1.0.0-beta.6
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/README.md +10 -2
- package/TODO.md +12 -4
- package/docs/changelogs/1.0-beta.md +99 -0
- package/{CHANGELOG.md → docs/changelogs/1.x.md} +7 -7
- package/jsdoc.json +33 -0
- package/lib/arrays.js +78 -0
- package/lib/context.js +86 -0
- package/{src → lib}/enum.js +30 -13
- package/{src → lib}/flags.js +6 -0
- package/lib/index.js +131 -0
- package/{src → lib}/lazy.js +33 -35
- package/{src → lib}/meta.js +38 -1
- package/lib/modules.js +113 -0
- package/lib/obj/clone.js +220 -0
- package/{src → lib}/obj/copyall.js +3 -0
- package/{src → lib}/obj/copyprops.js +1 -0
- package/lib/obj/index.js +23 -0
- package/{src → lib}/obj/lock.js +16 -13
- package/{src → lib}/obj/merge.js +2 -0
- package/{src → lib}/obj/ns.js +45 -8
- package/{src → lib}/objectid.js +2 -3
- package/{src → lib}/observable.js +23 -8
- package/{src → lib}/opt.js +6 -1
- package/lib/strings.js +192 -0
- package/lib/types/basics.js +154 -0
- package/lib/types/def.js +183 -0
- package/lib/types/index.js +55 -0
- package/lib/types/isa.js +186 -0
- package/lib/types/js.js +12 -0
- package/lib/types/needs.js +117 -0
- package/lib/types/root.js +92 -0
- package/lib/types/stringify.js +98 -0
- package/lib/types/typelist.js +168 -0
- package/package.json +26 -3
- package/test/arrays.js +19 -0
- package/test/meta.js +17 -0
- package/test/types.js +106 -23
- package/index.js +0 -64
- package/src/context.js +0 -47
- package/src/descriptors.js +0 -243
- package/src/obj/clone.js +0 -201
- package/src/obj/index.js +0 -18
- package/src/prop.js +0 -170
- package/src/strings.js +0 -76
- package/src/types.js +0 -545
package/src/descriptors.js
DELETED
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
const {InternalObjectId} = require('./objectid');
|
|
3
|
-
const Enum = require('./enum');
|
|
4
|
-
const {doesDescriptor,isObj,isComplex,def,B,F,N} = require('./types');
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Get a property descriptor.
|
|
8
|
-
*
|
|
9
|
-
* This is like `Object.getOwnPropertyDescriptor`, except that method
|
|
10
|
-
* fails if the property is inhereted. This method will travel through
|
|
11
|
-
* the entire prototype chain until it finds the descriptor.
|
|
12
|
-
*
|
|
13
|
-
* @param {object|function} obj - Object to find a property in.
|
|
14
|
-
* @param {string} prop - Name of the property we want the descriptor of.
|
|
15
|
-
* @param {mixed} [defval] The fallback value if no descriptor is found.
|
|
16
|
-
*
|
|
17
|
-
* @returns {mixed} - The descriptor if found, `defval` if not.
|
|
18
|
-
*/
|
|
19
|
-
function getProperty(obj, prop, defval)
|
|
20
|
-
{
|
|
21
|
-
if (!isComplex(obj)) throw new TypeError("Target must be an object or function");
|
|
22
|
-
// Yeah it looks like an infinite loop, but it's not.
|
|
23
|
-
while (true)
|
|
24
|
-
{
|
|
25
|
-
const desc = Object.getOwnPropertyDescriptor(obj, prop);
|
|
26
|
-
if (isObj(desc))
|
|
27
|
-
{ // Found it.
|
|
28
|
-
return desc;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Didn't find it, so let's try the next object in the prototype chain.
|
|
32
|
-
obj = Object.getPrototypeOf(obj);
|
|
33
|
-
if (!isComplex(obj))
|
|
34
|
-
{ // We've gone as far up the prototype chain as we can, bye now!
|
|
35
|
-
return defval;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
exports.getProperty = getProperty;
|
|
41
|
-
|
|
42
|
-
const DESC_ID = new InternalObjectId({name: '$LumDescriptor'});
|
|
43
|
-
const DESC_ADD = Enum(['ONE','SHORT', 'SET'], {flags: true});
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Create a magic Descriptor object.
|
|
47
|
-
* @param {object} desc - Descriptor template.
|
|
48
|
-
* @param {object} [opts] - Options (to be documented.)
|
|
49
|
-
* @returns {object} `desc`
|
|
50
|
-
*/
|
|
51
|
-
function descriptor(desc, opts={})
|
|
52
|
-
{
|
|
53
|
-
if (!isObj(opts)) throw new TypeError("Options must be an object");
|
|
54
|
-
|
|
55
|
-
if (typeof desc === B)
|
|
56
|
-
{ // This is a special case.
|
|
57
|
-
opts.accessorSafe = desc;
|
|
58
|
-
opts.add = DESC_ADD.ONE;
|
|
59
|
-
desc = {};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (!isObj(desc))
|
|
63
|
-
throw new TypeError("First parameter (desc) must be a descriptor template object");
|
|
64
|
-
|
|
65
|
-
if (!Object.isExtensible(desc))
|
|
66
|
-
throw new RangeError("First parameter (desc) must not be locked, sealed, frozen, etc.");
|
|
67
|
-
|
|
68
|
-
const accessorSafe = (typeof opts.accessorSafe === B)
|
|
69
|
-
? opts.accessorSafe
|
|
70
|
-
: (desc.writable === undefined);
|
|
71
|
-
|
|
72
|
-
DESC_ID.tag(desc);
|
|
73
|
-
|
|
74
|
-
// Add a function or other property.
|
|
75
|
-
const add = def(desc);
|
|
76
|
-
|
|
77
|
-
// Add a getter.
|
|
78
|
-
function accessor(name, getter, setter)
|
|
79
|
-
{
|
|
80
|
-
const adef = {configurable: true};
|
|
81
|
-
if (typeof getter === F) adef.get = getter;
|
|
82
|
-
if (typeof setter === F) adef.set = setter;
|
|
83
|
-
def(desc, name, adef);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
add('accessorSafe', accessorSafe);
|
|
87
|
-
|
|
88
|
-
add('whenDone', function(func)
|
|
89
|
-
{
|
|
90
|
-
if (typeof func === F)
|
|
91
|
-
{
|
|
92
|
-
add('done', func);
|
|
93
|
-
}
|
|
94
|
-
return this;
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
if (typeof opts.done === F)
|
|
98
|
-
{
|
|
99
|
-
desc.whenDone(opts.done);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
add('setValue', function (val, noClean)
|
|
103
|
-
{
|
|
104
|
-
if (this.get !== undefined || this.set !== undefined)
|
|
105
|
-
{
|
|
106
|
-
console.error("Accessor properties already defined", this);
|
|
107
|
-
}
|
|
108
|
-
else
|
|
109
|
-
{
|
|
110
|
-
this.value = val;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return this;
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
if (accessorSafe)
|
|
117
|
-
{
|
|
118
|
-
function validate ()
|
|
119
|
-
{
|
|
120
|
-
if (this.value !== undefined)
|
|
121
|
-
{
|
|
122
|
-
console.error("Data 'value' property defined", this);
|
|
123
|
-
return false;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
for (const arg of arguments)
|
|
127
|
-
{ // All accessor arguments must be functions.
|
|
128
|
-
if (typeof arg !== F) throw new TypeError("Parameter must be a function");
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return true;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
add('setGetter', function(func)
|
|
135
|
-
{
|
|
136
|
-
if (validate.call(this, func))
|
|
137
|
-
this.get = func;
|
|
138
|
-
return this;
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
add('setSetter', function(func)
|
|
142
|
-
{
|
|
143
|
-
if (validate.call(this, func))
|
|
144
|
-
this.set = func;
|
|
145
|
-
return this;
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
add('setAccessor', function(getter, setter)
|
|
149
|
-
{
|
|
150
|
-
if (validate.call(this, getter, setter))
|
|
151
|
-
{
|
|
152
|
-
this.get = getter;
|
|
153
|
-
this.set = setter;
|
|
154
|
-
}
|
|
155
|
-
return this;
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
} // accessorSafe
|
|
159
|
-
|
|
160
|
-
if (opts.add)
|
|
161
|
-
{
|
|
162
|
-
const addTypes
|
|
163
|
-
= (typeof opts.add === N)
|
|
164
|
-
? opts.add
|
|
165
|
-
: DESC_ADD.SET;
|
|
166
|
-
|
|
167
|
-
function addBool(propname)
|
|
168
|
-
{
|
|
169
|
-
const setBool = function()
|
|
170
|
-
{
|
|
171
|
-
this[propname] = true;
|
|
172
|
-
return this;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (addTypes & DESC_ADD.ONE)
|
|
176
|
-
{
|
|
177
|
-
const aname = propname[0];
|
|
178
|
-
accessor(aname, setBool);
|
|
179
|
-
}
|
|
180
|
-
if (addTypes & DESC_ADD.SHORT)
|
|
181
|
-
{
|
|
182
|
-
const aname = propname.substring(0,4);
|
|
183
|
-
accessor(aname, setBool);
|
|
184
|
-
}
|
|
185
|
-
if (addTypes & DESC_ADD.SET)
|
|
186
|
-
{
|
|
187
|
-
const aname = 'set'+ucfirst(propname);
|
|
188
|
-
accessor(aname, setBool);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
addBool('configurable');
|
|
193
|
-
addBool('enumerable');
|
|
194
|
-
addBool('writable');
|
|
195
|
-
|
|
196
|
-
} // addBools
|
|
197
|
-
|
|
198
|
-
// Is the descriptor ready to be used?
|
|
199
|
-
accessor('isReady', function()
|
|
200
|
-
{
|
|
201
|
-
return doesDescriptor(this);
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
return desc;
|
|
205
|
-
} // descriptor()
|
|
206
|
-
|
|
207
|
-
exports.descriptor = descriptor;
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Get a Descriptor object.
|
|
211
|
-
* @param {object} desc - Either a Descriptor, or a descriptor template.
|
|
212
|
-
* @returns {object}
|
|
213
|
-
*/
|
|
214
|
-
function getDescriptor(desc)
|
|
215
|
-
{
|
|
216
|
-
return DESC_ID.is(desc) ? desc : descriptor(desc);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
exports.getDescriptor = getDescriptor;
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* A factory for building magic Descriptor objects.
|
|
223
|
-
*/
|
|
224
|
-
const DESC =
|
|
225
|
-
{
|
|
226
|
-
get RO() { return descriptor(true) },
|
|
227
|
-
get CONF() { return descriptor(true).c },
|
|
228
|
-
get ENUM() { return descriptor(true).e },
|
|
229
|
-
get WRITE() { return descriptor(false).w },
|
|
230
|
-
get RW() { return descriptor(false).c.w },
|
|
231
|
-
get DEF() { return descriptor(true).c.e },
|
|
232
|
-
get OPEN() { return descriptor(false).c.e.w },
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
def(DESC)
|
|
236
|
-
('make', descriptor)
|
|
237
|
-
('is', DESC_ID.isFunction())
|
|
238
|
-
('get', getDescriptor)
|
|
239
|
-
('does', doesDescriptor)
|
|
240
|
-
('ADD', DESC_ADD);
|
|
241
|
-
|
|
242
|
-
exports.DESC = DESC;
|
|
243
|
-
|
package/src/obj/clone.js
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
// Import *most* required bits here.
|
|
2
|
-
const {B,N,F, isObj, isComplex, def} = require('../types');
|
|
3
|
-
const Enum = require('../enum');
|
|
4
|
-
const {getDescriptor, DESC} = require('../descriptors');
|
|
5
|
-
const copyProps = require('./copyprops');
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* An enum of supported modes for the `clone` method.
|
|
9
|
-
*
|
|
10
|
-
* `CLONE.DEFAULT` → Shallow clone of enumerable properties for most objects.
|
|
11
|
-
* `CLONE.JSON` → Deep clone using JSON serialization (Arrays included.)
|
|
12
|
-
* `CLONE.FULL` → Shallow clone of all object properties.
|
|
13
|
-
* `CLONE.ALL` → Shallow clone of all properties (Arrays included.)
|
|
14
|
-
*
|
|
15
|
-
*/
|
|
16
|
-
const CLONE = Enum(['DEF','JSON','FULL','ALL']);
|
|
17
|
-
|
|
18
|
-
exports.CLONE = CLONE;
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Clone an object or function.
|
|
22
|
-
*
|
|
23
|
-
* @param {object|function} obj - The object we want to clone.
|
|
24
|
-
* @param {object} [opts={}] - Options for the cloning process.
|
|
25
|
-
*
|
|
26
|
-
* @param {number} [opts.mode=MODE_DEFAULT] - One of the `CLONE.*` enum values.
|
|
27
|
-
*
|
|
28
|
-
* For any mode that doesn't saay "Arrays included", Array objects will
|
|
29
|
-
* use a shortcut technique of `obj.slice()` to create the clone.
|
|
30
|
-
*
|
|
31
|
-
* Note: The `CLONE` enum is also aliased as `clone.MODE` as an alternative.
|
|
32
|
-
*
|
|
33
|
-
* @param {boolean} [opts.addClone=false] - Call {@link Lum._.addClone} on the cloned object.
|
|
34
|
-
*
|
|
35
|
-
* The options sent to this function will be used as the defaults in
|
|
36
|
-
* the clone() method added to the object.
|
|
37
|
-
*
|
|
38
|
-
* @param {boolean} [opts.addLock=false] - Call {@link Lum._.addLock} on the cloned object.
|
|
39
|
-
*
|
|
40
|
-
* No further options for this, just add a lock() method to the clone.
|
|
41
|
-
*
|
|
42
|
-
* @param {?object} [opts.copy] Call {@link Lum._.copy} on the cloned object.
|
|
43
|
-
*
|
|
44
|
-
* Will pass the original `obj` as the source to copy from.
|
|
45
|
-
* Will pass `opts.copy` as the options.
|
|
46
|
-
*
|
|
47
|
-
* @return {object} - The clone of the object.
|
|
48
|
-
*/
|
|
49
|
-
function clone(obj, opts={})
|
|
50
|
-
{
|
|
51
|
-
//console.debug("Lum~clone()", obj, opts);
|
|
52
|
-
|
|
53
|
-
if (!isComplex(obj))
|
|
54
|
-
{ // Doesn't need cloning.
|
|
55
|
-
//console.debug("no cloning required");
|
|
56
|
-
return obj;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (!isObj(opts))
|
|
60
|
-
{ // Opts has to be a valid object.
|
|
61
|
-
opts = {};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const mode = typeof opts.mode === N ? opts.mode : CLONE.DEF;
|
|
65
|
-
const reclone = typeof opts.addClone === B ? opts.addClone : false;
|
|
66
|
-
const relock = typeof opts.addLock === B ? opts.addLock : false;
|
|
67
|
-
|
|
68
|
-
let copy;
|
|
69
|
-
|
|
70
|
-
//console.debug("::clone", {mode, reclone, relock});
|
|
71
|
-
|
|
72
|
-
if (mode === CLONE.JSON)
|
|
73
|
-
{ // Deep clone enumerable properties using JSON trickery.
|
|
74
|
-
//console.debug("::clone using JSON cloning");
|
|
75
|
-
copy = JSON.parse(JSON.stringify(obj));
|
|
76
|
-
}
|
|
77
|
-
else if (mode !== CLONE.ALL && Array.isArray(obj))
|
|
78
|
-
{ // Make a shallow copy using slice.
|
|
79
|
-
//console.debug("::clone using Array.slice()");
|
|
80
|
-
copy = obj.slice();
|
|
81
|
-
}
|
|
82
|
-
else
|
|
83
|
-
{ // Build a clone using a simple loop.
|
|
84
|
-
//console.debug("::clone using simple loop");
|
|
85
|
-
copy = {};
|
|
86
|
-
|
|
87
|
-
let props;
|
|
88
|
-
if (mode === CLONE.ALL || mode === CLONE.FULL)
|
|
89
|
-
{ // All object properties.
|
|
90
|
-
//console.debug("::clone getting all properties");
|
|
91
|
-
props = Object.getOwnPropertyNames(obj);
|
|
92
|
-
}
|
|
93
|
-
else
|
|
94
|
-
{ // Enumerable properties.
|
|
95
|
-
//console.debug("::clone getting enumerable properties");
|
|
96
|
-
props = Object.keys(obj);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
//console.debug("::clone[props]", props);
|
|
100
|
-
|
|
101
|
-
for (let p = 0; p < props.length; p++)
|
|
102
|
-
{
|
|
103
|
-
let prop = props[p];
|
|
104
|
-
copy[prop] = obj[prop];
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (reclone)
|
|
109
|
-
{ // Add the clone() method to the clone, with the passed opts as defaults.
|
|
110
|
-
addClone(copy, opts);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (opts.copy)
|
|
114
|
-
{ // Pass the clone through the copyProps() function as well.
|
|
115
|
-
copyProps(obj, copy, opts.copy);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (relock)
|
|
119
|
-
{ // Add the lock() method to the clone.
|
|
120
|
-
addLock(copy, opts);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return copy;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Alias the CLONE enum as clone.MODE
|
|
127
|
-
def(clone, 'MODE', CLONE);
|
|
128
|
-
|
|
129
|
-
// Export the clone here.
|
|
130
|
-
exports.clone = clone;
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Add a clone() method to an object.
|
|
134
|
-
*
|
|
135
|
-
* @param {object|function} obj - The object to add clone() to.
|
|
136
|
-
* @param {object} [defOpts=null] Default options for the clone() method.
|
|
137
|
-
*
|
|
138
|
-
* If `null` or anything other than an object, the defaults will be:
|
|
139
|
-
*
|
|
140
|
-
* ```{mode: CLONE.DEF, addClone: true, addLock: false}```
|
|
141
|
-
*
|
|
142
|
-
* @method Lum._.addClone
|
|
143
|
-
*/
|
|
144
|
-
function addClone(obj, defOpts=null)
|
|
145
|
-
{
|
|
146
|
-
if (!isObj(defOpts))
|
|
147
|
-
{ // Assign a default set of defaults.
|
|
148
|
-
defOpts = {mode: CLONE.DEF, addClone: true, addLock: false};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const defDesc = getDescriptor(defOpts.cloneDesc ?? DESC.CONF);
|
|
152
|
-
|
|
153
|
-
defDesc.setValue(function (opts)
|
|
154
|
-
{
|
|
155
|
-
if (!isObj(opts))
|
|
156
|
-
opts = defOpts;
|
|
157
|
-
return clone(obj, opts);
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
return def(obj, 'clone', defDesc);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
exports.addClone = addClone;
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Clone an object if it's not extensible (locked, sealed, frozen, etc.)
|
|
167
|
-
*
|
|
168
|
-
* If the object is extensible, it's returned as is.
|
|
169
|
-
*
|
|
170
|
-
* If not, if the object has a `clone()` method it will be used.
|
|
171
|
-
* Otherwise use the {@link Lum._.clone} method.
|
|
172
|
-
*
|
|
173
|
-
* @param {object} obj - The object to clone if needed.
|
|
174
|
-
* @param {object} [opts] - Options to pass to `clone()` method.
|
|
175
|
-
*
|
|
176
|
-
* @return {object} - Either the original object, or an extensible clone.
|
|
177
|
-
*
|
|
178
|
-
* @method Lum._.cloneIfLocked
|
|
179
|
-
*/
|
|
180
|
-
function cloneIfLocked(obj, opts)
|
|
181
|
-
{
|
|
182
|
-
if (!Object.isExtensible(obj))
|
|
183
|
-
{
|
|
184
|
-
if (typeof obj.clone === F)
|
|
185
|
-
{ // Use the object's clone() method.
|
|
186
|
-
return obj.clone(opts);
|
|
187
|
-
}
|
|
188
|
-
else
|
|
189
|
-
{ // Use our own clone method.
|
|
190
|
-
return clone(obj, opts);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// Return the object itself, it's fine.
|
|
195
|
-
return obj;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
exports.cloneIfLocked = cloneIfLocked;
|
|
199
|
-
|
|
200
|
-
// Import `addLock()` here *after* assigning the clone methods.
|
|
201
|
-
const {addLock} = require('./lock');
|
package/src/obj/index.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
// Object helper utilities.
|
|
2
|
-
// We *could* use `copyAll` to simply merge everything in here automatically.
|
|
3
|
-
// But I'm going to be more explicit and import everything I want separately.
|
|
4
|
-
// I may change my mind on that in the future, who knows.
|
|
5
|
-
|
|
6
|
-
const copyAll = require('./copyall');
|
|
7
|
-
const copyProps = require('./copyprops');
|
|
8
|
-
const {CLONE,clone,addClone,cloneIfLocked} = require('./clone');
|
|
9
|
-
const {lock,addLock} = require('./lock');
|
|
10
|
-
const {mergeNested,syncNested} = require('./merge');
|
|
11
|
-
const {SOA,nsString,nsArray,getObjectPath,setObjectPath} = require('./ns');
|
|
12
|
-
|
|
13
|
-
module.exports =
|
|
14
|
-
{
|
|
15
|
-
CLONE, clone, addClone, cloneIfLocked, lock, addLock,
|
|
16
|
-
mergeNested, syncNested, SOA, nsString, nsArray,
|
|
17
|
-
getObjectPath, setObjectPath, copyProps, copyAll,
|
|
18
|
-
}
|
package/src/prop.js
DELETED
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
const {isObj,isNil,notNil,isProperty,unbound,F} = require('./types');
|
|
3
|
-
const {DESC,getDescriptor} = require('./descriptors');
|
|
4
|
-
const {cloneIfLocked} = require('./obj/clone');
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* A magic wrapper for Object.defineProperty()
|
|
8
|
-
*
|
|
9
|
-
* @method Lum.prop
|
|
10
|
-
*
|
|
11
|
-
* More in-depth than the `def()` function, this has a bazillion different
|
|
12
|
-
* features, and will continue to evolve, while the simpler function is done.
|
|
13
|
-
*
|
|
14
|
-
* Rather than documenting the arguments in the usual manner, I'm
|
|
15
|
-
* going to simply show all of the ways this method can be called.
|
|
16
|
-
*
|
|
17
|
-
* Anywhere the `target` parameter is shown, this parameter can be an `object` or `function`.
|
|
18
|
-
* It's the target to which we're adding new properties.
|
|
19
|
-
*
|
|
20
|
-
* Anywhere the `property` parameter is shown, this parameter can be specified in two different
|
|
21
|
-
* forms. The first and simplest is as a `string` in which case it's simply the name of the property we're adding.
|
|
22
|
-
* The second more advanced form is as an `object`. If it is specified as an object, then it is a set of special options.
|
|
23
|
-
* In this case, a property of that `property` object called `name` will be used as the name of the property.
|
|
24
|
-
* If the `name` property is absent or `undefined`, it's the same as not passing the `property` parameter at all,
|
|
25
|
-
* and a *bound* function will be returned, using the custom options as its bound defaults.
|
|
26
|
-
*
|
|
27
|
-
* See below the usage
|
|
28
|
-
*
|
|
29
|
-
* `Lum.prop(object)`
|
|
30
|
-
*
|
|
31
|
-
* Return a function that is a bound copy of this function with
|
|
32
|
-
* the object as it's first parameter.
|
|
33
|
-
*
|
|
34
|
-
* `Lum.prop(object, property)`
|
|
35
|
-
*
|
|
36
|
-
* Add a property to the object which is mapped to a bound copy of
|
|
37
|
-
* this function with the object as it's first parameter.
|
|
38
|
-
*
|
|
39
|
-
* `Lum.prop(object, property, function, function)`
|
|
40
|
-
*
|
|
41
|
-
* Add a getter and setter property with the default descriptor.
|
|
42
|
-
*
|
|
43
|
-
* `Lum.prop(object, property, function, function, object)`
|
|
44
|
-
*
|
|
45
|
-
* Add a getter and setter property with specified Descriptor options.
|
|
46
|
-
* Do not use `get`, `set`, or `value` in the descriptor options.
|
|
47
|
-
*
|
|
48
|
-
* `Lum.prop(object, property, function, null, object)`
|
|
49
|
-
*
|
|
50
|
-
* Add a getter only with specified descriptor options.
|
|
51
|
-
* Same restrictions to the descriptor options as above.
|
|
52
|
-
* You can specify `{}` as the descriptor options to use the defaults.
|
|
53
|
-
*
|
|
54
|
-
* `Lum.prop(object, property, null, function, object)`
|
|
55
|
-
*
|
|
56
|
-
* Add a setter only with specified descriptor options.
|
|
57
|
-
* Same restrictions as above, and again you can use `{}` for defaults.
|
|
58
|
-
*
|
|
59
|
-
* `Lum.prop(object, property, !null)`
|
|
60
|
-
*
|
|
61
|
-
* Add a property with the specified non-null value.
|
|
62
|
-
* This uses the default descriptor.
|
|
63
|
-
*
|
|
64
|
-
* `Lum.prop(object, property, !null, object)`
|
|
65
|
-
*
|
|
66
|
-
* Add a property value with the specified descriptor options.
|
|
67
|
-
* Has the same restrictions to the descriptor options as above.
|
|
68
|
-
*
|
|
69
|
-
* `Lum.prop(object, property, null, object)`
|
|
70
|
-
*
|
|
71
|
-
* Add a property using the descriptor object alone.
|
|
72
|
-
* Use the newer and shorter `def()` function instead.
|
|
73
|
-
*
|
|
74
|
-
* `Lum.prop(object, property, Descriptor)`
|
|
75
|
-
*
|
|
76
|
-
* If you use `DESC.make()` or `descriptor()` to build a magic
|
|
77
|
-
* descriptor object, you can pass it and it'll be used with
|
|
78
|
-
* a few bonus features I need to document that aren't supported by
|
|
79
|
-
* the otherwise equivalent `def(object,property,descriptor)` call.
|
|
80
|
-
*
|
|
81
|
-
*/
|
|
82
|
-
function prop(obj, name, arg1, arg2, arg3)
|
|
83
|
-
{
|
|
84
|
-
let opts;
|
|
85
|
-
|
|
86
|
-
const isUnbound = unbound(this, true, true);
|
|
87
|
-
|
|
88
|
-
if (isObj(name))
|
|
89
|
-
{ // A way to set some special options.
|
|
90
|
-
opts = name;
|
|
91
|
-
name = opts.name;
|
|
92
|
-
}
|
|
93
|
-
else if (isUnbound)
|
|
94
|
-
{ // Use the default options.
|
|
95
|
-
opts = isObj(prop.options) ? prop.options : {};
|
|
96
|
-
}
|
|
97
|
-
else if (isObj(this))
|
|
98
|
-
{ // This is already a bound copy, so `this` is the options.
|
|
99
|
-
opts = this;
|
|
100
|
-
}
|
|
101
|
-
else
|
|
102
|
-
{ // Something weird is going on here...
|
|
103
|
-
throw new Error("Invalid `this` in a prop() function call");
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (isNil(name))
|
|
107
|
-
{ // A special case, returns a copy of this function bound to the object.
|
|
108
|
-
return prop.bind(opts, obj);
|
|
109
|
-
}
|
|
110
|
-
else if (!isProperty(name))
|
|
111
|
-
{ // The property must in every other case be a string.
|
|
112
|
-
throw new Error("property name must be a string or Symbol");
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
let desc;
|
|
116
|
-
|
|
117
|
-
if (arg1 === undefined && arg2 === undefined)
|
|
118
|
-
{ // Another special case, the property is a bound version of this.
|
|
119
|
-
return prop(obj, name, prop.bind(opts, obj));
|
|
120
|
-
}
|
|
121
|
-
else if (DESC.is(arg1) && arg2 === undefined)
|
|
122
|
-
{ // Yet another special case.
|
|
123
|
-
if (arg1.isReady)
|
|
124
|
-
{ // Already has a value or get/set properties assigned.
|
|
125
|
-
desc = arg1;
|
|
126
|
-
}
|
|
127
|
-
else
|
|
128
|
-
{ // We'll need to call setValue(), setGetter(), etc, then done().
|
|
129
|
-
return arg1.whenDone(function()
|
|
130
|
-
{
|
|
131
|
-
return prop(obj, name, this);
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
else if (typeof arg1 === F && typeof arg2 === F)
|
|
136
|
-
{ // A getter and setter were specified.
|
|
137
|
-
desc = getDescriptor(isObj(arg3) ? cloneIfLocked(arg3) : DESC.CONF);
|
|
138
|
-
desc.setAccessor(arg1, arg2);
|
|
139
|
-
}
|
|
140
|
-
else if (isObj(arg3))
|
|
141
|
-
{ // A custom descriptor for an accessor, find the accessor.
|
|
142
|
-
desc = getDescriptor(cloneIfLocked(arg3));
|
|
143
|
-
if (typeof arg1 === F)
|
|
144
|
-
{ // A getter-only accessor.
|
|
145
|
-
desc.setGetter(arg1);
|
|
146
|
-
}
|
|
147
|
-
else if (typeof arg2 === F)
|
|
148
|
-
{ // A setter-only accessor.
|
|
149
|
-
desc.setSetter(arg2);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
else
|
|
153
|
-
{ // Not a getter/setter, likely a standard value.
|
|
154
|
-
desc = getDescriptor(isObj(arg2) ? cloneIfLocked(arg2) : DESC.CONF);
|
|
155
|
-
|
|
156
|
-
if (notNil(arg1))
|
|
157
|
-
{ // If you really want a null 'value', use a custom descriptor.
|
|
158
|
-
desc.setValue(arg1);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// TODO:
|
|
163
|
-
// - Add different configurable return values.
|
|
164
|
-
// - Make default return values consistent with def().
|
|
165
|
-
|
|
166
|
-
// If we reached here, we should have a valid descriptor now.
|
|
167
|
-
return Object.defineProperty(obj, name, desc);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
module.exports = prop;
|
package/src/strings.js
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
// String methods.
|
|
2
|
-
const {isObj,root} = require('./types')
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Get the locale/language string.
|
|
6
|
-
*
|
|
7
|
-
* 1. If `navigator.language` exists it will be used.
|
|
8
|
-
* 2. If `Intl` exists it will be used.
|
|
9
|
-
* 3. If neither of those exist, uses `'en-US'` as a default.
|
|
10
|
-
*
|
|
11
|
-
* @returns string - The locale/language string.
|
|
12
|
-
*/
|
|
13
|
-
function getLocale()
|
|
14
|
-
{
|
|
15
|
-
if (isObj(root.navigator) && typeof root.navigator.language === S)
|
|
16
|
-
{
|
|
17
|
-
return root.navigator.language;
|
|
18
|
-
}
|
|
19
|
-
else if (isObj(root.Intl))
|
|
20
|
-
{
|
|
21
|
-
try
|
|
22
|
-
{
|
|
23
|
-
const lang = root.Intl.DateTimeFormat().resolvedOptions().locale;
|
|
24
|
-
return lang;
|
|
25
|
-
}
|
|
26
|
-
catch (err)
|
|
27
|
-
{
|
|
28
|
-
console.warn("Attempt to get locale from Intl failed", err);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// A last-ditch fallback.
|
|
33
|
-
return 'en-US';
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
exports.getLocale = getLocale;
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Make the first character of a string uppercase.
|
|
40
|
-
*
|
|
41
|
-
* @param {string} string - The input string.
|
|
42
|
-
* @param {boolean} [lcrest=false] Make the rest of the string lowercase?
|
|
43
|
-
* @param {string} [locale=getLocale()] The locale/language of the string.
|
|
44
|
-
*
|
|
45
|
-
* @returns string - The output string.
|
|
46
|
-
*/
|
|
47
|
-
function ucfirst ([ first, ...rest ], lcrest = false, locale = getLocale())
|
|
48
|
-
{
|
|
49
|
-
first = first.toLocaleUpperCase(locale);
|
|
50
|
-
rest = rest.join('');
|
|
51
|
-
if (lcrest)
|
|
52
|
-
{
|
|
53
|
-
rest = rest.toLocaleLowerCase(locale);
|
|
54
|
-
}
|
|
55
|
-
return first + rest;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
exports.ucfirst = ucfirst;
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Make the first character of each *word* in a string uppercase.
|
|
62
|
-
*
|
|
63
|
-
* @param {string} string - The input string.
|
|
64
|
-
* @param {boolean} [unicode=false] Use Unicode words? (Only uses ASCII words otherwise)
|
|
65
|
-
* @param {boolean} [lcrest=false] Make the rest of each word lowercase?
|
|
66
|
-
* @param {string} [locale=getLocale()] The locale/language of the string.
|
|
67
|
-
*
|
|
68
|
-
* @returns {string} - The output string.
|
|
69
|
-
*/
|
|
70
|
-
function ucwords(string, unicode = false, lcrest = false, locale = getLocale())
|
|
71
|
-
{
|
|
72
|
-
const regex = unicode ? /[0-9\p{L}]+/ug : /\w+/g;
|
|
73
|
-
return string.replace(regex, word => ucfirst(word, lcrest, locale));
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
exports.ucwords = ucwords;
|