native-document 1.0.17-1.8 → 1.0.17-2.1
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 +26 -1
- package/package.json +1 -1
- package/src/core/data/ObservableItem.js +8 -8
- package/src/core/wrappers/AttributesWrapper.js +25 -30
- package/src/core/wrappers/ElementCreator.js +4 -11
- package/src/core/wrappers/HtmlElementWrapper.js +10 -11
- package/src/core/wrappers/NDElement.js +1 -12
- package/src/core/wrappers/NdPrototype.js +40 -6
- package/src/core/wrappers/template-cloner/NodeCloner.js +10 -6
- package/src/core/wrappers/template-cloner/TemplateCloner.js +7 -4
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
+
## [1.0.172] - 2026-06-15
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- `Text(string)` — shorthand for `string.toNdChildren()`, parses Observable placeholders in template strings
|
|
19
|
+
- `String.prototype.toNdChildren()` — splits a string containing `{{obs:N}}` placeholders into a mixed array of strings and resolved Observables
|
|
20
|
+
- `ObservableItem.prototype.toString()` — auto-registers the Observable in MemoryManager and returns `{{obs:id}}`, enabling reactive interpolation via standard template literals
|
|
21
|
+
- `NDElement.prototype.className(classes)` — adds static classes, bypasses AttributesWrapper
|
|
22
|
+
- `NDElement.prototype.class(className, value)` — adds a reactive class binding, bypasses AttributesWrapper
|
|
23
|
+
- `__$isNativeNode` flag on DOM prototypes (`Element`, `Text`, `Comment`, `Document`, `DocumentFragment`) — faster alternative to `instanceof Node`
|
|
24
|
+
- `__$isValidNdChild` flag on all valid NdChild prototypes — single property check replaces multiple type guards
|
|
25
|
+
- `defineToNdElement`, `defineValidNdChild`, `defineNativeNode` — non-enumerable prototype helpers in `nd-element-extensions`
|
|
26
|
+
- camelCase variants added to `BOOLEAN_ATTRIBUTES` — removes `toLowerCase()` call on each attribute in the hot path
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- `ElementCreator.processChildren` and `getChild` — refactored for better performance
|
|
31
|
+
- `nd-element-extensions` — all prototype extensions converted to non-enumerable `defineProperty`
|
|
32
|
+
- `AttributesWrapper` — `options` defaults to `null` instead of `{}`, fixes truthy check issue
|
|
33
|
+
- NDElement events — inline handler (`on*`) used when no existing handler and no options; falls back to `addEventListener` for subsequent handlers or when options are provided
|
|
34
|
+
- `_prevent`, `_stop`, `_preventStop` — updated with same inline handler strategy
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
14
38
|
## [1.0.170] - 2026-06-10
|
|
15
39
|
|
|
16
40
|
### Added
|
|
@@ -216,7 +240,8 @@ Entries use the following categories:
|
|
|
216
240
|
|
|
217
241
|
---
|
|
218
242
|
|
|
219
|
-
[Unreleased]: https://github.com/afrocodeur/native-document/compare/v1.0.
|
|
243
|
+
[Unreleased]: https://github.com/afrocodeur/native-document/compare/v1.0.172...HEAD
|
|
244
|
+
[1.0.172]: https://github.com/afrocodeur/native-document/compare/v1.0.170...v1.0.172
|
|
220
245
|
[1.0.170]: https://github.com/afrocodeur/native-document/compare/v1.0.169...v1.0.170
|
|
221
246
|
[1.0.169]: https://github.com/afrocodeur/native-document/compare/v1.0.167...v1.0.169
|
|
222
247
|
[1.0.167]: https://github.com/afrocodeur/native-document/compare/v1.0.166...v1.0.167
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "native-document",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.172.1",
|
|
4
4
|
"description": "A reactive JavaScript framework that preserves native DOM simplicity without sacrificing modern features",
|
|
5
5
|
"author": "AfroCodeur <https://github.com/afrocodeur>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,10 +18,10 @@ import {$getFromStorage, $saveToStorage} from '../utils/localstorage';
|
|
|
18
18
|
* @param {boolean} [configs.propagation] - Controls whether changes propagate to parent observables
|
|
19
19
|
* @example
|
|
20
20
|
* const count = new ObservableItem(0);
|
|
21
|
-
* const name
|
|
21
|
+
* const name = new ObservableItem('John', { reset: true });
|
|
22
22
|
*/
|
|
23
23
|
export default function ObservableItem(value, configs = null) {
|
|
24
|
-
value =
|
|
24
|
+
value = value?.__$Observable ? value.val() : value;
|
|
25
25
|
|
|
26
26
|
this.$previousValue = null;
|
|
27
27
|
this.$currentValue = value;
|
|
@@ -29,13 +29,13 @@ export default function ObservableItem(value, configs = null) {
|
|
|
29
29
|
this.$isCleanedUp = false;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
this.$firstListener = null;
|
|
33
|
-
this.$listeners = null;
|
|
34
|
-
this.$watchers = null;
|
|
35
|
-
|
|
36
|
-
this.$
|
|
32
|
+
// this.$firstListener = null;
|
|
33
|
+
// this.$listeners = null;
|
|
34
|
+
// this.$watchers = null;
|
|
35
|
+
//
|
|
36
|
+
// this.$id = null;
|
|
37
37
|
|
|
38
|
-
if(configs) {
|
|
38
|
+
if(configs !== null) {
|
|
39
39
|
this.configs = configs;
|
|
40
40
|
if(configs.reset) {
|
|
41
41
|
this.$initialValue = Validator.isObject(value) ? deepClone(value) : value;
|
|
@@ -1,38 +1,9 @@
|
|
|
1
1
|
import Validator from '../utils/validator';
|
|
2
|
-
import NativeDocumentError from '../errors/NativeDocumentError';
|
|
3
2
|
import {BOOL_ATTRIBUTES_NAME, BOOLEAN_ATTRIBUTES} from './constants.js';
|
|
4
3
|
import {Observable} from '../data/Observable';
|
|
5
4
|
|
|
6
5
|
|
|
7
6
|
|
|
8
|
-
export const handleClassAttributeItem = (element, className, value) => {
|
|
9
|
-
if (value.__$isObservableChecker) {
|
|
10
|
-
let lastClass = value.val();
|
|
11
|
-
if (typeof lastClass === 'string') {
|
|
12
|
-
element.classes.toggle(lastClass, true);
|
|
13
|
-
value.subscribe((currentValue) => {
|
|
14
|
-
element.classes.remove(lastClass);
|
|
15
|
-
element.classes.toggle(currentValue, true);
|
|
16
|
-
lastClass = currentValue;
|
|
17
|
-
});
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (value.__$Observable) {
|
|
23
|
-
element.classes.toggle(className, value.val());
|
|
24
|
-
value.subscribe((shouldAdd) => element.classes.toggle(className, shouldAdd));
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (value.$hydrate) {
|
|
29
|
-
value.$hydrate(element, className);
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
element.classes.toggle(className, value);
|
|
34
|
-
};
|
|
35
|
-
|
|
36
7
|
/**
|
|
37
8
|
* Applies a reactive class map to an HTMLElement.
|
|
38
9
|
* Each key is a CSS class name; each value is a boolean or ObservableItem<boolean>.
|
|
@@ -44,7 +15,31 @@ export const handleClassAttributeItem = (element, className, value) => {
|
|
|
44
15
|
export const bindClassAttribute = (element, data) => {
|
|
45
16
|
for(const className in data) {
|
|
46
17
|
const value = data[className];
|
|
47
|
-
|
|
18
|
+
if (value.__$isObservableChecker) {
|
|
19
|
+
let lastClass = value.val();
|
|
20
|
+
if (typeof lastClass === 'string') {
|
|
21
|
+
element.classes.toggle(lastClass, true);
|
|
22
|
+
value.subscribe((currentValue) => {
|
|
23
|
+
element.classes.remove(lastClass);
|
|
24
|
+
element.classes.toggle(currentValue, true);
|
|
25
|
+
lastClass = currentValue;
|
|
26
|
+
});
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (value.__$Observable) {
|
|
32
|
+
element.classes.toggle(className, value.val());
|
|
33
|
+
value.subscribe((shouldAdd) => element.classes.toggle(className, shouldAdd));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (value.$hydrate) {
|
|
38
|
+
value.$hydrate(element, className);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
element.classes.toggle(className, value);
|
|
48
43
|
}
|
|
49
44
|
};
|
|
50
45
|
|
|
@@ -90,15 +90,8 @@ export const ElementCreator = {
|
|
|
90
90
|
}
|
|
91
91
|
if(Array.isArray(children)) {
|
|
92
92
|
for(let i = 0, length = children.length; i < length; i++) {
|
|
93
|
-
|
|
94
|
-
if(child
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
if(!child.__$isNativeNode) {
|
|
98
|
-
child = ElementCreator.getChild(children[i]);
|
|
99
|
-
if(child) {
|
|
100
|
-
parent.appendChild(child);
|
|
101
|
-
}
|
|
93
|
+
const child = ElementCreator.getChild(children[i]);
|
|
94
|
+
if(child === null) {
|
|
102
95
|
continue;
|
|
103
96
|
}
|
|
104
97
|
parent.appendChild(child);
|
|
@@ -120,11 +113,11 @@ export const ElementCreator = {
|
|
|
120
113
|
}
|
|
121
114
|
|
|
122
115
|
child = child.toNdElement();
|
|
123
|
-
if (child && child
|
|
116
|
+
if (child && (child instanceof Node)) {
|
|
124
117
|
return child;
|
|
125
118
|
}
|
|
126
119
|
|
|
127
|
-
while (child != null && !child
|
|
120
|
+
while (child != null && !(child instanceof Node)) {
|
|
128
121
|
child = child.toNdElement?.();
|
|
129
122
|
}
|
|
130
123
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import Anchor from '../elements/anchor/anchor';
|
|
2
2
|
import {ElementCreator} from './ElementCreator';
|
|
3
|
-
import {normalizeComponentArgs} from '../utils/args-types';
|
|
4
3
|
import './NdPrototype';
|
|
5
4
|
|
|
6
5
|
import '../../core/utils/prototypes.js';
|
|
@@ -19,7 +18,7 @@ import '../wrappers/prototypes/attributes-extensions';
|
|
|
19
18
|
* @returns {Text} Text node, reactive if value is an ObservableItem
|
|
20
19
|
*/
|
|
21
20
|
export const createTextNode = (value) => {
|
|
22
|
-
if(value) {
|
|
21
|
+
if(value != null) {
|
|
23
22
|
return value.toNdElement();
|
|
24
23
|
}
|
|
25
24
|
return ElementCreator.createTextNode();
|
|
@@ -58,11 +57,12 @@ export const createHtmlElement = (element, _attributes, _children = null) => {
|
|
|
58
57
|
attributes = _children;
|
|
59
58
|
children = _attributes;
|
|
60
59
|
}
|
|
60
|
+
element = element.cloneNode();
|
|
61
61
|
|
|
62
|
-
if(attributes) {
|
|
62
|
+
if(attributes != null) {
|
|
63
63
|
ElementCreator.processAttributes(element, attributes);
|
|
64
64
|
}
|
|
65
|
-
if(children) {
|
|
65
|
+
if(children != null) {
|
|
66
66
|
ElementCreator.processChildren(children, element);
|
|
67
67
|
}
|
|
68
68
|
return element;
|
|
@@ -75,6 +75,7 @@ export const createHtmlElement = (element, _attributes, _children = null) => {
|
|
|
75
75
|
*
|
|
76
76
|
* @param {string} name - HTML tag name (e.g. 'div', 'button', 'input'). Pass empty string to create a Fragment.
|
|
77
77
|
* @param {((element: HTMLElement) => HTMLElement)|null} [customWrapper=null] - Optional function to augment the element before returning
|
|
78
|
+
* @param {boolean} [isVoid=false] - If true, the element is a void element (no children allowed, e.g. input, img)
|
|
78
79
|
* @returns {(attr?: Object, children?: ValidChild) => HTMLElement} Element factory function
|
|
79
80
|
* @example
|
|
80
81
|
* const Div = HtmlElementWrapper('div');
|
|
@@ -89,14 +90,12 @@ export const createHtmlElement = (element, _attributes, _children = null) => {
|
|
|
89
90
|
export default function HtmlElementWrapper(name, customWrapper = null, isVoid = false) {
|
|
90
91
|
const elementCreator = isVoid ? createVoidHtmlElement : createHtmlElement;
|
|
91
92
|
if(name) {
|
|
92
|
-
if(customWrapper) {
|
|
93
|
+
if(customWrapper == null) {
|
|
93
94
|
let node = null;
|
|
94
95
|
let createElement = (attr, children) => {
|
|
95
96
|
node = document.createElement(name);
|
|
96
|
-
createElement = (
|
|
97
|
-
|
|
98
|
-
};
|
|
99
|
-
return elementCreator(customWrapper(node.cloneNode()), attr, children);;
|
|
97
|
+
createElement = elementCreator.bind(null, node);
|
|
98
|
+
return elementCreator(node.cloneNode(), attr, children);
|
|
100
99
|
};
|
|
101
100
|
|
|
102
101
|
return (attr, children) => createElement(attr, children);
|
|
@@ -106,9 +105,9 @@ export default function HtmlElementWrapper(name, customWrapper = null, isVoid =
|
|
|
106
105
|
let createElement = (attr, children) => {
|
|
107
106
|
node = document.createElement(name);
|
|
108
107
|
createElement = (attr, children) => {
|
|
109
|
-
return elementCreator(node.cloneNode(), attr, children);
|
|
108
|
+
return elementCreator(customWrapper(node.cloneNode()), attr, children);
|
|
110
109
|
};
|
|
111
|
-
return elementCreator(node.cloneNode(), attr, children)
|
|
110
|
+
return elementCreator(customWrapper(node.cloneNode()), attr, children);;
|
|
112
111
|
};
|
|
113
112
|
|
|
114
113
|
return (attr, children) => createElement(attr, children);
|
|
@@ -5,7 +5,7 @@ import DebugManager from '../utils/debug-manager.js';
|
|
|
5
5
|
import attributesWrapper, {
|
|
6
6
|
bindAttributeWithObservable,
|
|
7
7
|
bindClassAttribute,
|
|
8
|
-
bindStyleAttribute,
|
|
8
|
+
bindStyleAttribute,
|
|
9
9
|
} from './AttributesWrapper';
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -434,17 +434,6 @@ NDElement.prototype.style = function(style) {
|
|
|
434
434
|
return this;
|
|
435
435
|
};
|
|
436
436
|
|
|
437
|
-
NDElement.prototype.className = function(classes) {
|
|
438
|
-
this.$element.classes.add(classes);
|
|
439
|
-
return this;
|
|
440
|
-
};
|
|
441
|
-
|
|
442
|
-
NDElement.prototype.class = function(className, value) {
|
|
443
|
-
handleClassAttributeItem(this.$element, className, value);
|
|
444
|
-
return this;
|
|
445
|
-
};
|
|
446
|
-
|
|
447
|
-
|
|
448
437
|
/**
|
|
449
438
|
* Extends the NDElement prototype with new methods available to all NDElement instances.
|
|
450
439
|
* Use this to add global methods to all NDElements.
|
|
@@ -26,34 +26,67 @@ Object.defineProperty(NDElement.prototype, 'nd', {
|
|
|
26
26
|
EVENTS.forEach(eventSourceName => {
|
|
27
27
|
const eventName = eventSourceName.toLowerCase();
|
|
28
28
|
const inlineHandler = 'on'+eventName;
|
|
29
|
-
|
|
29
|
+
const fnName = 'on'+eventSourceName;
|
|
30
|
+
NDElement.prototype[fnName] = function(callback = null, options = null) {
|
|
30
31
|
if(!this.$element[inlineHandler] && !options) {
|
|
31
32
|
this.$element[inlineHandler] = callback;
|
|
32
|
-
|
|
33
|
-
this.$element.addEventListener(eventName, callback, options);
|
|
33
|
+
return this;
|
|
34
34
|
}
|
|
35
|
+
this.$element.addEventListener(eventName, callback, options);
|
|
35
36
|
return this;
|
|
36
37
|
};
|
|
38
|
+
if(!HTMLElement.prototype[fnName]) {
|
|
39
|
+
HTMLElement.prototype[fnName] = function(callback, options) {
|
|
40
|
+
if(!this[inlineHandler] && !options) {
|
|
41
|
+
this[inlineHandler] = callback;
|
|
42
|
+
return this;
|
|
43
|
+
}
|
|
44
|
+
this.addEventListener(eventName, callback, options);
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
37
48
|
});
|
|
38
49
|
|
|
39
50
|
EVENTS_WITH_STOP.forEach(eventSourceName => {
|
|
40
51
|
const eventName = eventSourceName.toLowerCase();
|
|
41
|
-
|
|
52
|
+
const stopFnName = 'onStop'+eventSourceName;
|
|
53
|
+
const preventStopFnName = 'onPreventStop'+eventSourceName;
|
|
54
|
+
|
|
55
|
+
NDElement.prototype[stopFnName] = function(callback = null, options = null) {
|
|
42
56
|
_stop(this.$element, eventName, callback, options);
|
|
43
57
|
return this;
|
|
44
58
|
};
|
|
45
|
-
NDElement.prototype[
|
|
59
|
+
NDElement.prototype[preventStopFnName] = function(callback = null, options = null) {
|
|
46
60
|
_preventStop(this.$element, eventName, callback, options);
|
|
47
61
|
return this;
|
|
48
62
|
};
|
|
63
|
+
if(HTMLElement.prototype[stopFnName]) {
|
|
64
|
+
HTMLElement.prototype[stopFnName] = function(callback = null, options = null) {
|
|
65
|
+
_stop(this, eventName, callback, options);
|
|
66
|
+
return this;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if(!HTMLElement.prototype[preventStopFnName]) {
|
|
70
|
+
HTMLElement.prototype[preventStopFnName] = function(callback = null, options = null) {
|
|
71
|
+
_preventStop(this, eventName, callback, options);
|
|
72
|
+
return this;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
49
75
|
});
|
|
50
76
|
|
|
51
77
|
EVENTS_WITH_PREVENT.forEach(eventSourceName => {
|
|
52
78
|
const eventName = eventSourceName.toLowerCase();
|
|
53
|
-
|
|
79
|
+
const preventFnName = 'onPrevent'+eventSourceName;
|
|
80
|
+
NDElement.prototype[preventFnName] = function(callback = null, options = null) {
|
|
54
81
|
_prevent(this.$element, eventName, callback, options);
|
|
55
82
|
return this;
|
|
56
83
|
};
|
|
84
|
+
if(HTMLElement.prototype[preventFnName]) {
|
|
85
|
+
HTMLElement.prototype[preventFnName] = function(callback = null, options = null) {
|
|
86
|
+
_prevent(this, eventName, callback, options);
|
|
87
|
+
return this;
|
|
88
|
+
};
|
|
89
|
+
}
|
|
57
90
|
});
|
|
58
91
|
|
|
59
92
|
|
|
@@ -160,6 +193,7 @@ const _preventStop = function(element, eventName, callback, options) {
|
|
|
160
193
|
const inlineHandler = 'on' + eventName;
|
|
161
194
|
if(!element[inlineHandler] && !options) {
|
|
162
195
|
element[inlineHandler] = handler;
|
|
196
|
+
return;
|
|
163
197
|
}
|
|
164
198
|
element.addEventListener(eventName, handler, options);
|
|
165
199
|
return this;
|
|
@@ -17,8 +17,12 @@ export default function NodeCloner($element) {
|
|
|
17
17
|
this.$styles = null;
|
|
18
18
|
this.$attrs = null;
|
|
19
19
|
this.$ndMethods = null;
|
|
20
|
+
this.$content = null;
|
|
20
21
|
}
|
|
21
22
|
|
|
23
|
+
NodeCloner.prototype.shouldBeHydrate = function() {
|
|
24
|
+
return this.$attrs !== null || this.$classes !== null || this.$styles !== null || this.$ndMethods !== null || this.$content !== null;
|
|
25
|
+
};
|
|
22
26
|
|
|
23
27
|
/**
|
|
24
28
|
* Attaches a template binding to the element by hydrating it with the specified method.
|
|
@@ -171,16 +175,16 @@ NodeCloner.prototype.attach = function(methodName, callback) {
|
|
|
171
175
|
* Registers a reactive text content binding for the element.
|
|
172
176
|
*
|
|
173
177
|
* @internal
|
|
174
|
-
* @param {Function}
|
|
178
|
+
* @param {Function} valueOrProperty - Function receiving data and returning the text content
|
|
175
179
|
* @returns {NodeCloner} this
|
|
176
180
|
*/
|
|
177
|
-
NodeCloner.prototype.text = function(
|
|
178
|
-
this.$content =
|
|
179
|
-
if(typeof
|
|
180
|
-
this.cloneNode = (data) => createTextNode(
|
|
181
|
+
NodeCloner.prototype.text = function(valueOrProperty) {
|
|
182
|
+
this.$content = valueOrProperty;
|
|
183
|
+
if(typeof valueOrProperty === 'function') {
|
|
184
|
+
this.cloneNode = (data) => createTextNode(valueOrProperty.apply(null, data));
|
|
181
185
|
return this;
|
|
182
186
|
}
|
|
183
|
-
this.cloneNode = (data) => createTextNode(data[0][
|
|
187
|
+
this.cloneNode = (data) => createTextNode(data[0][valueOrProperty]);
|
|
184
188
|
return this;
|
|
185
189
|
};
|
|
186
190
|
|
|
@@ -24,11 +24,11 @@ export function TemplateCloner($fn) {
|
|
|
24
24
|
|
|
25
25
|
const assignClonerToNode = ($node) => {
|
|
26
26
|
const childNodes = $node.childNodes;
|
|
27
|
-
let containDynamicNode =
|
|
27
|
+
let containDynamicNode = $node.nodeCloner?.shouldBeHydrate();
|
|
28
28
|
const childNodesLength = childNodes.length;
|
|
29
29
|
for(let i = 0; i < childNodesLength; i++) {
|
|
30
30
|
const child = childNodes[i];
|
|
31
|
-
if(child.nodeCloner) {
|
|
31
|
+
if(child.nodeCloner && child.nodeCloner.shouldBeHydrate()) {
|
|
32
32
|
containDynamicNode = true;
|
|
33
33
|
}
|
|
34
34
|
const localContainDynamicNode = assignClonerToNode(child);
|
|
@@ -179,9 +179,12 @@ export function useCache(fn) {
|
|
|
179
179
|
return node;
|
|
180
180
|
};
|
|
181
181
|
|
|
182
|
+
if(fn.length === 0) {
|
|
183
|
+
return () => wrapper();
|
|
184
|
+
}
|
|
182
185
|
if(fn.length < 2) {
|
|
183
|
-
return (
|
|
184
|
-
return wrapper(
|
|
186
|
+
return (arg) => {
|
|
187
|
+
return wrapper([arg]);
|
|
185
188
|
};
|
|
186
189
|
}
|
|
187
190
|
return (_, __, ...args) => {
|