From 8630e6017c41d5831894777a40cf21bbee34d357 Mon Sep 17 00:00:00 2001 From: headlessNode Date: Fri, 6 Dec 2024 20:06:18 +0500 Subject: [PATCH] feat: add fixer function --- .../rules/repl-namespace-order/lib/main.js | 142 +++++++++++++++--- .../test/fixtures/invalid.js | 89 +++++++++-- 2 files changed, 197 insertions(+), 34 deletions(-) diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/repl-namespace-order/lib/main.js b/lib/node_modules/@stdlib/_tools/eslint/rules/repl-namespace-order/lib/main.js index f451656f02a5..340ab1f31169 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/repl-namespace-order/lib/main.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/repl-namespace-order/lib/main.js @@ -37,57 +37,147 @@ var OPTS_COMPARE = { * @returns {Object} validators */ function main( context ) { + var expressions; var prevAlias; + var sorted; - return { - 'ObjectExpression': validate - }; + expressions = []; /** - * Checks whether packages are added to a REPL namespace object in alphabetical order according to alias (namespace key). + * Extracts the alias value from a given node. * * @private - * @param {ASTNode} node - node to examine + * @param {ASTNode} node - node containing properties to search + * @returns {string} alias value */ - function validate( node ) { - var properties; + function getAlias( node ) { + var props; var alias; - var prop; var i; - properties = node.properties; - for ( i = 0; i < properties.length; i++ ) { - prop = properties[ i ]; - if ( prop.key.value === 'alias' ) { - alias = prop.value.value; + props = node.properties; + for ( i = 0; i < props.length; i++ ) { + if ( props[ i ].key.value === 'alias' ) { + alias = props[ i ].value.value; if ( alias ) { - if ( - prevAlias && - alias.localeCompare( prevAlias, 'en', OPTS_COMPARE ) < 0 ) - { - report( prevAlias, alias, node ); - } else { - prevAlias = alias; - } + return alias; } } } } + /** + * Compares two nodes and determines their order based on the alias property. + * + * @private + * @param {ASTNode} a - first node + * @param {ASTNode} b - second node + * @returns {number} number indicating sort order + */ + function sortExpressions( a, b ) { + var aliasA = getAlias( a.arguments[ 0 ] ); + var aliasB = getAlias( b.arguments[ 0 ] ); + return aliasA.localeCompare( aliasB, 'en', OPTS_COMPARE ); + } + /** * Reports the error message. * * @private - * @param {string} last - name of first package - * @param {string} current - name of second package + * @param {string} current - name of first package + * @param {string} last - name of second package * @param {ASTNode} node - node to report */ - function report( last, current, node ) { + function report( current, last, node ) { context.report({ 'node': node, - 'message': '"'+current+'" should come before "'+last+'"' + 'message': '"'+last+'" should come before "'+current+'"', + 'fix': fix }); + + /** + * Fixes the lint error by reordering the packages. + * @private + * @param {Function} fixer - ESLint fixer + * @returns {(Object|null)} fix or null + */ + function fix( fixer ) { + var replacingText; + var startRange; + var endRange; + var source; + var txt; + var i; + + source = context.getSourceCode(); + replacingText = ''; + startRange = expressions[0].range[ 0 ]; + endRange = expressions[ expressions.length - 1 ].range[ 1 ]; + + sorted = expressions.slice().sort( sortExpressions ); + + for ( i = 0; i < sorted.length; i++ ) { + txt = source.getText( sorted[ i ] ); + replacingText += txt; + if ( i < sorted.length - 1 ) { + replacingText += ';\n\n'; + } + } + return fixer.replaceTextRange( [ startRange, endRange ], replacingText ); // eslint-disable-line max-len + } + } + + /** + * Checks whether the packages are added to REPL namespace object in alphabetical order according to alias (namespace key). + * + * @private + */ + function validate( ) { + var alias; + var i; + + for ( i = 0; i < expressions.length; i++ ) { + alias = getAlias( expressions[ i ].arguments[ 0 ] ); + if ( + prevAlias && + alias.localeCompare( prevAlias, 'en', OPTS_COMPARE ) < 0 + ) { + report( prevAlias, alias, expressions[ i ].arguments[ 0 ] ); + } else { + prevAlias = alias; + } + } + } + + /** + * Collects all expressions which add a package to REPL namespace. + * + * @private + * @param {ASTNode} node - node to examine + */ + function collectExpressions( node ) { + var object; + var alias; + + if ( + node.callee.type === 'MemberExpression' && + node.callee.object.name === 'ns' && + node.callee.property.name === 'push' + ) { + object = node.arguments[ 0 ]; + if ( object.type === 'ObjectExpression' ) { + alias = getAlias( object ); + if ( alias ) { + expressions.push( node ); + } + } + } } + + return { + 'CallExpression': collectExpressions, + 'Program:exit': validate + }; } @@ -95,9 +185,11 @@ function main( context ) { rule = { 'meta': { + 'type': 'layout', 'docs': { 'description': 'enforce that packages are added to a REPL namespace object in alphabetical order according to alias (namespace key)' }, + 'fixable': 'code', 'schema': [] }, 'create': main diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/repl-namespace-order/test/fixtures/invalid.js b/lib/node_modules/@stdlib/_tools/eslint/rules/repl-namespace-order/test/fixtures/invalid.js index ca56212d2543..babaf0a3aad2 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/repl-namespace-order/test/fixtures/invalid.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/repl-namespace-order/test/fixtures/invalid.js @@ -58,12 +58,67 @@ test = { 'message': '"hasInt8ArraySupport" should come before "hasMapSupport"', 'type': 'ObjectExpression' } - ] + ], + 'output': [ + 'ns.push({', + ' \'alias\': \'hasInt8ArraySupport\',', + ' \'path\': \'@stdlib/assert/has-int8array-support\',', + ' \'value\': require( \'@stdlib/assert/has-int8array-support\' ),', + ' \'type\': \'Function\',', + ' \'related\': []', + '});', + '', + 'ns.push({', + ' \'alias\': \'hasInt32ArraySupport\',', + ' \'path\': \'@stdlib/assert/has-int32array-support\',', + ' \'value\': require( \'@stdlib/assert/has-int32array-support\' ),', + ' \'type\': \'Function\',', + ' \'related\': []', + '});', + '', + 'ns.push({', + ' \'alias\': \'hasMapSupport\',', + ' \'path\': \'@stdlib/assert/has-map-support\',', + ' \'value\': require( \'@stdlib/assert/has-map-support\' ),', + ' \'type\': \'Function\',', + ' \'related\': []', + '});' + ].join( '\n' ) }; invalid.push( test ); test = { 'code': [ + 'ns.push({', + ' \'alias\': \'pop\',', + ' \'path\': \'@stdlib/utils/pop\',', + ' \'value\': require( \'@stdlib/utils/pop\' ),', + ' \'type\': \'Function\',', + ' \'related\': [', + ' \'@stdlib/utils/push\',', + ' \'@stdlib/utils/shift\',', + ' \'@stdlib/utils/unshift\'', + ' ]', + '});', + '', + 'ns.push({', + ' \'alias\': \'pluck\',', + ' \'path\': \'@stdlib/utils/pluck\',', + ' \'value\': require( \'@stdlib/utils/pluck\' ),', + ' \'type\': \'Function\',', + ' \'related\': [', + ' \'@stdlib/utils/deep-pluck\',', + ' \'@stdlib/utils/pick\'', + ' ]', + '});' + ].join( '\n' ), + 'errors': [ + { + 'message': '"pluck" should come before "pop"', + 'type': 'ObjectExpression' + } + ], + 'output': [ 'ns.push({', ' \'alias\': \'pluck\',', ' \'path\': \'@stdlib/utils/pluck\',', @@ -86,14 +141,9 @@ test = { ' \'@stdlib/utils/unshift\'', ' ]', '});' - ].join( '\n' ), - 'errors': [ - { - 'message': '"hasInt32ArraySupport" should come before "hasMapSupport"', - 'type': 'ObjectExpression' - } - ] + ].join( '\n' ) }; +invalid.push( test ); test = { 'code': [ @@ -122,7 +172,28 @@ test = { 'message': '"AFINN_96" should come before "AFINN_111"', 'type': 'ObjectExpression' } - ] + ], + 'output': [ + 'ns.push({', + ' \'alias\': \'AFINN_96\',', + ' \'path\': \'@stdlib/datasets/afinn-96\',', + ' \'value\': require( \'@stdlib/datasets/afinn-96\' ),', + ' \'type\': \'Function\',', + ' \'related\': [', + ' \'@stdlib/datasets/afinn-111\'', + ' ]', + '});', + '', + 'ns.push({', + ' \'alias\': \'AFINN_111\',', + ' \'path\': \'@stdlib/datasets/afinn-111\',', + ' \'value\': require( \'@stdlib/datasets/afinn-111\' ),', + ' \'type\': \'Function\',', + ' \'related\': [', + ' \'@stdlib/datasets/afinn-96\'', + ' ]', + '});' + ].join( '\n' ) }; invalid.push( test );