Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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**:

Expand Down Expand Up @@ -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({',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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({',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand All @@ -85,19 +123,74 @@ 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
};
}


// MAIN //

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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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\',',
Expand All @@ -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': [
Expand Down Expand Up @@ -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 );

Expand Down
Loading