Skip to content

Commit 6535079

Browse files
committed
build: add ESLint rule disallowing string concatenation in benchmark descriptions
--- type: pre_commit_static_analysis_report description: Results of running static analysis checks when committing changes. report: - task: lint_filenames status: passed - task: lint_editorconfig status: passed - task: lint_markdown status: passed - task: lint_package_json status: passed - task: lint_repl_help status: na - task: lint_javascript_src status: passed - task: lint_javascript_cli status: na - task: lint_javascript_examples status: passed - task: lint_javascript_tests status: passed - task: lint_javascript_benchmarks status: na - task: lint_python status: na - task: lint_r status: na - task: lint_c_src status: na - task: lint_c_examples status: na - task: lint_c_benchmarks status: na - task: lint_c_tests_fixtures status: na - task: lint_shell status: na - task: lint_typescript_declarations status: passed - task: lint_typescript_tests status: na - task: lint_license_headers status: passed ---
1 parent 1122999 commit 6535079

File tree

10 files changed

+615
-0
lines changed

10 files changed

+615
-0
lines changed

etc/eslint/.eslintrc.benchmarks.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,13 @@ eslint.rules[ 'stdlib/jsdoc-doctest' ] = 'off';
126126
*/
127127
eslint.rules[ 'stdlib/no-unnecessary-nested-functions' ] = 'off';
128128

129+
/**
130+
* Warn when using string concatenation in benchmark descriptions.
131+
*
132+
* @private
133+
*/
134+
eslint.rules[ 'stdlib/no-bench-string-concat' ] = 'warn';
135+
129136

130137
// EXPORTS //
131138

