@stdlib/array-to-fancy 0.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.
@@ -0,0 +1,51 @@
1
+ /**
2
+ * @license Apache-2.0
3
+ *
4
+ * Copyright (c) 2024 The Stdlib Authors.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ 'use strict';
20
+
21
+ // MODULES //
22
+
23
+ var isString = require( '@stdlib/assert-is-string' ).isPrimitive;
24
+ var RE_INTEGER = require( './re_integer.js' );
25
+
26
+
27
+ // MAIN //
28
+
29
+ /**
30
+ * Tests if an indexing expression is an integer.
31
+ *
32
+ * @private
33
+ * @param {(string|symbol)} prop - property name
34
+ * @returns {boolean} result
35
+ *
36
+ * @example
37
+ * var out = isIntegerString( '1' );
38
+ * // returns true
39
+ *
40
+ * @example
41
+ * var out = isIntegerString( ':' );
42
+ * // returns false
43
+ */
44
+ function isIntegerString( prop ) {
45
+ return ( isString( prop ) && RE_INTEGER.test( prop ) );
46
+ }
47
+
48
+
49
+ // EXPORTS //
50
+
51
+ module.exports = isIntegerString;
package/lib/main.js ADDED
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @license Apache-2.0
3
+ *
4
+ * Copyright (c) 2024 The Stdlib Authors.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ 'use strict';
20
+
21
+ // MODULES //
22
+
23
+ var factory = require( './factory.js' );
24
+
25
+
26
+ // MAIN //
27
+
28
+ /**
29
+ * Converts an array to an object supporting fancy indexing.
30
+ *
31
+ * @name array2fancy
32
+ * @type {Function}
33
+ * @param {ArrayLike} x - input array
34
+ * @param {Options} [options] - function options
35
+ * @param {boolean} [options.strict=false] - boolean indicating whether to enforce strict bounds checking
36
+ * @param {Function} [options.cache] - cache for resolving array index objects
37
+ * @throws {TypeError} first argument must be array-like
38
+ * @throws {TypeError} options argument must be an object
39
+ * @throws {TypeError} must provide valid options
40
+ * @returns {ArrayLike} fancy array
41
+ *
42
+ * @example
43
+ * var x = [ 1, 2, 3, 4, 5, 6 ];
44
+ *
45
+ * var y = array2fancy( x );
46
+ * // returns <Array>
47
+ *
48
+ * var z = y[ '1::2' ];
49
+ * // returns [ 2, 4, 6 ]
50
+ *
51
+ * var len = z.length;
52
+ * // returns 3
53
+ *
54
+ * var v = z[ 0 ];
55
+ * // returns 2
56
+ *
57
+ * v = z[ 1 ];
58
+ * // returns 4
59
+ *
60
+ * v = z[ 2 ];
61
+ * // returns 6
62
+ */
63
+ var array2fancy = factory();
64
+
65
+
66
+ // EXPORTS //
67
+
68
+ module.exports = array2fancy;
@@ -0,0 +1,69 @@
1
+ /**
2
+ * @license Apache-2.0
3
+ *
4
+ * Copyright (c) 2024 The Stdlib Authors.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ 'use strict';
20
+
21
+ // MODULES //
22
+
23
+ var trim = require( '@stdlib/string-base-trim' );
24
+ var format = require( '@stdlib/string-format' );
25
+
26
+
27
+ // FUNCTIONS //
28
+
29
+ /**
30
+ * Extracts an array index identifier from an array index indexing expression.
31
+ *
32
+ * @private
33
+ * @param {string} str - input string
34
+ * @returns {string} identifier
35
+ *
36
+ * @example
37
+ * var str = 'ArrayIndex<0>';
38
+ *
39
+ * var id = getIdentifier( str );
40
+ * // returns '0'
41
+ */
42
+ function getIdentifier( str ) {
43
+ return str.substring( 11, str.length-1 ); // ArrayIndex<XX> => XX
44
+ }
45
+
46
+
47
+ // MAIN //
48
+
49
+ /**
50
+ * Converts an indexing expression to an array index.
51
+ *
52
+ * @private
53
+ * @param {string} property - property name
54
+ * @param {Object} cache - cache for resolving array index objects
55
+ * @throws {Error} invalid array index
56
+ * @returns {(Object|null)} index object (or null)
57
+ */
58
+ function prop2array( property, cache ) {
59
+ var o = cache.get( getIdentifier( trim( property ) ) );
60
+ if ( o === null ) {
61
+ throw new Error( format( 'invalid operation. Unable to resolve array index. Value: `%s`.', property ) );
62
+ }
63
+ return o;
64
+ }
65
+
66
+
67
+ // EXPORTS //
68
+
69
+ module.exports = prop2array;
@@ -0,0 +1,163 @@
1
+ /**
2
+ * @license Apache-2.0
3
+ *
4
+ * Copyright (c) 2024 The Stdlib Authors.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ 'use strict';
20
+
21
+ // MODULES //
22
+
23
+ var trim = require( '@stdlib/string-base-trim' );
24
+ var seq2slice = require( '@stdlib/slice-base-seq2slice' );
25
+ var str2slice = require( '@stdlib/slice-base-str2slice' );
26
+ var startsWith = require( '@stdlib/string-base-starts-with' );
27
+ var format = require( '@stdlib/string-format' );
28
+ var RE_SUBSEQ = require( './re_subseq.js' );
29
+
30
+
31
+ // FUNCTIONS //
32
+
33
+ /**
34
+ * Tests if an indexing expression is a serialized Slice object.
35
+ *
36
+ * @private
37
+ * @param {string} prop - property name
38
+ * @returns {boolean} result
39
+ *
40
+ * @example
41
+ * var out = isSlice( 'Slice(null,null,1)' );
42
+ * // returns true
43
+ *
44
+ * @example
45
+ * var out = isSlice( ':' );
46
+ * // returns false
47
+ */
48
+ function isSlice( prop ) {
49
+ return (
50
+ prop[ 0 ] === 'S' &&
51
+ startsWith( prop, 'Slice(', 0 ) &&
52
+ prop[ prop.length-1 ] === ')'
53
+ );
54
+ }
55
+
56
+ /**
57
+ * Tests if an indexing expression is a subsequence.
58
+ *
59
+ * @private
60
+ * @param {string} prop - property name
61
+ * @returns {boolean} result
62
+ *
63
+ * @example
64
+ * var out = isSubsequence( '::-2' );
65
+ * // returns true
66
+ *
67
+ * @example
68
+ * var out = isSubsequence( '-2' );
69
+ * // returns false
70
+ */
71
+ function isSubsequence( prop ) {
72
+ // TODO: consider whether to make this check more robust (e.g., should we actually throw if someone tries to access `foo:bar`? If we make this check more exact, how would we distinguish between a non-existent `foo:bar` property and an actual error in the subsequence string?)
73
+ return RE_SUBSEQ.test( prop );
74
+ }
75
+
76
+ /**
77
+ * Parses a serialized Slice object.
78
+ *
79
+ * @private
80
+ * @param {string} raw - original unprocessed input string
81
+ * @param {string} str - serialized Slice object
82
+ * @throws {Error} invalid slice operation
83
+ * @returns {Slice} Slice object
84
+ *
85
+ * @example
86
+ * var s = parseSlice( ' Slice(null,null,1) ', 'Slice(null,null,1)' );
87
+ * // returns <Slice>
88
+ */
89
+ function parseSlice( raw, str ) {
90
+ var s = str2slice( str );
91
+ if ( s === null ) {
92
+ throw new Error( format( 'invalid operation. Unsupported slice operation. Value: `%s`.', raw ) );
93
+ }
94
+ return s;
95
+ }
96
+
97
+ /**
98
+ * Parses a subsequence string.
99
+ *
100
+ * @private
101
+ * @param {string} raw - original unprocessed input string
102
+ * @param {string} str - subsequence string
103
+ * @param {NonNegativeInteger} max - index upper bound
104
+ * @param {boolean} strict - boolean indicating whether to enforce strict bounds checking
105
+ * @throws {Error} invalid slice operation
106
+ * @throws {RangeError} slice exceeds array bounds
107
+ * @returns {Slice} Slice object
108
+ *
109
+ * @example
110
+ * var s = parseSubsequence( ' ::-2 ', '::-2', 10, false );
111
+ * // returns <Slice>
112
+ */
113
+ function parseSubsequence( raw, str, max, strict ) {
114
+ var s = seq2slice( str, max, true );
115
+ if ( s.code ) {
116
+ if ( s.code === 'ERR_SLICE_INVALID_INCREMENT' ) {
117
+ throw new Error( format( 'invalid operation. A subsequence increment must be a non-zero integer. Value: `%s`.', raw ) );
118
+ }
119
+ if ( s.code === 'ERR_SLICE_INVALID_SUBSEQUENCE' ) {
120
+ throw new Error( format( 'invalid operation. Unsupported slice operation. Value: `%s`.', raw ) );
121
+ }
122
+ // NOTE: the following error check must come last due to fall-through when in non-strict mode...
123
+ if ( s.code === 'ERR_SLICE_OUT_OF_BOUNDS' ) {
124
+ if ( strict ) {
125
+ throw new RangeError( format( 'invalid operation. Slice exceeds array bounds.' ) );
126
+ }
127
+ // Repeat parsing, this time allowing for out-of-bounds slices:
128
+ s = seq2slice( str, max, false );
129
+ }
130
+ }
131
+ return s;
132
+ }
133
+
134
+
135
+ // MAIN //
136
+
137
+ /**
138
+ * Converts an indexing expression to a Slice object.
139
+ *
140
+ * @private
141
+ * @param {Object} target - target object
142
+ * @param {string} property - property name
143
+ * @param {boolean} strict - boolean indicating whether to enforce strict bounds checking
144
+ * @throws {Error} invalid slice operation
145
+ * @throws {RangeError} slice exceeds array bounds
146
+ * @returns {(Slice|null)} slice object (or null)
147
+ */
148
+ function prop2slice( target, property, strict ) {
149
+ var prop = trim( property );
150
+ if ( isSlice( prop ) ) {
151
+ return parseSlice( property, prop );
152
+ }
153
+ if ( isSubsequence( prop ) ) {
154
+ return parseSubsequence( property, prop, target.length, strict );
155
+ }
156
+ // Everything else (including undefined/non-existent properties):
157
+ return null;
158
+ }
159
+
160
+
161
+ // EXPORTS //
162
+
163
+ module.exports = prop2slice;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @license Apache-2.0
3
+ *
4
+ * Copyright (c) 2024 The Stdlib Authors.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ 'use strict';
20
+
21
+ // MAIN //
22
+
23
+ /**
24
+ * Regular expression for testing whether a string is a serialized array index.
25
+ *
26
+ * @private
27
+ * @name RE_ARRAY_INDEX
28
+ * @type {RegExp}
29
+ *
30
+ * @example
31
+ * var bool = RE_ARRAY_INDEX.test( 'ArrayIndex<0>' );
32
+ * // returns true
33
+ *
34
+ * @example
35
+ * var bool = RE_ARRAY_INDEX.test( '0' );
36
+ * // returns false
37
+ *
38
+ * @example
39
+ * var bool = RE_ARRAY_INDEX.test( 'Slice(0,10,2)' );
40
+ * // returns false
41
+ */
42
+ var RE_ARRAY_INDEX = /\s*ArrayIndex<[^>]+>\s*/;
43
+
44
+
45
+ // EXPORTS //
46
+
47
+ module.exports = RE_ARRAY_INDEX;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @license Apache-2.0
3
+ *
4
+ * Copyright (c) 2024 The Stdlib Authors.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ 'use strict';
20
+
21
+ // MAIN //
22
+
23
+ /**
24
+ * Regular expression for testing whether a string is an integer string.
25
+ *
26
+ * @private
27
+ * @name RE_INTEGER
28
+ * @type {RegExp}
29
+ *
30
+ * @example
31
+ * var bool = RE_INTEGER.test( '10' );
32
+ * // returns true
33
+ *
34
+ * @example
35
+ * var bool = RE_INTEGER.test( '-1' );
36
+ * // returns true
37
+ *
38
+ * @example
39
+ * var bool = RE_INTEGER.test( '0:10:2' );
40
+ * // returns false
41
+ */
42
+ var RE_INTEGER = /^-?[0-9]+$/;
43
+
44
+
45
+ // EXPORTS //
46
+
47
+ module.exports = RE_INTEGER;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @license Apache-2.0
3
+ *
4
+ * Copyright (c) 2024 The Stdlib Authors.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ 'use strict';
20
+
21
+ // MAIN //
22
+
23
+ /**
24
+ * Regular expression for testing whether a string is a subsequence string.
25
+ *
26
+ * @private
27
+ * @name RE_SUBSEQ
28
+ * @type {RegExp}
29
+ *
30
+ * @example
31
+ * var bool = RE_SUBSEQ.test( '0:10:2' );
32
+ * // returns true
33
+ *
34
+ * @example
35
+ * var bool = RE_SUBSEQ.test( '0' );
36
+ * // returns false
37
+ *
38
+ * @example
39
+ * var bool = RE_SUBSEQ.test( 'Slice(0,10,2)' );
40
+ * // returns false
41
+ */
42
+ var RE_SUBSEQ = /:/;
43
+
44
+
45
+ // EXPORTS //
46
+
47
+ module.exports = RE_SUBSEQ;
@@ -0,0 +1,66 @@
1
+ /**
2
+ * @license Apache-2.0
3
+ *
4
+ * Copyright (c) 2024 The Stdlib Authors.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ 'use strict';
20
+
21
+ // MODULES //
22
+
23
+ var normalizeIndex = require( '@stdlib/ndarray-base-normalize-index' );
24
+ var format = require( '@stdlib/string-format' );
25
+
26
+
27
+ // MAIN //
28
+
29
+ /**
30
+ * Resolves an integer index from an integer string.
31
+ *
32
+ * @private
33
+ * @param {string} str - integer string
34
+ * @param {NonNegativeInteger} max - index upper bound (exclusive)
35
+ * @param {boolean} strict - boolean indicating whether to enforce strict bounds checking
36
+ * @throws {RangeError} index exceeds array bounds
37
+ * @returns {integer} integer index
38
+ *
39
+ * @example
40
+ * var idx = resolveIndex( '-1', 10, false );
41
+ * // returns 9
42
+ *
43
+ * @example
44
+ * var idx = resolveIndex( '-20', 10, false );
45
+ * // returns -20
46
+ */
47
+ function resolveIndex( str, max, strict ) {
48
+ var idx;
49
+ var i;
50
+
51
+ idx = parseInt( str, 10 );
52
+ i = normalizeIndex( idx, max-1 );
53
+ if ( i === -1 ) {
54
+ if ( strict ) {
55
+ throw new RangeError( format( 'invalid operation. Index exceeds array bounds.' ) );
56
+ }
57
+ // Return the non-normalized index, as this should fallback to default property handling and returning "undefined":
58
+ return idx;
59
+ }
60
+ return i;
61
+ }
62
+
63
+
64
+ // EXPORTS //
65
+
66
+ module.exports = resolveIndex;
package/lib/set.js ADDED
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @license Apache-2.0
3
+ *
4
+ * Copyright (c) 2024 The Stdlib Authors.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ 'use strict';
20
+
21
+ // MODULES //
22
+
23
+ var isString = require( '@stdlib/assert-is-string' ).isPrimitive;
24
+ var hasProperty = require( '@stdlib/assert-has-property' );
25
+ var isIntegerString = require( './is_integer_string.js' );
26
+ var setElement = require( './set_element.js' );
27
+ var setValue = require( './set_value.js' );
28
+ var setSlice = require( './set_slice.js' );
29
+
30
+
31
+ // MAIN //
32
+
33
+ /**
34
+ * Returns a trap for setting property values.
35
+ *
36
+ * @private
37
+ * @param {Object} ctx - context object
38
+ * @param {Function} ctx.setter - accessor for setting array elements
39
+ * @param {string} ctx.dtype - array data type
40
+ * @param {boolean} ctx.strict - boolean indicating whether to enforce strict bounds checking
41
+ * @param {Function} ctx.validator - function for validating new values
42
+ * @param {Function} ctx.setter - accessor for setting array elements
43
+ * @param {(Function|null)} ctx.preSetElement - function for normalizing new values (if necessary)
44
+ * @returns {Function} handler
45
+ */
46
+ function factory( ctx ) {
47
+ return set;
48
+
49
+ /**
50
+ * Trap for setting property values.
51
+ *
52
+ * @private
53
+ * @param {Object} target - target object
54
+ * @param {(string|symbol)} property - property name
55
+ * @param {*} value - new value
56
+ * @param {Object} receiver - the proxy object or an object inheriting from the proxy
57
+ * @throws {Error} invalid slice operation
58
+ * @throws {Error} assigned value must be broadcast compatible with output array view
59
+ * @throws {TypeError} assigned value cannot be safely cast to the output array data type
60
+ * @throws {TypeError} slice exceeds array bounds
61
+ * @throws {TypeError} index exceeds array bounds
62
+ * @returns {boolean} boolean indicating whether assignment succeeded
63
+ */
64
+ function set( target, property, value, receiver ) {
65
+ var out;
66
+
67
+ // Note that we need to check for an integer string *before* checking for an own property, as we want to explicitly handle *all* indexed properties, not just negative integers, in order to perform assignment validation...
68
+ if ( isIntegerString( property ) ) {
69
+ return setElement( target, property, value, ctx );
70
+ }
71
+ if ( hasProperty( property ) || !isString( property ) ) {
72
+ return setValue( target, property, value, ctx );
73
+ }
74
+ out = setSlice( target, property, value, receiver, ctx );
75
+ if ( out ) {
76
+ return out;
77
+ }
78
+ // If we were unsuccessful (e.g., due to an invalid subsequence, etc), set the "property" in the same way as would any normal property (e.g., if an indexing expression is an invalid subsequence, assign as would a regular property: `i = 'a:b:c'` => `x[i] = 1` => `v = x[i]` => `v === 1`):
79
+ return setValue( target, property, value, ctx );
80
+ }
81
+ }
82
+
83
+
84
+ // EXPORTS //
85
+
86
+ module.exports = factory;