@ckeditor/ckeditor5-utils 34.2.0 → 35.1.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 +324 -0
- package/LICENSE.md +1 -1
- package/package.json +19 -8
- package/src/areconnectedthroughproperties.js +54 -71
- package/src/ckeditorerror.js +92 -114
- package/src/collection.js +594 -762
- package/src/comparearrays.js +22 -28
- package/src/config.js +193 -223
- package/src/count.js +8 -12
- package/src/diff.js +85 -110
- package/src/difftochanges.js +47 -57
- package/src/dom/createelement.js +17 -25
- package/src/dom/emittermixin.js +202 -263
- package/src/dom/getancestors.js +9 -13
- package/src/dom/getborderwidths.js +10 -13
- package/src/dom/getcommonancestor.js +9 -15
- package/src/dom/getdatafromelement.js +5 -9
- package/src/dom/getpositionedancestor.js +9 -14
- package/src/dom/global.js +15 -4
- package/src/dom/indexof.js +7 -11
- package/src/dom/insertat.js +2 -4
- package/src/dom/iscomment.js +2 -5
- package/src/dom/isnode.js +10 -12
- package/src/dom/isrange.js +2 -4
- package/src/dom/istext.js +2 -4
- package/src/dom/isvisible.js +2 -4
- package/src/dom/iswindow.js +11 -16
- package/src/dom/position.js +220 -410
- package/src/dom/rect.js +335 -414
- package/src/dom/remove.js +5 -8
- package/src/dom/resizeobserver.js +109 -342
- package/src/dom/scroll.js +151 -183
- package/src/dom/setdatainelement.js +5 -9
- package/src/dom/tounit.js +10 -12
- package/src/elementreplacer.js +30 -44
- package/src/emittermixin.js +368 -634
- package/src/env.js +109 -116
- package/src/eventinfo.js +12 -65
- package/src/fastdiff.js +96 -128
- package/src/first.js +8 -12
- package/src/focustracker.js +77 -133
- package/src/index.js +0 -9
- package/src/inserttopriorityarray.js +9 -30
- package/src/isiterable.js +2 -4
- package/src/keyboard.js +117 -196
- package/src/keystrokehandler.js +72 -88
- package/src/language.js +9 -15
- package/src/locale.js +61 -158
- package/src/mapsequal.js +12 -17
- package/src/mix.js +17 -16
- package/src/nth.js +8 -11
- package/src/objecttomap.js +7 -11
- package/src/observablemixin.js +474 -778
- package/src/priorities.js +20 -32
- package/src/spy.js +3 -6
- package/src/toarray.js +2 -13
- package/src/tomap.js +8 -10
- package/src/translation-service.js +57 -93
- package/src/uid.js +34 -38
- package/src/unicode.js +28 -43
- package/src/version.js +134 -143
package/src/comparearrays.js
CHANGED
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
* @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
5
|
/**
|
|
7
6
|
* @module utils/comparearrays
|
|
8
7
|
*/
|
|
9
|
-
|
|
10
8
|
/**
|
|
11
9
|
* Compares how given arrays relate to each other. One array can be: same as another array, prefix of another array
|
|
12
10
|
* or completely different. If arrays are different, first index at which they differ is returned. Otherwise,
|
|
@@ -21,31 +19,27 @@
|
|
|
21
19
|
*
|
|
22
20
|
* @param {Array} a Array that is compared.
|
|
23
21
|
* @param {Array} b Array to compare with.
|
|
24
|
-
* @returns {module:utils/comparearrays~ArrayRelation} How array `a` is related to `b`.
|
|
22
|
+
* @returns {module:utils/comparearrays~ArrayRelation|Number} How array `a` is related to `b`.
|
|
25
23
|
*/
|
|
26
|
-
export default function compareArrays(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
24
|
+
export default function compareArrays(a, b) {
|
|
25
|
+
const minLen = Math.min(a.length, b.length);
|
|
26
|
+
for (let i = 0; i < minLen; i++) {
|
|
27
|
+
if (a[i] != b[i]) {
|
|
28
|
+
// The arrays are different.
|
|
29
|
+
return i;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Both arrays were same at all points.
|
|
33
|
+
if (a.length == b.length) {
|
|
34
|
+
// If their length is also same, they are the same.
|
|
35
|
+
return 'same';
|
|
36
|
+
}
|
|
37
|
+
else if (a.length < b.length) {
|
|
38
|
+
// Compared array is shorter so it is a prefix of the other array.
|
|
39
|
+
return 'prefix';
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
// Compared array is longer so it is an extension of the other array.
|
|
43
|
+
return 'extension';
|
|
44
|
+
}
|
|
47
45
|
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* @typedef {'extension'|'same'|'prefix'} module:utils/comparearrays~ArrayRelation
|
|
51
|
-
*/
|
package/src/config.js
CHANGED
|
@@ -2,245 +2,215 @@
|
|
|
2
2
|
* @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
5
|
/**
|
|
7
6
|
* @module utils/config
|
|
8
7
|
*/
|
|
9
|
-
|
|
10
8
|
import { isPlainObject, isElement, cloneDeepWith } from 'lodash-es';
|
|
11
|
-
|
|
12
9
|
/**
|
|
13
10
|
* Handles a configuration dictionary.
|
|
14
11
|
*/
|
|
15
12
|
export default class Config {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
source = null;
|
|
206
|
-
break;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Nested object becomes a source.
|
|
210
|
-
source = source[ part ];
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Always returns undefined for non existing configuration.
|
|
214
|
-
return source ? cloneConfig( source[ name ] ) : undefined;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Iterates through passed object and calls {@link #_setToTarget} method with object key and value for each property.
|
|
219
|
-
*
|
|
220
|
-
* @private
|
|
221
|
-
* @param {Object} target Nested config object.
|
|
222
|
-
* @param {Object} configuration Configuration data set
|
|
223
|
-
* @param {Boolean} [isDefine] Defines if passed configuration is default configuration or not.
|
|
224
|
-
*/
|
|
225
|
-
_setObjectToTarget( target, configuration, isDefine ) {
|
|
226
|
-
Object.keys( configuration ).forEach( key => {
|
|
227
|
-
this._setToTarget( target, key, configuration[ key ], isDefine );
|
|
228
|
-
} );
|
|
229
|
-
}
|
|
13
|
+
/**
|
|
14
|
+
* Creates an instance of the {@link ~Config} class.
|
|
15
|
+
*
|
|
16
|
+
* @param {Object} [configurations] The initial configurations to be set. Usually, provided by the user.
|
|
17
|
+
* @param {Object} [defaultConfigurations] The default configurations. Usually, provided by the system.
|
|
18
|
+
*/
|
|
19
|
+
constructor(configurations, defaultConfigurations) {
|
|
20
|
+
/**
|
|
21
|
+
* Store for the whole configuration.
|
|
22
|
+
*
|
|
23
|
+
* @private
|
|
24
|
+
* @member {Object}
|
|
25
|
+
*/
|
|
26
|
+
this._config = {};
|
|
27
|
+
// Set default configuration.
|
|
28
|
+
if (defaultConfigurations) {
|
|
29
|
+
// Clone the configuration to make sure that the properties will not be shared
|
|
30
|
+
// between editors and make the watchdog feature work correctly.
|
|
31
|
+
this.define(cloneConfig(defaultConfigurations));
|
|
32
|
+
}
|
|
33
|
+
// Set initial configuration.
|
|
34
|
+
if (configurations) {
|
|
35
|
+
this._setObjectToTarget(this._config, configurations);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Set configuration values.
|
|
40
|
+
*
|
|
41
|
+
* It accepts both a name/value pair or an object, which properties and values will be used to set
|
|
42
|
+
* configurations.
|
|
43
|
+
*
|
|
44
|
+
* It also accepts setting a "deep configuration" by using dots in the name. For example, `'resize.width'` sets
|
|
45
|
+
* the value for the `width` configuration in the `resize` subset.
|
|
46
|
+
*
|
|
47
|
+
* config.set( 'width', 500 );
|
|
48
|
+
* config.set( 'toolbar.collapsed', true );
|
|
49
|
+
*
|
|
50
|
+
* // Equivalent to:
|
|
51
|
+
* config.set( {
|
|
52
|
+
* width: 500
|
|
53
|
+
* toolbar: {
|
|
54
|
+
* collapsed: true
|
|
55
|
+
* }
|
|
56
|
+
* } );
|
|
57
|
+
*
|
|
58
|
+
* Passing an object as the value will amend the configuration, not replace it.
|
|
59
|
+
*
|
|
60
|
+
* config.set( 'toolbar', {
|
|
61
|
+
* collapsed: true,
|
|
62
|
+
* } );
|
|
63
|
+
*
|
|
64
|
+
* config.set( 'toolbar', {
|
|
65
|
+
* color: 'red',
|
|
66
|
+
* } );
|
|
67
|
+
*
|
|
68
|
+
* config.get( 'toolbar.collapsed' ); // true
|
|
69
|
+
* config.get( 'toolbar.color' ); // 'red'
|
|
70
|
+
*
|
|
71
|
+
* @param {String|Object} name The configuration name or an object from which take properties as
|
|
72
|
+
* configuration entries. Configuration names are case-sensitive.
|
|
73
|
+
* @param {*} value The configuration value. Used if a name is passed.
|
|
74
|
+
*/
|
|
75
|
+
set(name, value) {
|
|
76
|
+
this._setToTarget(this._config, name, value);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Does exactly the same as {@link #set} with one exception – passed configuration extends
|
|
80
|
+
* existing one, but does not overwrite already defined values.
|
|
81
|
+
*
|
|
82
|
+
* This method is supposed to be called by plugin developers to setup plugin's configurations. It would be
|
|
83
|
+
* rarely used for other needs.
|
|
84
|
+
*
|
|
85
|
+
* @param {String|Object} name The configuration name or an object from which take properties as
|
|
86
|
+
* configuration entries. Configuration names are case-sensitive.
|
|
87
|
+
* @param {*} value The configuration value. Used if a name is passed.
|
|
88
|
+
*/
|
|
89
|
+
define(name, value) {
|
|
90
|
+
const isDefine = true;
|
|
91
|
+
this._setToTarget(this._config, name, value, isDefine);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Gets the value for a configuration entry.
|
|
95
|
+
*
|
|
96
|
+
* config.get( 'name' );
|
|
97
|
+
*
|
|
98
|
+
* Deep configurations can be retrieved by separating each part with a dot.
|
|
99
|
+
*
|
|
100
|
+
* config.get( 'toolbar.collapsed' );
|
|
101
|
+
*
|
|
102
|
+
* @param {String} name The configuration name. Configuration names are case-sensitive.
|
|
103
|
+
* @returns {*} The configuration value or `undefined` if the configuration entry was not found.
|
|
104
|
+
*/
|
|
105
|
+
get(name) {
|
|
106
|
+
return this._getFromSource(this._config, name);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Iterates over all top level configuration names.
|
|
110
|
+
*
|
|
111
|
+
* @returns {Iterable.<String>}
|
|
112
|
+
*/
|
|
113
|
+
*names() {
|
|
114
|
+
for (const name of Object.keys(this._config)) {
|
|
115
|
+
yield name;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Saves passed configuration to the specified target (nested object).
|
|
120
|
+
*
|
|
121
|
+
* @private
|
|
122
|
+
* @param {Object} target Nested config object.
|
|
123
|
+
* @param {String|Object} name The configuration name or an object from which take properties as
|
|
124
|
+
* configuration entries. Configuration names are case-sensitive.
|
|
125
|
+
* @param {*} value The configuration value. Used if a name is passed.
|
|
126
|
+
* @param {Boolean} [isDefine=false] Define if passed configuration should overwrite existing one.
|
|
127
|
+
*/
|
|
128
|
+
_setToTarget(target, name, value, isDefine = false) {
|
|
129
|
+
// In case of an object, iterate through it and call `_setToTarget` again for each property.
|
|
130
|
+
if (isPlainObject(name)) {
|
|
131
|
+
this._setObjectToTarget(target, name, isDefine);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
// The configuration name should be split into parts if it has dots. E.g. `resize.width` -> [`resize`, `width`].
|
|
135
|
+
const parts = name.split('.');
|
|
136
|
+
// Take the name of the configuration out of the parts. E.g. `resize.width` -> `width`.
|
|
137
|
+
name = parts.pop();
|
|
138
|
+
// Iterate over parts to check if currently stored configuration has proper structure.
|
|
139
|
+
for (const part of parts) {
|
|
140
|
+
// If there is no object for specified part then create one.
|
|
141
|
+
if (!isPlainObject(target[part])) {
|
|
142
|
+
target[part] = {};
|
|
143
|
+
}
|
|
144
|
+
// Nested object becomes a target.
|
|
145
|
+
target = target[part];
|
|
146
|
+
}
|
|
147
|
+
// In case of value is an object.
|
|
148
|
+
if (isPlainObject(value)) {
|
|
149
|
+
// We take care of proper config structure.
|
|
150
|
+
if (!isPlainObject(target[name])) {
|
|
151
|
+
target[name] = {};
|
|
152
|
+
}
|
|
153
|
+
target = target[name];
|
|
154
|
+
// And iterate through this object calling `_setToTarget` again for each property.
|
|
155
|
+
this._setObjectToTarget(target, value, isDefine);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
// Do nothing if we are defining configuration for non empty name.
|
|
159
|
+
if (isDefine && typeof target[name] != 'undefined') {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
target[name] = value;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Get specified configuration from specified source (nested object).
|
|
166
|
+
*
|
|
167
|
+
* @private
|
|
168
|
+
* @param {Object} source level of nested object.
|
|
169
|
+
* @param {String} name The configuration name. Configuration names are case-sensitive.
|
|
170
|
+
* @returns {*} The configuration value or `undefined` if the configuration entry was not found.
|
|
171
|
+
*/
|
|
172
|
+
_getFromSource(source, name) {
|
|
173
|
+
// The configuration name should be split into parts if it has dots. E.g. `resize.width` -> [`resize`, `width`].
|
|
174
|
+
const parts = name.split('.');
|
|
175
|
+
// Take the name of the configuration out of the parts. E.g. `resize.width` -> `width`.
|
|
176
|
+
name = parts.pop();
|
|
177
|
+
// Iterate over parts to check if currently stored configuration has proper structure.
|
|
178
|
+
for (const part of parts) {
|
|
179
|
+
if (!isPlainObject(source[part])) {
|
|
180
|
+
source = null;
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
// Nested object becomes a source.
|
|
184
|
+
source = source[part];
|
|
185
|
+
}
|
|
186
|
+
// Always returns undefined for non existing configuration.
|
|
187
|
+
return source ? cloneConfig(source[name]) : undefined;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Iterates through passed object and calls {@link #_setToTarget} method with object key and value for each property.
|
|
191
|
+
*
|
|
192
|
+
* @private
|
|
193
|
+
* @param {Object} target Nested config object.
|
|
194
|
+
* @param {Object} configuration Configuration data set
|
|
195
|
+
* @param {Boolean} [isDefine] Defines if passed configuration is default configuration or not.
|
|
196
|
+
*/
|
|
197
|
+
_setObjectToTarget(target, configuration, isDefine) {
|
|
198
|
+
Object.keys(configuration).forEach(key => {
|
|
199
|
+
this._setToTarget(target, key, configuration[key], isDefine);
|
|
200
|
+
});
|
|
201
|
+
}
|
|
230
202
|
}
|
|
231
|
-
|
|
232
203
|
// Clones configuration object or value.
|
|
233
204
|
// @param {*} source Source configuration
|
|
234
205
|
// @returns {*} Cloned configuration value.
|
|
235
|
-
function cloneConfig(
|
|
236
|
-
|
|
206
|
+
function cloneConfig(source) {
|
|
207
|
+
return cloneDeepWith(source, leaveDOMReferences);
|
|
237
208
|
}
|
|
238
|
-
|
|
239
209
|
// A customized function for cloneDeepWith.
|
|
240
210
|
// It will leave references to DOM Elements instead of cloning them.
|
|
241
211
|
//
|
|
242
212
|
// @param {*} value
|
|
243
213
|
// @returns {Element|undefined}
|
|
244
|
-
function leaveDOMReferences(
|
|
245
|
-
|
|
214
|
+
function leaveDOMReferences(value) {
|
|
215
|
+
return isElement(value) ? value : undefined;
|
|
246
216
|
}
|
package/src/count.js
CHANGED
|
@@ -2,25 +2,21 @@
|
|
|
2
2
|
* @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
5
|
/**
|
|
7
6
|
* @module utils/count
|
|
8
7
|
*/
|
|
9
|
-
|
|
10
8
|
/**
|
|
11
9
|
* Returns the number of items return by the iterator.
|
|
12
10
|
*
|
|
13
11
|
* count( [ 1, 2, 3, 4, 5 ] ); // 5;
|
|
14
12
|
*
|
|
15
|
-
* @param {Iterable.<*>}
|
|
16
|
-
* @returns {Number} Number of items returned by that
|
|
13
|
+
* @param {Iterable.<*>} iterable Any iterable.
|
|
14
|
+
* @returns {Number} Number of items returned by that iterable.
|
|
17
15
|
*/
|
|
18
|
-
export default function count(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return count;
|
|
16
|
+
export default function count(iterable) {
|
|
17
|
+
let count = 0;
|
|
18
|
+
for (const _ of iterable) { // eslint-disable-line no-unused-vars
|
|
19
|
+
count++;
|
|
20
|
+
}
|
|
21
|
+
return count;
|
|
26
22
|
}
|