diff --git a/etc/eslint/rules/stdlib.js b/etc/eslint/rules/stdlib.js index 1c84b79de46c..deedb96f41f3 100644 --- a/etc/eslint/rules/stdlib.js +++ b/etc/eslint/rules/stdlib.js @@ -1,4 +1,4 @@ -/* eslint-disable stdlib/jsdoc-doctest-marker, stdlib/jsdoc-doctest, stdlib/jsdoc-example-require-spacing, stdlib/jsdoc-no-tabs */ +/* eslint-disable stdlib/jsdoc-doctest-marker, stdlib/jsdoc-example-require-spacing, stdlib/jsdoc-no-tabs */ /** * @license Apache-2.0 @@ -275,6 +275,28 @@ rules[ 'stdlib/empty-line-before-comment' ] = 'error'; */ rules[ 'stdlib/eol-open-bracket-spacing' ] = 'error'; +/** +* Require that format calls are provided an expected number of arguments. +* +* @name format-args +* @memberof rules +* @type {string} +* @default 'error' +* +* @example +* // Bad... +* var format = require( '@stdlib/string/format' ); +* +* var str = format( '%s %s', 'foo' ); +* +* @example +* // Good... +* var format = require( '@stdlib/string/format' ); +* +* var str = format( '%s %s', 'foo', 'bar' ); +*/ +rules[ 'stdlib/format-args' ] = 'error'; + /** * Require blockquotes to have `2` character indentation. * diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/README.md b/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/README.md new file mode 100644 index 000000000000..ca129272e17f --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/README.md @@ -0,0 +1,140 @@ + + +# format-args + +> [ESLint rule][eslint-rules] requiring that format calls are provided an expected number of arguments. + +
+ +
+ + + +
+ +## Usage + +```javascript +var rule = require( '@stdlib/_tools/eslint/rules/format-args' ); +``` + +#### rule + +[ESLint rule][eslint-rules] requiring that calls to the format function exported by [`@stdlib/string/format`][@stdlib/string/format] are provided a number of arguments matching the number of placeholders in the format string. + +**Bad**: + + + +```javascript +var format = require( '@stdlib/string/format' ); + +var str = format( '%s %s', 'foo' ); +``` + +**Good**: + +```javascript +var format = require( '@stdlib/string/format' ); + +var str = format( '%s %s', 'foo', 'bar' ); +// returns 'foo bar' +``` + +
+ + + +
+ +## Notes + +- The rule only applies when the format function is resolved from a `require( '@stdlib/string/format' )` statement, thus guarding against unrelated symbols sharing the same name and against shadowed symbols. +- The rule skips calls in which the format string is not a string literal, calls containing spread elements, calls via `#.call` and `#.apply`, and format strings containing positional placeholders (e.g., `%1$s`). + +
+ + + +
+ +## Examples + + + +```javascript +var Linter = require( 'eslint' ).Linter; +var rule = require( '@stdlib/_tools/eslint/rules/format-args' ); + +var linter = new Linter(); + +var code = [ + 'var format = require( \'@stdlib/string/format\' );', + '', + 'var str = format( \'%s %s\', \'foo\' );' +].join( '\n' ); + +linter.defineRule( 'format-args', rule ); + +var result = linter.verify( code, { + 'rules': { + 'format-args': 'error' + } +}); +/* returns + [ + { + 'ruleId': 'format-args', + 'severity': 2, + 'message': 'Unexpected number of format arguments. Format string expects 2 argument(s), but 1 argument(s) were provided.', + 'line': 3, + 'column': 11, + 'nodeType': 'CallExpression', + 'endLine': 3, + 'endColumn': 35 + } + ] +*/ +``` + +
+ + + + + + + + + + + + + + diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/examples/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/examples/index.js new file mode 100644 index 000000000000..7426e1feebdd --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/examples/index.js @@ -0,0 +1,52 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +var Linter = require( 'eslint' ).Linter; +var rule = require( './../lib' ); + +var linter = new Linter(); +var code = [ + 'var format = require( \'@stdlib/string/format\' );', + '', + 'var str = format( \'%s %s\', \'foo\' );' +].join( '\n' ); + +linter.defineRule( 'format-args', rule ); + +var results = linter.verify( code, { + 'rules': { + 'format-args': 'error' + } +}); +console.log( results ); +/* => + [ + { + 'ruleId': 'format-args', + 'severity': 2, + 'message': 'Unexpected number of format arguments. Format string expects 2 argument(s), but 1 argument(s) were provided.', + 'line': 3, + 'column': 11, + 'nodeType': 'CallExpression', + 'endLine': 3, + 'endColumn': 35 + } + ] +*/ diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/lib/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/lib/index.js new file mode 100644 index 000000000000..3a8300dc0481 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/lib/index.js @@ -0,0 +1,39 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +/** +* ESLint rule requiring that format calls are provided an expected number of arguments. +* +* @module @stdlib/_tools/eslint/rules/format-args +* +* @example +* var rule = require( '@stdlib/_tools/eslint/rules/format-args' ); +* +* console.log( rule ); +*/ + +// MODULES // + +var main = require( './main.js' ); + + +// EXPORTS // + +module.exports = main; diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/lib/main.js b/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/lib/main.js new file mode 100644 index 000000000000..8712f5f8d1db --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/lib/main.js @@ -0,0 +1,204 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var isString = require( '@stdlib/assert/is-string' ).isPrimitive; +var formatTokenize = require( '@stdlib/string/base/format-tokenize' ); + + +// VARIABLES // + +var PKG = '@stdlib/string/format'; +var rule; + + +// FUNCTIONS // + +/** +* Returns a boolean indicating whether a provided identifier name resolves to the format function exported by `@stdlib/string/format`. +* +* ## Notes +* +* - The function walks parent scopes and inspects the **nearest** binding for the provided name, thus guarding against shadowed symbols. +* +* @private +* @param {Object} scope - scope +* @param {string} name - identifier name +* @returns {boolean} boolean indicating whether an identifier name resolves to the format function +*/ +function isFormat( scope, name ) { + var v; + + while ( scope ) { + if ( scope.set.has( name ) ) { + v = scope.set.get( name ); + if ( + v.defs.length > 0 && + v.defs[ 0 ].node.type === 'VariableDeclarator' && + v.defs[ 0 ].node.init && + v.defs[ 0 ].node.init.type === 'CallExpression' && + v.defs[ 0 ].node.init.callee.name === 'require' && + v.defs[ 0 ].node.init.arguments.length > 0 && + v.defs[ 0 ].node.init.arguments[ 0 ].value === PKG + ) { + return true; + } + return false; + } + scope = scope.upper; + } + return false; +} + +/** +* Resolves the number of arguments expected by a format string. +* +* ## Notes +* +* - The function returns `-1` if a format string contains positional placeholders (e.g., `%1$s`), as the number of expected arguments cannot be resolved by simply counting placeholders. +* +* @private +* @param {string} str - format string +* @returns {integer} number of expected arguments or `-1` +*/ +function argumentCount( str ) { + var tokens; + var count; + var tok; + var i; + + tokens = formatTokenize( str ); + count = 0; + for ( i = 0; i < tokens.length; i++ ) { + tok = tokens[ i ]; + + // Plain (non-placeholder) string parts (including the `%` resulting from an escaped `%%`) do not consume arguments... + if ( isString( tok ) ) { + continue; + } + // Bail on positional placeholders (e.g., `%1$s`), as arguments may be consumed out-of-order and/or reused: + if ( tok.mapping !== void 0 ) { + return -1; + } + count += 1; + + // Dynamic widths and precisions (e.g., `%*d` and `%.*f`) each consume an additional argument... + if ( tok.width === '*' ) { + count += 1; + } + if ( tok.precision === '*' ) { + count += 1; + } + } + return count; +} + +/** +* Rule for requiring that format calls are provided an expected number of arguments. +* +* @param {Object} context - ESLint context +* @returns {Object} validators +*/ +function main( context ) { + var source = context.sourceCode; + + /** + * Reports the error message. + * + * @private + * @param {ASTNode} node - node to report + * @param {integer} expected - number of expected arguments + * @param {integer} actual - number of provided arguments + */ + function report( node, expected, actual ) { + context.report({ + 'node': node, + 'message': 'Unexpected number of format arguments. Format string expects ' + expected + ' argument(s), but ' + actual + ' argument(s) were provided.' + }); + } + + /** + * Validates a call expression. + * + * @private + * @param {ASTNode} node - node to examine + */ + function validate( node ) { + var expected; + var args; + var i; + + // Note: member expression callees (e.g., `format.call( ... )` and `format.apply( ... )`) are intentionally skipped, as the callee is not an `Identifier` node... + if ( + node.callee === void 0 || + node.callee.type !== 'Identifier' || + !isFormat( source.getScope( node ), node.callee.name ) + ) { + return; + } + args = node.arguments; + + // Only check calls in which the format string is a string literal... + if ( + args.length === 0 || + args[ 0 ].type !== 'Literal' || + !isString( args[ 0 ].value ) + ) { + return; + } + // Skip calls containing spread elements, as the number of provided arguments cannot be statically resolved... + for ( i = 1; i < args.length; i++ ) { + if ( args[ i ].type === 'SpreadElement' ) { + return; + } + } + expected = argumentCount( args[ 0 ].value ); + if ( expected === -1 ) { + return; + } + if ( args.length-1 !== expected ) { + report( node, expected, args.length-1 ); + } + } + + return { + 'CallExpression': validate + }; +} + + +// MAIN // + +rule = { + 'meta': { + 'type': 'problem', + 'docs': { + 'description': 'require that format calls are provided an expected number of arguments' + }, + 'schema': [] + }, + 'create': main +}; + + +// EXPORTS // + +module.exports = rule; diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/package.json new file mode 100644 index 000000000000..ab0e31a7c94f --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/package.json @@ -0,0 +1,65 @@ +{ + "name": "@stdlib/_tools/eslint/rules/format-args", + "version": "0.0.0", + "description": "ESLint rule requiring that format calls are provided an expected number of arguments.", + "license": "Apache-2.0", + "author": { + "name": "The Stdlib Authors", + "url": "https://github.com/stdlib-js/stdlib/graphs/contributors" + }, + "contributors": [ + { + "name": "The Stdlib Authors", + "url": "https://github.com/stdlib-js/stdlib/graphs/contributors" + } + ], + "bin": {}, + "main": "./lib", + "directories": { + "example": "./examples", + "lib": "./lib", + "test": "./test" + }, + "scripts": {}, + "homepage": "https://github.com/stdlib-js/stdlib", + "repository": { + "type": "git", + "url": "git://github.com/stdlib-js/stdlib.git" + }, + "bugs": { + "url": "https://github.com/stdlib-js/stdlib/issues" + }, + "dependencies": {}, + "devDependencies": {}, + "engines": { + "node": ">=0.10.0", + "npm": ">2.7.0" + }, + "os": [ + "aix", + "darwin", + "freebsd", + "linux", + "macos", + "openbsd", + "sunos", + "win32", + "windows" + ], + "keywords": [ + "stdlib", + "tools", + "tool", + "eslint", + "lint", + "custom", + "rules", + "rule", + "plugin", + "format", + "interpolate", + "string", + "arguments", + "placeholders" + ] +} diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/test/fixtures/invalid.js b/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/test/fixtures/invalid.js new file mode 100644 index 000000000000..179317e306d1 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/test/fixtures/invalid.js @@ -0,0 +1,140 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +var invalid = []; + +// Too few arguments... +var test = { + 'code': [ + 'var format = require( \'@stdlib/string/format\' );', + '', + 'var str = format( \'%s %s\', \'foo\' );' + ].join( '\n' ), + 'errors': [ + { + 'message': 'Unexpected number of format arguments. Format string expects 2 argument(s), but 1 argument(s) were provided.', + 'type': 'CallExpression' + } + ] +}; +invalid.push( test ); + +// Too many arguments... +test = { + 'code': [ + 'var format = require( \'@stdlib/string/format\' );', + '', + 'var str = format( \'%s %s\', \'foo\', \'bar\', \'beep\' );' + ].join( '\n' ), + 'errors': [ + { + 'message': 'Unexpected number of format arguments. Format string expects 2 argument(s), but 3 argument(s) were provided.', + 'type': 'CallExpression' + } + ] +}; +invalid.push( test ); + +// Missing all arguments... +test = { + 'code': [ + 'var format = require( \'@stdlib/string/format\' );', + '', + 'var str = format( \'%s\' );' + ].join( '\n' ), + 'errors': [ + { + 'message': 'Unexpected number of format arguments. Format string expects 1 argument(s), but 0 argument(s) were provided.', + 'type': 'CallExpression' + } + ] +}; +invalid.push( test ); + +// Nested call expressions... +test = { + 'code': [ + 'var format = require( \'@stdlib/string/format\' );', + '', + 'throw new Error( format( \'invalid argument. Must be a string. Value: `%s`.\' ) );' + ].join( '\n' ), + 'errors': [ + { + 'message': 'Unexpected number of format arguments. Format string expects 1 argument(s), but 0 argument(s) were provided.', + 'type': 'CallExpression' + } + ] +}; +invalid.push( test ); + +// Aliases other than `format`... +test = { + 'code': [ + 'var fmt = require( \'@stdlib/string/format\' );', + '', + 'var str = fmt( \'%s %s\', \'foo\' );' + ].join( '\n' ), + 'errors': [ + { + 'message': 'Unexpected number of format arguments. Format string expects 2 argument(s), but 1 argument(s) were provided.', + 'type': 'CallExpression' + } + ] +}; +invalid.push( test ); + +// Usage in nested scopes resolving to an outer require... +test = { + 'code': [ + 'var format = require( \'@stdlib/string/format\' );', + '', + 'function foo( x ) {', + ' return format( \'%s %s\', x );', + '}' + ].join( '\n' ), + 'errors': [ + { + 'message': 'Unexpected number of format arguments. Format string expects 2 argument(s), but 1 argument(s) were provided.', + 'type': 'CallExpression' + } + ] +}; +invalid.push( test ); + +// Dynamic widths consume an additional argument... +test = { + 'code': [ + 'var format = require( \'@stdlib/string/format\' );', + '', + 'var str = format( \'%*d\', 10 );' + ].join( '\n' ), + 'errors': [ + { + 'message': 'Unexpected number of format arguments. Format string expects 2 argument(s), but 1 argument(s) were provided.', + 'type': 'CallExpression' + } + ] +}; +invalid.push( test ); + + +// EXPORTS // + +module.exports = invalid; diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/test/fixtures/unvalidated.js b/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/test/fixtures/unvalidated.js new file mode 100644 index 000000000000..65a0b80fa0e0 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/test/fixtures/unvalidated.js @@ -0,0 +1,56 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +var unvalidated = []; + +var test = { + 'code': [ + 'var x = 123;' + ].join( '\n' ) +}; +unvalidated.push( test ); + +test = { + 'code': [ + 'var str = format( \'%s %s\', \'foo\' );' + ].join( '\n' ) +}; +unvalidated.push( test ); + +test = { + 'code': [ + 'var format = require( \'@stdlib/string/format\' );' + ].join( '\n' ) +}; +unvalidated.push( test ); + +test = { + 'code': [ + 'var format = require( \'@stdlib/string/format\' );', + '', + 'var str = format();' + ].join( '\n' ) +}; +unvalidated.push( test ); + + +// EXPORTS // + +module.exports = unvalidated; diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/test/fixtures/valid.js b/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/test/fixtures/valid.js new file mode 100644 index 000000000000..bd1ce1ce75fc --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/test/fixtures/valid.js @@ -0,0 +1,181 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +var valid = []; + +var test = { + 'code': [ + 'var format = require( \'@stdlib/string/format\' );', + '', + 'var str = format( \'%s %s\', \'foo\', \'bar\' );' + ].join( '\n' ) +}; +valid.push( test ); + +test = { + 'code': [ + 'var format = require( \'@stdlib/string/format\' );', + '', + 'var str = format( \'beep\' );' + ].join( '\n' ) +}; +valid.push( test ); + +test = { + 'code': [ + 'var format = require( \'@stdlib/string/format\' );', + '', + 'throw new Error( format( \'invalid argument. Must provide a string. Value: `%s`.\', \'foo\' ) );' + ].join( '\n' ) +}; +valid.push( test ); + +// Escaped percent signs do not consume arguments... +test = { + 'code': [ + 'var format = require( \'@stdlib/string/format\' );', + '', + 'var str = format( \'%d%%\', 10 );' + ].join( '\n' ) +}; +valid.push( test ); + +// Dynamic widths and precisions each consume an additional argument... +test = { + 'code': [ + 'var format = require( \'@stdlib/string/format\' );', + '', + 'var str = format( \'%*d\', 5, 10 );' + ].join( '\n' ) +}; +valid.push( test ); + +test = { + 'code': [ + 'var format = require( \'@stdlib/string/format\' );', + '', + 'var str = format( \'%.*f\', 2, 3.14159 );' + ].join( '\n' ) +}; +valid.push( test ); + +// Positional placeholders are skipped... +test = { + 'code': [ + 'var format = require( \'@stdlib/string/format\' );', + '', + 'var str = format( \'%1$s %1$s\', \'foo\' );' + ].join( '\n' ) +}; +valid.push( test ); + +// Non-literal format strings are skipped... +test = { + 'code': [ + 'var format = require( \'@stdlib/string/format\' );', + '', + 'var str = \'%s %s\';', + 'var out = format( str, \'foo\' );' + ].join( '\n' ) +}; +valid.push( test ); + +// Spread elements are skipped... +test = { + 'code': [ + 'var format = require( \'@stdlib/string/format\' );', + '', + 'var args = [ \'foo\' ];', + 'var str = format( \'%s %s\', ...args );' + ].join( '\n' ), + 'parserOptions': { + 'ecmaVersion': 2018 + } +}; +valid.push( test ); + +// Calls via `#.call` and `#.apply` are skipped... +test = { + 'code': [ + 'var format = require( \'@stdlib/string/format\' );', + '', + 'var str = format.call( null, \'%s %s\', \'foo\' );' + ].join( '\n' ) +}; +valid.push( test ); + +test = { + 'code': [ + 'var format = require( \'@stdlib/string/format\' );', + '', + 'var str = format.apply( null, [ \'%s %s\', \'foo\' ] );' + ].join( '\n' ) +}; +valid.push( test ); + +// Shadowed symbols are not flagged... +test = { + 'code': [ + 'var format = require( \'@stdlib/string/format\' );', + '', + 'function foo( format ) {', + ' return format( \'%s %s\', \'foo\' );', + '}' + ].join( '\n' ) +}; +valid.push( test ); + +test = { + 'code': [ + 'var format = require( \'@stdlib/string/format\' );', + '', + 'function foo() {', + ' var format = require( \'d3-format\' );', + ' return format( \'%s %s\', \'foo\' );', + '}' + ].join( '\n' ) +}; +valid.push( test ); + +// Unrelated symbols sharing the same name are not flagged... +test = { + 'code': [ + 'var format = require( \'d3-format\' );', + '', + 'var str = format( \'%s %s\', \'foo\' );' + ].join( '\n' ) +}; +valid.push( test ); + +test = { + 'code': [ + 'function format( str ) {', + ' return str;', + '}', + '', + 'var str = format( \'%s %s\', \'foo\' );' + ].join( '\n' ) +}; +valid.push( test ); + + +// EXPORTS // + +module.exports = valid; diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/test/test.js b/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/test/test.js new file mode 100644 index 000000000000..38346420ddd9 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/format-args/test/test.js @@ -0,0 +1,98 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var tape = require( 'tape' ); +var RuleTester = require( 'eslint' ).RuleTester; +var rule = require( './../lib' ); + + +// FIXTURES // + +var valid = require( './fixtures/valid.js' ); +var invalid = require( './fixtures/invalid.js' ); +var unvalidated = require( './fixtures/unvalidated.js' ); + + +// TESTS // + +tape( 'main export is an object', function test( t ) { + t.ok( true, __filename ); + t.strictEqual( typeof rule, 'object', 'main export is an object' ); + t.end(); +}); + +tape( 'the function positively validates format calls which are provided an expected number of arguments', function test( t ) { + var tester = new RuleTester({ + 'parserOptions': { + 'ecmaVersion': 2020 + } + }); + + try { + tester.run( 'format-args', rule, { + 'valid': valid, + 'invalid': [] + }); + t.pass( 'passed without errors' ); + } catch ( err ) { + t.fail( 'encountered an error: ' + err.message ); + } + t.end(); +}); + +tape( 'the function negatively validates format calls which are provided an unexpected number of arguments', function test( t ) { + var tester = new RuleTester({ + 'parserOptions': { + 'ecmaVersion': 2020 + } + }); + + try { + tester.run( 'format-args', rule, { + 'valid': [], + 'invalid': invalid + }); + t.pass( 'passed without errors' ); + } catch ( err ) { + t.fail( 'encountered an error: ' + err.message ); + } + t.end(); +}); + +tape( 'the function does not validate code not containing checkable format calls', function test( t ) { + var tester = new RuleTester({ + 'parserOptions': { + 'ecmaVersion': 2020 + } + }); + + try { + tester.run( 'format-args', rule, { + 'valid': unvalidated, + 'invalid': [] + }); + t.pass( 'passed without errors' ); + } catch ( err ) { + t.fail( 'encountered an error: ' + err.message ); + } + t.end(); +}); diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/lib/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/lib/index.js index c90cab4a4289..6b5328c148d4 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/lib/index.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/lib/index.js @@ -108,6 +108,15 @@ setReadOnly( rules, 'eol-open-bracket-spacing', require( '@stdlib/_tools/eslint/ */ setReadOnly( rules, 'first-unit-test', require( '@stdlib/_tools/eslint/rules/first-unit-test' ) ); +/** +* @name format-args +* @memberof rules +* @readonly +* @type {Function} +* @see {@link module:@stdlib/_tools/eslint/rules/format-args} +*/ +setReadOnly( rules, 'format-args', require( '@stdlib/_tools/eslint/rules/format-args' ) ); + /** * @name jsdoc-blockquote-indentation * @memberof rules