Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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 @@ -37,67 +37,159 @@ 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
};
}


// MAIN //

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
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