diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/repl-namespace-order/README.md b/lib/node_modules/@stdlib/_tools/eslint/rules/repl-namespace-order/README.md index c6bc1a2448a0..2d4de5d418cc 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/repl-namespace-order/README.md +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/repl-namespace-order/README.md @@ -38,7 +38,7 @@ var rule = require( '@stdlib/_tools/eslint/rules/repl-namespace-order' ); #### rule -[ESLint rule][eslint-rules] to enforce that packages are added to a REPL namespace object in alphabetical order according to alias (namespace key). +[ESLint rule][eslint-rules] to enforce that packages are added to a REPL namespace object in alphabetical order according to alias (namespace key). **Bad**: @@ -117,8 +117,6 @@ var result; var code; code = [ - '/* eslint-enable stdlib/repl-namespace-order */', - '', '/* When adding names to the namespace, ensure that they are added in alphabetical order according to alias (namespace key). */', '', 'ns.push({', diff --git a/lib/node_modules/@stdlib/_tools/eslint/rules/repl-namespace-order/examples/index.js b/lib/node_modules/@stdlib/_tools/eslint/rules/repl-namespace-order/examples/index.js index 789d95dc36b9..fcff2649d875 100644 --- a/lib/node_modules/@stdlib/_tools/eslint/rules/repl-namespace-order/examples/index.js +++ b/lib/node_modules/@stdlib/_tools/eslint/rules/repl-namespace-order/examples/index.js @@ -26,8 +26,6 @@ var result; var code; code = [ - '/* eslint-enable stdlib/repl-namespace-order */', - '', '/* When adding names to the namespace, ensure that they are added in alphabetical order according to alias (namespace key). */', '', 'ns.push({', 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..a75bd4e8b64d 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,43 +37,81 @@ var OPTS_COMPARE = { * @returns {Object} validators */ function main( context ) { + var expressions; var prevAlias; - 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 ); + } + + /** + * 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 sorted; + 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 + } + /** * Reports the error message. * @@ -85,9 +123,62 @@ function main( context ) { function report( last, current, node ) { context.report({ 'node': node, - 'message': '"'+current+'" should come before "'+last+'"' + 'message': '"'+current+'" should come before "'+last+'"', + 'fix': fix }); } + + /** + * Checks whether the packages are added to a 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 a 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 +186,11 @@ function main( context ) { rule = { 'meta': { + 'type': 'suggestion', '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 );