diff --git a/lib/node_modules/@stdlib/string/truncate-middle/README.md b/lib/node_modules/@stdlib/string/truncate-middle/README.md
index c41420b914c3..4aef543b6cb3 100644
--- a/lib/node_modules/@stdlib/string/truncate-middle/README.md
+++ b/lib/node_modules/@stdlib/string/truncate-middle/README.md
@@ -40,7 +40,7 @@ limitations under the License.
var truncateMiddle = require( '@stdlib/string/truncate-middle' );
```
-#### truncate( str, len\[, seq] )
+#### truncate( str, len\[, seq]\[, options] )
Truncates a string in the middle to a specified length.
@@ -49,6 +49,16 @@ var out = truncateMiddle( 'beep boop', 7 );
// returns 'be...op'
```
+The function supports the following options:
+
+- **mode**: type of characters to return. Must be one of the following:
+
+ - `'grapheme'`: grapheme clusters. Appropriate for strings containing visual characters which can span multiple Unicode code points (e.g., emoji).
+ - `'code_point'`: Unicode code points. Appropriate for strings containing visual characters which are comprised of more than one Unicode code unit (e.g., ideographic symbols and punctuation and mathematical alphanumerics).
+ - `'code_unit'`: UTF-16 code units. Appropriate for strings containing visual characters drawn from the basic multilingual plane (BMP) (e.g., common characters, such as those from the Latin, Greek, and Cyrillic alphabets).
+
+ Default: `'grapheme'`.
+
By default, the truncated string uses the replacement sequence `'...'`. To customize the replacement sequence, provide a `seq` argument:
```javascript
@@ -67,6 +77,10 @@ out = truncateMiddle( 'beep boop', 7, '!!!' );
+## Notes
+
+- By default, the function assumes the general case in which an input string may contain an arbitrary number of grapheme clusters. This assumption comes with a performance cost. Accordingly, if an input string is known to only contain visual characters of a particular type (e.g., only alphanumeric), one can achieve better performance by specifying the appropriate `mode` option.
+
@@ -131,6 +145,7 @@ Options:
--len length String length.
--seq str Custom replacement sequence. Default: '...'.
--split sep Delimiter for stdin data. Default: '/\\r?\\n/'.
+ --mode mode Type of character to return. Default: 'grapheme'.
```
diff --git a/lib/node_modules/@stdlib/string/truncate-middle/benchmark/benchmark.js b/lib/node_modules/@stdlib/string/truncate-middle/benchmark/benchmark.js
index 659606852940..f187f5753a13 100644
--- a/lib/node_modules/@stdlib/string/truncate-middle/benchmark/benchmark.js
+++ b/lib/node_modules/@stdlib/string/truncate-middle/benchmark/benchmark.js
@@ -22,70 +22,124 @@
var bench = require( '@stdlib/bench' );
var isString = require( '@stdlib/assert/is-string' ).isPrimitive;
-var fromCodePoint = require( '@stdlib/string/from-code-point' );
var pkg = require( './../package.json' ).name;
var truncateMiddle = require( './../lib' );
-// FUNCTIONS //
+// MAIN //
-/**
-* Creates a benchmark function.
-*
-* @private
-* @param {PositiveInteger} len - string length
-* @returns {Function} benchmark function
-*/
-function createBenchmark( len ) {
- return benchmark;
-
- /**
- * Benchmark function.
- *
- * @private
- * @param {Benchmark} b - benchmark instance
- */
- function benchmark( b ) {
- var out;
- var i;
-
- b.tic();
- for ( i = 0; i < b.iterations; i++ ) {
- out = truncateMiddle( fromCodePoint( i%126 )+'eep boop', len );
- if ( typeof out !== 'string' ) {
- b.fail( 'should return a string' );
- }
- }
- b.toc();
- if ( !isString( out ) ) {
+bench( pkg, function benchmark( b ) {
+ var values;
+ var out;
+ var i;
+
+ values = [
+ 'beep boop',
+ 'foo bar',
+ 'xyz abc'
+ ];
+
+ b.tic();
+ for ( i = 0; i < b.iterations; i++ ) {
+ out = truncateMiddle( values[ i%values.length ], 6 );
+ if ( typeof out !== 'string' ) {
b.fail( 'should return a string' );
}
- b.pass( 'benchmark finished' );
- b.end();
}
-}
+ b.toc();
+ if ( !isString( out ) ) {
+ b.fail( 'should return a string' );
+ }
+ b.pass( 'benchmark finished' );
+ b.end();
+});
+bench( pkg+':mode=grapheme', function benchmark( b ) {
+ var values;
+ var opts;
+ var out;
+ var i;
-// MAIN //
+ values = [
+ 'beep boop',
+ 'foo bar',
+ 'xyz abc'
+ ];
+ opts = {
+ 'mode': 'grapheme'
+ };
-/**
-* Main execution sequence.
-*
-* @private
-*/
-function main() {
- var min;
- var max;
- var f;
+ b.tic();
+ for ( i = 0; i < b.iterations; i++ ) {
+ out = truncateMiddle( values[ i%values.length ], 6, opts );
+ if ( typeof out !== 'string' ) {
+ b.fail( 'should return a string' );
+ }
+ }
+ b.toc();
+ if ( !isString( out ) ) {
+ b.fail( 'should return a string' );
+ }
+ b.pass( 'benchmark finished' );
+ b.end();
+});
+
+bench( pkg+':mode=code_point', function benchmark( b ) {
+ var values;
+ var opts;
+ var out;
var i;
- min = 1;
- max = 10;
+ values = [
+ 'beep boop',
+ 'foo bar',
+ 'xyz abc'
+ ];
+ opts = {
+ 'mode': 'code_point'
+ };
- for ( i = min; i <= max; i++ ) {
- f = createBenchmark( i );
- bench( pkg+':len='+i, f );
+ b.tic();
+ for ( i = 0; i < b.iterations; i++ ) {
+ out = truncateMiddle( values[ i%values.length ], 6, opts );
+ if ( typeof out !== 'string' ) {
+ b.fail( 'should return a string' );
+ }
+ }
+ b.toc();
+ if ( !isString( out ) ) {
+ b.fail( 'should return a string' );
}
-}
+ b.pass( 'benchmark finished' );
+ b.end();
+});
-main();
+bench( pkg+':mode=code_unit', function benchmark( b ) {
+ var values;
+ var opts;
+ var out;
+ var i;
+
+ values = [
+ 'beep boop',
+ 'foo bar',
+ 'xyz abc'
+ ];
+ opts = {
+ 'mode': 'code_unit'
+ };
+
+ b.tic();
+ for ( i = 0; i < b.iterations; i++ ) {
+ out = truncateMiddle( values[ i%values.length ], 6, opts );
+ if ( typeof out !== 'string' ) {
+ b.fail( 'should return a string' );
+ }
+ }
+ b.toc();
+ if ( !isString( out ) ) {
+ b.fail( 'should return a string' );
+ }
+ b.pass( 'benchmark finished' );
+ b.end();
+});
diff --git a/lib/node_modules/@stdlib/string/truncate-middle/bin/cli b/lib/node_modules/@stdlib/string/truncate-middle/bin/cli
index 6dd44410a809..8229e528a158 100644
--- a/lib/node_modules/@stdlib/string/truncate-middle/bin/cli
+++ b/lib/node_modules/@stdlib/string/truncate-middle/bin/cli
@@ -45,6 +45,7 @@ function main() {
var split;
var flags;
var args;
+ var opts;
var cli;
var len;
@@ -62,6 +63,10 @@ function main() {
if ( flags.help || flags.version ) {
return;
}
+ opts = {};
+ if ( flags.mode ) {
+ opts.mode = flags.mode;
+ }
// Get any provided command-line arguments:
args = cli.args();
@@ -81,9 +86,9 @@ function main() {
return stdin( onRead );
}
if ( flags.seq ) {
- console.log( truncateMiddle( args[ 0 ], len, flags.seq ) ); // eslint-disable-line no-console
+ console.log( truncateMiddle( args[ 0 ], len, flags.seq, opts ) ); // eslint-disable-line no-console
} else {
- console.log( truncateMiddle( args[ 0 ], len ) ); // eslint-disable-line no-console
+ console.log( truncateMiddle( args[ 0 ], len, opts ) ); // eslint-disable-line no-console
}
/**
@@ -108,11 +113,11 @@ function main() {
}
if ( flags.seq ) {
for ( i = 0; i < lines.length; i++ ) {
- console.log( truncateMiddle( lines[ i ], len, flags.seq ) ); // eslint-disable-line no-console
+ console.log( truncateMiddle( lines[ i ], len, flags.seq, opts ) ); // eslint-disable-line no-console
}
} else {
for ( i = 0; i < lines.length; i++ ) {
- console.log( truncateMiddle( lines[ i ], len ) ); // eslint-disable-line no-console
+ console.log( truncateMiddle( lines[ i ], len, opts ) ); // eslint-disable-line no-console
}
}
}
diff --git a/lib/node_modules/@stdlib/string/truncate-middle/docs/repl.txt b/lib/node_modules/@stdlib/string/truncate-middle/docs/repl.txt
index d8ce1900bfcb..67d1cab4c5fb 100644
--- a/lib/node_modules/@stdlib/string/truncate-middle/docs/repl.txt
+++ b/lib/node_modules/@stdlib/string/truncate-middle/docs/repl.txt
@@ -1,5 +1,5 @@
-{{alias}}( str, len[, seq] )
+{{alias}}( str, len[, seq][, options] )
Truncates a string in the middle to a specified length.
Parameters
@@ -13,6 +13,25 @@
seq: string (optional)
Custom replacement sequence. Default: '...'.
+ options: Object (optional)
+ Options.
+
+ options.mode: string (optional)
+ Type of characters to return. The following modes are supported:
+
+ - grapheme: grapheme clusters. Appropriate for strings containing visual
+ characters which can span multiple Unicode code points (e.g., emoji).
+ - code_point: Unicode code points. Appropriate for strings containing
+ visual characters which are comprised of more than one Unicode code
+ unit (e.g., ideographic symbols and punctuation and mathematical
+ alphanumerics).
+ - code_unit': UTF-16 code units. Appropriate for strings containing
+ visual characters drawn from the basic multilingual plane (BMP) (e.g.,
+ common characters, such as those from the Latin, Greek, and Cyrillic
+ alphabets).
+
+ Default: 'grapheme'.
+
Returns
-------
out: string
diff --git a/lib/node_modules/@stdlib/string/truncate-middle/docs/types/index.d.ts b/lib/node_modules/@stdlib/string/truncate-middle/docs/types/index.d.ts
index a2f969c6a6a4..5977d674ed92 100644
--- a/lib/node_modules/@stdlib/string/truncate-middle/docs/types/index.d.ts
+++ b/lib/node_modules/@stdlib/string/truncate-middle/docs/types/index.d.ts
@@ -20,6 +20,75 @@
///
+// tslint:disable:unified-signatures
+
+/**
+* Interface describing function options.
+*/
+interface Options {
+ /**
+ * Specifies the type of characters to return (default: 'grapheme').
+ *
+ * ## Notes
+ *
+ * - The following option values are supported:
+ *
+ * - `'grapheme'`: grapheme clusters. Appropriate for strings containing visual characters which can span multiple Unicode code points (e.g., emoji).
+ * - `'code_point'`: Unicode code points. Appropriate for strings containing visual characters which are comprised of more than one Unicode code unit (e.g., ideographic symbols and punctuation and mathematical alphanumerics).
+ * - `'code_unit'`: UTF-16 code units. Appropriate for strings containing visual characters drawn from the basic multilingual plane (BMP) (e.g., common characters, such as those from the Latin, Greek, and Cyrillic alphabets).
+ */
+ mode?: 'grapheme' | 'code_point' | 'code_unit';
+}
+
+/**
+* Truncates a string in the middle to a specified length.
+*
+* @param str - input string
+* @param len - output string length (including sequence)
+* @param seq - custom replacement sequence (default: `...`)
+* @param options - options
+* @returns truncated string
+*
+* @example
+* var str = 'beep boop';
+* var out = truncateMiddle( str, 5, '>>>', {
+* 'mode': 'code_unit'
+* });
+* // returns 'b>>>p'
+*
+* @example
+* var str = 'πΊ Wolf Brothers πΊ';
+* var out = truncateMiddle( str, 6, '..', {
+* 'mode': 'grapheme'
+* });
+* // returns 'πΊ .. πΊ'
+*/
+declare function truncateMiddle( str: string, len: number, seq: string, options?:Options ): string; // tslint-disable-line max-line-length
+
+/**
+* Truncates a string in the middle to a specified length.
+*
+* @param str - input string
+* @param len - output string length (including sequence)
+* @param options - options
+* @returns truncated string
+*
+* @example
+* var str = 'beep boop';
+* var out = truncateMiddle( str, 5, {
+* 'mode': 'code_unit'
+* });
+* // returns 'b...p'
+*
+* @example
+* var str = 'πΊ Wolf Brothers πΊ';
+* var out = truncateMiddle( str, 7, {
+* 'mode': 'grapheme'
+* });
+* // returns 'πΊ ... πΊ'
+*/
+declare function truncateMiddle( str: string, len: number, options?:Options ): string; // tslint-disable-line max-line-length
+
/**
* Truncates a string in the middle to a specified length.
*
diff --git a/lib/node_modules/@stdlib/string/truncate-middle/docs/types/test.ts b/lib/node_modules/@stdlib/string/truncate-middle/docs/types/test.ts
index 08cf129e8f73..278f51bc4bae 100644
--- a/lib/node_modules/@stdlib/string/truncate-middle/docs/types/test.ts
+++ b/lib/node_modules/@stdlib/string/truncate-middle/docs/types/test.ts
@@ -25,6 +25,8 @@ import truncateMiddle = require( './index' );
{
truncateMiddle( 'abcdefghi', 3 ); // $ExpectType string
truncateMiddle( 'abcdefghi', 10, '|' ); // $ExpectType string
+ truncateMiddle( 'abcdefghi', 10, {} ); // $ExpectType string
+ truncateMiddle( 'abcdefghi', 10, '|', {} ); // $ExpectType string
}
// The compiler throws an error if the function is not provided a string as its first argument...
@@ -35,6 +37,27 @@ import truncateMiddle = require( './index' );
truncateMiddle( [], 6 ); // $ExpectError
truncateMiddle( {}, 6 ); // $ExpectError
truncateMiddle( ( x: number ): number => x, 6 ); // $ExpectError
+
+ truncateMiddle( true, 6, '$' ); // $ExpectError
+ truncateMiddle( false, 6, '$' ); // $ExpectError
+ truncateMiddle( 3, 6, '$' ); // $ExpectError
+ truncateMiddle( [], 6, '$' ); // $ExpectError
+ truncateMiddle( {}, 6, '$' ); // $ExpectError
+ truncateMiddle( ( x: number ): number => x, 6, '$' ); // $ExpectError
+
+ truncateMiddle( true, 6, {} ); // $ExpectError
+ truncateMiddle( false, 6, {} ); // $ExpectError
+ truncateMiddle( 3, 6, {} ); // $ExpectError
+ truncateMiddle( [], 6, {} ); // $ExpectError
+ truncateMiddle( {}, 6, {} ); // $ExpectError
+ truncateMiddle( ( x: number ): number => x, 6, {} ); // $ExpectError
+
+ truncateMiddle( true, 6, '$', {} ); // $ExpectError
+ truncateMiddle( false, 6, '$', {} ); // $ExpectError
+ truncateMiddle( 3, 6, '$', {} ); // $ExpectError
+ truncateMiddle( [], 6, '$', {} ); // $ExpectError
+ truncateMiddle( {}, 6, '$', {} ); // $ExpectError
+ truncateMiddle( ( x: number ): number => x, 6, '$', {} ); // $ExpectError
}
// The compiler throws an error if the function is not provided a number as its second argument...
@@ -42,23 +65,71 @@ import truncateMiddle = require( './index' );
truncateMiddle( 'abd', true ); // $ExpectError
truncateMiddle( 'abd', false ); // $ExpectError
truncateMiddle( 'abd', 'abc' ); // $ExpectError
- truncateMiddle( 'abd', [], 0 ); // $ExpectError
- truncateMiddle( 'abd', {}, 0 ); // $ExpectError
- truncateMiddle( 'abd', ( x: number ): number => x, 0 ); // $ExpectError
+ truncateMiddle( 'abd', [] ); // $ExpectError
+ truncateMiddle( 'abd', {} ); // $ExpectError
+ truncateMiddle( 'abd', ( x: number ): number => x ); // $ExpectError
+
+ truncateMiddle( 'abd', true, {} ); // $ExpectError
+ truncateMiddle( 'abd', false, {} ); // $ExpectError
+ truncateMiddle( 'abd', 'abc', {} ); // $ExpectError
+ truncateMiddle( 'abd', [], {} ); // $ExpectError
+ truncateMiddle( 'abd', {}, {} ); // $ExpectError
+ truncateMiddle( 'abd', ( x: number ): number => x, {} ); // $ExpectError
+
+ truncateMiddle( 'abd', true, '$' ); // $ExpectError
+ truncateMiddle( 'abd', false, '$' ); // $ExpectError
+ truncateMiddle( 'abd', 'abc', '$' ); // $ExpectError
+ truncateMiddle( 'abd', [], '$' ); // $ExpectError
+ truncateMiddle( 'abd', {}, '$' ); // $ExpectError
+ truncateMiddle( 'abd', ( x: number ): number => x, '$' ); // $ExpectError
+
+ truncateMiddle( 'abd', true, '$', {} ); // $ExpectError
+ truncateMiddle( 'abd', false, '$', {} ); // $ExpectError
+ truncateMiddle( 'abd', 'abc', '$', {} ); // $ExpectError
+ truncateMiddle( 'abd', [], '$', {} ); // $ExpectError
+ truncateMiddle( 'abd', {}, '$', {} ); // $ExpectError
+ truncateMiddle( 'abd', ( x: number ): number => x, '$', {} ); // $ExpectError
}
-// The compiler throws an error if the function is not provided a string as its third argument...
+// The compiler throws an error if the function is not provided a valid third argument...
{
truncateMiddle( 'beep boop', 4, true ); // $ExpectError
truncateMiddle( 'beep boop', 4, false ); // $ExpectError
truncateMiddle( 'beep boop', 4, 123 ); // $ExpectError
- truncateMiddle( 'beep boop', 4, [], 0 ); // $ExpectError
- truncateMiddle( 'beep boop', 4, {}, 0 ); // $ExpectError
- truncateMiddle( 'beep boop', 4, ( x: number ): number => x, 0 ); // $ExpectError
+ truncateMiddle( 'beep boop', 4, [] ); // $ExpectError
+ truncateMiddle( 'beep boop', 4, ( x: number ): number => x ); // $ExpectError
+}
+
+// The compiler throws an error if the function is not provided a valid fourth argument...
+{
+ truncateMiddle( 'beep boop', 4, '%', true ); // $ExpectError
+ truncateMiddle( 'beep boop', 4, '%', false ); // $ExpectError
+ truncateMiddle( 'beep boop', 4, '%', 123 ); // $ExpectError
+ truncateMiddle( 'beep boop', 4, '%', [] ); // $ExpectError
+ truncateMiddle( 'beep boop', 4, '%', ( x: number ): number => x ); // $ExpectError
+}
+
+// The compiler throws an error if the function is provided an invalid `mode` option...
+{
+ truncateMiddle( 'beep boop', 4, '%', { 'mode': true } ); // $ExpectError
+ truncateMiddle( 'beep boop', 4, '%', { 'mode': false } ); // $ExpectError
+ truncateMiddle( 'beep boop', 4, '%', { 'mode': null } ); // $ExpectError
+ truncateMiddle( 'beep boop', 4, '%', { 'mode': '' } ); // $ExpectError
+ truncateMiddle( 'beep boop', 4, '%', { 'mode': [] } ); // $ExpectError
+ truncateMiddle( 'beep boop', 4, '%', { 'mode': {} } ); // $ExpectError
+ truncateMiddle( 'beep boop', 4, '%', { 'mode': ( x: number ): number => x } ); // $ExpectError
+
+ truncateMiddle( 'beep boop', 4, { 'mode': true } ); // $ExpectError
+ truncateMiddle( 'beep boop', 4, { 'mode': false } ); // $ExpectError
+ truncateMiddle( 'beep boop', 4, { 'mode': null } ); // $ExpectError
+ truncateMiddle( 'beep boop', 4, { 'mode': '' } ); // $ExpectError
+ truncateMiddle( 'beep boop', 4, { 'mode': [] } ); // $ExpectError
+ truncateMiddle( 'beep boop', 4, { 'mode': {} } ); // $ExpectError
+ truncateMiddle( 'beep boop', 4, { 'mode': ( x: number ): number => x } ); // $ExpectError
}
// The compiler throws an error if the function is provided an unsupported number of arguments...
{
truncateMiddle(); // $ExpectError
- truncateMiddle( 'abc', 4, '|', true ); // $ExpectError
+ truncateMiddle( 'abcdefghi', 10, '|', {}, 5 ); // $ExpectError
}
diff --git a/lib/node_modules/@stdlib/string/truncate-middle/docs/usage.txt b/lib/node_modules/@stdlib/string/truncate-middle/docs/usage.txt
index cefc9d416af5..724f5a080fe3 100644
--- a/lib/node_modules/@stdlib/string/truncate-middle/docs/usage.txt
+++ b/lib/node_modules/@stdlib/string/truncate-middle/docs/usage.txt
@@ -8,3 +8,4 @@ Options:
--len length String length.
--seq str Custom replacement sequence. Default: '...'.
--split sep Delimiter for stdin data. Default: '/\\r?\\n/'.
+ --mode mode Type of character to return. Default: 'grapheme'.
diff --git a/lib/node_modules/@stdlib/string/truncate-middle/etc/cli_opts.json b/lib/node_modules/@stdlib/string/truncate-middle/etc/cli_opts.json
index e51a71a6e339..5a62700e760f 100644
--- a/lib/node_modules/@stdlib/string/truncate-middle/etc/cli_opts.json
+++ b/lib/node_modules/@stdlib/string/truncate-middle/etc/cli_opts.json
@@ -2,7 +2,8 @@
"string": [
"len",
"seq",
- "split"
+ "split",
+ "mode"
],
"boolean": [
"help",
diff --git a/lib/node_modules/@stdlib/string/truncate-middle/lib/main.js b/lib/node_modules/@stdlib/string/truncate-middle/lib/main.js
index 49b89a500675..ef0cbb4eaab0 100644
--- a/lib/node_modules/@stdlib/string/truncate-middle/lib/main.js
+++ b/lib/node_modules/@stdlib/string/truncate-middle/lib/main.js
@@ -22,11 +22,24 @@
var isString = require( '@stdlib/assert/is-string' ).isPrimitive;
var isNonNegativeInteger = require( '@stdlib/assert/is-nonnegative-integer' ).isPrimitive;
-var numGraphemeClusters = require( '@stdlib/string/num-grapheme-clusters' );
-var nextGraphemeClusterBreak = require( '@stdlib/string/next-grapheme-cluster-break' );
+var isPlainObject = require( '@stdlib/assert/is-plain-object' );
+var hasOwnProp = require( '@stdlib/assert/has-own-property' );
+var contains = require( '@stdlib/array/base/assert/contains' ).factory;
+var truncateMiddleCodeUnit = require( '@stdlib/string/base/truncate-middle' );
+var truncateMiddleCodePoint = require( '@stdlib/string/base/truncate-middle-code-point' );
+var truncateMiddleGraphemeCluster = require( '@stdlib/string/base/truncate-middle-grapheme-cluster' ); // eslint-disable-line id-length
var format = require( '@stdlib/string/format' );
-var round = require( '@stdlib/math/base/special/round' );
-var floor = require( '@stdlib/math/base/special/floor' );
+
+
+// VARIABLES //
+
+var MODES = [ 'grapheme', 'code_point', 'code_unit' ];
+var FCNS = {
+ 'grapheme': truncateMiddleGraphemeCluster,
+ 'code_point': truncateMiddleCodePoint,
+ 'code_unit': truncateMiddleCodeUnit
+};
+var isMode = contains( MODES );
// MAIN //
@@ -37,9 +50,12 @@ var floor = require( '@stdlib/math/base/special/floor' );
* @param {string} str - input string
* @param {integer} len - output string length (including sequence)
* @param {string} [seq='...'] - custom replacement sequence
-* @throws {TypeError} first argument must be a string
+* @param {Options} [options] - options
+* @param {string} [options.mode="grapheme"] - type of "character" to return (must be either `grapheme`, `code_point`, or `code_unit`)
+* @throws {TypeError} must provide a string primitive
* @throws {TypeError} second argument must be a nonnegative integer
-* @throws {TypeError} third argument must be a string
+* @throws {TypeError} options argument must be an object
+* @throws {TypeError} must provide valid options
* @returns {string} truncated string
*
* @example
@@ -72,54 +88,51 @@ var floor = require( '@stdlib/math/base/special/floor' );
* var out = truncateMiddle( str, 7 );
* // returns 'πΊ ... πΊ'
*/
-function truncateMiddle( str, len, seq ) {
- var seqLength;
- var fromIndex;
- var strLength;
- var seqStart;
- var nVisual;
- var seqEnd;
- var idx2;
- var idx1;
+function truncateMiddle( str, len ) {
+ var options;
+ var nargs;
+ var opts;
+ var seq;
+
if ( !isString( str ) ) {
throw new TypeError( format( 'invalid argument. First argument must be a string. Value: `%s`.', str ) );
}
if ( !isNonNegativeInteger( len ) ) {
throw new TypeError( format( 'invalid argument. Second argument must be a nonnegative integer. Value: `%s`.', len ) );
}
- if ( arguments.length > 2 ) {
+ nargs = arguments.length;
+ opts = {
+ 'mode': 'grapheme'
+ };
+ if ( nargs === 2 ) {
+ seq = '...';
+ } else if ( nargs === 3 ) {
+ seq = arguments[ 2 ];
+ if ( isPlainObject( seq ) ) {
+ options = seq;
+ seq = '...';
+ } else if ( !isString( seq ) ) {
+ throw new TypeError( format( 'invalid argument. Third argument must be a string. Value: `%s`.', seq ) );
+ }
+ } else { // nargs > 3
+ seq = arguments[ 2 ];
if ( !isString( seq ) ) {
throw new TypeError( format( 'invalid argument. Third argument must be a string. Value: `%s`.', seq ) );
}
+ options = arguments[ 3 ];
+ if ( !isPlainObject( options ) ) {
+ throw new TypeError( format( 'invalid argument. Options argument must be an object. Value: `%s`.', options ) );
+ }
}
- seq = seq || '...';
- seqLength = numGraphemeClusters( seq );
- strLength = numGraphemeClusters( str );
- fromIndex = 0;
- if ( len > strLength ) {
- return str;
- }
- if ( len - seqLength < 0 ) {
- return seq.slice( 0, len );
- }
- seqStart = round( ( len - seqLength ) / 2 );
- seqEnd = strLength - floor( ( len - seqLength ) / 2 );
- nVisual = 0;
- while ( nVisual < seqStart ) {
- idx1 = nextGraphemeClusterBreak( str, fromIndex );
- fromIndex = idx1;
- nVisual += 1;
- }
- idx2 = idx1;
- while ( idx2 > 0 ) {
- idx2 = nextGraphemeClusterBreak( str, fromIndex );
- if ( idx2 >= seqEnd + fromIndex - nVisual ) {
- break;
+ if ( options ) {
+ if ( hasOwnProp( options, 'mode' ) ) {
+ opts.mode = options.mode;
+ if ( !isMode( opts.mode ) ) {
+ throw new TypeError( format( 'invalid option. `%s` option must be one of the following: "%s". Value: `%s`.', 'mode', MODES.join( '", "' ), opts.mode ) );
+ }
}
- fromIndex = idx2;
- nVisual += 1;
}
- return str.substring( 0, idx1 ) + seq + str.substring( idx2 );
+ return FCNS[ opts.mode ](str, len, seq );
}
diff --git a/lib/node_modules/@stdlib/string/truncate-middle/test/test.cli.js b/lib/node_modules/@stdlib/string/truncate-middle/test/test.cli.js
index 055f17187a53..73e15a3d3e02 100644
--- a/lib/node_modules/@stdlib/string/truncate-middle/test/test.cli.js
+++ b/lib/node_modules/@stdlib/string/truncate-middle/test/test.cli.js
@@ -190,6 +190,66 @@ tape( 'the command-line interface truncates a string in the middle (custom seque
}
});
+tape( 'the command-line interface supports specifying the type of characters to return', opts, function test( t ) {
+ var cmd = [
+ EXEC_PATH,
+ '-e',
+ '"process.stdin.isTTY = true; process.argv[ 2 ] = \'beep boop\'; process.argv[ 3 ] = \'--len=5\'; process.argv[ 4 ] = \'--mode=code_point\'; require( \''+fpath+'\' );"'
+ ];
+
+ exec( cmd.join( ' ' ), done );
+
+ function done( error, stdout, stderr ) {
+ if ( error ) {
+ t.fail( error.message );
+ } else {
+ t.strictEqual( stdout.toString(), 'b...p\n', 'expected value' );
+ t.strictEqual( stderr.toString(), '', 'does not print to `stderr`' );
+ }
+ t.end();
+ }
+});
+
+tape( 'the command-line interface supports specifying the type of characters to return (custom sequence)', opts, function test( t ) {
+ var cmd = [
+ EXEC_PATH,
+ '-e',
+ '"process.stdin.isTTY = true; process.argv[ 2 ] = \'beep boop\'; process.argv[ 3 ] = \'--len=5\'; process.argv[ 4 ] = \'--seq=!\'; process.argv[ 5 ] = \'--mode=code_point\'; require( \''+fpath+'\' );"'
+ ];
+
+ exec( cmd.join( ' ' ), done );
+
+ function done( error, stdout, stderr ) {
+ if ( error ) {
+ t.fail( error.message );
+ } else {
+ t.strictEqual( stdout.toString(), 'be!op\n', 'expected value' );
+ t.strictEqual( stderr.toString(), '', 'does not print to `stderr`' );
+ }
+ t.end();
+ }
+});
+
+tape( 'if provided an invalid option, the command-line interface prints an error and sets a non-zero exit code', opts, function test( t ) {
+ var cmd = [
+ EXEC_PATH,
+ '-e',
+ '"process.stdin.isTTY = true; process.argv[ 2 ] = \'beep\'; process.argv[ 3 ] = \'--len=5\'; process.argv[ 4 ] = \'--mode=foo\'; require( \''+fpath+'\' );"'
+ ];
+
+ exec( cmd.join( ' ' ), done );
+
+ function done( error, stdout, stderr ) {
+ if ( error ) {
+ t.pass( error.message );
+ t.strictEqual( error.code, 1, 'expected exit code' );
+ }
+ t.strictEqual( stdout.toString(), '', 'does not print to `stdout`' );
+ t.strictEqual( stderr.toString().length > 0, true, 'expected value' );
+ t.end();
+ }
+});
+
tape( 'the command-line interface supports use as a standard stream', opts, function test( t ) {
var cmd = [
'printf "beep boop\nHello World!"',
@@ -258,6 +318,29 @@ tape( 'the command-line interface supports specifying a custom delimiter when us
}
});
+tape( 'the command-line interface supports specifying the type of characters to return when used as a standard stream', opts, function test( t ) {
+ var cmd = [
+ 'printf \'beep boop\tHello World!\'',
+ '|',
+ EXEC_PATH,
+ fpath,
+ '--len=5',
+ '--mode code_point'
+ ];
+
+ exec( cmd.join( ' ' ), done );
+
+ function done( error, stdout, stderr ) {
+ if ( error ) {
+ t.fail( error.message );
+ } else {
+ t.strictEqual( stdout.toString(), 'b...!\n', 'expected value' );
+ t.strictEqual( stderr.toString(), '', 'does not print to `stderr`' );
+ }
+ t.end();
+ }
+});
+
tape( 'the command-line interface supports specifying a custom delimiter when used as a standard stream (regexp)', opts, function test( t ) {
var cmd = [
'printf \'beep boop\tHello World!\'',
@@ -281,6 +364,29 @@ tape( 'the command-line interface supports specifying a custom delimiter when us
}
});
+tape( 'when used as a standard stream, if provided an invalid option, the command-line interface prints an error and sets a non-zero exit code', opts, function test( t ) {
+ var cmd = [
+ 'printf \'beep boop\tHello World!\'',
+ '|',
+ EXEC_PATH,
+ fpath,
+ '--len=5',
+ '--mode=foo'
+ ];
+
+ exec( cmd.join( ' ' ), done );
+
+ function done( error, stdout, stderr ) {
+ if ( error ) {
+ t.pass( error.message );
+ t.strictEqual( error.code, 1, 'expected exit code' );
+ }
+ t.strictEqual( stdout.toString(), '', 'does not print to `stdout`' );
+ t.strictEqual( stderr.toString().length > 0, true, 'expected value' );
+ t.end();
+ }
+});
+
tape( 'when used as a standard stream, if an error is encountered when reading from `stdin`, the command-line interface prints an error and sets a non-zero exit code', opts, function test( t ) {
var script;
var opts;
diff --git a/lib/node_modules/@stdlib/string/truncate-middle/test/test.js b/lib/node_modules/@stdlib/string/truncate-middle/test/test.js
index e7b87730d105..d40153713b78 100644
--- a/lib/node_modules/@stdlib/string/truncate-middle/test/test.js
+++ b/lib/node_modules/@stdlib/string/truncate-middle/test/test.js
@@ -88,7 +88,7 @@ tape( 'the function throws an error if not provided a nonnegative integer as its
}
});
-tape( 'the function throws an error if provided a non-string as a third argument', function test( t ) {
+tape( 'the function throws an error if provided an invalid third argument (custom sequence)', function test( t ) {
var values;
var i;
@@ -99,7 +99,6 @@ tape( 'the function throws an error if provided a non-string as a third argument
void 0,
true,
[],
- {},
function noop() {}
];
@@ -115,7 +114,117 @@ tape( 'the function throws an error if provided a non-string as a third argument
}
});
-tape( 'the function truncates a string to the specified length', function test( t ) {
+tape( 'the function throws an error if provided an invalid third argument', function test( t ) {
+ var values;
+ var i;
+
+ values = [
+ 5,
+ NaN,
+ null,
+ void 0,
+ true,
+ [],
+ function noop() {}
+ ];
+
+ for ( i = 0; i < values.length; i++ ) {
+ t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] );
+ }
+ t.end();
+
+ function badValue( value ) {
+ return function badValue() {
+ truncateMiddle( 'beep boop', 5, value, {} );
+ };
+ }
+});
+
+tape( 'the function throws an error if provided a non-object as a fourth argument', function test( t ) {
+ var values;
+ var i;
+
+ values = [
+ 5,
+ NaN,
+ null,
+ void 0,
+ true,
+ [],
+ function noop() {}
+ ];
+
+ for ( i = 0; i < values.length; i++ ) {
+ t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] );
+ }
+ t.end();
+
+ function badValue( value ) {
+ return function badValue() {
+ truncateMiddle( 'beep boop', 5, '>>>', value );
+ };
+ }
+});
+
+tape( 'the function throws an error if provided a `mode` option which is not a supported mode (third argument)', function test( t ) {
+ var values;
+ var i;
+
+ values = [
+ 'abc',
+ 3,
+ null,
+ true,
+ void 0,
+ NaN,
+ [],
+ function noop() {}
+ ];
+
+ for ( i = 0; i < values.length; i++ ) {
+ t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] );
+ }
+ t.end();
+
+ function badValue( value ) {
+ return function badValue() {
+ truncateMiddle( 'beep boop', 5, {
+ 'mode': value
+ });
+ };
+ }
+});
+
+tape( 'the function throws an error if provided a `mode` option which is not a supported mode (fourth argument)', function test( t ) {
+ var values;
+ var i;
+
+ values = [
+ 'abc',
+ 3,
+ null,
+ true,
+ void 0,
+ NaN,
+ [],
+ function noop() {}
+ ];
+
+ for ( i = 0; i < values.length; i++ ) {
+ t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] );
+ }
+ t.end();
+
+ function badValue( value ) {
+ return function badValue() {
+ truncateMiddle( 'beep boop', 5, '>>>', {
+ 'mode': value
+ });
+ };
+ }
+});
+
+tape( 'the function truncates a string to the specified length (default)', function test( t ) {
var expected;
var actual;
var str;
@@ -154,52 +263,169 @@ tape( 'the function truncates a string to the specified length', function test(
t.end();
});
-tape( 'the function truncates a string to the specified length (custom replacement sequence)', function test( t ) {
+tape( 'the function truncates a string to the specified length (custom replacement sequence; mode=grapheme)', function test( t ) {
var expected;
var actual;
+ var opts;
var str;
var len;
+ opts = {
+ 'mode': 'grapheme'
+ };
+
str = 'beep boop';
len = 5;
expected = 'be|op';
- actual = truncateMiddle( str, len, '|' );
+ actual = truncateMiddle( str, len, '|', opts );
t.strictEqual( actual, expected, 'returns expected value' );
str = 'beep boop';
len = 10;
expected = 'beep boop';
- actual = truncateMiddle( str, len, '!' );
+ actual = truncateMiddle( str, len, '!', opts );
t.strictEqual( actual, expected, 'returns expected value' );
str = 'beep boop';
len = 3;
expected = 'b!p';
- actual = truncateMiddle( str, len, '!' );
+ actual = truncateMiddle( str, len, '!', opts );
t.strictEqual( actual, expected, 'returns expected value' );
str = 'beep boop';
len = 5;
expected = 'beπop';
- actual = truncateMiddle( str, len, 'π' );
+ actual = truncateMiddle( str, len, 'π', opts );
t.strictEqual( actual, expected, 'returns expected value' );
str = 'beep boop foo bar';
len = 10;
expected = 'be π π πar';
- actual = truncateMiddle( str, len, ' π π π' );
+ actual = truncateMiddle( str, len, ' π π π', opts );
t.strictEqual( actual, expected, 'returns expected value' );
str = 'πΊ Wolf Brothers πΊ';
len = 8;
expected = 'πΊ Wo>s πΊ';
- actual = truncateMiddle( str, len, '>' );
+ actual = truncateMiddle( str, len, '>', opts );
t.strictEqual( actual, expected, 'returns expected value' );
str = 'Hello, world, says π€, the robot!';
len = 10;
expected = 'Helloπ€bot!';
- actual = truncateMiddle( str, len, 'π€' );
+ actual = truncateMiddle( str, len, 'π€', opts );
+ t.strictEqual( actual, expected, 'returns expected value' );
+
+ t.end();
+});
+
+tape( 'the function truncates a string to the specified length (custom replacement sequence; mode=code_point)', function test( t ) {
+ var expected;
+ var actual;
+ var opts;
+ var str;
+ var len;
+
+ opts = {
+ 'mode': 'code_point'
+ };
+
+ str = 'beep boop';
+ len = 5;
+ expected = 'be|op';
+ actual = truncateMiddle( str, len, '|', opts );
+ t.strictEqual( actual, expected, 'returns expected value' );
+
+ str = 'beep boop';
+ len = 10;
+ expected = 'beep boop';
+ actual = truncateMiddle( str, len, '!', opts );
+ t.strictEqual( actual, expected, 'returns expected value' );
+
+ str = 'beep boop';
+ len = 3;
+ expected = 'b!p';
+ actual = truncateMiddle( str, len, '!', opts );
+ t.strictEqual( actual, expected, 'returns expected value' );
+
+ str = 'beep boop';
+ len = 5;
+ expected = 'beπop';
+ actual = truncateMiddle( str, len, 'π', opts );
+ t.strictEqual( actual, expected, 'returns expected value' );
+
+ str = 'beep boop foo bar';
+ len = 10;
+ expected = 'be π π πar';
+ actual = truncateMiddle( str, len, ' π π π', opts );
+ t.strictEqual( actual, expected, 'returns expected value' );
+
+ str = 'πΊ Wolf Brothers πΊ';
+ len = 8;
+ expected = 'πΊ W>rs πΊ';
+ actual = truncateMiddle( str, len, '>', opts );
+ t.strictEqual( actual, expected, 'returns expected value' );
+
+ str = 'Hello, world, says π€, the robot!';
+ len = 10;
+ expected = 'Helloπ€bot!';
+ actual = truncateMiddle( str, len, 'π€', opts );
+ t.strictEqual( actual, expected, 'returns expected value' );
+
+ t.end();
+});
+
+tape( 'the function truncates a string to the specified length (custom replacement sequence; mode=code_unit)', function test( t ) {
+ var expected;
+ var actual;
+ var opts;
+ var str;
+ var len;
+
+ opts = {
+ 'mode': 'code_unit'
+ };
+
+ str = 'beep boop';
+ len = 5;
+ expected = 'be|op';
+ actual = truncateMiddle( str, len, '|', opts );
+ t.strictEqual( actual, expected, 'returns expected value' );
+
+ str = 'beep boop';
+ len = 10;
+ expected = 'beep boop';
+ actual = truncateMiddle( str, len, '!', opts );
+ t.strictEqual( actual, expected, 'returns expected value' );
+
+ str = 'beep boop';
+ len = 3;
+ expected = 'b!p';
+ actual = truncateMiddle( str, len, '!', opts );
+ t.strictEqual( actual, expected, 'returns expected value' );
+
+ str = 'beep boop';
+ len = 5;
+ expected = 'beπp';
+ actual = truncateMiddle( str, len, 'π', opts );
+ t.strictEqual( actual, expected, 'returns expected value' );
+
+ str = 'beep boop foo bar';
+ len = 10;
+ expected = 'b π π π';
+ actual = truncateMiddle( str, len, ' π π π', opts );
+ t.strictEqual( actual, expected, 'returns expected value' );
+
+ str = 'πΊ Wolf Brothers πΊ';
+ len = 8;
+ expected = 'πΊ W> πΊ';
+ actual = truncateMiddle( str, len, '>', opts );
+ t.strictEqual( actual, expected, 'returns expected value' );
+
+ str = 'Hello, world, says π€, the robot!';
+ len = 10;
+ expected = 'Hellπ€bot!';
+ actual = truncateMiddle( str, len, 'π€', opts );
t.strictEqual( actual, expected, 'returns expected value' );
t.end();