lib/node_modules/@stdlib/_tools/eslint/rules/lib/index.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,15 @@ setReadOnly( rules, 'new-cap-error', require( '@stdlib/_tools/eslint/rules/new-c
837837
*/
838838
setReadOnly( rules, 'new-cap-regexp', require( '@stdlib/_tools/eslint/rules/new-cap-regexp' ) );
839839

840+
/**
841+
* @name no-bench-string-concat
842+
* @memberof rules
843+
* @readonly
844+
* @type {Function}
845+
* @see {@link module:@stdlib/_tools/eslint/rules/no-bench-string-concat}
846+
*/
847+
setReadOnly( rules, 'no-bench-string-concat', require( '@stdlib/_tools/eslint/rules/no-bench-string-concat' ) );
848+
840849
/**
841850
* @name no-builtin-big-int
842851
* @memberof rules
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
<!--
2+
3+
@license Apache-2.0
4+
5+
Copyright (c) 2025 The Stdlib Authors.
6+
7+
Licensed under the Apache License, Version 2.0 (the "License");
8+
you may not use this file except in compliance with the License.
9+
You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
19+
-->
20+
21+
# no-bench-string-concat
22+
23+
> [ESLint rule][eslint-rules] enforcing that `@stdlib/string/format` is used instead of string concatenation in benchmark descriptions.
24+
25+
<section class="intro">
26+
27+
</section>
28+
29+
<!-- /.intro -->
30+
31+
<section class="usage">
32+
33+
## Usage
34+
35+
```javascript
36+
var rule = require( '@stdlib/_tools/eslint/rules/no-bench-string-concat' );
37+
```
38+
39+
#### rule
40+
41+
[ESLint rule][eslint-rules] enforcing that `@stdlib/string/format` is used instead of string concatenation in benchmark descriptions.
42+
43+
**Bad**:
44+
45+
<!-- eslint-disable stdlib/no-bench-string-concat, no-restricted-syntax -->
46+
47+
```javascript
48+
bench( pkg+':len='+len, function benchmark( b ) {
49+
// ...
50+
});
51+
```
52+
53+
**Good**:
54+
55+
<!-- eslint-disable no-restricted-syntax -->
56+
57+
```javascript
58+
var format = require( '@stdlib/string/format' );
59+
60+
bench( format( '%s:len=%d', pkg, len ), function benchmark( b ) {
61+
// ...
62+
});
63+
```
64+
65+
</section>
66+
67+
<!-- /.usage -->
68+
69+
<section class="examples">
70+
71+
## Examples
72+
73+
<!-- eslint no-undef: "error" -->
74+
75+
```javascript
76+
var Linter = require( 'eslint' ).Linter;
77+
var rule = require( '@stdlib/_tools/eslint/rules/no-bench-string-concat' );
78+
79+
var linter = new Linter();
80+
var result;
81+
var code;
82+
83+
code = 'bench( pkg+\':len=\'+len, f );';
84+
85+
linter.defineRule( 'no-bench-string-concat', rule );
86+
87+
result = linter.verify( code, {
88+
'rules': {
89+
'no-bench-string-concat': 'error'
90+
}
91+
});
92+
/* returns
93+
[
94+
{
95+
'ruleId': 'no-bench-string-concat',
96+
'severity': 2,
97+
'message': 'Use `@stdlib/string/format` instead of string concatenation for benchmark descriptions.',
98+
'line': 1,
99+
'column': 8,
100+
'nodeType': 'BinaryExpression',
101+
'endLine': 1,
102+
'endColumn': 23
103+
}
104+
]
105+
*/
106+
```
107+
108+
</section>
109+
110+
<!-- /.examples -->
111+
112+
<!-- Section for related `stdlib` packages. Do not manually edit this section, as it is automatically populated. -->
113+
114+
<section class="related">
115+
116+
</section>
117+
118+
<!-- /.related -->
119+
120+
<!-- Section for all links. Make sure to keep an empty line after the `section` element and another before the `/section` close. -->
121+
122+
<section class="links">
123+
124+
[eslint-rules]: https://eslint.org/docs/developer-guide/working-with-rules
125+
126+
</section>
127+
128+
<!-- /.links -->
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2025 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+
var Linter = require( 'eslint' ).Linter;
22+
var rule = require( './../lib' );
23+
24+
var linter = new Linter();
25+
var result;
26+
var code;
27+
28+
code = 'bench( pkg+\':len=\'+len, f );';
29+
30+
linter.defineRule( 'no-bench-string-concat', rule );
31+
32+
result = linter.verify( code, {
33+
'rules': {
34+
'no-bench-string-concat': 'error'
35+
}
36+
});
37+
console.log( result );
38+
/* =>
39+
[
40+
{
41+
'ruleId': 'no-bench-string-concat',
42+
'severity': 2,
43+
'message': 'Use `@stdlib/string/format` instead of string concatenation for benchmark descriptions.',
44+
'line': 1,
45+
'column': 8,
46+
'nodeType': 'BinaryExpression',
47+
'endLine': 1,
48+
'endColumn': 23
49+
}
50+
]
51+
*/
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2025 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+
/**
22+
* ESLint rule enforcing that string concatenation is not used in benchmark descriptions.
23+
*
24+
* @module @stdlib/_tools/eslint/rules/no-bench-string-concat
25+
*
26+
* @example
27+
* var rule = require( '@stdlib/_tools/eslint/rules/no-bench-string-concat' );
28+
*
29+
* console.log( rule );
30+
*/
31+
32+
// MODULES //
33+
34+
var main = require( './main.js' );
35+
36+
37+
// EXPORTS //
38+
39+
module.exports = main;
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2025 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+
// VARIABLES //
22+
23+
var rule;
24+
25+
26+
// FUNCTIONS //
27+
28+
/**
29+
* Checks whether a node is a BinaryExpression with a '+' operator.
30+
*
31+
* @private
32+
* @param {ASTNode} node - AST node
33+
* @returns {boolean} boolean indicating whether the node is a string concatenation
34+
*/
35+
function isStringConcatenation( node ) {
36+
if ( node.type !== 'BinaryExpression' ) {
37+
return false;
38+
}
39+
if ( node.operator !== '+' ) {
40+
return false;
41+
}
42+
return true;
43+
}
44+
45+
/**
46+
* Rule for validating that `@stdlib/string/format` is used instead of string concatenation in benchmark descriptions.
47+
*
48+
* @param {Object} context - ESLint context
49+
* @returns {Object} validators
50+
*/
51+
function main( context ) {
52+
/**
53+
* Reports the error message.
54+
*
55+
* @private
56+
* @param {ASTNode} node - node to report
57+
*/
58+
function report( node ) {
59+
context.report({
60+
'node': node,
61+
'message': 'Use `@stdlib/string/format` instead of string concatenation for benchmark descriptions.'
62+
});
63+
}
64+
65+
/**
66+
* Checks whether a `bench()` call uses string concatenation in its first argument.
67+
*
68+
* @private
69+
* @param {ASTNode} node - CallExpression node to examine
70+
*/
71+
function validate( node ) {
72+
var firstArg;
73+
var callee;
74+
75+
callee = node.callee;
76+
77+
// Check if this is a call to `bench`:
78+
if ( callee.type !== 'Identifier' || callee.name !== 'bench' ) {
79+
return;
80+
}
81+
82+
// Check if there is at least one argument:
83+
if ( node.arguments.length === 0 ) {
84+
return;
85+
}
86+
87+
firstArg = node.arguments[ 0 ];
88+
89+
// Check if the first argument is string concatenation:
90+
if ( isStringConcatenation( firstArg ) ) {
91+
report( firstArg );
92+
}
93+
}
94+
95+
return {
96+
'CallExpression': validate
97+
};
98+
}
99+
100+
101+
// MAIN //
102+
103+
rule = {
104+
'meta': {
105+
'docs': {
106+
'description': 'enforce that `@stdlib/string/format` is used instead of string concatenation in benchmark descriptions'
107+
},
108+
'schema': []
109+
},
110+
'create': main
111+
};
112+
113+
114+
// EXPORTS //
115+
116+
module.exports = rule;

0 commit comments

Comments
 (0)