@lumjs/compat 1.0.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/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ # Changelog
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [1.0.0] - 2022-07-29
10
+ ### Added
11
+ - Initial release.
12
+
13
+ [Unreleased]: https://github.com/supernovus/lum.compat.js/compare/v1.0.0...HEAD
14
+ [1.0.0]: https://github.com/supernovus/lum.compat.js/releases/tag/v1.0.0
15
+
package/README.md ADDED
@@ -0,0 +1,56 @@
1
+ # lum.compat.js
2
+
3
+ As the libraries grow over time, features can change a lot, and backwards
4
+ compatibility is not always easy to maintain.
5
+
6
+ This library serves two purposes. The first is to be like the corresponding
7
+ [lum/lum-compat](https://github.com/supernovus/lum.compat.php) PHP library,
8
+ offering some generic compatibility functions.
9
+
10
+ The second is to be a repository for some older, deprecated functionality from
11
+ the [@lumjs/core](https://github.com/supernovus/lum.core.js) library.
12
+
13
+ By keeping some of the old sub-modules here as optional plugins, I can keep
14
+ legacy code up and running until I can rewrite it to no longer use those
15
+ features.
16
+
17
+ ## Entry Points
18
+
19
+ To keep features simple and separated, there's a few different entry points
20
+ exported from this library.
21
+
22
+ ### `@lumjs/compat`
23
+
24
+ The main entrypoint is reserved for generic compatibility functions.
25
+
26
+ ### `@lumjs/compat/v4-meta`
27
+
28
+ This entry-point adds several overly convoluted meta-programming features that
29
+ had been in the original `core` library in the legacy `v4` but during the
30
+ early stages of the rewrite I decided were just bloat that could be done better.
31
+
32
+ | Core Property | Description |
33
+ | --------------- | --------------------------------------------------------- |
34
+ | `descriptors` | A sub-module for creating magic Descriptor objects. |
35
+ | `DESC` | The primary API for the `descriptors` sub-module. |
36
+ | `prop()` | An `Object.defineProperty` wrapper using `descriptors`. |
37
+
38
+ These were all features I overthought and overdesigned, and added layers of
39
+ complexity that were not required. The `prop()` function has been replaced by
40
+ `core.def()` which has a cleaner and simpler API and doesn't require the evil
41
+ dark magic that was the `descriptors` module.
42
+
43
+ ## Official URLs
44
+
45
+ This library can be found in two places:
46
+
47
+ * [Github](https://github.com/supernovus/lum.compat.js)
48
+ * [NPM](https://www.npmjs.com/package/@lumjs/compat)
49
+
50
+ ## Author
51
+
52
+ Timothy Totten <2010@totten.ca>
53
+
54
+ ## License
55
+
56
+ [MIT](https://spdx.org/licenses/MIT.html)
package/jsdoc.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "tags":
3
+ {
4
+ "allowUnknownTags": true
5
+ },
6
+ "source":
7
+ {
8
+ "include": ["./lib"]
9
+ },
10
+ "opts":
11
+ {
12
+ "destination": "./docs/api",
13
+ "recurse": true
14
+ },
15
+ "plugins":
16
+ [
17
+ "plugins/markdown"
18
+ ],
19
+ "templates":
20
+ {
21
+ "cleverLinks": false,
22
+ "monospaceLinks": false,
23
+ "default":
24
+ {
25
+ "outputSourceFiles": true
26
+ },
27
+ "path": "ink-docstrap",
28
+ "theme": "cerulean",
29
+ "navType": "vertical",
30
+ "linenums": true,
31
+ "dateFormat": "YYYY-MM-DD, hh:mm:ss"
32
+ }
33
+ }
@@ -0,0 +1,210 @@
1
+ const core = require('@lumjs/core');
2
+ const {InternalObjectId,Enum,types} = core;
3
+ const {doesDescriptor,isObj,isComplex,def,B,F,N} = types;
4
+
5
+ // We moved getProperty() to the `@lumjs/core/obj` module.
6
+ const getProperty = core.obj.getProperty;
7
+ exports.getProperty = getProperty;
8
+
9
+ const DESC_ID = new InternalObjectId({name: '$LumDescriptor'});
10
+ const DESC_ADD = Enum(['ONE', 'SHORT', 'SET'], {flags: true});
11
+
12
+ /**
13
+ * Create a magic Descriptor object.
14
+ * @param {object} desc - Descriptor template.
15
+ * @param {object} [opts] - Options (to be documented.)
16
+ * @returns {object} `desc`
17
+ */
18
+ function descriptor(desc, opts={})
19
+ {
20
+ if (!isObj(opts)) throw new TypeError("Options must be an object");
21
+
22
+ if (typeof desc === B)
23
+ { // This is a special case.
24
+ opts.accessorSafe = desc;
25
+ opts.add = DESC_ADD.ONE;
26
+ desc = {};
27
+ }
28
+
29
+ if (!isObj(desc))
30
+ throw new TypeError("First parameter (desc) must be a descriptor template object");
31
+
32
+ if (!Object.isExtensible(desc))
33
+ throw new RangeError("First parameter (desc) must not be locked, sealed, frozen, etc.");
34
+
35
+ const accessorSafe = (typeof opts.accessorSafe === B)
36
+ ? opts.accessorSafe
37
+ : (desc.writable === undefined);
38
+
39
+ DESC_ID.tag(desc);
40
+
41
+ // Add a function or other property.
42
+ const add = def(desc);
43
+
44
+ // Add a getter.
45
+ function accessor(name, getter, setter)
46
+ {
47
+ const adef = {configurable: true};
48
+ if (typeof getter === F) adef.get = getter;
49
+ if (typeof setter === F) adef.set = setter;
50
+ def(desc, name, adef);
51
+ }
52
+
53
+ add('accessorSafe', accessorSafe);
54
+
55
+ add('whenDone', function(func)
56
+ {
57
+ if (typeof func === F)
58
+ {
59
+ add('done', func);
60
+ }
61
+ return this;
62
+ });
63
+
64
+ if (typeof opts.done === F)
65
+ {
66
+ desc.whenDone(opts.done);
67
+ }
68
+
69
+ add('setValue', function (val, noClean)
70
+ {
71
+ if (this.get !== undefined || this.set !== undefined)
72
+ {
73
+ console.error("Accessor properties already defined", this);
74
+ }
75
+ else
76
+ {
77
+ this.value = val;
78
+ }
79
+
80
+ return this;
81
+ });
82
+
83
+ if (accessorSafe)
84
+ {
85
+ function validate ()
86
+ {
87
+ if (this.value !== undefined)
88
+ {
89
+ console.error("Data 'value' property defined", this);
90
+ return false;
91
+ }
92
+
93
+ for (const arg of arguments)
94
+ { // All accessor arguments must be functions.
95
+ if (typeof arg !== F) throw new TypeError("Parameter must be a function");
96
+ }
97
+
98
+ return true;
99
+ }
100
+
101
+ add('setGetter', function(func)
102
+ {
103
+ if (validate.call(this, func))
104
+ this.get = func;
105
+ return this;
106
+ });
107
+
108
+ add('setSetter', function(func)
109
+ {
110
+ if (validate.call(this, func))
111
+ this.set = func;
112
+ return this;
113
+ });
114
+
115
+ add('setAccessor', function(getter, setter)
116
+ {
117
+ if (validate.call(this, getter, setter))
118
+ {
119
+ this.get = getter;
120
+ this.set = setter;
121
+ }
122
+ return this;
123
+ });
124
+
125
+ } // accessorSafe
126
+
127
+ if (opts.add)
128
+ {
129
+ const addTypes
130
+ = (typeof opts.add === N)
131
+ ? opts.add
132
+ : DESC_ADD.SET;
133
+
134
+ function addBool(propname)
135
+ {
136
+ const setBool = function()
137
+ {
138
+ this[propname] = true;
139
+ return this;
140
+ }
141
+
142
+ if (addTypes & DESC_ADD.ONE)
143
+ {
144
+ const aname = propname[0];
145
+ accessor(aname, setBool);
146
+ }
147
+ if (addTypes & DESC_ADD.SHORT)
148
+ {
149
+ const aname = propname.substring(0,4);
150
+ accessor(aname, setBool);
151
+ }
152
+ if (addTypes & DESC_ADD.SET)
153
+ {
154
+ const aname = 'set'+ucfirst(propname);
155
+ accessor(aname, setBool);
156
+ }
157
+ }
158
+
159
+ addBool('configurable');
160
+ addBool('enumerable');
161
+ addBool('writable');
162
+
163
+ } // addBools
164
+
165
+ // Is the descriptor ready to be used?
166
+ accessor('isReady', function()
167
+ {
168
+ return doesDescriptor(this);
169
+ });
170
+
171
+ return desc;
172
+ } // descriptor()
173
+
174
+ exports.descriptor = descriptor;
175
+
176
+ /**
177
+ * Get a Descriptor object.
178
+ * @param {object} desc - Either a Descriptor, or a descriptor template.
179
+ * @returns {object}
180
+ */
181
+ function getDescriptor(desc)
182
+ {
183
+ return DESC_ID.is(desc) ? desc : descriptor(desc);
184
+ }
185
+
186
+ exports.getDescriptor = getDescriptor;
187
+
188
+ /**
189
+ * A factory for building magic Descriptor objects.
190
+ */
191
+ const DESC =
192
+ {
193
+ get RO() { return descriptor(true) },
194
+ get CONF() { return descriptor(true).c },
195
+ get ENUM() { return descriptor(true).e },
196
+ get WRITE() { return descriptor(false).w },
197
+ get RW() { return descriptor(false).c.w },
198
+ get DEF() { return descriptor(true).c.e },
199
+ get OPEN() { return descriptor(false).c.e.w },
200
+ }
201
+
202
+ def(DESC)
203
+ ('make', descriptor)
204
+ ('is', DESC_ID.isFunction())
205
+ ('get', getDescriptor)
206
+ ('does', doesDescriptor)
207
+ ('ADD', DESC_ADD);
208
+
209
+ exports.DESC = DESC;
210
+
package/lib/index.js ADDED
@@ -0,0 +1,27 @@
1
+ // Compatibility jank.
2
+
3
+ const semver = require('semver');
4
+ const PKGJSON = 'package.json';
5
+
6
+ // A super simplistic package info wrapper.
7
+ class Package
8
+ {
9
+ constructor(pkg)
10
+ {
11
+ this.file = pkg+'/'+PKGJSON;
12
+ this.info = require(this.conf);
13
+ this.version = semver.parse(this.info.version);
14
+ }
15
+
16
+ satisfies(range, options)
17
+ {
18
+ return semver.satisfies(this.version, range, options);
19
+ }
20
+
21
+ static new(pkg)
22
+ {
23
+ return new Package(pkg);
24
+ }
25
+ }
26
+
27
+ exports.Package = Package;
package/lib/prop.js ADDED
@@ -0,0 +1,164 @@
1
+ const core = require('@lumjs/core');
2
+ const {isObj,isNil,notNil,isProperty,unbound,F} = core.types;
3
+ const {cloneIfLocked} = core.obj;
4
+
5
+ const {DESC,getDescriptor} = require('./descriptors');
6
+
7
+ /**
8
+ * A magic wrapper for Object.defineProperty()
9
+ *
10
+ * Rather than documenting the arguments in the usual manner, I'm
11
+ * going to simply show all of the ways this method can be called.
12
+ *
13
+ * Anywhere the `target` parameter is shown, this parameter can be an `object` or `function`.
14
+ * It's the target to which we're adding new properties.
15
+ *
16
+ * Anywhere the `property` parameter is shown, this parameter can be specified in two different
17
+ * forms. The first and simplest is as a `string` in which case it's simply the name of the property we're adding.
18
+ * The second more advanced form is as an `object`. If it is specified as an object, then it is a set of special options.
19
+ * In this case, a property of that `property` object called `name` will be used as the name of the property.
20
+ * If the `name` property is absent or `undefined`, it's the same as not passing the `property` parameter at all,
21
+ * and a *bound* function will be returned, using the custom options as its bound defaults.
22
+ *
23
+ * See below the usage
24
+ *
25
+ * `Lum.prop(object)`
26
+ *
27
+ * Return a function that is a bound copy of this function with
28
+ * the object as it's first parameter.
29
+ *
30
+ * `Lum.prop(object, property)`
31
+ *
32
+ * Add a property to the object which is mapped to a bound copy of
33
+ * this function with the object as it's first parameter.
34
+ *
35
+ * `Lum.prop(object, property, function, function)`
36
+ *
37
+ * Add a getter and setter property with the default descriptor.
38
+ *
39
+ * `Lum.prop(object, property, function, function, object)`
40
+ *
41
+ * Add a getter and setter property with specified Descriptor options.
42
+ * Do not use `get`, `set`, or `value` in the descriptor options.
43
+ *
44
+ * `Lum.prop(object, property, function, null, object)`
45
+ *
46
+ * Add a getter only with specified descriptor options.
47
+ * Same restrictions to the descriptor options as above.
48
+ * You can specify `{}` as the descriptor options to use the defaults.
49
+ *
50
+ * `Lum.prop(object, property, null, function, object)`
51
+ *
52
+ * Add a setter only with specified descriptor options.
53
+ * Same restrictions as above, and again you can use `{}` for defaults.
54
+ *
55
+ * `Lum.prop(object, property, !null)`
56
+ *
57
+ * Add a property with the specified non-null value.
58
+ * This uses the default descriptor.
59
+ *
60
+ * `Lum.prop(object, property, !null, object)`
61
+ *
62
+ * Add a property value with the specified descriptor options.
63
+ * Has the same restrictions to the descriptor options as above.
64
+ *
65
+ * `Lum.prop(object, property, null, object)`
66
+ *
67
+ * Add a property using the descriptor object alone.
68
+ * Use the newer and shorter `def()` function instead.
69
+ *
70
+ * `Lum.prop(object, property, Descriptor)`
71
+ *
72
+ * If you use `DESC.make()` or `descriptor()` to build a magic
73
+ * descriptor object, you can pass it and it'll be used with
74
+ * a few bonus features I need to document that aren't supported by
75
+ * the otherwise equivalent `def(object,property,descriptor)` call.
76
+ *
77
+ * @alias module:@lumjs/compat/v4-meta.prop
78
+ * @deprecated Replaced by `@lumjs/core.def` method.
79
+ */
80
+ function prop(obj, name, arg1, arg2, arg3)
81
+ {
82
+ let opts;
83
+
84
+ const isUnbound = unbound(this, true, true);
85
+
86
+ if (isObj(name))
87
+ { // A way to set some special options.
88
+ opts = name;
89
+ name = opts.name;
90
+ }
91
+ else if (isUnbound)
92
+ { // Use the default options.
93
+ opts = isObj(prop.options) ? prop.options : {};
94
+ }
95
+ else if (isObj(this))
96
+ { // This is already a bound copy, so `this` is the options.
97
+ opts = this;
98
+ }
99
+ else
100
+ { // Something weird is going on here...
101
+ throw new Error("Invalid `this` in a prop() function call");
102
+ }
103
+
104
+ if (isNil(name))
105
+ { // A special case, returns a copy of this function bound to the object.
106
+ return prop.bind(opts, obj);
107
+ }
108
+ else if (!isProperty(name))
109
+ { // The property must in every other case be a string.
110
+ throw new Error("property name must be a string or Symbol");
111
+ }
112
+
113
+ let desc;
114
+
115
+ if (arg1 === undefined && arg2 === undefined)
116
+ { // Another special case, the property is a bound version of this.
117
+ return prop(obj, name, prop.bind(opts, obj));
118
+ }
119
+ else if (DESC.is(arg1) && arg2 === undefined)
120
+ { // Yet another special case.
121
+ if (arg1.isReady)
122
+ { // Already has a value or get/set properties assigned.
123
+ desc = arg1;
124
+ }
125
+ else
126
+ { // We'll need to call setValue(), setGetter(), etc, then done().
127
+ return arg1.whenDone(function()
128
+ {
129
+ return prop(obj, name, this);
130
+ });
131
+ }
132
+ }
133
+ else if (typeof arg1 === F && typeof arg2 === F)
134
+ { // A getter and setter were specified.
135
+ desc = getDescriptor(isObj(arg3) ? cloneIfLocked(arg3) : DESC.CONF);
136
+ desc.setAccessor(arg1, arg2);
137
+ }
138
+ else if (isObj(arg3))
139
+ { // A custom descriptor for an accessor, find the accessor.
140
+ desc = getDescriptor(cloneIfLocked(arg3));
141
+ if (typeof arg1 === F)
142
+ { // A getter-only accessor.
143
+ desc.setGetter(arg1);
144
+ }
145
+ else if (typeof arg2 === F)
146
+ { // A setter-only accessor.
147
+ desc.setSetter(arg2);
148
+ }
149
+ }
150
+ else
151
+ { // Not a getter/setter, likely a standard value.
152
+ desc = getDescriptor(isObj(arg2) ? cloneIfLocked(arg2) : DESC.CONF);
153
+
154
+ if (notNil(arg1))
155
+ { // If you really want a null 'value', use a custom descriptor.
156
+ desc.setValue(arg1);
157
+ }
158
+ }
159
+
160
+ // If we reached here, we should have a valid descriptor now.
161
+ return Object.defineProperty(obj, name, desc);
162
+ }
163
+
164
+ module.exports = prop;
package/lib/v4-meta.js ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Lum.js v4 Meta-Programming helpers.
3
+ * @module @lumjs/compat/v4-meta
4
+ */
5
+
6
+ /**
7
+ * Descriptors magic objects module.
8
+ */
9
+ exports.descriptors = require('./descriptors');
10
+
11
+ /**
12
+ * The `prop()` function.
13
+ */
14
+ exports.prop = require('./prop');
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@lumjs/compat",
3
+ "version": "1.0.0",
4
+ "main": "lib/index.js",
5
+ "exports": {
6
+ ".": "./lib/index.js",
7
+ "./v4-meta": "./lib/v4-meta.js",
8
+ "./package.json": "./package.json"
9
+ },
10
+ "license": "MIT",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/supernovus/lum.compat.js.git"
14
+ },
15
+ "dependencies": {
16
+ "@lumjs/core": "^1.1.0",
17
+ "semver": "^7.3.7"
18
+ },
19
+ "scripts":
20
+ {
21
+ "build-docs": "jsdoc -c ./jsdoc.json"
22
+ }
23
+ }