From 8a617b987f2bea28c87fede38678b9a3a04cb7fe Mon Sep 17 00:00:00 2001 From: Philipp Burckhardt Date: Fri, 5 Sep 2025 22:48:02 -0500 Subject: [PATCH 01/18] build: add `tsdoc-doctest` ESLint rule for linting return annotations in TSDoc examples --- 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: na - task: lint_package_json status: na - task: lint_repl_help status: na - task: lint_javascript_src status: passed - task: lint_javascript_cli status: na - task: lint_javascript_examples status: na - task: lint_javascript_tests status: na - 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: na - task: lint_typescript_tests status: na - task: lint_license_headers status: passed --- --- etc/eslint/plugins/typescript.js | 5 +- etc/eslint/rules/typescript.js | 11 + .../@stdlib/_tools/eslint/rules/lib/index.js | 9 + .../eslint/rules/tsdoc-doctest/README.md | 194 ++++++++ .../rules/tsdoc-doctest/examples/index.js | 76 +++ .../tsdoc-doctest/lib/add_package_to_scope.js | 81 ++++ .../tsdoc-doctest/lib/create_vm_scope.js | 83 ++++ .../eslint/rules/tsdoc-doctest/lib/index.js | 39 ++ .../eslint/rules/tsdoc-doctest/lib/main.js | 446 ++++++++++++++++++ .../tsdoc-doctest/lib/scope_defaults.json | 15 + .../eslint/rules/tsdoc-doctest/lib/window.js | 35 ++ .../eslint/rules/tsdoc-doctest/package.json | 54 +++ .../tsdoc-doctest/test/fixtures/invalid.js | 164 +++++++ .../test/fixtures/unvalidated.js | 69 +++ .../tsdoc-doctest/test/fixtures/valid.js | 162 +++++++ .../eslint/rules/tsdoc-doctest/test/test.js | 104 ++++ 16 files changed, 1546 insertions(+), 1 deletion(-) create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/README.md create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/examples/index.js create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/add_package_to_scope.js create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/create_vm_scope.js create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/index.js create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/scope_defaults.json create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/window.js create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/package.json create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/invalid.js create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/unvalidated.js create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/valid.js create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/test.js diff --git a/etc/eslint/plugins/typescript.js b/etc/eslint/plugins/typescript.js index 5553eb157e03..5775526ae0a2 100644 --- a/etc/eslint/plugins/typescript.js +++ b/etc/eslint/plugins/typescript.js @@ -30,7 +30,10 @@ var plugins = [ 'eslint-plugin-jsdoc', // Required for TypeScript support: - '@typescript-eslint' + '@typescript-eslint', + + // Stdlib custom rules: + 'stdlib' ]; diff --git a/etc/eslint/rules/typescript.js b/etc/eslint/rules/typescript.js index 1639beb44f67..f4c7a6cdb624 100644 --- a/etc/eslint/rules/typescript.js +++ b/etc/eslint/rules/typescript.js @@ -2712,6 +2712,17 @@ rules[ 'yoda' ] = 'error'; */ rules[ 'expect-type/expect' ] = 'error'; +/** +* Ensures return annotations in TSDoc examples match the actual output. +* +* @name stdlib/tsdoc-doctest +* @memberof rules +* @type {string} +* @default 'error' +* @see {@link module:@stdlib/_tools/eslint/rules/tsdoc-doctest} +*/ +rules[ 'stdlib/tsdoc-doctest' ] = 'error'; + // EXPORTS // 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 a83887850934..35de7aa7f5f4 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/lib/index.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/lib/index.js @@ -1071,6 +1071,15 @@ setReadOnly( rules, 'section-headers', require( '@stdlib/_tools/eslint/rules/sec */ setReadOnly( rules, 'ternary-condition-parentheses', require( '@stdlib/_tools/eslint/rules/ternary-condition-parentheses' ) ); +/** +* @name tsdoc-doctest +* @memberof rules +* @readonly +* @type {Function} +* @see {@link module:@stdlib/_tools/eslint/rules/tsdoc-doctest} +*/ +setReadOnly( rules, 'tsdoc-doctest', require( '@stdlib/_tools/eslint/rules/tsdoc-doctest' ) ); + /** * @name uppercase-required-constants * @memberof rules diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/README.md b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/README.md new file mode 100644 index 000000000000..7a8f286db962 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/README.md @@ -0,0 +1,194 @@ + + +# tsdoc-doctest + +> [ESLint rule][eslint-rules] to ensure that return annotations in TSDoc examples match the actual output. + +
+ +
+ + + +
+ +## Usage + +```javascript +var rule = require( '@stdlib/_tools/eslint/rules/tsdoc-doctest' ); +``` + +#### rule + +[ESLint rule][eslint-rules] to ensure that return annotations in TSDoc examples match the actual output. The rule validates `@example` blocks in TSDoc comments within `.d.ts` files. + +The rule: + +- Extracts `@example` blocks from TSDoc comments in TypeScript declaration files +- Loads the actual JavaScript package corresponding to the declaration file +- Executes the example code in a sandboxed environment +- Compares the actual output with the expected return annotations +- Supports functions, constants, classes, and namespace objects +- Handles `// returns`, `// throws`, and `// =>` annotations + +**Bad**: + + + +```typescript +/** +* Adds two numbers. +* +* @param x - first number +* @param y - second number +* @returns sum of x and y +* +* @example +* var result = add( 2, 3 ); +* // returns 6 +*/ +declare function add( x: number, y: number ): number; + +export = add; +``` + +**Good**: + +```typescript +/** +* Adds two numbers. +* +* @param x - first number +* @param y - second number +* @returns sum of x and y +* +* @example +* var result = add( 2, 3 ); +* // returns 5 +*/ +declare function add( x: number, y: number ): number; + +export = add; +``` + +
+ + + +
+ +## Examples + + + +```javascript +var Linter = require( 'eslint' ).Linter; +var parser = require( '@typescript-eslint/parser' ); +var rule = require( '@stdlib/_tools/eslint/rules/tsdoc-doctest' ); + +var linter = new Linter(); + +// Register the TypeScript parser and ESLint rule: +linter.defineParser( '@typescript-eslint/parser', parser ); +linter.defineRule( 'tsdoc-doctest', rule ); + +// Generate our source code with incorrect return annotation: +var code = [ + '/**', + '* Returns the absolute value of a number.', + '*', + '* @param x - input value', + '* @returns absolute value', + '*', + '* @example', + '* var result = abs( -3 );', + '* // returns 2', + '*/', + 'declare function abs( x: number ): number;', + '', + 'export = abs;' +].join( '\n' ); + +// Lint the code: +var result = linter.verify( code, { + 'parser': '@typescript-eslint/parser', + 'parserOptions': { + 'ecmaVersion': 2018, + 'sourceType': 'module' + }, + 'rules': { + 'tsdoc-doctest': 'error' + } +}, { + 'filename': 'lib/node_modules/@stdlib/math/base/special/abs/docs/types/index.d.ts' +}); + +console.log( result ); +/* => + [ + { + 'ruleId': 'tsdoc-doctest', + 'severity': 2, + 'message': 'Displayed return value is `2`, but expected `3` instead', + 'line': 9, + 'column': 1, + 'nodeType': null, + 'endLine': 10, + 'endColumn': 37 + } + ] +*/ +``` + +
+ + + +
+ +## Notes + +- The rule requires that the TypeScript declaration file path follows the stdlib convention: `lib/node_modules/@stdlib//docs/types/index.d.ts` +- The corresponding JavaScript package must be loadable via `require('@stdlib/')` +- The rule skips validation if the package cannot be loaded +- Examples are executed in a sandboxed VM context with limited globals + +
+ + + + + + + + + + + + + + diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/examples/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/examples/index.js new file mode 100644 index 000000000000..421c7bc433ec --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/examples/index.js @@ -0,0 +1,76 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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 parser = require( '@typescript-eslint/parser' ); +var rule = require( './../lib' ); + +var linter = new Linter(); + +// Register the TypeScript parser and ESLint rule: +linter.defineParser( '@typescript-eslint/parser', parser ); +linter.defineRule( 'tsdoc-doctest', rule ); + +// Generate our source code with incorrect return annotation: +var code = [ + '/**', + '* Returns the absolute value of a number.', + '*', + '* @param x - input value', + '* @returns absolute value', + '*', + '* @example', + '* var result = abs( -3 );', + '* // returns 2', + '*/', + 'declare function abs( x: number ): number;', + '', + 'export = abs;' +].join( '\n' ); + +// Lint the code: +var result = linter.verify( code, { + 'parser': '@typescript-eslint/parser', + 'parserOptions': { + 'ecmaVersion': 2018, + 'sourceType': 'module' + }, + 'rules': { + 'tsdoc-doctest': 'error' + } +}, { + 'filename': 'lib/node_modules/@stdlib/math/base/special/abs/docs/types/index.d.ts' +}); + +console.log( result ); +/* => + [ + { + 'ruleId': 'tsdoc-doctest', + 'severity': 2, + 'message': 'Displayed return value is `2`, but expected `3` instead', + 'line': 9, + 'column': 1, + 'nodeType': null, + 'endLine': 10, + 'endColumn': 37 + } + ] +*/ diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/add_package_to_scope.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/add_package_to_scope.js new file mode 100644 index 000000000000..54771dd152a3 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/add_package_to_scope.js @@ -0,0 +1,81 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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'; + +// VARIABLES // + +// Regular expressions for matching TypeScript declarations: +var RE_DECLARE_FUNCTION = /declare\s+function\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*[<(]/; +var RE_DECLARE_VAR = /declare\s+var\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:/; +var RE_DECLARE_CLASS = /declare\s+class\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s/; +var RE_DECLARE_VAR_NAMESPACE = /declare\s+var\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:\s*[A-Z][a-zA-Z0-9_$]*/; +var RE_DECLARE_CONST = /declare\s+const\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:/; + + +// MAIN // + +/** +* Adds package export to scope based on TypeScript declarations. +* +* @param {Object} scope - VM scope object to add the package export to +* @param {*} pkg - package export value to be added to scope +* @param {string} sourceText - TypeScript declaration source text to parse for identifier names +*/ +function addPackageToScope( scope, pkg, sourceText ) { + var namespaceMatch; + var funcMatch; + + if ( typeof pkg === 'function' ) { + // Try to match declare function pattern (handles generics with <): + funcMatch = sourceText.match( RE_DECLARE_FUNCTION ); + if ( !funcMatch ) { + // Try to match declare var pattern: + funcMatch = sourceText.match( RE_DECLARE_VAR ); + } + if ( !funcMatch ) { + // Try to match declare class pattern (for constructor functions): + funcMatch = sourceText.match( RE_DECLARE_CLASS ); + } + if ( funcMatch ) { + scope[ funcMatch[1] ] = pkg; + } + } else if ( typeof pkg === 'object' && pkg !== null ) { + // Handle namespace objects and other object interfaces: + namespaceMatch = sourceText.match( RE_DECLARE_VAR_NAMESPACE ); + if ( namespaceMatch ) { + scope[ namespaceMatch[1] ] = pkg; + } + // Also check for const declarations (e.g., Complex64/Complex128 constants): + funcMatch = sourceText.match( RE_DECLARE_CONST ); + if ( funcMatch ) { + scope[ funcMatch[1] ] = pkg; + } + } else { + // Try to match declare const pattern: + funcMatch = sourceText.match( RE_DECLARE_CONST ); + if ( funcMatch ) { + scope[ funcMatch[1] ] = pkg; + } + } +} + + +// EXPORTS // + +module.exports = addPackageToScope; diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/create_vm_scope.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/create_vm_scope.js new file mode 100644 index 000000000000..004c3c94e57e --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/create_vm_scope.js @@ -0,0 +1,83 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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 proc = require( 'process' ); +var format = require( 'util' ).format; +var Buffer = require( '@stdlib/buffer/ctor' ); +var isString = require( '@stdlib/assert/is-string' ).isPrimitive; +var windowShim = require( './window.js' ); + + +// FUNCTIONS // + +/** +* Shim for `console.log` function that returns the logged data instead of printing it to `stdout`. +* +* @private +* @param {*} data - data to be logged +* @param {...*} args - substitution values +* @returns {*} return value +*/ +function log( data ) { + if ( isString( data ) ) { + return format.apply( null, arguments ); + } + return data; +} + + +// MAIN // + +/** +* Creates a VM execution scope with necessary globals. +* +* @param {string} dir - directory path +* @param {string} filename - file name +* @returns {Object} VM scope object +*/ +function createVMScope( dir, filename ) { + return { + 'require': require, + 'exports': exports, // eslint-disable-line node/exports-style + 'module': module, + 'process': proc, + 'setTimeout': setTimeout, + 'clearTimeout': clearTimeout, + 'setInterval': setInterval, + 'clearInterval': clearInterval, + 'window': windowShim, + 'Buffer': Buffer, + '__dirname': dir, + '__filename': filename, + 'console': { + 'dir': log, + 'error': log, + 'log': log, + 'warn': log + } + }; +} + + +// EXPORTS // + +module.exports = createVMScope; diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/index.js new file mode 100644 index 000000000000..bb012d0f7c87 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/index.js @@ -0,0 +1,39 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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 to ensure return annotations in TypeScript declaration examples match the actual output. +* +* @module @stdlib/_tools/eslint/rules/tsdoc-doctest +* +* @example +* var rule = require( '@stdlib/_tools/eslint/rules/tsdoc-doctest' ); +* +* console.log( rule ); +*/ + +// MODULES // + +var main = require( './main.js' ); + + +// EXPORTS // + +module.exports = main; diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js new file mode 100644 index 000000000000..29547bfaf69c --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js @@ -0,0 +1,446 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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 vm = require( 'vm' ); +var dirname = require( 'path' ).dirname; +var resolve = require( 'path' ).resolve; +var existsSync = require( 'fs' ).existsSync; // eslint-disable-line node/no-sync +var logger = require( 'debug' ); +var isNull = require( '@stdlib/assert/is-null' ); +var isNumber = require( '@stdlib/assert/is-number' ); +var contains = require( '@stdlib/assert/contains' ); +var replace = require( '@stdlib/string/replace' ); +var objectKeys = require( '@stdlib/utils/keys' ); +var compareValues = require( '@stdlib/_tools/doctest/compare-values' ); +var createAnnotationValue = require( '@stdlib/_tools/doctest/create-annotation-value' ); +var createVMScope = require( './create_vm_scope.js' ); +var addPackageToScope = require( './add_package_to_scope.js' ); +var SCOPE_DEFAULTS = require( './scope_defaults.json' ); + + +// VARIABLES // + +var debug = logger( 'tsdoc-doctest' ); +var RE_TSDOC = /\/\*\*[\s\S]+?\*\//g; +var RE_EXAMPLE = /@example\s*([\s\S]*?)(?=\n\s*@\w|\*\/|$)/g; +var RE_NEWLINE = /\r?\n/g; +var RE_ANNOTATION = /(?:\n|^)(?:var|let|const)? ?([a-zA-Z0-9._]+) ?=[^;]*?;\n\/\/ ?(returns|([A-Za-z][A-Za-z_0-9]*)? ?=>|throws) {0,1}([\s\S]*?)(\n|$)/g; +var RE_CONSOLE = /console\.(?:dir|error|log)/; +var RE_COMMENT_PREFIX = /^\s*\*\s?/gm; +var rule; + + +// FUNCTIONS // + +/** +* Counts the number of lines in the given string. +* +* @private +* @param {string} str - input string +* @returns {number} number of lines +*/ +function countLines( str ) { + return ( str.match( RE_NEWLINE ) || '' ).length; +} + +/** +* Searches for variable in scope matching the expected value. +* +* @private +* @param {Object} scope - VM scope +* @param {any} expected - expected value to search for +* @returns {string} variable name or `?` if no match found +*/ +function findName( scope, expected ) { + var keys = objectKeys( scope ); + var key; + var i; + for ( i = 0; i < keys.length; i++ ) { + key = keys[ i ]; + if ( + !contains( SCOPE_DEFAULTS, key ) && + !compareValues( scope[ key ], expected ) + ) { + return key; + } + } + return '?'; +} + +/** +* Resolves the implementation path relative to a TypeScript declaration file. +* +* @private +* @param {string} filepath - TypeScript declaration file path +* @param {string} implementationPath - relative path to implementation +* @returns {string|null} resolved implementation path or null if not found +*/ +function resolveImplementationPath( filepath, implementationPath ) { + var implPath; + var baseDir; + + baseDir = dirname( resolve( filepath ) ); + implPath = resolve( baseDir, implementationPath ); + if ( existsSync( implPath ) ) { + return implPath; + } + return null; +} + +/** +* Cleans TSDoc comment by removing comment prefixes. +* +* @private +* @param {string} comment - TSDoc comment +* @returns {string} cleaned comment +*/ +function cleanTSDocComment( comment ) { + // Remove opening /** and closing */ + var cleaned = comment.replace( /^\/\*\*/, '' ).replace( /\*\/$/, '' ); + + // Remove * at the beginning of lines + cleaned = replace( cleaned, RE_COMMENT_PREFIX, '' ); + return cleaned; +} + +/** +* Processes a single example code block, finding and validating annotations. +* +* @private +* @param {string} code - example code +* @param {number} commentIdx - comment index +* @param {Array} comments - all comments +* @param {Object} scope - VM execution scope +* @param {Function} report - error reporting function +* @param {Object} opts - options object +* @param {Object} sourceCode - source code object +*/ +function processExampleCode( code, commentIdx, comments, scope, report, opts, sourceCode ) { + var returnAnnotationPattern; + var valueStartInAnnotation; + var commentStartIdx; + var annotationMatch; + var annotationStart; + var exampleStartIdx; + var annotationEnd; + var intermediary; + var replacement; + var exampleIdx; + var remaining; + var expected; + var codeIdx; + var actual; + var last; + var line; + var type; + var loc; + var msg; + var out; + var arr; + + // VM context already created in validate() function + + last = 0; + RE_ANNOTATION.lastIndex = 0; + try { + arr = RE_ANNOTATION.exec( code ); + while ( !isNull( arr ) ) { + // Run intermediary code + intermediary = code.substring( last, arr.index ); + last = arr.index + arr[ 0 ].length; + if ( intermediary ) { + vm.runInContext( intermediary, scope ); + } + + // Calculate line of current code chunk within the comment + commentStartIdx = sourceCode.text.indexOf( comments[ commentIdx ] ); + + // Find the annotation in the original comment + returnAnnotationPattern = new RegExp( '// ' + arr[ 2 ] + '\\s+' + arr[ 4 ].replace( /[.*+?^${}()|[\]\\]/g, '\\$&' ) ); + annotationMatch = comments[ commentIdx ].match( returnAnnotationPattern ); + + if ( !annotationMatch ) { + continue; + } + + codeIdx = comments[ commentIdx ].indexOf( annotationMatch[ 0 ] ); + line = countLines( sourceCode.text.substring( 0, commentStartIdx + codeIdx ) ) + 1; + loc = { + 'start': { + 'line': line, + 'column': 0 + }, + 'end': { + 'line': line + countLines( arr[ 0 ] ), + 'column': arr[ 0 ].length + } + }; + + // Run code preceding return annotation + try { + out = vm.runInContext( arr[ 0 ], scope ); + if ( RE_CONSOLE.test( arr[ 1 ] ) ) { + actual = out; + } else { + actual = scope[ arr[ 1 ] ]; + } + if ( arr[ 3 ] ) { + actual = vm.runInContext( arr[ 3 ], scope ); + } + expected = arr[ 4 ]; + msg = compareValues( actual, expected ); + if ( msg ) { + opts.includeDecimal = isNumber( actual ) && contains( expected, '.' ); + replacement = createAnnotationValue( actual, opts ); + + // Find the position of the return value in the annotation + valueStartInAnnotation = annotationMatch[ 0 ].indexOf( arr[ 4 ] ); + loc.range = [ + // Position of arr[4] start in source text + commentStartIdx + codeIdx + valueStartInAnnotation, + + // Position of arr[4] end in source text + commentStartIdx + codeIdx + valueStartInAnnotation + arr[ 4 ].length + ]; + report( loc, msg, replacement ); + } + } catch ( err ) { + type = '<'+err.name+'>'; + if ( arr[ 2 ] !== 'throws' ) { + if ( arr[ 3 ] ) { + msg = 'Encountered an error: `'+err.message+'`.'; + } else { + msg = 'Encountered an error while running code: `'+err.message+'`. '; + msg += 'Did you mean to include a `// throws '+type+'` annotation instead of `// '+arr[ 2 ]+' '+arr[ 4 ]+'`?'; + } + } + else if ( arr[ 4 ] !== type ) { + msg = 'Code should have a `// throws '+type+'` annotation, but received: `// '+arr[ 2 ]+' '+arr[ 4 ]+'`'; + } + if ( msg ) { + replacement = ( arr[ 3 ] ) ? findName( scope, arr[ 4 ] ) + ' => ' + arr[ 4 ] : 'throws '+type; + + // Find annotation part in the match (after "// ") + annotationStart = arr[ 0 ].indexOf( '// ' ) + 3; + annotationEnd = arr[ 0 ].length - arr[ 5 ].length; + loc.range = [ + commentStartIdx + codeIdx + annotationStart, + commentStartIdx + codeIdx + annotationEnd + ]; + report( loc, msg, replacement ); + } + } + arr = RE_ANNOTATION.exec( code ); + } + + // Run any remaining code + remaining = code.substring( last ); + if ( remaining ) { + vm.runInContext( remaining, scope ); + } + } catch ( err ) { + // Calculate the line number for the example that caused the error + exampleStartIdx = sourceCode.text.indexOf( comments[ commentIdx ] ); + exampleIdx = comments[ commentIdx ].indexOf( code ); + line = countLines( sourceCode.text.substring( 0, exampleStartIdx + exampleIdx ) ) + 1; + loc = { + 'start': { + 'line': line, + 'column': 0 + }, + 'end': { + 'line': line + countLines( code ), + 'column': 0 + } + }; + + // Do not report errors in TypeScript declaration files due to modules failing to load + if ( contains( err.message, 'Cannot find module' ) ) { + return; + } + report( loc, 'Encountered an error while running example code: '+err.message ); + } +} + + +// MAIN // + +/** +* Rule for validating that return annotations in TypeScript declaration examples match the actual output. +* +* @param {Object} context - ESLint context +* @returns {Object} validators +*/ +function main( context ) { + var sourceCode; + var filename; + var options; + var dir; + + sourceCode = context.getSourceCode(); + filename = context.getFilename(); + options = context.options[ 0 ] || {}; + + // Only process TypeScript declaration files + if ( !filename.endsWith( '.d.ts' ) ) { + return {}; + } + + dir = dirname( filename ); + + /** + * Reports the error message. + * + * @private + * @param {Object} loc - error location info + * @param {string} msg - error message + * @param {string} replacement - fixed return annotation + */ + function report( loc, msg, replacement ) { + var result = { + 'message': msg, + 'loc': loc + }; + if ( replacement ) { + result.fix = fix; + } + context.report( result ); + + /** + * Applies a fix to the offending code. + * + * @private + * @param {Object} fixer - object to apply a fix + * @returns {Object} fixing object + */ + function fix( fixer ) { + return fixer.replaceTextRange( loc.range, replacement ); + } + } + + /** + * Validates examples in TSDoc comments. + * + * @private + */ + function validate() { + var implementationPath; + var implPath; + var examples; + var comments; + var example; + var cleaned; + var comment; + var scope; + var code; + var opts; + var pkg; + var i; + var j; + + // Resolve implementation path relative to TypeScript declaration file path: + implementationPath = options.implementationPath || '../../lib'; + implPath = resolveImplementationPath( filename, implementationPath ); + if ( !implPath ) { + debug( 'Could not resolve implementation path: ' + implementationPath + ' from ' + filename ); + return; + } + + // Try to load the implementation directly: + try { + pkg = require( implPath ); // eslint-disable-line stdlib/no-dynamic-require + } catch ( err ) { + debug( 'Could not load implementation: ' + implPath + '. Error: ' + err.message ); + return; + } + + // Get all TSDoc comments: + comments = sourceCode.text.match( RE_TSDOC ); + if ( !comments ) { + return; + } + + // Create a single VM scope and context for all examples: + scope = createVMScope( dir, filename ); + addPackageToScope( scope, pkg, sourceCode.text ); + vm.createContext( scope ); + + opts = { + 'includeDecimal': false + }; + + for ( i = 0; i < comments.length; i++ ) { + comment = comments[ i ]; + cleaned = cleanTSDocComment( comment ); + + // Extract @example blocks: + RE_EXAMPLE.lastIndex = 0; + examples = []; + example = RE_EXAMPLE.exec( cleaned ); + while ( example !== null ) { + examples.push( example[ 1 ] ); + example = RE_EXAMPLE.exec( cleaned ); + } + + for ( j = 0; j < examples.length; j++ ) { + code = examples[ j ].trim(); + + // Process the example code and validate annotations (reusing VM context): + processExampleCode( code, i, comments, scope, report, opts, sourceCode ); + } + } + } + + return { + 'Program': validate + }; +} + + +// MAIN // + +rule = { + 'meta': { + 'docs': { + 'description': 'ensure return annotations in TSDoc examples match the actual output' + }, + 'fixable': 'code', + 'schema': [ + { + 'type': 'object', + 'properties': { + 'implementationPath': { + 'type': 'string', + 'default': '../../lib' + } + }, + 'additionalProperties': false + } + ] + }, + 'create': main +}; + + +// EXPORTS // + +module.exports = rule; diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/scope_defaults.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/scope_defaults.json new file mode 100644 index 000000000000..fab6c5ea05dc --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/scope_defaults.json @@ -0,0 +1,15 @@ +[ + "require", + "exports", + "module", + "process", + "setTimeout", + "clearTimeout", + "setInterval", + "clearInterval", + "window", + "Buffer", + "__dirname", + "__filename", + "console" +] diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/window.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/window.js new file mode 100644 index 000000000000..ce9936203e42 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/window.js @@ -0,0 +1,35 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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 noop = require( '@stdlib/utils/noop' ); + + +// MAIN // + +var shim = { + 'open': noop +}; + + +// EXPORTS // + +module.exports = shim; diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/package.json new file mode 100644 index 000000000000..a76dd13fbcd8 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/package.json @@ -0,0 +1,54 @@ +{ + "name": "@stdlib/_tools/eslint/rules/tsdoc-doctest", + "version": "0.0.0", + "description": "ESLint rule to ensure return annotations in TSDoc examples match the actual output.", + "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" + } + ], + "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" + }, + "keywords": [ + "stdlib", + "tools", + "tool", + "eslint", + "lint", + "custom", + "rule", + "doctest", + "tsdoc", + "typescript" + ], + "__stdlib__": { + "envs": { + "node": true + } + } +} diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/invalid.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/invalid.js new file mode 100644 index 000000000000..6a74a3955af7 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/invalid.js @@ -0,0 +1,164 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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 join = require( 'path' ).join; +var rootDir = require( '@stdlib/_tools/utils/root-dir' ); + + +// VARIABLES // + +var ROOT_DIR = rootDir(); +var invalid = []; +var test; + + +// TESTS // + +test = { + 'code': [ + '/**', + '* Returns the absolute value.', + '*', + '* @param x - input value', + '* @returns absolute value', + '*', + '* @example', + '* var v = abs( -1.0 );', + '* // returns 2.0', + '*/', + 'declare function abs( x: number ): number;', + '', + 'export = abs;' + ].join( '\n' ), + 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/math/base/special/abs/docs/types/index.d.ts' ), + 'output': [ + '/**', + '* Returns the absolute value.', + '*', + '* @param x - input value', + '* @returns absolute value', + '*', + '* @example', + '* var v = abs( -1.0 );', + '* // returns 1', + '*/', + 'declare function abs( x: number ): number;', + '', + 'export = abs;' + ].join( '\n' ), + 'errors': [ + { + 'message': 'Displayed return value is `2.0`, but expected `1` instead', + 'type': null + } + ] +}; +invalid.push( test ); + +test = { + 'code': [ + '/**', + '* Returns the square root.', + '*', + '* @param x - input value', + '* @returns square root', + '*', + '* @example', + '* var v = sqrt( 4.0 );', + '* // returns 3.0', + '*', + '* @example', + '* var v = sqrt( 9.0 );', + '* // returns 3.0', + '*/', + 'declare function sqrt( x: number ): number;', + '', + 'export = sqrt;' + ].join( '\n' ), + 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/math/base/special/sqrt/docs/types/index.d.ts' ), + 'output': [ + '/**', + '* Returns the square root.', + '*', + '* @param x - input value', + '* @returns square root', + '*', + '* @example', + '* var v = sqrt( 4.0 );', + '* // returns 2', + '*', + '* @example', + '* var v = sqrt( 9.0 );', + '* // returns 3.0', + '*/', + 'declare function sqrt( x: number ): number;', + '', + 'export = sqrt;' + ].join( '\n' ), + 'errors': [ + { + 'message': 'Displayed return value is `3.0`, but expected `2` instead', + 'type': null + } + ] +}; +invalid.push( test ); + +test = { + 'code': [ + '/**', + '* The mathematical constant pi.', + '*', + '* @example', + '* var pi = PI;', + '* // returns 3.14', + '*/', + 'declare const PI: number;', + '', + 'export = PI;' + ].join( '\n' ), + 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/constants/float64/pi/docs/types/index.d.ts' ), + 'output': [ + '/**', + '* The mathematical constant pi.', + '*', + '* @example', + '* var pi = PI;', + '* // returns ~3.142', + '*/', + 'declare const PI: number;', + '', + 'export = PI;' + ].join( '\n' ), + 'errors': [ + { + 'message': 'Displayed return value is `3.14`, but expected `3.141592653589793` instead', + 'type': null + } + ] +}; +invalid.push( test ); + + +// EXPORTS // + +module.exports = invalid; diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/unvalidated.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/unvalidated.js new file mode 100644 index 000000000000..413b6eae7042 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/unvalidated.js @@ -0,0 +1,69 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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 join = require( 'path' ).join; +var rootDir = require( '@stdlib/_tools/utils/root-dir' ); + + +// VARIABLES // + +var ROOT_DIR = rootDir(); +var unvalidated = []; +var test; + +// Test files without examples or non-TypeScript files +test = { + 'code': [ + '/**', + '* Function without @example block.', + '*/', + 'declare function noExample( x: number ): number;', + '', + 'export = noExample;' + ].join( '\n' ), + 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/test/no-example/docs/types/index.d.ts' ) +}; +unvalidated.push( test ); + +test = { + 'code': [ + '/**', + '* Not a TypeScript file.', + '*', + '* @example', + '* var result = test();', + '* // returns true', + '*/', + 'function test() {', + ' return true;', + '}', + '', + 'module.exports = test;' + ].join( '\n' ), + 'filename': 'test.js' +}; +unvalidated.push( test ); + + +// EXPORTS // + +module.exports = unvalidated; diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/valid.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/valid.js new file mode 100644 index 000000000000..6a8ce939318b --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/valid.js @@ -0,0 +1,162 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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 join = require( 'path' ).join; +var rootDir = require( '@stdlib/_tools/utils/root-dir' ); + + +// VARIABLES // + +var ROOT_DIR = rootDir(); +var valid = []; +var test; + + +// TESTS // + +test = { + 'code': [ + '/**', + '* Returns the absolute value.', + '*', + '* @param x - input value', + '* @returns absolute value', + '*', + '* @example', + '* var v = abs( -1.0 );', + '* // returns 1', + '*/', + 'declare function abs( x: number ): number;', + '', + 'export = abs;' + ].join( '\n' ), + 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/math/base/special/abs/docs/types/index.d.ts' ) +}; +valid.push( test ); + +test = { + 'code': [ + '/**', + '* Returns the square root.', + '*', + '* @param x - input value', + '* @returns square root', + '*', + '* @example', + '* var v = sqrt( 4.0 );', + '* // returns 2', + '*', + '* @example', + '* var v = sqrt( 9.0 );', + '* // returns 3', + '*/', + 'declare function sqrt( x: number ): number;', + '', + 'export = sqrt;' + ].join( '\n' ), + 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/math/base/special/sqrt/docs/types/index.d.ts' ) +}; +valid.push( test ); + +test = { + 'code': [ + '/**', + '* The mathematical constant pi.', + '*', + '* @example', + '* var pi = PI;', + '* // returns ~3.142', + '*/', + 'declare const PI: number;', + '', + 'export = PI;' + ].join( '\n' ), + 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/constants/float64/pi/docs/types/index.d.ts' ) +}; +valid.push( test ); + +test = { + 'code': [ + '/**', + '* Complex number array constructor.', + '*', + '* @example', + '* var arr = new Complex64Array();', + '* // returns ', + '*', + '* var len = arr.length;', + '* // returns 0', + '*/', + 'declare class Complex64Array {', + ' constructor();', + ' readonly length: number;', + '}', + '', + 'declare var Complex64Array: {', + ' new(): Complex64Array;', + '};', + '', + 'export = Complex64Array;' + ].join( '\n' ), + 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/array/complex64/docs/types/index.d.ts' ) +}; +valid.push( test ); + +test = { + 'code': [ + '/**', + '* Console log example.', + '*', + '* @param msg - message to log', + '*', + '* @example', + '* console.log( format( "Hello %s", "World" ) );', + '* // => \'Hello World\'', + '*/', + 'declare function format( template: string, ...args: any[] ): string;', + '', + 'export = format;' + ].join( '\n' ), + 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/string/format/docs/types/index.d.ts' ) +}; +valid.push( test ); + +test = { + 'code': [ + '/**', + '* TypeScript declaration without examples.', + '*', + '* @param x - input value', + '* @returns doubled value', + '*/', + 'declare function double( x: number ): number;', + '', + 'export = double;' + ].join( '\n' ), + 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/math/base/special/double/docs/types/index.d.ts' ) +}; +valid.push( test ); + + +// EXPORTS // + +module.exports = valid; diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/test.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/test.js new file mode 100644 index 000000000000..4a7a28dac555 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/test.js @@ -0,0 +1,104 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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 code where all return annotations inside of example code match the actual output', function test( t ) { + var tester = new RuleTester({ + 'parser': require.resolve( '@typescript-eslint/parser' ), + 'parserOptions': { + 'ecmaVersion': 2018, + 'sourceType': 'module' + } + }); + + try { + tester.run( 'tsdoc-doctest', 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 code where not all return annotations inside of example code match the actual output', function test( t ) { + var tester = new RuleTester({ + 'parser': require.resolve( '@typescript-eslint/parser' ), + 'parserOptions': { + 'ecmaVersion': 2018, + 'sourceType': 'module' + } + }); + + try { + tester.run( 'tsdoc-doctest', 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 comments without TSDoc examples', function test( t ) { + var tester = new RuleTester({ + 'parser': require.resolve( '@typescript-eslint/parser' ), + 'parserOptions': { + 'ecmaVersion': 2018, + 'sourceType': 'module' + } + }); + + try { + tester.run( 'tsdoc-doctest', rule, { + 'valid': unvalidated, + 'invalid': [] + }); + t.pass( 'passed without errors' ); + } catch ( err ) { + t.fail( 'encountered an error: ' + err.message ); + } + t.end(); +}); From 115b700d3767416b409ff0f451b3202cb4c98a1f Mon Sep 17 00:00:00 2001 From: Philipp Burckhardt Date: Tue, 16 Sep 2025 11:45:54 -0500 Subject: [PATCH 02/18] build: minor refactoring --- 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: na - task: lint_package_json status: na - task: lint_repl_help status: na - task: lint_javascript_src status: passed - task: lint_javascript_cli status: na - task: lint_javascript_examples status: na - task: lint_javascript_tests status: na - 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: na - task: lint_typescript_tests status: na - task: lint_license_headers status: passed --- --- .../eslint/rules/tsdoc-doctest/lib/main.js | 62 ++++++++++++++++--- 1 file changed, 55 insertions(+), 7 deletions(-) diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js index 29547bfaf69c..a52897e60576 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js @@ -16,6 +16,8 @@ * limitations under the License. */ +/* eslint-disable max-len, max-lines */ + 'use strict'; // MODULES // @@ -43,14 +45,51 @@ var debug = logger( 'tsdoc-doctest' ); var RE_TSDOC = /\/\*\*[\s\S]+?\*\//g; var RE_EXAMPLE = /@example\s*([\s\S]*?)(?=\n\s*@\w|\*\/|$)/g; var RE_NEWLINE = /\r?\n/g; -var RE_ANNOTATION = /(?:\n|^)(?:var|let|const)? ?([a-zA-Z0-9._]+) ?=[^;]*?;\n\/\/ ?(returns|([A-Za-z][A-Za-z_0-9]*)? ?=>|throws) {0,1}([\s\S]*?)(\n|$)/g; +var RE_ANNOTATION = /(?:\n|^)(?:var|let|const)? ?([a-zA-Z0-9._]+) ?=[^;]*;\n\/\/ ?(returns|([A-Za-z][A-Za-z_0-9]*)? ?=>|throws) ?([\s\S]*?)(\n|$)/g; var RE_CONSOLE = /console\.(?:dir|error|log)/; var RE_COMMENT_PREFIX = /^\s*\*\s?/gm; +var RE_SPECIAL_CHARS = /[.*+?^${}()|[\]\\]/g; +var regexCache = {}; +var lineCountCache = {}; var rule; // FUNCTIONS // +/** +* Escapes special regex characters in a string. +* +* @private +* @param {string} str - string to escape +* @returns {string} escaped string +*/ +function escapeRegex( str ) { + return str.replace( RE_SPECIAL_CHARS, '\\$&' ); +} + +/** +* Gets or creates a cached regex for finding return annotations. +* +* @private +* @param {string} annotationType - type of annotation (returns, throws, etc.) +* @param {string} value - expected value +* @returns {RegExp} compiled regular expression +*/ +function getAnnotationRegex( annotationType, value ) { + var escapedValue; + var pattern; + var key; + + escapedValue = escapeRegex( value ); + key = [ annotationType, escapedValue ].join( '::' ); + + if ( !regexCache[ key ] ) { + pattern = '// ' + annotationType + '\\s+' + escapedValue; + regexCache[ key ] = new RegExp( pattern ); + } + return regexCache[ key ]; +} + /** * Counts the number of lines in the given string. * @@ -59,7 +98,15 @@ var rule; * @returns {number} number of lines */ function countLines( str ) { - return ( str.match( RE_NEWLINE ) || '' ).length; + var matches; + + // Use cached result if available + if ( lineCountCache[ str ] ) { + return lineCountCache[ str ]; + } + matches = str.match( RE_NEWLINE ); + lineCountCache[ str ] = ( matches ) ? matches.length : 0; + return lineCountCache[ str ]; } /** @@ -78,7 +125,7 @@ function findName( scope, expected ) { key = keys[ i ]; if ( !contains( SCOPE_DEFAULTS, key ) && - !compareValues( scope[ key ], expected ) + compareValues( scope[ key ], expected ) === null ) { return key; } @@ -175,7 +222,7 @@ function processExampleCode( code, commentIdx, comments, scope, report, opts, so commentStartIdx = sourceCode.text.indexOf( comments[ commentIdx ] ); // Find the annotation in the original comment - returnAnnotationPattern = new RegExp( '// ' + arr[ 2 ] + '\\s+' + arr[ 4 ].replace( /[.*+?^${}()|[\]\\]/g, '\\$&' ) ); + returnAnnotationPattern = getAnnotationRegex( arr[ 2 ], arr[ 4 ] ); annotationMatch = comments[ commentIdx ].match( returnAnnotationPattern ); if ( !annotationMatch ) { @@ -281,9 +328,6 @@ function processExampleCode( code, commentIdx, comments, scope, report, opts, so } } - -// MAIN // - /** * Rule for validating that return annotations in TypeScript declaration examples match the actual output. * @@ -357,6 +401,10 @@ function main( context ) { var i; var j; + // Clear caches to prevent memory leaks + regexCache = {}; + lineCountCache = {}; + // Resolve implementation path relative to TypeScript declaration file path: implementationPath = options.implementationPath || '../../lib'; implPath = resolveImplementationPath( filename, implementationPath ); From 2b5611bca7198e8809e6f6b839c509283ae227f4 Mon Sep 17 00:00:00 2001 From: Philipp Burckhardt Date: Wed, 17 Sep 2025 01:13:11 -0500 Subject: [PATCH 03/18] refactor: clean-up and handle interface case --- 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: na - task: lint_repl_help status: na - task: lint_javascript_src status: passed - task: lint_javascript_cli status: na - task: lint_javascript_examples status: na - 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: na - task: lint_typescript_tests status: na - task: lint_license_headers status: passed --- --- .../eslint/rules/tsdoc-doctest/README.md | 20 +++------ .../tsdoc-doctest/lib/add_package_to_scope.js | 9 ++++ .../eslint/rules/tsdoc-doctest/lib/main.js | 39 +++++++--------- .../tsdoc-doctest/test/fixtures/invalid.js | 45 +++++++++++++++++++ .../tsdoc-doctest/test/fixtures/valid.js | 22 +++++++++ 5 files changed, 97 insertions(+), 38 deletions(-) diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/README.md b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/README.md index 7a8f286db962..c55769725baf 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/README.md +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/README.md @@ -40,15 +40,6 @@ var rule = require( '@stdlib/_tools/eslint/rules/tsdoc-doctest' ); [ESLint rule][eslint-rules] to ensure that return annotations in TSDoc examples match the actual output. The rule validates `@example` blocks in TSDoc comments within `.d.ts` files. -The rule: - -- Extracts `@example` blocks from TSDoc comments in TypeScript declaration files -- Loads the actual JavaScript package corresponding to the declaration file -- Executes the example code in a sandboxed environment -- Compares the actual output with the expected return annotations -- Supports functions, constants, classes, and namespace objects -- Handles `// returns`, `// throws`, and `// =>` annotations - **Bad**: @@ -140,9 +131,7 @@ var result = linter.verify( code, { }, { 'filename': 'lib/node_modules/@stdlib/math/base/special/abs/docs/types/index.d.ts' }); - -console.log( result ); -/* => +/* returns [ { 'ruleId': 'tsdoc-doctest', @@ -166,10 +155,11 @@ console.log( result ); ## Notes -- The rule requires that the TypeScript declaration file path follows the stdlib convention: `lib/node_modules/@stdlib//docs/types/index.d.ts` - The corresponding JavaScript package must be loadable via `require('@stdlib/')` -- The rule skips validation if the package cannot be loaded -- Examples are executed in a sandboxed VM context with limited globals +- The rule skips validation if the package cannot be loaded. +- Examples are executed in a sandboxed VM context with limited globals. +- The rule validates assignment-form examples (e.g., `var x = fn(...);` followed by an annotation). It does not validate console output or expression-only forms using `// =>`. +- The implementation path the rule uses to load the JavaScript implementation can be overridden via the `implementationPath` rule option (default: `../../lib` relative to the declaration file). diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/add_package_to_scope.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/add_package_to_scope.js index 54771dd152a3..458eb5acf0a7 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/add_package_to_scope.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/add_package_to_scope.js @@ -26,6 +26,7 @@ var RE_DECLARE_VAR = /declare\s+var\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:/; var RE_DECLARE_CLASS = /declare\s+class\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s/; var RE_DECLARE_VAR_NAMESPACE = /declare\s+var\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:\s*[A-Z][a-zA-Z0-9_$]*/; var RE_DECLARE_CONST = /declare\s+const\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:/; +var RE_DECLARE_VAR_INTERFACE = /declare\s+var\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:\s*([A-Z][a-zA-Z0-9_$]*)/; // MAIN // @@ -38,6 +39,7 @@ var RE_DECLARE_CONST = /declare\s+const\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:/; * @param {string} sourceText - TypeScript declaration source text to parse for identifier names */ function addPackageToScope( scope, pkg, sourceText ) { + var interfaceMatch; var namespaceMatch; var funcMatch; @@ -55,6 +57,13 @@ function addPackageToScope( scope, pkg, sourceText ) { if ( funcMatch ) { scope[ funcMatch[1] ] = pkg; } + // Also check for declare var with interface pattern (e.g., declare var ctor: Int32Vector): + interfaceMatch = sourceText.match( RE_DECLARE_VAR_INTERFACE ); + if ( interfaceMatch ) { + // Make the function available under both the variable name and the interface name: + scope[ interfaceMatch[1] ] = pkg; // e.g., ctor + scope[ interfaceMatch[2] ] = pkg; // e.g., Int32Vector + } } else if ( typeof pkg === 'object' && pkg !== null ) { // Handle namespace objects and other object interfaces: namespaceMatch = sourceText.match( RE_DECLARE_VAR_NAMESPACE ); diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js index a52897e60576..846ebf4665e1 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js @@ -46,7 +46,6 @@ var RE_TSDOC = /\/\*\*[\s\S]+?\*\//g; var RE_EXAMPLE = /@example\s*([\s\S]*?)(?=\n\s*@\w|\*\/|$)/g; var RE_NEWLINE = /\r?\n/g; var RE_ANNOTATION = /(?:\n|^)(?:var|let|const)? ?([a-zA-Z0-9._]+) ?=[^;]*;\n\/\/ ?(returns|([A-Za-z][A-Za-z_0-9]*)? ?=>|throws) ?([\s\S]*?)(\n|$)/g; -var RE_CONSOLE = /console\.(?:dir|error|log)/; var RE_COMMENT_PREFIX = /^\s*\*\s?/gm; var RE_SPECIAL_CHARS = /[.*+?^${}()|[\]\\]/g; var regexCache = {}; @@ -201,27 +200,23 @@ function processExampleCode( code, commentIdx, comments, scope, report, opts, so var type; var loc; var msg; - var out; var arr; - // VM context already created in validate() function - last = 0; RE_ANNOTATION.lastIndex = 0; try { arr = RE_ANNOTATION.exec( code ); while ( !isNull( arr ) ) { - // Run intermediary code intermediary = code.substring( last, arr.index ); last = arr.index + arr[ 0 ].length; if ( intermediary ) { vm.runInContext( intermediary, scope ); } - // Calculate line of current code chunk within the comment + // Calculate line of current code chunk within the comment: commentStartIdx = sourceCode.text.indexOf( comments[ commentIdx ] ); - // Find the annotation in the original comment + // Find the annotation in the original comment: returnAnnotationPattern = getAnnotationRegex( arr[ 2 ], arr[ 4 ] ); annotationMatch = comments[ commentIdx ].match( returnAnnotationPattern ); @@ -242,14 +237,12 @@ function processExampleCode( code, commentIdx, comments, scope, report, opts, so } }; - // Run code preceding return annotation + // Run code preceding return annotation: try { - out = vm.runInContext( arr[ 0 ], scope ); - if ( RE_CONSOLE.test( arr[ 1 ] ) ) { - actual = out; - } else { - actual = scope[ arr[ 1 ] ]; - } + vm.runInContext( arr[ 0 ], scope ); + + // For assignment-form examples, read the assigned variable from scope: + actual = scope[ arr[ 1 ] ]; if ( arr[ 3 ] ) { actual = vm.runInContext( arr[ 3 ], scope ); } @@ -259,13 +252,13 @@ function processExampleCode( code, commentIdx, comments, scope, report, opts, so opts.includeDecimal = isNumber( actual ) && contains( expected, '.' ); replacement = createAnnotationValue( actual, opts ); - // Find the position of the return value in the annotation + // Find the position of the return value in the annotation: valueStartInAnnotation = annotationMatch[ 0 ].indexOf( arr[ 4 ] ); loc.range = [ - // Position of arr[4] start in source text + // Position of arr[4] start in source text: commentStartIdx + codeIdx + valueStartInAnnotation, - // Position of arr[4] end in source text + // Position of arr[4] end in source text: commentStartIdx + codeIdx + valueStartInAnnotation + arr[ 4 ].length ]; report( loc, msg, replacement ); @@ -286,7 +279,7 @@ function processExampleCode( code, commentIdx, comments, scope, report, opts, so if ( msg ) { replacement = ( arr[ 3 ] ) ? findName( scope, arr[ 4 ] ) + ' => ' + arr[ 4 ] : 'throws '+type; - // Find annotation part in the match (after "// ") + // Find annotation part in the match (after "// "): annotationStart = arr[ 0 ].indexOf( '// ' ) + 3; annotationEnd = arr[ 0 ].length - arr[ 5 ].length; loc.range = [ @@ -299,13 +292,12 @@ function processExampleCode( code, commentIdx, comments, scope, report, opts, so arr = RE_ANNOTATION.exec( code ); } - // Run any remaining code remaining = code.substring( last ); if ( remaining ) { vm.runInContext( remaining, scope ); } } catch ( err ) { - // Calculate the line number for the example that caused the error + // Calculate the line number for the example that caused the error... exampleStartIdx = sourceCode.text.indexOf( comments[ commentIdx ] ); exampleIdx = comments[ commentIdx ].indexOf( code ); line = countLines( sourceCode.text.substring( 0, exampleStartIdx + exampleIdx ) ) + 1; @@ -320,7 +312,7 @@ function processExampleCode( code, commentIdx, comments, scope, report, opts, so } }; - // Do not report errors in TypeScript declaration files due to modules failing to load + // Do not report errors in TypeScript declaration files due to modules failing to load: if ( contains( err.message, 'Cannot find module' ) ) { return; } @@ -344,7 +336,7 @@ function main( context ) { filename = context.getFilename(); options = context.options[ 0 ] || {}; - // Only process TypeScript declaration files + // Only process TypeScript declaration files: if ( !filename.endsWith( '.d.ts' ) ) { return {}; } @@ -401,7 +393,7 @@ function main( context ) { var i; var j; - // Clear caches to prevent memory leaks + // Clear caches to prevent memory leaks: regexCache = {}; lineCountCache = {}; @@ -468,6 +460,7 @@ function main( context ) { rule = { 'meta': { + 'type': 'problem', 'docs': { 'description': 'ensure return annotations in TSDoc examples match the actual output' }, diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/invalid.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/invalid.js index 6a74a3955af7..86f0a0c4e549 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/invalid.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/invalid.js @@ -74,6 +74,51 @@ test = { }; invalid.push( test ); +test = { + 'code': [ + '/**', + '* Abbreviated Int32Vector example (invalid).', + '*', + '* @example', + "* var numel = require( '@stdlib/ndarray/numel' );", + '*', + '* var arr = new Int32Vector();', + '* // returns ', + '*', + '* var len = numel( arr );', + '* // returns 1', + '*/', + 'declare var ctor: Int32Vector;', + '', + 'export = ctor;' + ].join( '\n' ), + 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/ndarray/vector/int32/docs/types/index.d.ts' ), + 'output': [ + '/**', + '* Abbreviated Int32Vector example (invalid).', + '*', + '* @example', + "* var numel = require( '@stdlib/ndarray/numel' );", + '*', + '* var arr = new Int32Vector();', + '* // returns ', + '*', + '* var len = numel( arr );', + '* // returns 0', + '*/', + 'declare var ctor: Int32Vector;', + '', + 'export = ctor;' + ].join( '\n' ), + 'errors': [ + { + 'message': 'Displayed return value is `1`, but expected `0` instead', + 'type': null + } + ] +}; +invalid.push( test ); + test = { 'code': [ '/**', diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/valid.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/valid.js index 6a8ce939318b..2bda4e062112 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/valid.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/valid.js @@ -156,6 +156,28 @@ test = { }; valid.push( test ); +test = { + 'code': [ + '/**', + '* Abbreviated Int32Vector example.', + '*', + '* @example', + "* var numel = require( '@stdlib/ndarray/numel' );", + '*', + '* var arr = new Int32Vector();', + '* // returns ', + '*', + '* var len = numel( arr );', + '* // returns 0', + '*/', + 'declare var ctor: Int32Vector;', + '', + 'export = ctor;' + ].join( '\n' ), + 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/ndarray/vector/int32/docs/types/index.d.ts' ) +}; +valid.push( test ); + // EXPORTS // From 66ddee18a0e2ca0b9c32bb3b1ed8ca55a32868e7 Mon Sep 17 00:00:00 2001 From: Philipp Burckhardt Date: Sun, 21 Sep 2025 22:09:23 -0500 Subject: [PATCH 04/18] build: use built-ins, resolve via `package.json`, and avoid rootDir --- 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: na - 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: na - 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: na - task: lint_typescript_tests status: na - task: lint_license_headers status: passed --- --- .../eslint/rules/tsdoc-doctest/lib/main.js | 98 +++++++++++++------ .../tsdoc-doctest/test/fixtures/invalid.js | 10 +- .../@stdlib/array/complex64/lib/index.js | 30 ++++++ .../@stdlib/array/complex64/package.json | 59 +++++++++++ .../@stdlib/constants/float64/pi/lib/index.js | 30 ++++++ .../@stdlib/constants/float64/pi/package.json | 52 ++++++++++ .../math/base/special/abs/lib/index.js | 30 ++++++ .../math/base/special/abs/package.json | 51 ++++++++++ .../math/base/special/sqrt/lib/index.js | 30 ++++++ .../math/base/special/sqrt/package.json | 51 ++++++++++ .../@stdlib/ndarray/numel/lib/index.js | 30 ++++++ .../@stdlib/ndarray/numel/package.json | 51 ++++++++++ .../@stdlib/ndarray/vector/int32/lib/index.js | 29 ++++++ .../@stdlib/ndarray/vector/int32/package.json | 49 ++++++++++ .../@stdlib/string/format/lib/index.js | 30 ++++++ .../@stdlib/string/format/package.json | 53 ++++++++++ .../test/fixtures/unvalidated.js | 31 +++--- .../tsdoc-doctest/test/fixtures/valid.js | 34 ++----- 18 files changed, 671 insertions(+), 77 deletions(-) create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/array/complex64/lib/index.js create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/array/complex64/package.json create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/constants/float64/pi/lib/index.js create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/constants/float64/pi/package.json create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/abs/lib/index.js create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/abs/package.json create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/sqrt/lib/index.js create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/sqrt/package.json create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/numel/lib/index.js create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/numel/package.json create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/vector/int32/lib/index.js create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/vector/int32/package.json create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/string/format/lib/index.js create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/string/format/package.json diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js index 846ebf4665e1..f98ae9d4266a 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js @@ -25,12 +25,16 @@ var vm = require( 'vm' ); var dirname = require( 'path' ).dirname; var resolve = require( 'path' ).resolve; +var join = require( 'path' ).join; var existsSync = require( 'fs' ).existsSync; // eslint-disable-line node/no-sync +var readFileSync = require( 'fs' ).readFileSync; // eslint-disable-line node/no-sync var logger = require( 'debug' ); var isNull = require( '@stdlib/assert/is-null' ); var isNumber = require( '@stdlib/assert/is-number' ); var contains = require( '@stdlib/assert/contains' ); var replace = require( '@stdlib/string/replace' ); +var endsWith = require( '@stdlib/string/ends-with' ); +var trim = require( '@stdlib/string/trim' ); var objectKeys = require( '@stdlib/utils/keys' ); var compareValues = require( '@stdlib/_tools/doctest/compare-values' ); var createAnnotationValue = require( '@stdlib/_tools/doctest/create-annotation-value' ); @@ -63,7 +67,7 @@ var rule; * @returns {string} escaped string */ function escapeRegex( str ) { - return str.replace( RE_SPECIAL_CHARS, '\\$&' ); + return replace( str, RE_SPECIAL_CHARS, '\\$&' ); } /** @@ -133,22 +137,73 @@ function findName( scope, expected ) { } /** -* Resolves the implementation path relative to a TypeScript declaration file. +* Finds the nearest package.json file by traversing up the directory tree. +* +* @private +* @param {string} filepath - starting file path +* @returns {string|null} path to package.json or null if not found +*/ +function findNearestPackageJSON( filepath ) { + var pkgPath; + var dir; + + dir = dirname( resolve( filepath ) ); + while ( dir !== dirname( dir ) ) { // Stop at root + pkgPath = join( dir, 'package.json' ); + if ( existsSync( pkgPath ) ) { + return pkgPath; + } + dir = dirname( dir ); + } + return null; +} + +/** +* Resolves the implementation path from package.json. * * @private * @param {string} filepath - TypeScript declaration file path -* @param {string} implementationPath - relative path to implementation * @returns {string|null} resolved implementation path or null if not found */ -function resolveImplementationPath( filepath, implementationPath ) { +function resolveImplementationPath( filepath ) { var implPath; - var baseDir; + var mainPath; + var pkgJSON; + var pkgPath; + var pkgDir; + + // Find the nearest package.json: + pkgPath = findNearestPackageJSON( filepath ); + if ( !pkgPath ) { + debug( 'Could not find package.json for: ' + filepath ); + return null; + } + + // Read and parse package.json: + try { + pkgJSON = JSON.parse( readFileSync( pkgPath, 'utf8' ) ); + } catch ( err ) { + debug( 'Could not read/parse package.json: ' + pkgPath + '. Error: ' + err.message ); + return null; + } + + // Get the main entry point: + mainPath = pkgJSON.main || './lib'; + pkgDir = dirname( pkgPath ); + implPath = resolve( pkgDir, mainPath ); - baseDir = dirname( resolve( filepath ) ); - implPath = resolve( baseDir, implementationPath ); + // Check if it's a directory or file: if ( existsSync( implPath ) ) { return implPath; } + // Try with index.js if it's a directory: + if ( existsSync( join( implPath, 'index.js' ) ) ) { + return join( implPath, 'index.js' ); + } + // Try adding .js extension: + if ( existsSync( implPath + '.js' ) ) { + return implPath + '.js'; + } return null; } @@ -161,7 +216,7 @@ function resolveImplementationPath( filepath, implementationPath ) { */ function cleanTSDocComment( comment ) { // Remove opening /** and closing */ - var cleaned = comment.replace( /^\/\*\*/, '' ).replace( /\*\/$/, '' ); + var cleaned = replace( replace( comment, /^\/\*\*/, '' ), /\*\/$/, '' ); // Remove * at the beginning of lines cleaned = replace( cleaned, RE_COMMENT_PREFIX, '' ); @@ -329,15 +384,13 @@ function processExampleCode( code, commentIdx, comments, scope, report, opts, so function main( context ) { var sourceCode; var filename; - var options; var dir; sourceCode = context.getSourceCode(); filename = context.getFilename(); - options = context.options[ 0 ] || {}; // Only process TypeScript declaration files: - if ( !filename.endsWith( '.d.ts' ) ) { + if ( !endsWith( filename, '.d.ts' ) ) { return {}; } @@ -379,7 +432,6 @@ function main( context ) { * @private */ function validate() { - var implementationPath; var implPath; var examples; var comments; @@ -397,11 +449,10 @@ function main( context ) { regexCache = {}; lineCountCache = {}; - // Resolve implementation path relative to TypeScript declaration file path: - implementationPath = options.implementationPath || '../../lib'; - implPath = resolveImplementationPath( filename, implementationPath ); + // Resolve implementation path from nearest package.json: + implPath = resolveImplementationPath( filename ); if ( !implPath ) { - debug( 'Could not resolve implementation path: ' + implementationPath + ' from ' + filename ); + debug( 'Could not resolve implementation path from package.json for: ' + filename ); return; } @@ -442,7 +493,7 @@ function main( context ) { } for ( j = 0; j < examples.length; j++ ) { - code = examples[ j ].trim(); + code = trim( examples[ j ] ); // Process the example code and validate annotations (reusing VM context): processExampleCode( code, i, comments, scope, report, opts, sourceCode ); @@ -465,18 +516,7 @@ rule = { 'description': 'ensure return annotations in TSDoc examples match the actual output' }, 'fixable': 'code', - 'schema': [ - { - 'type': 'object', - 'properties': { - 'implementationPath': { - 'type': 'string', - 'default': '../../lib' - } - }, - 'additionalProperties': false - } - ] + 'schema': [] }, 'create': main }; diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/invalid.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/invalid.js index 86f0a0c4e549..a84324f49fcb 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/invalid.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/invalid.js @@ -21,12 +21,10 @@ // MODULES // var join = require( 'path' ).join; -var rootDir = require( '@stdlib/_tools/utils/root-dir' ); // VARIABLES // -var ROOT_DIR = rootDir(); var invalid = []; var test; @@ -49,7 +47,7 @@ test = { '', 'export = abs;' ].join( '\n' ), - 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/math/base/special/abs/docs/types/index.d.ts' ), + 'filename': join( __dirname, 'packages/@stdlib/math/base/special/abs/docs/types/index.d.ts' ), 'output': [ '/**', '* Returns the absolute value.', @@ -92,7 +90,7 @@ test = { '', 'export = ctor;' ].join( '\n' ), - 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/ndarray/vector/int32/docs/types/index.d.ts' ), + 'filename': join( __dirname, 'packages/@stdlib/ndarray/vector/int32/docs/types/index.d.ts' ), 'output': [ '/**', '* Abbreviated Int32Vector example (invalid).', @@ -139,7 +137,7 @@ test = { '', 'export = sqrt;' ].join( '\n' ), - 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/math/base/special/sqrt/docs/types/index.d.ts' ), + 'filename': join( __dirname, 'packages/@stdlib/math/base/special/sqrt/docs/types/index.d.ts' ), 'output': [ '/**', '* Returns the square root.', @@ -181,7 +179,7 @@ test = { '', 'export = PI;' ].join( '\n' ), - 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/constants/float64/pi/docs/types/index.d.ts' ), + 'filename': join( __dirname, 'packages/@stdlib/constants/float64/pi/docs/types/index.d.ts' ), 'output': [ '/**', '* The mathematical constant pi.', diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/array/complex64/lib/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/array/complex64/lib/index.js new file mode 100644 index 000000000000..8196bcfbd971 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/array/complex64/lib/index.js @@ -0,0 +1,30 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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-disable stdlib/jsdoc-main-export */ + +// MODULES // + +var Complex64Array = require( '@stdlib/array/complex64' ); + + +// EXPORTS // + +module.exports = Complex64Array; diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/array/complex64/package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/array/complex64/package.json new file mode 100644 index 000000000000..623ec5dbca91 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/array/complex64/package.json @@ -0,0 +1,59 @@ +{ + "name": "@stdlib/array/complex64", + "version": "0.0.0", + "description": "64-bit complex number array.", + "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" + } + ], + "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" + }, + "main": "./lib", + "directories": { + "doc": "./docs", + "example": "./examples", + "lib": "./lib", + "test": "./test" + }, + "types": "./docs/types", + "keywords": [ + "stdlib", + "stdtypes", + "types", + "data", + "structure", + "array", + "typed", + "typed array", + "typed-array", + "complex64", + "complex", + "cmplx", + "float32", + "single", + "single-precision", + "float", + "floating", + "floating-point" + ] +} diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/constants/float64/pi/lib/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/constants/float64/pi/lib/index.js new file mode 100644 index 000000000000..992d23228221 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/constants/float64/pi/lib/index.js @@ -0,0 +1,30 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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-disable stdlib/jsdoc-main-export */ + +// MODULES // + +var PI = require( '@stdlib/constants/float64/pi' ); + + +// EXPORTS // + +module.exports = PI; diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/constants/float64/pi/package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/constants/float64/pi/package.json new file mode 100644 index 000000000000..f5f2f27785b4 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/constants/float64/pi/package.json @@ -0,0 +1,52 @@ +{ + "name": "@stdlib/constants/float64/pi", + "version": "0.0.0", + "description": "The mathematical constant pi.", + "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" + } + ], + "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" + }, + "main": "./lib", + "directories": { + "doc": "./docs", + "example": "./examples", + "lib": "./lib", + "test": "./test" + }, + "types": "./docs/types", + "keywords": [ + "stdlib", + "stdmath", + "constant", + "const", + "mathematics", + "math", + "pi", + "ieee754", + "double", + "dbl", + "float64" + ] +} diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/abs/lib/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/abs/lib/index.js new file mode 100644 index 000000000000..75e38321bd6c --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/abs/lib/index.js @@ -0,0 +1,30 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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-disable stdlib/jsdoc-main-export */ + +// MODULES // + +var abs = require( '@stdlib/math/base/special/abs' ); + + +// EXPORTS // + +module.exports = abs; diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/abs/package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/abs/package.json new file mode 100644 index 000000000000..e0964a5d4a15 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/abs/package.json @@ -0,0 +1,51 @@ +{ + "name": "@stdlib/math/base/special/abs", + "version": "0.0.0", + "description": "Compute the absolute value of a double-precision floating-point number.", + "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" + } + ], + "main": "./lib", + "directories": { + "doc": "./docs", + "example": "./examples", + "lib": "./lib", + "test": "./test" + }, + "types": "./docs/types", + "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" + }, + "keywords": [ + "stdlib", + "stdmath", + "mathematics", + "math", + "math.abs", + "abs", + "absolute", + "value", + "magnitude", + "number" + ] +} diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/sqrt/lib/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/sqrt/lib/index.js new file mode 100644 index 000000000000..2913421bfede --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/sqrt/lib/index.js @@ -0,0 +1,30 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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-disable stdlib/jsdoc-main-export */ + +// MODULES // + +var sqrt = require( '@stdlib/math/base/special/sqrt' ); + + +// EXPORTS // + +module.exports = sqrt; diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/sqrt/package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/sqrt/package.json new file mode 100644 index 000000000000..0e4f6a30a6cc --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/sqrt/package.json @@ -0,0 +1,51 @@ +{ + "name": "@stdlib/math/base/special/sqrt", + "version": "0.0.0", + "description": "Compute the principal square root of a double-precision floating-point number.", + "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" + } + ], + "main": "./lib", + "directories": { + "doc": "./docs", + "example": "./examples", + "lib": "./lib", + "test": "./test" + }, + "types": "./docs/types", + "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" + }, + "keywords": [ + "stdlib", + "stdmath", + "mathematics", + "math", + "math.sqrt", + "sqrt", + "square", + "root", + "principal", + "number" + ] +} diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/numel/lib/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/numel/lib/index.js new file mode 100644 index 000000000000..680e11ab655c --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/numel/lib/index.js @@ -0,0 +1,30 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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-disable stdlib/jsdoc-main-export */ + +// MODULES // + +var numel = require( '@stdlib/ndarray/numel' ); + + +// EXPORTS // + +module.exports = numel; diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/numel/package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/numel/package.json new file mode 100644 index 000000000000..beb30ba97eba --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/numel/package.json @@ -0,0 +1,51 @@ +{ + "name": "@stdlib/ndarray/numel", + "version": "0.0.0", + "description": "Return the number of elements in an ndarray.", + "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" + } + ], + "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" + }, + "main": "./lib", + "directories": { + "doc": "./docs", + "example": "./examples", + "lib": "./lib", + "test": "./test" + }, + "types": "./docs/types", + "keywords": [ + "stdlib", + "stdtypes", + "types", + "data", + "structure", + "vector", + "ndarray", + "numel", + "elements", + "length" + ] +} diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/vector/int32/lib/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/vector/int32/lib/index.js new file mode 100644 index 000000000000..3d88c78485d3 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/vector/int32/lib/index.js @@ -0,0 +1,29 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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-disable stdlib/jsdoc-main-export */ + +// MODULES // + +var Int32Vector = require( '@stdlib/ndarray/vector/int32' ); + +// EXPORTS //` + +module.exports = Int32Vector; diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/vector/int32/package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/vector/int32/package.json new file mode 100644 index 000000000000..ba7544b277fc --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/vector/int32/package.json @@ -0,0 +1,49 @@ +{ + "name": "@stdlib/ndarray/vector/int32", + "version": "0.0.0", + "description": "Create an ndarray vector constructor.", + "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" + } + ], + "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" + }, + "main": "./lib", + "directories": { + "doc": "./docs", + "example": "./examples", + "lib": "./lib", + "test": "./test" + }, + "types": "./docs/types", + "keywords": [ + "stdlib", + "stdtypes", + "types", + "data", + "structure", + "vector", + "ndarray", + "int32" + ] +} diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/string/format/lib/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/string/format/lib/index.js new file mode 100644 index 000000000000..a795b3385c3f --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/string/format/lib/index.js @@ -0,0 +1,30 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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-disable stdlib/jsdoc-main-export */ + +// MODULES // + +var format = require( '@stdlib/string/format' ); + + +// EXPORTS // + +module.exports = format; diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/string/format/package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/string/format/package.json new file mode 100644 index 000000000000..d4ea988c1f40 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/string/format/package.json @@ -0,0 +1,53 @@ +{ + "name": "@stdlib/string/format", + "version": "0.0.0", + "description": "Insert provided variable values into a format string.", + "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" + } + ], + "main": "./lib", + "directories": { + "doc": "./docs", + "example": "./examples", + "lib": "./lib", + "test": "./test" + }, + "types": "./docs/types", + "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" + }, + "keywords": [ + "stdlib", + "stdstring", + "utilities", + "utility", + "utils", + "util", + "string", + "str", + "format", + "fmt", + "sprintf", + "template" + ] +} diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/unvalidated.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/unvalidated.js index 413b6eae7042..e07efcbc85c3 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/unvalidated.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/unvalidated.js @@ -18,15 +18,8 @@ 'use strict'; -// MODULES // - -var join = require( 'path' ).join; -var rootDir = require( '@stdlib/_tools/utils/root-dir' ); - - // VARIABLES // -var ROOT_DIR = rootDir(); var unvalidated = []; var test; @@ -34,32 +27,38 @@ var test; test = { 'code': [ '/**', - '* Function without @example block.', + '* Not a TypeScript declaration file.', + '*', + '* @example', + '* var result = test();', + '* // returns true', '*/', - 'declare function noExample( x: number ): number;', + 'function test() {', + ' return true;', + '}', '', - 'export = noExample;' + 'module.exports = test;' ].join( '\n' ), - 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/test/no-example/docs/types/index.d.ts' ) + 'filename': 'test.js' }; unvalidated.push( test ); test = { 'code': [ '/**', - '* Not a TypeScript file.', + '* Regular TypeScript file (not .d.ts).', '*', '* @example', - '* var result = test();', + '* const result = test();', '* // returns true', '*/', - 'function test() {', + 'function test(): boolean {', ' return true;', '}', '', - 'module.exports = test;' + 'export default test;' ].join( '\n' ), - 'filename': 'test.js' + 'filename': 'test.ts' }; unvalidated.push( test ); diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/valid.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/valid.js index 2bda4e062112..1343dddc72da 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/valid.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/valid.js @@ -21,12 +21,10 @@ // MODULES // var join = require( 'path' ).join; -var rootDir = require( '@stdlib/_tools/utils/root-dir' ); // VARIABLES // -var ROOT_DIR = rootDir(); var valid = []; var test; @@ -43,13 +41,13 @@ test = { '*', '* @example', '* var v = abs( -1.0 );', - '* // returns 1', + '* // returns 1.0', '*/', 'declare function abs( x: number ): number;', '', 'export = abs;' ].join( '\n' ), - 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/math/base/special/abs/docs/types/index.d.ts' ) + 'filename': join( __dirname, 'packages/@stdlib/math/base/special/abs/docs/types/index.d.ts' ) }; valid.push( test ); @@ -63,7 +61,7 @@ test = { '*', '* @example', '* var v = sqrt( 4.0 );', - '* // returns 2', + '* // returns 2.0', '*', '* @example', '* var v = sqrt( 9.0 );', @@ -73,7 +71,7 @@ test = { '', 'export = sqrt;' ].join( '\n' ), - 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/math/base/special/sqrt/docs/types/index.d.ts' ) + 'filename': join( __dirname, 'packages/@stdlib/math/base/special/sqrt/docs/types/index.d.ts' ) }; valid.push( test ); @@ -90,7 +88,7 @@ test = { '', 'export = PI;' ].join( '\n' ), - 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/constants/float64/pi/docs/types/index.d.ts' ) + 'filename': join( __dirname, 'packages/@stdlib/constants/float64/pi/docs/types/index.d.ts' ) }; valid.push( test ); @@ -117,7 +115,7 @@ test = { '', 'export = Complex64Array;' ].join( '\n' ), - 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/array/complex64/docs/types/index.d.ts' ) + 'filename': join( __dirname, 'packages/@stdlib/array/complex64/docs/types/index.d.ts' ) }; valid.push( test ); @@ -136,23 +134,7 @@ test = { '', 'export = format;' ].join( '\n' ), - 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/string/format/docs/types/index.d.ts' ) -}; -valid.push( test ); - -test = { - 'code': [ - '/**', - '* TypeScript declaration without examples.', - '*', - '* @param x - input value', - '* @returns doubled value', - '*/', - 'declare function double( x: number ): number;', - '', - 'export = double;' - ].join( '\n' ), - 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/math/base/special/double/docs/types/index.d.ts' ) + 'filename': join( __dirname, 'packages/@stdlib/string/format/docs/types/index.d.ts' ) }; valid.push( test ); @@ -174,7 +156,7 @@ test = { '', 'export = ctor;' ].join( '\n' ), - 'filename': join( ROOT_DIR, 'lib/node_modules/@stdlib/ndarray/vector/int32/docs/types/index.d.ts' ) + 'filename': join( __dirname, 'packages/@stdlib/ndarray/vector/int32/docs/types/index.d.ts' ) }; valid.push( test ); From 08e5f064df22d3eceaeba4f22e257b7f2b62049c Mon Sep 17 00:00:00 2001 From: Philipp Burckhardt Date: Sun, 21 Sep 2025 22:31:16 -0500 Subject: [PATCH 05/18] build: use existing escapeRegExpString --- 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: na - task: lint_package_json status: na - task: lint_repl_help status: na - task: lint_javascript_src status: passed - task: lint_javascript_cli status: na - task: lint_javascript_examples status: na - task: lint_javascript_tests status: na - 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: na - task: lint_typescript_tests status: na - task: lint_license_headers status: passed --- --- .../eslint/rules/tsdoc-doctest/lib/main.js | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js index f98ae9d4266a..42a356dae831 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js @@ -35,6 +35,7 @@ var contains = require( '@stdlib/assert/contains' ); var replace = require( '@stdlib/string/replace' ); var endsWith = require( '@stdlib/string/ends-with' ); var trim = require( '@stdlib/string/trim' ); +var escapeRegExpString = require( '@stdlib/utils/escape-regexp-string' ); var objectKeys = require( '@stdlib/utils/keys' ); var compareValues = require( '@stdlib/_tools/doctest/compare-values' ); var createAnnotationValue = require( '@stdlib/_tools/doctest/create-annotation-value' ); @@ -49,9 +50,8 @@ var debug = logger( 'tsdoc-doctest' ); var RE_TSDOC = /\/\*\*[\s\S]+?\*\//g; var RE_EXAMPLE = /@example\s*([\s\S]*?)(?=\n\s*@\w|\*\/|$)/g; var RE_NEWLINE = /\r?\n/g; -var RE_ANNOTATION = /(?:\n|^)(?:var|let|const)? ?([a-zA-Z0-9._]+) ?=[^;]*;\n\/\/ ?(returns|([A-Za-z][A-Za-z_0-9]*)? ?=>|throws) ?([\s\S]*?)(\n|$)/g; +var RE_ANNOTATION = /(?:\n|^)(?:var|let|const)? ?([a-zA-Z0-9._]+) ?=[^;]*;\n\/\/ ?(returns|([A-Za-z][A-Za-z_0-9]*)? ?=>|throws) ?([\s\S]*?)(?=\n|$)/g; var RE_COMMENT_PREFIX = /^\s*\*\s?/gm; -var RE_SPECIAL_CHARS = /[.*+?^${}()|[\]\\]/g; var regexCache = {}; var lineCountCache = {}; var rule; @@ -59,17 +59,6 @@ var rule; // FUNCTIONS // -/** -* Escapes special regex characters in a string. -* -* @private -* @param {string} str - string to escape -* @returns {string} escaped string -*/ -function escapeRegex( str ) { - return replace( str, RE_SPECIAL_CHARS, '\\$&' ); -} - /** * Gets or creates a cached regex for finding return annotations. * @@ -83,7 +72,7 @@ function getAnnotationRegex( annotationType, value ) { var pattern; var key; - escapedValue = escapeRegex( value ); + escapedValue = escapeRegExpString( value ); key = [ annotationType, escapedValue ].join( '::' ); if ( !regexCache[ key ] ) { @@ -336,7 +325,7 @@ function processExampleCode( code, commentIdx, comments, scope, report, opts, so // Find annotation part in the match (after "// "): annotationStart = arr[ 0 ].indexOf( '// ' ) + 3; - annotationEnd = arr[ 0 ].length - arr[ 5 ].length; + annotationEnd = arr[ 0 ].length; loc.range = [ commentStartIdx + codeIdx + annotationStart, commentStartIdx + codeIdx + annotationEnd From fab2c2ee36375fc59af3a74d723f6b454714e568 Mon Sep 17 00:00:00 2001 From: Philipp Burckhardt Date: Mon, 22 Sep 2025 00:56:20 -0500 Subject: [PATCH 06/18] refactor: address PR feedback --- 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: na - task: lint_repl_help status: na - task: lint_javascript_src status: passed - task: lint_javascript_cli status: na - task: lint_javascript_examples status: na - task: lint_javascript_tests status: na - 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: na - task: lint_typescript_tests status: na - task: lint_license_headers status: passed --- --- .../eslint/rules/tsdoc-doctest/README.md | 12 +- .../tsdoc-doctest/lib/add_package_to_scope.js | 84 +++++--- .../tsdoc-doctest/lib/create_vm_scope.js | 5 +- .../eslint/rules/tsdoc-doctest/lib/main.js | 112 +++++------ .../tsdoc-doctest/test/fixtures/invalid.js | 51 +++++ .../complex64/{package.json => _package.json} | 0 .../pi/{package.json => _package.json} | 0 .../abs/{package.json => _package.json} | 0 .../math/base/special/pow/_package.json | 188 ++++++++++++++++++ .../math/base/special/pow/lib/index.js | 30 +++ .../sqrt/{package.json => _package.json} | 0 .../numel/{package.json => _package.json} | 0 .../int32/{package.json => _package.json} | 0 .../format/{package.json => _package.json} | 0 .../tsdoc-doctest/test/fixtures/valid.js | 25 +++ .../eslint/rules/tsdoc-doctest/test/test.js | 17 +- 16 files changed, 416 insertions(+), 108 deletions(-) rename lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/array/complex64/{package.json => _package.json} (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/constants/float64/pi/{package.json => _package.json} (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/abs/{package.json => _package.json} (100%) create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/pow/_package.json create mode 100644 lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/pow/lib/index.js rename lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/sqrt/{package.json => _package.json} (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/numel/{package.json => _package.json} (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/vector/int32/{package.json => _package.json} (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/string/format/{package.json => _package.json} (100%) diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/README.md b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/README.md index c55769725baf..9592aa16d6a5 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/README.md +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/README.md @@ -38,7 +38,7 @@ var rule = require( '@stdlib/_tools/eslint/rules/tsdoc-doctest' ); #### rule -[ESLint rule][eslint-rules] to ensure that return annotations in TSDoc examples match the actual output. The rule validates `@example` blocks in TSDoc comments within `.d.ts` files. +[ESLint rule][eslint-rules] to ensure that return annotations in TSDoc examples match the actual output. Return annotations may start with `returns`, `throws`, or `=>`. `returns` follow variable declarations or assignment expressions, whereas `=>` follow expression-only forms including `console.log` calls. The rule validates `@example` blocks in TSDoc comments within `.d.ts` files by automatically resolving the corresponding implementation via the nearest `package.json` file. **Bad**: @@ -129,7 +129,7 @@ var result = linter.verify( code, { 'tsdoc-doctest': 'error' } }, { - 'filename': 'lib/node_modules/@stdlib/math/base/special/abs/docs/types/index.d.ts' + 'filename': '/path/to/project/lib/node_modules/@stdlib/math/base/special/abs/docs/types/index.d.ts' }); /* returns [ @@ -155,11 +155,9 @@ var result = linter.verify( code, { ## Notes -- The corresponding JavaScript package must be loadable via `require('@stdlib/')` -- The rule skips validation if the package cannot be loaded. -- Examples are executed in a sandboxed VM context with limited globals. -- The rule validates assignment-form examples (e.g., `var x = fn(...);` followed by an annotation). It does not validate console output or expression-only forms using `// =>`. -- The implementation path the rule uses to load the JavaScript implementation can be overridden via the `implementationPath` rule option (default: `../../lib` relative to the declaration file). +- The rule automatically resolves the implementation path by traversing up the directory tree to find the nearest `package.json` file and using its `main` field. +- The rule skips validation if the `package.json` file cannot be found or if the resolved implementation cannot be loaded. +- Examples are executed in a sandboxed VM context with limited globals for security. diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/add_package_to_scope.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/add_package_to_scope.js index 458eb5acf0a7..8b70523fed50 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/add_package_to_scope.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/add_package_to_scope.js @@ -21,19 +21,49 @@ // VARIABLES // // Regular expressions for matching TypeScript declarations: + +/** +* Regular expression to match function declarations like "declare function abs( x: number ): number;" (captures function name). +* +* @type {RegExp} +*/ var RE_DECLARE_FUNCTION = /declare\s+function\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*[<(]/; + +/** +* Regular expression to match variable declarations like "declare var someVar: SomeType;" (captures variable name). +* +* @type {RegExp} +*/ var RE_DECLARE_VAR = /declare\s+var\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:/; + +/** +* Regular expression to match class declarations like "declare class Complex64Array {" (captures class name). +* +* @type {RegExp} +*/ var RE_DECLARE_CLASS = /declare\s+class\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s/; -var RE_DECLARE_VAR_NAMESPACE = /declare\s+var\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:\s*[A-Z][a-zA-Z0-9_$]*/; + +/** +* Regular expression to match const declarations like "declare const PI: number;" (captures constant name). +* +* @type {RegExp} +*/ var RE_DECLARE_CONST = /declare\s+const\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:/; + +/** +* Regular expression to match variable declarations with interface types like "declare var ctor: Int32Vector;" (captures variable name and interface name). +* +* @type {RegExp} +*/ var RE_DECLARE_VAR_INTERFACE = /declare\s+var\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:\s*([A-Z][a-zA-Z0-9_$]*)/; // MAIN // /** -* Adds package export to scope based on TypeScript declarations. +* Adds a package export to the scope based on TypeScript declarations. * +* @private * @param {Object} scope - VM scope object to add the package export to * @param {*} pkg - package export value to be added to scope * @param {string} sourceText - TypeScript declaration source text to parse for identifier names @@ -41,45 +71,33 @@ var RE_DECLARE_VAR_INTERFACE = /declare\s+var\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:\s function addPackageToScope( scope, pkg, sourceText ) { var interfaceMatch; var namespaceMatch; - var funcMatch; + var pkgType; + var match; - if ( typeof pkg === 'function' ) { - // Try to match declare function pattern (handles generics with <): - funcMatch = sourceText.match( RE_DECLARE_FUNCTION ); - if ( !funcMatch ) { - // Try to match declare var pattern: - funcMatch = sourceText.match( RE_DECLARE_VAR ); - } - if ( !funcMatch ) { - // Try to match declare class pattern (for constructor functions): - funcMatch = sourceText.match( RE_DECLARE_CLASS ); - } - if ( funcMatch ) { - scope[ funcMatch[1] ] = pkg; + pkgType = typeof pkg; + if ( pkgType === 'function' ) { + match = sourceText.match( RE_DECLARE_FUNCTION ) || + sourceText.match( RE_DECLARE_VAR ) || + sourceText.match( RE_DECLARE_CLASS ); + if ( match ) { + scope[ match[1] ] = pkg; } - // Also check for declare var with interface pattern (e.g., declare var ctor: Int32Vector): interfaceMatch = sourceText.match( RE_DECLARE_VAR_INTERFACE ); if ( interfaceMatch ) { - // Make the function available under both the variable name and the interface name: + // Make the function available under both the variable and interface names: scope[ interfaceMatch[1] ] = pkg; // e.g., ctor scope[ interfaceMatch[2] ] = pkg; // e.g., Int32Vector } - } else if ( typeof pkg === 'object' && pkg !== null ) { - // Handle namespace objects and other object interfaces: - namespaceMatch = sourceText.match( RE_DECLARE_VAR_NAMESPACE ); - if ( namespaceMatch ) { - scope[ namespaceMatch[1] ] = pkg; - } - // Also check for const declarations (e.g., Complex64/Complex128 constants): - funcMatch = sourceText.match( RE_DECLARE_CONST ); - if ( funcMatch ) { - scope[ funcMatch[1] ] = pkg; - } } else { - // Try to match declare const pattern: - funcMatch = sourceText.match( RE_DECLARE_CONST ); - if ( funcMatch ) { - scope[ funcMatch[1] ] = pkg; + if ( pkgType === 'object' && pkg !== null ) { + namespaceMatch = sourceText.match( RE_DECLARE_VAR_INTERFACE ); + if ( namespaceMatch ) { + scope[ namespaceMatch[1] ] = pkg; + } + } + match = sourceText.match( RE_DECLARE_CONST ); + if ( match ) { + scope[ match[1] ] = pkg; } } } diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/create_vm_scope.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/create_vm_scope.js index 004c3c94e57e..3d8b054caa0c 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/create_vm_scope.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/create_vm_scope.js @@ -34,8 +34,8 @@ var windowShim = require( './window.js' ); * * @private * @param {*} data - data to be logged -* @param {...*} args - substitution values -* @returns {*} return value +* @param {...*} [args] - substitution values +* @returns {*} formatted string if first argument is string, otherwise first argument */ function log( data ) { if ( isString( data ) ) { @@ -50,6 +50,7 @@ function log( data ) { /** * Creates a VM execution scope with necessary globals. * +* @private * @param {string} dir - directory path * @param {string} filename - file name * @returns {Object} VM scope object diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js index 42a356dae831..137d9e8178bc 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js @@ -23,20 +23,21 @@ // MODULES // var vm = require( 'vm' ); -var dirname = require( 'path' ).dirname; var resolve = require( 'path' ).resolve; -var join = require( 'path' ).join; -var existsSync = require( 'fs' ).existsSync; // eslint-disable-line node/no-sync var readFileSync = require( 'fs' ).readFileSync; // eslint-disable-line node/no-sync var logger = require( 'debug' ); +var resolveParentPath = require( '@stdlib/fs/resolve-parent-path' ).sync; +var dirname = require( '@stdlib/utils/dirname' ); var isNull = require( '@stdlib/assert/is-null' ); var isNumber = require( '@stdlib/assert/is-number' ); var contains = require( '@stdlib/assert/contains' ); var replace = require( '@stdlib/string/replace' ); var endsWith = require( '@stdlib/string/ends-with' ); var trim = require( '@stdlib/string/trim' ); +var reEOL = require( '@stdlib/regexp/eol' ); var escapeRegExpString = require( '@stdlib/utils/escape-regexp-string' ); var objectKeys = require( '@stdlib/utils/keys' ); +var tryRequire = require( '@stdlib/utils/try-require' ); var compareValues = require( '@stdlib/_tools/doctest/compare-values' ); var createAnnotationValue = require( '@stdlib/_tools/doctest/create-annotation-value' ); var createVMScope = require( './create_vm_scope.js' ); @@ -49,9 +50,18 @@ var SCOPE_DEFAULTS = require( './scope_defaults.json' ); var debug = logger( 'tsdoc-doctest' ); var RE_TSDOC = /\/\*\*[\s\S]+?\*\//g; var RE_EXAMPLE = /@example\s*([\s\S]*?)(?=\n\s*@\w|\*\/|$)/g; -var RE_NEWLINE = /\r?\n/g; -var RE_ANNOTATION = /(?:\n|^)(?:var|let|const)? ?([a-zA-Z0-9._]+) ?=[^;]*;\n\/\/ ?(returns|([A-Za-z][A-Za-z_0-9]*)? ?=>|throws) ?([\s\S]*?)(?=\n|$)/g; +var RE_ANNOTATION = /(?:\n|^)(?:var|let|const)? ?([a-zA-Z0-9._]+) ?=?[^;]*;\n\/\/ ?(returns|([A-Za-z][A-Za-z_0-9]*)? ?=>|throws) ?([\s\S]*?)(?=\n|$)/g; var RE_COMMENT_PREFIX = /^\s*\*\s?/gm; +var DEFAULT_ERROR_LOC = { + 'start': { + 'line': 1, + 'column': 0 + }, + 'end': { + 'line': 1, + 'column': 0 + } +}; var regexCache = {}; var lineCountCache = {}; var rule; @@ -73,7 +83,7 @@ function getAnnotationRegex( annotationType, value ) { var key; escapedValue = escapeRegExpString( value ); - key = [ annotationType, escapedValue ].join( '::' ); + key = annotationType + '::' + escapedValue; if ( !regexCache[ key ] ) { pattern = '// ' + annotationType + '\\s+' + escapedValue; @@ -90,14 +100,14 @@ function getAnnotationRegex( annotationType, value ) { * @returns {number} number of lines */ function countLines( str ) { - var matches; + var lines; // Use cached result if available if ( lineCountCache[ str ] ) { return lineCountCache[ str ]; } - matches = str.match( RE_NEWLINE ); - lineCountCache[ str ] = ( matches ) ? matches.length : 0; + lines = str.split( reEOL() ); + lineCountCache[ str ] = lines.length - 1; return lineCountCache[ str ]; } @@ -106,7 +116,7 @@ function countLines( str ) { * * @private * @param {Object} scope - VM scope -* @param {any} expected - expected value to search for +* @param {*} expected - expected value to search for * @returns {string} variable name or `?` if no match found */ function findName( scope, expected ) { @@ -125,44 +135,25 @@ function findName( scope, expected ) { return '?'; } -/** -* Finds the nearest package.json file by traversing up the directory tree. -* -* @private -* @param {string} filepath - starting file path -* @returns {string|null} path to package.json or null if not found -*/ -function findNearestPackageJSON( filepath ) { - var pkgPath; - var dir; - - dir = dirname( resolve( filepath ) ); - while ( dir !== dirname( dir ) ) { // Stop at root - pkgPath = join( dir, 'package.json' ); - if ( existsSync( pkgPath ) ) { - return pkgPath; - } - dir = dirname( dir ); - } - return null; -} - /** * Resolves the implementation path from package.json. * * @private * @param {string} filepath - TypeScript declaration file path -* @returns {string|null} resolved implementation path or null if not found +* @returns {(string|null)} resolved implementation path or null if not found */ function resolveImplementationPath( filepath ) { - var implPath; var mainPath; var pkgJSON; var pkgPath; var pkgDir; + var opts; // Find the nearest package.json: - pkgPath = findNearestPackageJSON( filepath ); + opts = { + 'dir': dirname( resolve( filepath ) ) + }; + pkgPath = resolveParentPath( 'package.json', opts ); if ( !pkgPath ) { debug( 'Could not find package.json for: ' + filepath ); return null; @@ -179,21 +170,7 @@ function resolveImplementationPath( filepath ) { // Get the main entry point: mainPath = pkgJSON.main || './lib'; pkgDir = dirname( pkgPath ); - implPath = resolve( pkgDir, mainPath ); - - // Check if it's a directory or file: - if ( existsSync( implPath ) ) { - return implPath; - } - // Try with index.js if it's a directory: - if ( existsSync( join( implPath, 'index.js' ) ) ) { - return join( implPath, 'index.js' ); - } - // Try adding .js extension: - if ( existsSync( implPath + '.js' ) ) { - return implPath + '.js'; - } - return null; + return resolve( pkgDir, mainPath ); } /** @@ -242,6 +219,7 @@ function processExampleCode( code, commentIdx, comments, scope, report, opts, so var last; var line; var type; + var out; var loc; var msg; var arr; @@ -281,14 +259,20 @@ function processExampleCode( code, commentIdx, comments, scope, report, opts, so } }; - // Run code preceding return annotation: + // Run code preceding return annotation and capture result: try { - vm.runInContext( arr[ 0 ], scope ); + out = vm.runInContext( arr[ 0 ], scope ); - // For assignment-form examples, read the assigned variable from scope: - actual = scope[ arr[ 1 ] ]; + // Determine actual value based on annotation form: if ( arr[ 3 ] ) { + // Expression form with named variable: someExpression; // variable => value actual = vm.runInContext( arr[ 3 ], scope ); + } else if ( arr[ 1 ] && arr[ 1 ] !== 'console.log' && !arr[ 2 ].match( /^=>/ ) ) { + // Assignment form: var x = expression; // returns value + actual = scope[ arr[ 1 ] ]; + } else { + // Bare expression form (incl. console.log): someExpression; // => value + actual = out; } expected = arr[ 4 ]; msg = compareValues( actual, expected ); @@ -356,10 +340,7 @@ function processExampleCode( code, commentIdx, comments, scope, report, opts, so } }; - // Do not report errors in TypeScript declaration files due to modules failing to load: - if ( contains( err.message, 'Cannot find module' ) ) { - return; - } + // Always report errors so programmer errors are not swallowed: report( loc, 'Encountered an error while running example code: '+err.message ); } } @@ -422,14 +403,14 @@ function main( context ) { */ function validate() { var implPath; - var examples; var comments; - var example; + var examples; var cleaned; + var example; var comment; var scope; - var code; var opts; + var code; var pkg; var i; var j; @@ -442,14 +423,15 @@ function main( context ) { implPath = resolveImplementationPath( filename ); if ( !implPath ) { debug( 'Could not resolve implementation path from package.json for: ' + filename ); + report( DEFAULT_ERROR_LOC, 'Could not resolve implementation path from package.json for this declaration file.' ); return; } // Try to load the implementation directly: - try { - pkg = require( implPath ); // eslint-disable-line stdlib/no-dynamic-require - } catch ( err ) { - debug( 'Could not load implementation: ' + implPath + '. Error: ' + err.message ); + pkg = tryRequire( implPath ); + if ( pkg instanceof Error ) { + debug( 'Could not load implementation: ' + implPath + '. Error: ' + pkg.message ); + report( DEFAULT_ERROR_LOC, 'Could not load implementation: '+implPath+' ('+pkg.message+').' ); return; } diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/invalid.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/invalid.js index a84324f49fcb..eb567e378352 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/invalid.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/invalid.js @@ -201,6 +201,57 @@ test = { }; invalid.push( test ); +test = { + 'code': [ + '/**', + '* Evaluates the exponential function.', + '*', + '* @param b - base', + '* @param x - exponent', + '* @returns function value', + '*', + '* @example', + '* console.log( pow( 3.0, 2.0 ) );', + '* // => 8.0', + '*', + '* @example', + '* console.log( pow( 2.0, 2.0 ) );', + '* // => 4.0', + '*/', + 'declare function pow( b: number, x: number ): number;', + '', + 'export = pow;' + ].join( '\n' ), + 'output': [ + '/**', + '* Evaluates the exponential function.', + '*', + '* @param b - base', + '* @param x - exponent', + '* @returns function value', + '*', + '* @example', + '* console.log( pow( 3.0, 2.0 ) );', + '* // => 9', + '*', + '* @example', + '* console.log( pow( 2.0, 2.0 ) );', + '* // => 4.0', + '*/', + 'declare function pow( b: number, x: number ): number;', + '', + 'export = pow;' + ].join( '\n' ), + 'filename': join( __dirname, 'packages/@stdlib/math/base/special/pow/docs/types/index.d.ts' ), + 'errors': [ + { + 'message': 'Displayed return value is `8.0`, but expected `9` instead', + 'type': null + } + ] +}; +invalid.push( test ); + // EXPORTS // diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/array/complex64/package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/array/complex64/_package.json similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/array/complex64/package.json rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/array/complex64/_package.json diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/constants/float64/pi/package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/constants/float64/pi/_package.json similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/constants/float64/pi/package.json rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/constants/float64/pi/_package.json diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/abs/package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/abs/_package.json similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/abs/package.json rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/abs/_package.json diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/pow/_package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/pow/_package.json new file mode 100644 index 000000000000..165b914260c3 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/pow/_package.json @@ -0,0 +1,188 @@ +{ + "name": "@stdlib/math/base/special/pow", + "version": "0.0.0", + "description": "Exponential function.", + "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" + } + ], + "main": "./lib", + "gypfile": true, + "directories": { + "benchmark": "./benchmark", + "doc": "./docs", + "example": "./examples", + "include": "./include", + "lib": "./lib", + "scripts": "./scripts", + "src": "./src", + "test": "./test" + }, + "types": "./docs/types", + "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", + "stdmath", + "mathematics", + "math", + "math.pow", + "pow", + "power", + "natural", + "exponential", + "function", + "number" + ], + "__stdlib__": { + "scaffold": { + "$schema": "math/base@v1.0", + "base_alias": "pow", + "alias": "pow", + "pkg_desc": "exponential function", + "desc": "exponential function", + "short_desc": "exponential function", + "parameters": [ + { + "name": "x", + "desc": "base", + "type": { + "javascript": "number", + "jsdoc": "number", + "c": "double", + "dtype": "float64" + }, + "domain": [ + { + "min": "-infinity", + "max": "infinity" + } + ], + "rand": { + "prng": "random/base/uniform", + "parameters": [ + -10, + 10 + ] + }, + "example_values": [ + -1.2, + 2, + -3.1, + 4, + 5.5, + 100, + 8.9, + 3.141592653589793, + 11.3, + -3.141592653589793, + 13.5, + 14.6, + -15.7, + 16.8, + -17.9, + 10, + -19.11, + 20.12, + -21.15, + 1 + ] + }, + { + "name": "y", + "desc": "exponent", + "type": { + "javascript": "number", + "jsdoc": "number", + "c": "double", + "dtype": "float64" + }, + "domain": [ + { + "min": "-infinity", + "max": "infinity" + } + ], + "rand": { + "prng": "random/base/uniform", + "parameters": [ + -10, + 10 + ] + }, + "example_values": [ + 1.2, + -2, + 3, + -0.5, + 0, + -5.6, + 8.9, + -10, + 1.5, + -12, + 13.5, + 14.6, + -15.7, + 6, + -17, + 18, + -9, + 2.12, + -1.15, + -2 + ] + } + ], + "returns": { + "desc": "function value", + "type": { + "javascript": "number", + "jsdoc": "number", + "c": "double", + "dtype": "float64" + } + }, + "keywords": [ + "natural", + "exponential", + "pow", + "power" + ], + "extra_keywords": [ + "math.pow" + ] + } + } +} diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/pow/lib/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/pow/lib/index.js new file mode 100644 index 000000000000..cc9321a7408d --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/pow/lib/index.js @@ -0,0 +1,30 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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-disable stdlib/jsdoc-main-export */ + +// MODULES // + +var pow = require( '@stdlib/math/base/special/pow' ); + + +// EXPORTS // + +module.exports = pow; diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/sqrt/package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/sqrt/_package.json similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/sqrt/package.json rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/sqrt/_package.json diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/numel/package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/numel/_package.json similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/numel/package.json rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/numel/_package.json diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/vector/int32/package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/vector/int32/_package.json similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/vector/int32/package.json rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/vector/int32/_package.json diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/string/format/package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/string/format/_package.json similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/string/format/package.json rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/string/format/_package.json diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/valid.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/valid.js index 1343dddc72da..834904f315eb 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/valid.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/valid.js @@ -160,6 +160,31 @@ test = { }; valid.push( test ); +test = { + 'code': [ + '/**', + '* Evaluates the exponential function.', + '*', + '* @param b - base', + '* @param x - exponent', + '* @returns function value', + '*', + '* @example', + '* console.log( pow( 3.0, 2.0 ) );', + '* // => 9.0', + '*', + '* @example', + '* console.log( pow( 2.0, 2.0 ) );', + '* // => 4.0', + '*/', + 'declare function pow( b: number, x: number ): number;', + '', + 'export = pow;' + ].join( '\n' ), + 'filename': join( __dirname, 'packages/@stdlib/math/base/special/pow/docs/types/index.d.ts' ) +}; +valid.push( test ); + // EXPORTS // diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/test.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/test.js index 4a7a28dac555..d5de68857305 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/test.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/test.js @@ -21,8 +21,23 @@ // MODULES // var tape = require( 'tape' ); +var proxyquire = require( 'proxyquire' ); var RuleTester = require( 'eslint' ).RuleTester; -var rule = require( './../lib' ); +var resolveParentPath = require( '@stdlib/fs/resolve-parent-path' ); + +// Mock the rule to work with renamed _package.json files: +var rule = proxyquire( './../lib/main.js', { + '@stdlib/fs/resolve-parent-path': { + 'sync': function mockResolveParentPath( target, opts ) { + // If looking for package.json, search for _package.json instead: + if ( target === 'package.json' ) { + target = '_package.json'; + } + // Use the original function with the modified target: + return resolveParentPath.sync( target, opts ); + } + } +}); // FIXTURES // From 2cee94f92dfab4d2f5ef2dfbe9a1b57d3fd529f9 Mon Sep 17 00:00:00 2001 From: Philipp Burckhardt Date: Sat, 27 Sep 2025 10:42:38 -0500 Subject: [PATCH 07/18] chore: rename lint rule --- 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: na - task: lint_typescript_tests status: na - task: lint_license_headers status: passed --- --- etc/eslint/rules/typescript.js | 6 +++--- .../@stdlib/_tools/eslint/rules/lib/index.js | 6 +++--- .../README.md | 19 ++++++++++--------- .../examples/index.js | 6 +++--- .../lib/add_package_to_scope.js | 0 .../lib/create_vm_scope.js | 0 .../lib/index.js | 4 ++-- .../lib/main.js | 0 .../lib/scope_defaults.json | 0 .../lib/window.js | 0 .../package.json | 2 +- .../test/fixtures/invalid.js | 0 .../@stdlib/array/complex64/_package.json | 0 .../@stdlib/array/complex64/lib/index.js | 0 .../constants/float64/pi/_package.json | 0 .../@stdlib/constants/float64/pi/lib/index.js | 0 .../math/base/special/abs/_package.json | 0 .../math/base/special/abs/lib/index.js | 0 .../math/base/special/pow/_package.json | 0 .../math/base/special/pow/lib/index.js | 0 .../math/base/special/sqrt/_package.json | 0 .../math/base/special/sqrt/lib/index.js | 0 .../@stdlib/ndarray/numel/_package.json | 0 .../@stdlib/ndarray/numel/lib/index.js | 0 .../ndarray/vector/int32/_package.json | 0 .../@stdlib/ndarray/vector/int32/lib/index.js | 0 .../@stdlib/string/format/_package.json | 0 .../@stdlib/string/format/lib/index.js | 0 .../test/fixtures/unvalidated.js | 0 .../test/fixtures/valid.js | 0 .../test/test.js | 6 +++--- 31 files changed, 25 insertions(+), 24 deletions(-) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/README.md (77%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/examples/index.js (92%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/lib/add_package_to_scope.js (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/lib/create_vm_scope.js (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/lib/index.js (85%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/lib/main.js (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/lib/scope_defaults.json (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/lib/window.js (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/package.json (94%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/test/fixtures/invalid.js (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/test/fixtures/packages/@stdlib/array/complex64/_package.json (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/test/fixtures/packages/@stdlib/array/complex64/lib/index.js (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/test/fixtures/packages/@stdlib/constants/float64/pi/_package.json (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/test/fixtures/packages/@stdlib/constants/float64/pi/lib/index.js (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/test/fixtures/packages/@stdlib/math/base/special/abs/_package.json (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/test/fixtures/packages/@stdlib/math/base/special/abs/lib/index.js (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/test/fixtures/packages/@stdlib/math/base/special/pow/_package.json (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/test/fixtures/packages/@stdlib/math/base/special/pow/lib/index.js (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/test/fixtures/packages/@stdlib/math/base/special/sqrt/_package.json (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/test/fixtures/packages/@stdlib/math/base/special/sqrt/lib/index.js (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/test/fixtures/packages/@stdlib/ndarray/numel/_package.json (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/test/fixtures/packages/@stdlib/ndarray/numel/lib/index.js (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/test/fixtures/packages/@stdlib/ndarray/vector/int32/_package.json (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/test/fixtures/packages/@stdlib/ndarray/vector/int32/lib/index.js (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/test/fixtures/packages/@stdlib/string/format/_package.json (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/test/fixtures/packages/@stdlib/string/format/lib/index.js (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/test/fixtures/unvalidated.js (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/test/fixtures/valid.js (100%) rename lib/node_modules/@stdlib/_tools/eslint/rules/{tsdoc-doctest => tsdoc-declarations-doctest}/test/test.js (95%) diff --git a/etc/eslint/rules/typescript.js b/etc/eslint/rules/typescript.js index f4c7a6cdb624..1cdfa733846e 100644 --- a/etc/eslint/rules/typescript.js +++ b/etc/eslint/rules/typescript.js @@ -2715,13 +2715,13 @@ rules[ 'expect-type/expect' ] = 'error'; /** * Ensures return annotations in TSDoc examples match the actual output. * -* @name stdlib/tsdoc-doctest +* @name stdlib/tsdoc-declarations-doctest * @memberof rules * @type {string} * @default 'error' -* @see {@link module:@stdlib/_tools/eslint/rules/tsdoc-doctest} +* @see {@link module:@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest} */ -rules[ 'stdlib/tsdoc-doctest' ] = 'error'; +rules[ 'stdlib/tsdoc-declarations-doctest' ] = 'error'; // EXPORTS // 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 35de7aa7f5f4..817b943efba0 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/lib/index.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/lib/index.js @@ -1072,13 +1072,13 @@ setReadOnly( rules, 'section-headers', require( '@stdlib/_tools/eslint/rules/sec setReadOnly( rules, 'ternary-condition-parentheses', require( '@stdlib/_tools/eslint/rules/ternary-condition-parentheses' ) ); /** -* @name tsdoc-doctest +* @name tsdoc-declarations-doctest * @memberof rules * @readonly * @type {Function} -* @see {@link module:@stdlib/_tools/eslint/rules/tsdoc-doctest} +* @see {@link module:@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest} */ -setReadOnly( rules, 'tsdoc-doctest', require( '@stdlib/_tools/eslint/rules/tsdoc-doctest' ) ); +setReadOnly( rules, 'tsdoc-declarations-doctest', require( '@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest' ) ); /** * @name uppercase-required-constants diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/README.md b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/README.md similarity index 77% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/README.md rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/README.md index 9592aa16d6a5..2680b772702b 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/README.md +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/README.md @@ -18,9 +18,9 @@ limitations under the License. --> -# tsdoc-doctest +# tsdoc-declarations-doctest -> [ESLint rule][eslint-rules] to ensure that return annotations in TSDoc examples match the actual output. +> [ESLint rule][eslint-rules] to ensure that return annotations in TSDoc examples match the actual output in TypeScript declaration files (`.d.ts`).
@@ -33,16 +33,16 @@ limitations under the License. ## Usage ```javascript -var rule = require( '@stdlib/_tools/eslint/rules/tsdoc-doctest' ); +var rule = require( '@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest' ); ``` #### rule -[ESLint rule][eslint-rules] to ensure that return annotations in TSDoc examples match the actual output. Return annotations may start with `returns`, `throws`, or `=>`. `returns` follow variable declarations or assignment expressions, whereas `=>` follow expression-only forms including `console.log` calls. The rule validates `@example` blocks in TSDoc comments within `.d.ts` files by automatically resolving the corresponding implementation via the nearest `package.json` file. +[ESLint rule][eslint-rules] to ensure that return annotations in TSDoc examples match the actual output in TypeScript declaration files (`.d.ts`). Return annotations may start with `returns`, `throws`, or `=>`. `returns` follow variable declarations or assignment expressions, whereas `=>` follow expression-only forms including `console.log` calls. The rule validates `@example` blocks in TSDoc comments within `.d.ts` files by automatically resolving the corresponding implementation via the nearest `package.json` file. **Bad**: - + ```typescript /** @@ -93,13 +93,13 @@ export = add; ```javascript var Linter = require( 'eslint' ).Linter; var parser = require( '@typescript-eslint/parser' ); -var rule = require( '@stdlib/_tools/eslint/rules/tsdoc-doctest' ); +var rule = require( '@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest' ); var linter = new Linter(); // Register the TypeScript parser and ESLint rule: linter.defineParser( '@typescript-eslint/parser', parser ); -linter.defineRule( 'tsdoc-doctest', rule ); +linter.defineRule( 'tsdoc-declarations-doctest', rule ); // Generate our source code with incorrect return annotation: var code = [ @@ -126,7 +126,7 @@ var result = linter.verify( code, { 'sourceType': 'module' }, 'rules': { - 'tsdoc-doctest': 'error' + 'tsdoc-declarations-doctest': 'error' } }, { 'filename': '/path/to/project/lib/node_modules/@stdlib/math/base/special/abs/docs/types/index.d.ts' @@ -134,7 +134,7 @@ var result = linter.verify( code, { /* returns [ { - 'ruleId': 'tsdoc-doctest', + 'ruleId': 'tsdoc-declarations-doctest', 'severity': 2, 'message': 'Displayed return value is `2`, but expected `3` instead', 'line': 9, @@ -158,6 +158,7 @@ var result = linter.verify( code, { - The rule automatically resolves the implementation path by traversing up the directory tree to find the nearest `package.json` file and using its `main` field. - The rule skips validation if the `package.json` file cannot be found or if the resolved implementation cannot be loaded. - Examples are executed in a sandboxed VM context with limited globals for security. +- This rule is specifically designed for TypeScript declaration files and will only process files with a `.d.ts` extension.
diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/examples/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/examples/index.js similarity index 92% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/examples/index.js rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/examples/index.js index 421c7bc433ec..dbee7790d027 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/examples/index.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/examples/index.js @@ -26,7 +26,7 @@ var linter = new Linter(); // Register the TypeScript parser and ESLint rule: linter.defineParser( '@typescript-eslint/parser', parser ); -linter.defineRule( 'tsdoc-doctest', rule ); +linter.defineRule( 'tsdoc-declarations-doctest', rule ); // Generate our source code with incorrect return annotation: var code = [ @@ -53,7 +53,7 @@ var result = linter.verify( code, { 'sourceType': 'module' }, 'rules': { - 'tsdoc-doctest': 'error' + 'tsdoc-declarations-doctest': 'error' } }, { 'filename': 'lib/node_modules/@stdlib/math/base/special/abs/docs/types/index.d.ts' @@ -63,7 +63,7 @@ console.log( result ); /* => [ { - 'ruleId': 'tsdoc-doctest', + 'ruleId': 'tsdoc-declarations-doctest', 'severity': 2, 'message': 'Displayed return value is `2`, but expected `3` instead', 'line': 9, diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/add_package_to_scope.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/add_package_to_scope.js similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/add_package_to_scope.js rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/add_package_to_scope.js diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/create_vm_scope.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/create_vm_scope.js similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/create_vm_scope.js rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/create_vm_scope.js diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/index.js similarity index 85% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/index.js rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/index.js index bb012d0f7c87..2888b085c545 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/index.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/index.js @@ -21,10 +21,10 @@ /** * ESLint rule to ensure return annotations in TypeScript declaration examples match the actual output. * -* @module @stdlib/_tools/eslint/rules/tsdoc-doctest +* @module @stdlib/_tools/eslint/rules/tsdoc-declarations-doctest * * @example -* var rule = require( '@stdlib/_tools/eslint/rules/tsdoc-doctest' ); +* var rule = require( '@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest' ); * * console.log( rule ); */ diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/main.js similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/main.js rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/main.js diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/scope_defaults.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/scope_defaults.json similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/scope_defaults.json rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/scope_defaults.json diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/window.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/window.js similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/lib/window.js rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/window.js diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/package.json similarity index 94% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/package.json rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/package.json index a76dd13fbcd8..ec5c7edfc07a 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/package.json +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/package.json @@ -1,5 +1,5 @@ { - "name": "@stdlib/_tools/eslint/rules/tsdoc-doctest", + "name": "@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest", "version": "0.0.0", "description": "ESLint rule to ensure return annotations in TSDoc examples match the actual output.", "license": "Apache-2.0", diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/invalid.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/invalid.js similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/invalid.js rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/invalid.js diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/array/complex64/_package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/array/complex64/_package.json similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/array/complex64/_package.json rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/array/complex64/_package.json diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/array/complex64/lib/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/array/complex64/lib/index.js similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/array/complex64/lib/index.js rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/array/complex64/lib/index.js diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/constants/float64/pi/_package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/constants/float64/pi/_package.json similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/constants/float64/pi/_package.json rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/constants/float64/pi/_package.json diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/constants/float64/pi/lib/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/constants/float64/pi/lib/index.js similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/constants/float64/pi/lib/index.js rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/constants/float64/pi/lib/index.js diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/abs/_package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/math/base/special/abs/_package.json similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/abs/_package.json rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/math/base/special/abs/_package.json diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/abs/lib/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/math/base/special/abs/lib/index.js similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/abs/lib/index.js rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/math/base/special/abs/lib/index.js diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/pow/_package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/math/base/special/pow/_package.json similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/pow/_package.json rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/math/base/special/pow/_package.json diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/pow/lib/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/math/base/special/pow/lib/index.js similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/pow/lib/index.js rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/math/base/special/pow/lib/index.js diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/sqrt/_package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/math/base/special/sqrt/_package.json similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/sqrt/_package.json rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/math/base/special/sqrt/_package.json diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/sqrt/lib/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/math/base/special/sqrt/lib/index.js similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/math/base/special/sqrt/lib/index.js rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/math/base/special/sqrt/lib/index.js diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/numel/_package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/ndarray/numel/_package.json similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/numel/_package.json rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/ndarray/numel/_package.json diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/numel/lib/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/ndarray/numel/lib/index.js similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/numel/lib/index.js rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/ndarray/numel/lib/index.js diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/vector/int32/_package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/ndarray/vector/int32/_package.json similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/vector/int32/_package.json rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/ndarray/vector/int32/_package.json diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/vector/int32/lib/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/ndarray/vector/int32/lib/index.js similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/ndarray/vector/int32/lib/index.js rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/ndarray/vector/int32/lib/index.js diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/string/format/_package.json b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/string/format/_package.json similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/string/format/_package.json rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/string/format/_package.json diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/string/format/lib/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/string/format/lib/index.js similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/packages/@stdlib/string/format/lib/index.js rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/packages/@stdlib/string/format/lib/index.js diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/unvalidated.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/unvalidated.js similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/unvalidated.js rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/unvalidated.js diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/valid.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/valid.js similarity index 100% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/fixtures/valid.js rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/fixtures/valid.js diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/test.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/test.js similarity index 95% rename from lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/test.js rename to lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/test.js index d5de68857305..c06ff39a3c79 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-doctest/test/test.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/test/test.js @@ -65,7 +65,7 @@ tape( 'the function positively validates code where all return annotations insid }); try { - tester.run( 'tsdoc-doctest', rule, { + tester.run( 'tsdoc-declarations-doctest', rule, { 'valid': valid, 'invalid': [] }); @@ -86,7 +86,7 @@ tape( 'the function negatively validates code where not all return annotations i }); try { - tester.run( 'tsdoc-doctest', rule, { + tester.run( 'tsdoc-declarations-doctest', rule, { 'valid': [], 'invalid': invalid }); @@ -107,7 +107,7 @@ tape( 'the function does not validate comments without TSDoc examples', function }); try { - tester.run( 'tsdoc-doctest', rule, { + tester.run( 'tsdoc-declarations-doctest', rule, { 'valid': unvalidated, 'invalid': [] }); From 86ac0f0808702e1c8eefa72869871aa945b740f8 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 29 Sep 2025 03:06:31 -0700 Subject: [PATCH 08/18] docs: fix comment Signed-off-by: Athan --- etc/eslint/plugins/typescript.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/eslint/plugins/typescript.js b/etc/eslint/plugins/typescript.js index 5775526ae0a2..e030322a9d7b 100644 --- a/etc/eslint/plugins/typescript.js +++ b/etc/eslint/plugins/typescript.js @@ -32,7 +32,7 @@ var plugins = [ // Required for TypeScript support: '@typescript-eslint', - // Stdlib custom rules: + // Custom stdlib rules: 'stdlib' ]; From 1d346e55e7936388782f91bf13516a0664eb4f26 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 29 Sep 2025 03:07:49 -0700 Subject: [PATCH 09/18] docs: update description Signed-off-by: Athan --- .../_tools/eslint/rules/tsdoc-declarations-doctest/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/README.md b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/README.md index 2680b772702b..15a297d7f26c 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/README.md +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/README.md @@ -20,7 +20,7 @@ limitations under the License. # tsdoc-declarations-doctest -> [ESLint rule][eslint-rules] to ensure that return annotations in TSDoc examples match the actual output in TypeScript declaration files (`.d.ts`). +> [ESLint rule][eslint-rules] to ensure that return annotations in TSDoc examples match the actual output in TypeScript declaration files (`*.d.ts`).
From eb49b5feba7a3f2580de480f41acd8092985fe20 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 29 Sep 2025 03:08:18 -0700 Subject: [PATCH 10/18] docs: update description Signed-off-by: Athan --- .../_tools/eslint/rules/tsdoc-declarations-doctest/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/README.md b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/README.md index 15a297d7f26c..98718d9ae29b 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/README.md +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/README.md @@ -38,7 +38,7 @@ var rule = require( '@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest' ); #### rule -[ESLint rule][eslint-rules] to ensure that return annotations in TSDoc examples match the actual output in TypeScript declaration files (`.d.ts`). Return annotations may start with `returns`, `throws`, or `=>`. `returns` follow variable declarations or assignment expressions, whereas `=>` follow expression-only forms including `console.log` calls. The rule validates `@example` blocks in TSDoc comments within `.d.ts` files by automatically resolving the corresponding implementation via the nearest `package.json` file. +[ESLint rule][eslint-rules] to ensure that return annotations in TSDoc examples match the actual output in TypeScript declaration files (`*.d.ts`). Return annotations may start with `returns`, `throws`, or `=>`. `returns` follow variable declarations or assignment expressions, whereas `=>` follow expression-only forms including `console.log` calls. The rule validates `@example` blocks in TSDoc comments within `.d.ts` files by automatically resolving the corresponding implementation via the nearest `package.json` file. **Bad**: From f965f20632d9f418d6de15b9917609d22ab75202 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 29 Sep 2025 03:12:06 -0700 Subject: [PATCH 11/18] docs: fix notes placement and update description Signed-off-by: Athan --- .../tsdoc-declarations-doctest/README.md | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/README.md b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/README.md index 98718d9ae29b..8ffdf68fc546 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/README.md +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/README.md @@ -38,7 +38,7 @@ var rule = require( '@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest' ); #### rule -[ESLint rule][eslint-rules] to ensure that return annotations in TSDoc examples match the actual output in TypeScript declaration files (`*.d.ts`). Return annotations may start with `returns`, `throws`, or `=>`. `returns` follow variable declarations or assignment expressions, whereas `=>` follow expression-only forms including `console.log` calls. The rule validates `@example` blocks in TSDoc comments within `.d.ts` files by automatically resolving the corresponding implementation via the nearest `package.json` file. +[ESLint rule][eslint-rules] to ensure that return annotations in TSDoc examples match the actual output in TypeScript declaration files (`*.d.ts`). **Bad**: @@ -84,6 +84,20 @@ export = add; +
+ +## Notes + +- Return annotations may start with `returns`, `throws`, or `=>`. `returns` follow variable declarations or assignment expressions, whereas `=>` follow expression-only forms including `console.log` calls. +- The rule validates `@example` blocks in TSDoc comments within `*.d.ts` files by resolving the corresponding implementation via the nearest `package.json` file in the same or a parent directory and using its `main` field. +- The rule skips validation if the `package.json` file cannot be found or if the resolved implementation cannot be loaded. +- Examples are executed in a sandboxed VM context with limited globals for security. +- This rule is specifically designed for TypeScript declaration files and will only process files with a `*.d.ts` filename extension. + +
+ + +
## Examples @@ -151,19 +165,6 @@ var result = linter.verify( code, { -
- -## Notes - -- The rule automatically resolves the implementation path by traversing up the directory tree to find the nearest `package.json` file and using its `main` field. -- The rule skips validation if the `package.json` file cannot be found or if the resolved implementation cannot be loaded. -- Examples are executed in a sandboxed VM context with limited globals for security. -- This rule is specifically designed for TypeScript declaration files and will only process files with a `.d.ts` extension. - -
- - - From 1a1fc84ab5f4056a55f53cb12b3f3a3837046597 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 29 Sep 2025 03:17:15 -0700 Subject: [PATCH 14/18] docs: fix comment style Signed-off-by: Athan --- .../lib/add_package_to_scope.js | 32 +++---------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/add_package_to_scope.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/add_package_to_scope.js index 8b70523fed50..dc90de60a8cb 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/add_package_to_scope.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/add_package_to_scope.js @@ -20,41 +20,19 @@ // VARIABLES // -// Regular expressions for matching TypeScript declarations: - -/** -* Regular expression to match function declarations like "declare function abs( x: number ): number;" (captures function name). -* -* @type {RegExp} -*/ +// Regular expression to match function declarations such as "declare function abs( x: number ): number;" (captures function name): var RE_DECLARE_FUNCTION = /declare\s+function\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*[<(]/; -/** -* Regular expression to match variable declarations like "declare var someVar: SomeType;" (captures variable name). -* -* @type {RegExp} -*/ +// Regular expression to match variable declarations such as "declare var someVar: SomeType;" (captures variable name): var RE_DECLARE_VAR = /declare\s+var\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:/; -/** -* Regular expression to match class declarations like "declare class Complex64Array {" (captures class name). -* -* @type {RegExp} -*/ +// Regular expression to match class declarations such as "declare class Complex64Array {" (captures class name): var RE_DECLARE_CLASS = /declare\s+class\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s/; -/** -* Regular expression to match const declarations like "declare const PI: number;" (captures constant name). -* -* @type {RegExp} -*/ +// Regular expression to match const declarations such as "declare const PI: number;" (captures constant name): var RE_DECLARE_CONST = /declare\s+const\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:/; -/** -* Regular expression to match variable declarations with interface types like "declare var ctor: Int32Vector;" (captures variable name and interface name). -* -* @type {RegExp} -*/ +// Regular expression to match variable declarations with interface types such as "declare var ctor: Int32Vector;" (captures variable name and interface name): var RE_DECLARE_VAR_INTERFACE = /declare\s+var\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:\s*([A-Z][a-zA-Z0-9_$]*)/; From adbc30359e49c63353d9e012ca0112ba6cba042f Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 29 Sep 2025 03:18:27 -0700 Subject: [PATCH 15/18] style: don't break expressions Signed-off-by: Athan --- .../tsdoc-declarations-doctest/lib/add_package_to_scope.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/add_package_to_scope.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/add_package_to_scope.js index dc90de60a8cb..88b5fc3b2401 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/add_package_to_scope.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/add_package_to_scope.js @@ -54,9 +54,7 @@ function addPackageToScope( scope, pkg, sourceText ) { pkgType = typeof pkg; if ( pkgType === 'function' ) { - match = sourceText.match( RE_DECLARE_FUNCTION ) || - sourceText.match( RE_DECLARE_VAR ) || - sourceText.match( RE_DECLARE_CLASS ); + match = sourceText.match( RE_DECLARE_FUNCTION ) || sourceText.match( RE_DECLARE_VAR ) || sourceText.match( RE_DECLARE_CLASS ); // eslint-disable-line max-len if ( match ) { scope[ match[1] ] = pkg; } From 75bc34df7292d8df120013557eceb2c30d2e8e96 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 29 Sep 2025 03:39:31 -0700 Subject: [PATCH 16/18] refactor: avoid unnecessary intermediate variable Signed-off-by: Athan --- .../_tools/eslint/rules/tsdoc-declarations-doctest/lib/main.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/main.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/main.js index 137d9e8178bc..b8cac5b430b8 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/main.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/main.js @@ -185,8 +185,7 @@ function cleanTSDocComment( comment ) { var cleaned = replace( replace( comment, /^\/\*\*/, '' ), /\*\/$/, '' ); // Remove * at the beginning of lines - cleaned = replace( cleaned, RE_COMMENT_PREFIX, '' ); - return cleaned; + return replace( cleaned, RE_COMMENT_PREFIX, '' ); } /** From 7a94b5a5e37a0643e55675f977639252979a051a Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 29 Sep 2025 03:40:05 -0700 Subject: [PATCH 17/18] docs: update description Signed-off-by: Athan --- .../_tools/eslint/rules/tsdoc-declarations-doctest/lib/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/main.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/main.js index b8cac5b430b8..004bd0f8122d 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/main.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/main.js @@ -136,7 +136,7 @@ function findName( scope, expected ) { } /** -* Resolves the implementation path from package.json. +* Resolves the implementation path from the nearest parent `package.json`. * * @private * @param {string} filepath - TypeScript declaration file path From 3fe88ba436fefdf080fd45719a772fa9ce2e9857 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 29 Sep 2025 03:40:43 -0700 Subject: [PATCH 18/18] docs: update description Signed-off-by: Athan --- .../_tools/eslint/rules/tsdoc-declarations-doctest/lib/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/main.js b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/main.js index 004bd0f8122d..48e7ea182e5c 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/main.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/tsdoc-declarations-doctest/lib/main.js @@ -112,7 +112,7 @@ function countLines( str ) { } /** -* Searches for variable in scope matching the expected value. +* Searches for a variable in scope matching the expected value. * * @private * @param {Object} scope - VM scope