@@ -8,6 +8,12 @@ import importType from '../core/importType';
8
8
import isStaticRequire from '../core/staticRequire' ;
9
9
import docsUrl from '../docsUrl' ;
10
10
11
+ const categories = {
12
+ named : 'named' ,
13
+ import : 'import' ,
14
+ exports : 'exports' ,
15
+ } ;
16
+
11
17
const defaultGroups = [ 'builtin' , 'external' , 'parent' , 'sibling' , 'index' ] ;
12
18
13
19
// REPORTING AND FIXING
@@ -169,16 +175,38 @@ function isPlainImportEquals(node) {
169
175
return node . type === 'TSImportEqualsDeclaration' && node . moduleReference . expression ;
170
176
}
171
177
172
- function isModuleExports ( node ) {
173
- return node . parent . parent . type === 'Program'
174
- && (
175
- node . left . type === 'Identifier'
176
- && node . left . name === 'exports' )
177
- || node . left . type === 'MemberExpression'
178
- && node . left . object . type === 'Identifier'
179
- && node . left . object . name === 'module'
180
- && node . left . property . type === 'Identifier'
181
- && node . left . property . name === 'exports' ;
178
+ function isCJSExports ( context , node ) {
179
+ if ( node . type === 'MemberExpression'
180
+ && node . object . type === 'Identifier'
181
+ && node . property . type === 'Identifier'
182
+ && node . object . name === 'module'
183
+ && node . property . name === 'exports' ) {
184
+ return context . sourceCode . getScope ( node ) . variables . findIndex ( ( variable ) => variable . name === 'module' ) === - 1 ;
185
+ } else if ( node . type === 'Identifier'
186
+ && node . name === 'exports' ) {
187
+ return context . sourceCode . getScope ( node ) . variables . findIndex ( ( variable ) => variable . name === 'exports' ) === - 1 ;
188
+ }
189
+ }
190
+
191
+ function getNamedCJSExports ( context , node ) {
192
+ if ( node . type !== 'MemberExpression' ) {
193
+ return ;
194
+ }
195
+ const result = [ ] ;
196
+ let root = node ;
197
+ while ( root . type === 'MemberExpression' ) {
198
+ if ( root . property . type !== 'Identifier' ) {
199
+ return ;
200
+ }
201
+ result . unshift ( root . property . name ) ;
202
+ root = root . object ;
203
+ }
204
+ if ( isCJSExports ( context , root ) ) {
205
+ return result ;
206
+ }
207
+ if ( isCJSExports ( context , root . parent ) ) {
208
+ return result . slice ( 1 ) ;
209
+ }
182
210
}
183
211
184
212
function canCrossNodeWhileReorder ( node ) {
@@ -216,13 +244,15 @@ function makeImportDescription(node) {
216
244
return 'import' ;
217
245
}
218
246
219
- function fixOutOfOrder ( context , firstNode , secondNode , order , named ) {
247
+ function fixOutOfOrder ( context , firstNode , secondNode , order , category ) {
248
+ const isNamed = category === categories . named ;
249
+ const isExports = category === categories . exports ;
220
250
const sourceCode = context . getSourceCode ( ) ;
221
251
222
252
const {
223
253
firstRoot,
224
254
secondRoot,
225
- } = named ? {
255
+ } = isNamed ? {
226
256
firstRoot : firstNode . node ,
227
257
secondRoot : secondNode . node ,
228
258
} : {
@@ -257,7 +287,7 @@ function fixOutOfOrder(context, firstNode, secondNode, order, named) {
257
287
return text . slice ( 0 , i + 1 ) ;
258
288
}
259
289
260
- if ( named ) {
290
+ if ( isNamed ) {
261
291
const firstCode = sourceCode . text . substring ( firstRootStart , firstRootEnd ) ;
262
292
const secondCode = sourceCode . text . substring ( secondRootStart , secondRootEnd ) ;
263
293
@@ -285,7 +315,7 @@ function fixOutOfOrder(context, firstNode, secondNode, order, named) {
285
315
} ) ;
286
316
}
287
317
} else {
288
- const canFix = canReorderItems ( firstRoot , secondRoot ) ;
318
+ const canFix = isExports || canReorderItems ( firstRoot , secondRoot ) ;
289
319
let newCode = sourceCode . text . substring ( secondRootStart , secondRootEnd ) ;
290
320
291
321
if ( newCode [ newCode . length - 1 ] !== '\n' ) {
@@ -314,16 +344,16 @@ function fixOutOfOrder(context, firstNode, secondNode, order, named) {
314
344
}
315
345
}
316
346
317
- function reportOutOfOrder ( context , imported , outOfOrder , order , named ) {
347
+ function reportOutOfOrder ( context , imported , outOfOrder , order , category ) {
318
348
outOfOrder . forEach ( function ( imp ) {
319
349
const found = imported . find ( function hasHigherRank ( importedItem ) {
320
350
return importedItem . rank > imp . rank ;
321
351
} ) ;
322
- fixOutOfOrder ( context , found , imp , order , named ) ;
352
+ fixOutOfOrder ( context , found , imp , order , category ) ;
323
353
} ) ;
324
354
}
325
355
326
- function makeOutOfOrderReport ( context , imported , named ) {
356
+ function makeOutOfOrderReport ( context , imported , category ) {
327
357
const outOfOrder = findOutOfOrder ( imported ) ;
328
358
if ( ! outOfOrder . length ) {
329
359
return ;
@@ -333,10 +363,10 @@ function makeOutOfOrderReport(context, imported, named) {
333
363
const reversedImported = reverse ( imported ) ;
334
364
const reversedOrder = findOutOfOrder ( reversedImported ) ;
335
365
if ( reversedOrder . length < outOfOrder . length ) {
336
- reportOutOfOrder ( context , reversedImported , reversedOrder , 'after' , named ) ;
366
+ reportOutOfOrder ( context , reversedImported , reversedOrder , 'after' , category ) ;
337
367
return ;
338
368
}
339
- reportOutOfOrder ( context , imported , outOfOrder , 'before' , named ) ;
369
+ reportOutOfOrder ( context , imported , outOfOrder , 'before' , category ) ;
340
370
}
341
371
342
372
const compareString = ( a , b ) => {
@@ -810,6 +840,7 @@ module.exports = {
810
840
} ;
811
841
}
812
842
const importMap = new Map ( ) ;
843
+ const exportMap = new Map ( ) ;
813
844
814
845
function getBlockImports ( node ) {
815
846
if ( ! importMap . has ( node ) ) {
@@ -818,6 +849,13 @@ module.exports = {
818
849
return importMap . get ( node ) ;
819
850
}
820
851
852
+ function getBlockExports ( node ) {
853
+ if ( ! exportMap . has ( node ) ) {
854
+ exportMap . set ( node , [ ] ) ;
855
+ }
856
+ return exportMap . get ( node ) ;
857
+ }
858
+
821
859
function makeNamedOrderReport ( context , namedImports ) {
822
860
if ( namedImports . length > 1 ) {
823
861
const imports = namedImports . map (
@@ -837,7 +875,7 @@ module.exports = {
837
875
mutateRanksToAlphabetize ( imports , alphabetize ) ;
838
876
}
839
877
840
- makeOutOfOrderReport ( context , imports , true ) ;
878
+ makeOutOfOrderReport ( context , imports , categories . named ) ;
841
879
}
842
880
}
843
881
@@ -964,25 +1002,39 @@ module.exports = {
964
1002
} : { } ,
965
1003
...named . cjsExports && {
966
1004
AssignmentExpression : function orderModuleExportNames ( node ) {
967
- if ( isModuleExports ( node ) ) {
968
- if ( node . right . type === 'ObjectExpression' ) {
969
- for ( let i = 0 ; i < node . right . properties . length ; i ++ ) {
970
- if ( node . right . properties [ i ] . key . type !== 'Identifier' || node . right . properties [ i ] . value . type !== 'Identifier' ) {
971
- return ;
1005
+ if ( node . parent . type === 'ExpressionStatement' ) {
1006
+ if ( isCJSExports ( context , node . left ) ) {
1007
+ if ( node . right . type === 'ObjectExpression' ) {
1008
+ for ( let i = 0 ; i < node . right . properties . length ; i ++ ) {
1009
+ if ( node . right . properties [ i ] . key . type !== 'Identifier' || node . right . properties [ i ] . value . type !== 'Identifier' ) {
1010
+ return ;
1011
+ }
972
1012
}
973
- }
974
1013
975
- makeNamedOrderReport (
976
- context ,
977
- node . right . properties . map (
978
- ( prop ) => ( {
979
- node : prop ,
980
- value : prop . key . name ,
981
- type : 'export' ,
982
- ...prop . key . range [ 0 ] !== prop . value . range [ 0 ] && {
983
- alias : prop . value . name ,
984
- } ,
985
- } ) ) ) ;
1014
+ makeNamedOrderReport (
1015
+ context ,
1016
+ node . right . properties . map (
1017
+ ( prop ) => ( {
1018
+ node : prop ,
1019
+ value : prop . key . name ,
1020
+ type : 'export' ,
1021
+ ...prop . key . range [ 0 ] !== prop . value . range [ 0 ] && {
1022
+ alias : prop . value . name ,
1023
+ } ,
1024
+ } ) ) ) ;
1025
+ }
1026
+ } else {
1027
+ const nameParts = getNamedCJSExports ( context , node . left ) ;
1028
+ if ( nameParts && nameParts . length > 0 ) {
1029
+ const name = nameParts . join ( '.' ) ;
1030
+ getBlockExports ( node . parent . parent ) . push ( {
1031
+ node,
1032
+ value : name ,
1033
+ displayName : name ,
1034
+ type : 'export' ,
1035
+ rank : 0 ,
1036
+ } ) ;
1037
+ }
986
1038
}
987
1039
}
988
1040
} ,
@@ -997,10 +1049,18 @@ module.exports = {
997
1049
mutateRanksToAlphabetize ( imported , alphabetize ) ;
998
1050
}
999
1051
1000
- makeOutOfOrderReport ( context , imported , false ) ;
1052
+ makeOutOfOrderReport ( context , imported , categories . import ) ;
1053
+ } ) ;
1054
+
1055
+ exportMap . forEach ( ( exported ) => {
1056
+ if ( alphabetize . order !== 'ignore' ) {
1057
+ mutateRanksToAlphabetize ( exported , alphabetize ) ;
1058
+ makeOutOfOrderReport ( context , exported , categories . exports ) ;
1059
+ }
1001
1060
} ) ;
1002
1061
1003
1062
importMap . clear ( ) ;
1063
+ exportMap . clear ( ) ;
1004
1064
} ,
1005
1065
} ;
1006
1066
} ,
0 commit comments