Skip to content

Commit eb5c99a

Browse files
committed
Merge branch 'develop' of https://github.com/stdlib-js/stdlib into misc-wip-kgryte
2 parents 3e707d9 + 33f3321 commit eb5c99a

File tree

29 files changed

+1194
-214
lines changed

29 files changed

+1194
-214
lines changed

lib/node_modules/@stdlib/_tools/doctest/compare-values/lib/main.js

+103-7
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,14 @@ var roundn = require( '@stdlib/math/base/special/roundn' );
2424
var epsdiff = require( '@stdlib/math/base/utils/float64-epsilon-difference' );
2525
var indexOf = require( '@stdlib/utils/index-of' );
2626
var typeOf = require( '@stdlib/utils/type-of' );
27+
var deepEqual = require( '@stdlib/assert/deep-equal' );
2728
var isNull = require( '@stdlib/assert/is-null' );
2829
var isNumber = require( '@stdlib/assert/is-number' ).isPrimitive;
30+
var isObject = require( '@stdlib/assert/is-object' );
31+
var isBoolean = require( '@stdlib/assert/is-boolean' ).isPrimitive;
32+
var isString = require( '@stdlib/assert/is-string' ).isPrimitive;
2933
var isObjectLike = require( '@stdlib/assert/is-object-like' );
34+
var isTypedArray = require( '@stdlib/assert/is-typed-array' );
3035
var startsWith = require( '@stdlib/string/starts-with' );
3136
var contains = require( '@stdlib/assert/contains' );
3237
var endsWith = require( '@stdlib/string/ends-with' );
@@ -43,6 +48,7 @@ var RE_SINGLE_QUOTED_KEYS = /'([^']*)'/g;
4348
var RE_COMMA_BEFORE = / ([\]}])/g;
4449
var RE_COMMA_AFTER = /([{[,:]) /g;
4550
var RE_DECIMAL_DOT = /([\d]).0([^\d])/g;
51+
var RE_INSTANCE_ANNOTATION = /<([^>]+)>(\[?[^\]]*\]?)/;
4652

4753

4854
// FUNCTIONS //
@@ -75,6 +81,76 @@ function formatJSON( str ) {
7581
return out;
7682
}
7783

84+
/**
85+
* Checks whether expected values are type placeholders and if so, whether the actual return values are of the respective type.
86+
*
87+
* @private
88+
* @param {*} actual - actual return value
89+
* @param {string} expected - return value annotation
90+
* @returns {(boolean|string)} boolean indicating whether annotation is a placeholder or error message in case the annotation and value do not match
91+
*/
92+
function checkForPlaceholders( actual, expected ) {
93+
if ( expected === '<boolean>' || expected === '<Boolean>' ) {
94+
if ( !isBoolean( actual ) ) {
95+
return 'Expected a boolean, but received: `'+actual+'`';
96+
}
97+
return true;
98+
}
99+
if ( expected === '<string>'|| expected === '<String>' ) {
100+
if ( !isString( actual ) ) {
101+
return 'Expected a string, but received: `'+actual+'`';
102+
}
103+
return true;
104+
}
105+
if ( expected === '<number>' || expected === '<Number>' ) {
106+
if ( !isNumber( actual ) ) {
107+
return 'Expected a number, but received: `'+actual+'`';
108+
}
109+
return true;
110+
}
111+
if ( expected === '<Node>' ) {
112+
if ( !isObject( actual ) ) {
113+
return 'Expected a node object, but received: `'+actual+'`';
114+
}
115+
return true;
116+
}
117+
return false;
118+
}
119+
120+
/**
121+
* For a typed array, if the return annotation asserts deep instance equality, check whether it corresponds to the actual value; otherwise, check whether the return annotation signals the correct type.
122+
*
123+
* @private
124+
* @param {*} actual - actual return value
125+
* @param {string} expected - return value annotation
126+
* @returns {(string|null)} error message in case the annotation and value do not match, `null` otherwise
127+
*/
128+
function checkTypedArrays( actual, expected ) {
129+
var entries;
130+
var match;
131+
var type;
132+
var i;
133+
134+
match = RE_INSTANCE_ANNOTATION.exec( expected );
135+
if ( match ) {
136+
type = match[ 1 ];
137+
entries = match[ 2 ];
138+
if ( actual.constructor.name !== type ) {
139+
return 'Expected instance type <'+actual.constructor.name+'>, but observed <'+type+'>';
140+
}
141+
if ( entries ) {
142+
entries = JSON.parse( entries );
143+
for ( i = 0; i < entries.length; i++ ) {
144+
if ( entries[ i ] !== actual[ i ] ) {
145+
return 'Expected array entries ['+entries+'], but observed ['+actual+']';
146+
}
147+
}
148+
}
149+
return null;
150+
}
151+
return 'Typed arrays should be documented using instance annotation';
152+
}
153+
78154

79155
// MAIN //
80156

@@ -91,14 +167,18 @@ function formatJSON( str ) {
91167
* // returns null
92168
*/
93169
function compareValues( actual, expected ) {
94-
var parsed;
170+
var expectedString;
171+
var expectedValue;
172+
var actualString;
173+
var actualValue;
95174
var parts;
96175
var dgts;
97176
var type;
98177
var msg1;
99178
var msg2;
100179
var a;
101180
var b;
181+
102182
if ( contains( expected, '||' ) ) {
103183
parts = expected.split( '||' );
104184
a = trim( parts[ 0 ] );
@@ -110,6 +190,14 @@ function compareValues( actual, expected ) {
110190
}
111191
return null;
112192
}
193+
if ( contains( expected, 'e.g.' ) ) {
194+
// Early return since we cannot compare actual value to return annotation value:
195+
return null;
196+
}
197+
msg1 = checkForPlaceholders( actual, expected );
198+
if ( msg1 ) {
199+
return ( isString( msg1 ) ) ? msg1 : null;
200+
}
113201
if ( expected === 'NaN' ) {
114202
if ( !isNaN( actual ) ) {
115203
return 'Displayed return value is `NaN`, but function returns `'+actual+'` instead';
@@ -160,13 +248,21 @@ function compareValues( actual, expected ) {
160248
return 'Displayed return value is `'+expected+'`, but function returns `'+actual+'` instead';
161249
}
162250
}
163-
else if ( isObjectLike( actual ) ) {
251+
else if ( isTypedArray( actual ) ) {
252+
return checkTypedArrays( actual, expected );
253+
}
254+
if ( isObjectLike( actual ) ) {
164255
if ( !contains( expected, '...' ) ) {
165-
// Check for deep equality via `JSON.stringify`:
166-
parsed = formatJSON( expected );
167-
actual = JSON.stringify( actual );
168-
if ( parsed !== actual ) {
169-
return 'Displayed return value is `'+parsed+'`, but function returns `'+actual+'` instead';
256+
expectedString = formatJSON( expected );
257+
try {
258+
expectedValue = JSON.parse( expectedString );
259+
} catch ( err ) {
260+
return 'Malformed return annotation. Encountered error while parsing: '+err.message;
261+
}
262+
actualString = JSON.stringify( actual );
263+
actualValue = JSON.parse( actualString );
264+
if ( !deepEqual( expectedValue, actualValue ) ) {
265+
return 'Displayed return value is `'+expectedString+'`, but function returns `'+actualString+'` instead';
170266
}
171267
}
172268
}

lib/node_modules/@stdlib/_tools/doctest/compare-values/test/test.js

+76
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
// MODULES //
2222

2323
var tape = require( 'tape' );
24+
var Float64Array = require( '@stdlib/array/float64' );
2425
var compareValues = require( './../lib' );
2526

2627

@@ -31,4 +32,79 @@ tape( 'main export is a function', function test( t ) {
3132
t.end();
3233
});
3334

35+
tape( 'the function compares an array and a corresponding return annotation', function test( t ) {
36+
var expected;
37+
var actual;
38+
var msg;
39+
40+
actual = [ 0, 2, 3 ];
41+
expected = '[ 0, 2, 3 ]';
42+
t.strictEqual( compareValues( actual, expected ), null, 'returns null' );
43+
44+
actual = [ 0, 2, 3 ];
45+
expected = '[ 0, 2, 2 ]';
46+
msg = 'Displayed return value is `[0,2,2]`, but function returns `[0,2,3]` instead';
47+
t.strictEqual( compareValues( actual, expected ), msg, 'returns expected message' );
48+
49+
t.end();
50+
});
51+
52+
tape( 'the function compares a typed array and a corresponding return annotation', function test( t ) {
53+
var expected;
54+
var actual;
55+
var msg;
56+
57+
actual = new Float64Array( [ 0, 2, 3 ] );
58+
expected = '<Float64Array>[ 0, 2, 3 ]';
59+
t.strictEqual( compareValues( actual, expected ), null, 'returns null' );
60+
61+
actual = new Float64Array( [ 0, 2, 3 ] );
62+
expected = '<Float64Array>[ 0, 2, 2 ]';
63+
msg = 'Expected array entries [0,2,2], but observed [0,2,3]';
64+
t.strictEqual( compareValues( actual, expected ), msg, 'returns expected message' );
65+
66+
actual = new Float64Array( [ 0, 2, 3 ] );
67+
expected = '<Float32Array>[ 0, 2, 2 ]';
68+
msg = 'Expected instance type <Float64Array>, but observed <Float32Array>';
69+
t.strictEqual( compareValues( actual, expected ), msg, 'returns expected message' );
70+
71+
t.end();
72+
});
73+
74+
tape( 'the function compares a value with a type equality return annotation', function test( t ) {
75+
var expected;
76+
var actual;
77+
var msg;
78+
79+
actual = 2.3;
80+
expected = '<number>';
81+
t.strictEqual( compareValues( actual, expected ), null, 'returns null' );
82+
83+
actual = 2.3;
84+
expected = '<string>';
85+
msg = 'Expected a string, but received: `2.3`';
86+
t.strictEqual( compareValues( actual, expected ), msg, 'returns expected message' );
87+
88+
actual = '2.3';
89+
expected = '<number>';
90+
msg = 'Expected a number, but received: `2.3`';
91+
t.strictEqual( compareValues( actual, expected ), msg, 'returns expected message' );
92+
93+
actual = true;
94+
expected = '<boolean>';
95+
t.strictEqual( compareValues( actual, expected ), null, 'returns null' );
96+
97+
actual = true;
98+
expected = '<number>';
99+
msg = 'Expected a number, but received: `true`';
100+
t.strictEqual( compareValues( actual, expected ), msg, 'returns expected message' );
101+
102+
actual = 0;
103+
expected = '<boolean>';
104+
msg = 'Expected a boolean, but received: `0`';
105+
t.strictEqual( compareValues( actual, expected ), msg, 'returns expected message' );
106+
107+
t.end();
108+
});
109+
34110
// TODO: Add tests

lib/node_modules/@stdlib/_tools/eslint/rules/doctest/lib/main.js

+6-47
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@ var format = require( 'util' ).format;
2626
var dirname = require( 'path' ).dirname;
2727
var Buffer = require( '@stdlib/buffer/ctor' );
2828
var isNull = require( '@stdlib/assert/is-null' );
29-
var isObject = require( '@stdlib/assert/is-object' );
30-
var isNumber = require( '@stdlib/assert/is-number' ).isPrimitive;
31-
var isBoolean = require( '@stdlib/assert/is-boolean' ).isPrimitive;
3229
var isString = require( '@stdlib/assert/is-string' ).isPrimitive;
3330
var replace = require( '@stdlib/string/replace' );
3431
var startsWith = require( '@stdlib/string/starts-with' );
@@ -39,8 +36,9 @@ var compareValues = require( '@stdlib/_tools/doctest/compare-values' );
3936
// VARIABLES //
4037

4138
var RE_JSDOC = /\/\*\*[\s\S]+?\*\//g;
39+
var RE_ESLINT_INLINE = / ?\/\/ eslint-disable-(?:next-)?line[^\n]*\n/g;
4240
var RE_NEWLINE = /\r?\n/g;
43-
var RE_ANNOTATION = /(?:var|let|const)? ?([a-zA-Z0-9.]*) ?=?[^\n]*\n\/\/ ?(?:returns|=>|throws) {0,1}([\s\S]*?)(?:\n|$)/g;
41+
var RE_ANNOTATION = /(?:var|let|const)? ?([a-zA-Z0-9.]+) ?=?[^;]*;\n\/\/ ?(?:returns|=>|throws) {0,1}([\s\S]*?)(?:\n|$)/g;
4442
var rule;
4543

4644

@@ -90,6 +88,7 @@ function main( context ) {
9088

9189
source = context.getSourceCode();
9290
sourceCode = replace( source.text, RE_JSDOC, '' );
91+
sourceCode = replace( sourceCode, RE_ESLINT_INLINE, '\n' );
9392
filename = context.getFilename();
9493
dir = dirname( filename );
9594
/**
@@ -184,7 +183,6 @@ function main( context ) {
184183
if ( code ) {
185184
vm.runInContext( code, scope );
186185
}
187-
188186
// Run code preceding return annotation:
189187
out = vm.runInContext( arr[ 0 ], scope );
190188
if ( arr[ 1 ] === 'console.log' ) {
@@ -213,11 +211,9 @@ function main( context ) {
213211
a = actual[ i ];
214212
b = expected[ i ];
215213
loc = positions[ i ];
216-
if ( !checkForPlaceholders( a, b, loc ) ) {
217-
msg = compareValues( a, b );
218-
if ( msg ) {
219-
report( loc, msg );
220-
}
214+
msg = compareValues( a, b );
215+
if ( msg ) {
216+
report( loc, msg );
221217
}
222218
}
223219
} catch ( err ) {
@@ -238,43 +234,6 @@ function main( context ) {
238234
return {
239235
'Program': validate
240236
};
241-
242-
/**
243-
* Checks whether expected values are type placeholders and if so, whether the actual return values are of the respective type.
244-
*
245-
* @private
246-
* @param {*} actual - actual return value
247-
* @param {string} expected - return value annotation
248-
* @param {Object} loc - error location info
249-
* @returns {boolean} boolean indicating whether annotation is a placeholder and the actual return type matches
250-
*/
251-
function checkForPlaceholders( actual, expected, loc ) {
252-
if ( expected === '<boolean>' || expected === '<Boolean>' ) {
253-
if ( !isBoolean( actual ) ) {
254-
report( loc, 'Expected a boolean, but received: `'+actual+'`' );
255-
}
256-
return true;
257-
}
258-
if ( expected === '<string>'|| expected === '<String>' ) {
259-
if ( !isString( actual ) ) {
260-
report( loc, 'Expected a string, but received: `'+actual+'`' );
261-
}
262-
return true;
263-
}
264-
if ( expected === '<number>' || expected === '<Number>' ) {
265-
if ( !isNumber( actual ) ) {
266-
report( loc, 'Expected a number, but received: `'+actual+'`' );
267-
}
268-
return true;
269-
}
270-
if ( expected === '<Node>' ) {
271-
if ( !isObject( actual ) ) {
272-
report( loc, 'Expected a node object, but received: `'+actual+'`' );
273-
}
274-
return true;
275-
}
276-
return false;
277-
}
278237
}
279238

280239

0 commit comments

Comments
 (0)