Skip to content

Commit caa46c4

Browse files
headlessNodekgrytePlaneshifter
authored
feat: add fixer function eslint/rules/repl-namespace-order
PR-URL: #3350 Co-authored-by: Athan Reines <[email protected]> Co-authored-by: Philipp Burckhardt <[email protected]> Reviewed-by: Philipp Burckhardt <[email protected]> Signed-off-by: Muhammad Haris <[email protected]>
1 parent aa5eadc commit caa46c4

File tree

4 files changed

+196
-36
lines changed

4 files changed

+196
-36
lines changed

lib/node_modules/@stdlib/_tools/eslint/rules/repl-namespace-order/README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ var rule = require( '@stdlib/_tools/eslint/rules/repl-namespace-order' );
3838

3939
#### rule
4040

41-
[ESLint rule][eslint-rules] to enforce that packages are added to a REPL namespace object in alphabetical order according to alias (namespace key).
41+
[ESLint rule][eslint-rules] to enforce that packages are added to a REPL namespace object in alphabetical order according to alias (namespace key).
4242

4343
**Bad**:
4444

@@ -117,8 +117,6 @@ var result;
117117
var code;
118118

119119
code = [
120-
'/* eslint-enable stdlib/repl-namespace-order */',
121-
'',
122120
'/* When adding names to the namespace, ensure that they are added in alphabetical order according to alias (namespace key). */',
123121
'',
124122
'ns.push({',

lib/node_modules/@stdlib/_tools/eslint/rules/repl-namespace-order/examples/index.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ var result;
2626
var code;
2727

2828
code = [
29-
'/* eslint-enable stdlib/repl-namespace-order */',
30-
'',
3129
'/* When adding names to the namespace, ensure that they are added in alphabetical order according to alias (namespace key). */',
3230
'',
3331
'ns.push({',

lib/node_modules/@stdlib/_tools/eslint/rules/repl-namespace-order/lib/main.js

Lines changed: 115 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -37,43 +37,81 @@ var OPTS_COMPARE = {
3737
* @returns {Object} validators
3838
*/
3939
function main( context ) {
40+
var expressions;
4041
var prevAlias;
4142

42-
return {
43-
'ObjectExpression': validate
44-
};
43+
expressions = [];
4544

4645
/**
47-
* Checks whether packages are added to a REPL namespace object in alphabetical order according to alias (namespace key).
46+
* Extracts the alias value from a given node.
4847
*
4948
* @private
50-
* @param {ASTNode} node - node to examine
49+
* @param {ASTNode} node - node containing properties to search
50+
* @returns {string} alias value
5151
*/
52-
function validate( node ) {
53-
var properties;
52+
function getAlias( node ) {
53+
var props;
5454
var alias;
55-
var prop;
5655
var i;
5756

58-
properties = node.properties;
59-
for ( i = 0; i < properties.length; i++ ) {
60-
prop = properties[ i ];
61-
if ( prop.key.value === 'alias' ) {
62-
alias = prop.value.value;
57+
props = node.properties;
58+
for ( i = 0; i < props.length; i++ ) {
59+
if ( props[ i ].key.value === 'alias' ) {
60+
alias = props[ i ].value.value;
6361
if ( alias ) {
64-
if (
65-
prevAlias &&
66-
alias.localeCompare( prevAlias, 'en', OPTS_COMPARE ) < 0 )
67-
{
68-
report( prevAlias, alias, node );
69-
} else {
70-
prevAlias = alias;
71-
}
62+
return alias;
7263
}
7364
}
7465
}
7566
}
7667

68+
/**
69+
* Compares two nodes and determines their order based on the alias property.
70+
*
71+
* @private
72+
* @param {ASTNode} a - first node
73+
* @param {ASTNode} b - second node
74+
* @returns {number} number indicating sort order
75+
*/
76+
function sortExpressions( a, b ) {
77+
var aliasA = getAlias( a.arguments[ 0 ] );
78+
var aliasB = getAlias( b.arguments[ 0 ] );
79+
return aliasA.localeCompare( aliasB, 'en', OPTS_COMPARE );
80+
}
81+
82+
/**
83+
* Fixes the lint error by reordering the packages.
84+
*
85+
* @private
86+
* @param {Function} fixer - ESLint fixer
87+
* @returns {(Object|null)} fix or null
88+
*/
89+
function fix( fixer ) {
90+
var replacingText;
91+
var startRange;
92+
var endRange;
93+
var sorted;
94+
var source;
95+
var txt;
96+
var i;
97+
98+
source = context.getSourceCode();
99+
replacingText = '';
100+
startRange = expressions[0].range[ 0 ];
101+
endRange = expressions[ expressions.length - 1 ].range[ 1 ];
102+
103+
sorted = expressions.slice().sort( sortExpressions );
104+
105+
for ( i = 0; i < sorted.length; i++ ) {
106+
txt = source.getText( sorted[ i ] );
107+
replacingText += txt;
108+
if ( i < sorted.length - 1 ) {
109+
replacingText += ';\n\n';
110+
}
111+
}
112+
return fixer.replaceTextRange( [ startRange, endRange ], replacingText ); // eslint-disable-line max-len
113+
}
114+
77115
/**
78116
* Reports the error message.
79117
*
@@ -85,19 +123,74 @@ function main( context ) {
85123
function report( last, current, node ) {
86124
context.report({
87125
'node': node,
88-
'message': '"'+current+'" should come before "'+last+'"'
126+
'message': '"'+current+'" should come before "'+last+'"',
127+
'fix': fix
89128
});
90129
}
130+
131+
/**
132+
* Checks whether the packages are added to a REPL namespace object in alphabetical order according to alias (namespace key).
133+
*
134+
* @private
135+
*/
136+
function validate() {
137+
var alias;
138+
var i;
139+
140+
for ( i = 0; i < expressions.length; i++ ) {
141+
alias = getAlias( expressions[ i ].arguments[ 0 ] );
142+
if (
143+
prevAlias &&
144+
alias.localeCompare( prevAlias, 'en', OPTS_COMPARE ) < 0
145+
) {
146+
report( prevAlias, alias, expressions[ i ].arguments[ 0 ] );
147+
} else {
148+
prevAlias = alias;
149+
}
150+
}
151+
}
152+
153+
/**
154+
* Collects all expressions which add a package to a REPL namespace.
155+
*
156+
* @private
157+
* @param {ASTNode} node - node to examine
158+
*/
159+
function collectExpressions( node ) {
160+
var object;
161+
var alias;
162+
163+
if (
164+
node.callee.type === 'MemberExpression' &&
165+
node.callee.object.name === 'ns' &&
166+
node.callee.property.name === 'push'
167+
) {
168+
object = node.arguments[ 0 ];
169+
if ( object.type === 'ObjectExpression' ) {
170+
alias = getAlias( object );
171+
if ( alias ) {
172+
expressions.push( node );
173+
}
174+
}
175+
}
176+
}
177+
178+
return {
179+
'CallExpression': collectExpressions,
180+
'Program:exit': validate
181+
};
91182
}
92183

93184

94185
// MAIN //
95186

96187
rule = {
97188
'meta': {
189+
'type': 'suggestion',
98190
'docs': {
99191
'description': 'enforce that packages are added to a REPL namespace object in alphabetical order according to alias (namespace key)'
100192
},
193+
'fixable': 'code',
101194
'schema': []
102195
},
103196
'create': main

lib/node_modules/@stdlib/_tools/eslint/rules/repl-namespace-order/test/fixtures/invalid.js

Lines changed: 80 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,67 @@ test = {
5858
'message': '"hasInt8ArraySupport" should come before "hasMapSupport"',
5959
'type': 'ObjectExpression'
6060
}
61-
]
61+
],
62+
'output': [
63+
'ns.push({',
64+
' \'alias\': \'hasInt8ArraySupport\',',
65+
' \'path\': \'@stdlib/assert/has-int8array-support\',',
66+
' \'value\': require( \'@stdlib/assert/has-int8array-support\' ),',
67+
' \'type\': \'Function\',',
68+
' \'related\': []',
69+
'});',
70+
'',
71+
'ns.push({',
72+
' \'alias\': \'hasInt32ArraySupport\',',
73+
' \'path\': \'@stdlib/assert/has-int32array-support\',',
74+
' \'value\': require( \'@stdlib/assert/has-int32array-support\' ),',
75+
' \'type\': \'Function\',',
76+
' \'related\': []',
77+
'});',
78+
'',
79+
'ns.push({',
80+
' \'alias\': \'hasMapSupport\',',
81+
' \'path\': \'@stdlib/assert/has-map-support\',',
82+
' \'value\': require( \'@stdlib/assert/has-map-support\' ),',
83+
' \'type\': \'Function\',',
84+
' \'related\': []',
85+
'});'
86+
].join( '\n' )
6287
};
6388
invalid.push( test );
6489

6590
test = {
6691
'code': [
92+
'ns.push({',
93+
' \'alias\': \'pop\',',
94+
' \'path\': \'@stdlib/utils/pop\',',
95+
' \'value\': require( \'@stdlib/utils/pop\' ),',
96+
' \'type\': \'Function\',',
97+
' \'related\': [',
98+
' \'@stdlib/utils/push\',',
99+
' \'@stdlib/utils/shift\',',
100+
' \'@stdlib/utils/unshift\'',
101+
' ]',
102+
'});',
103+
'',
104+
'ns.push({',
105+
' \'alias\': \'pluck\',',
106+
' \'path\': \'@stdlib/utils/pluck\',',
107+
' \'value\': require( \'@stdlib/utils/pluck\' ),',
108+
' \'type\': \'Function\',',
109+
' \'related\': [',
110+
' \'@stdlib/utils/deep-pluck\',',
111+
' \'@stdlib/utils/pick\'',
112+
' ]',
113+
'});'
114+
].join( '\n' ),
115+
'errors': [
116+
{
117+
'message': '"pluck" should come before "pop"',
118+
'type': 'ObjectExpression'
119+
}
120+
],
121+
'output': [
67122
'ns.push({',
68123
' \'alias\': \'pluck\',',
69124
' \'path\': \'@stdlib/utils/pluck\',',
@@ -86,14 +141,9 @@ test = {
86141
' \'@stdlib/utils/unshift\'',
87142
' ]',
88143
'});'
89-
].join( '\n' ),
90-
'errors': [
91-
{
92-
'message': '"hasInt32ArraySupport" should come before "hasMapSupport"',
93-
'type': 'ObjectExpression'
94-
}
95-
]
144+
].join( '\n' )
96145
};
146+
invalid.push( test );
97147

98148
test = {
99149
'code': [
@@ -122,7 +172,28 @@ test = {
122172
'message': '"AFINN_96" should come before "AFINN_111"',
123173
'type': 'ObjectExpression'
124174
}
125-
]
175+
],
176+
'output': [
177+
'ns.push({',
178+
' \'alias\': \'AFINN_96\',',
179+
' \'path\': \'@stdlib/datasets/afinn-96\',',
180+
' \'value\': require( \'@stdlib/datasets/afinn-96\' ),',
181+
' \'type\': \'Function\',',
182+
' \'related\': [',
183+
' \'@stdlib/datasets/afinn-111\'',
184+
' ]',
185+
'});',
186+
'',
187+
'ns.push({',
188+
' \'alias\': \'AFINN_111\',',
189+
' \'path\': \'@stdlib/datasets/afinn-111\',',
190+
' \'value\': require( \'@stdlib/datasets/afinn-111\' ),',
191+
' \'type\': \'Function\',',
192+
' \'related\': [',
193+
' \'@stdlib/datasets/afinn-96\'',
194+
' ]',
195+
'});'
196+
].join( '\n' )
126197
};
127198
invalid.push( test );
128199

0 commit comments

Comments
 (0)