@@ -95,8 +95,12 @@ function create(context) {
95
95
const options = context . options
96
96
/** @type {[string, string] } */
97
97
const order = ( options [ 0 ] && options [ 0 ] . order ) || DEFAULT_ORDER
98
+ /** @type {boolean } */
99
+ const defineExposeLast = ( options [ 0 ] && options [ 0 ] . defineExposeLast ) || false
98
100
/** @type {Map<string, ASTNode> } */
99
101
const macrosNodes = new Map ( )
102
+ /** @type {ASTNode } */
103
+ let defineExposeNode
100
104
101
105
return utils . compositingVisitors (
102
106
utils . defineScriptSetupVisitor ( context , {
@@ -111,6 +115,9 @@ function create(context) {
111
115
} ,
112
116
onDefineSlotsExit ( node ) {
113
117
macrosNodes . set ( MACROS_SLOTS , getDefineMacrosStatement ( node ) )
118
+ } ,
119
+ onDefineExposeExit ( node ) {
120
+ defineExposeNode = getDefineMacrosStatement ( node )
114
121
}
115
122
} ) ,
116
123
{
@@ -131,6 +138,14 @@ function create(context) {
131
138
( data ) => utils . isDef ( data . node )
132
139
)
133
140
141
+ // check last node
142
+ if ( defineExposeLast ) {
143
+ const lastNode = program . body [ program . body . length - 1 ]
144
+ if ( defineExposeNode && lastNode !== defineExposeNode ) {
145
+ reportExposeNotOnBottom ( defineExposeNode , lastNode )
146
+ }
147
+ }
148
+
134
149
for ( const [ index , should ] of orderedList . entries ( ) ) {
135
150
const targetStatement = program . body [ firstStatementIndex + index ]
136
151
@@ -172,6 +187,58 @@ function create(context) {
172
187
} )
173
188
}
174
189
190
+ /**
191
+ * @param {ASTNode } node
192
+ * @param {ASTNode } lastNode
193
+ */
194
+ function reportExposeNotOnBottom ( node , lastNode ) {
195
+ context . report ( {
196
+ node,
197
+ loc : node . loc ,
198
+ messageId : 'defineExposeNotTheLast' ,
199
+ suggest : [
200
+ {
201
+ messageId : 'putExposeAtTheLast' ,
202
+ fix ( fixer ) {
203
+ return moveNodeToLast ( fixer , node , lastNode )
204
+ }
205
+ }
206
+ ]
207
+ } )
208
+ }
209
+
210
+ /**
211
+ * Move all lines of "node" with its comments to after the "target"
212
+ * @param {RuleFixer } fixer
213
+ * @param {ASTNode } node
214
+ * @param {ASTNode } target
215
+ */
216
+ function moveNodeToLast ( fixer , node , target ) {
217
+ // get comments under tokens(if any)
218
+ const beforeNodeToken = sourceCode . getTokenBefore ( node )
219
+ const nodeComment = sourceCode . getTokenAfter ( beforeNodeToken , {
220
+ includeComments : true
221
+ } )
222
+ const nextNodeComment = sourceCode . getTokenAfter ( node , {
223
+ includeComments : true
224
+ } )
225
+
226
+ // remove position: node (and comments) to next node (and comments)
227
+ const cutStart = getLineStartIndex ( nodeComment , beforeNodeToken )
228
+ const cutEnd = getLineStartIndex ( nextNodeComment , node )
229
+
230
+ // insert text: comment + node
231
+ const textNode = sourceCode . getText (
232
+ node ,
233
+ node . range [ 0 ] - beforeNodeToken . range [ 1 ]
234
+ )
235
+
236
+ return [
237
+ fixer . insertTextAfter ( target , textNode ) ,
238
+ fixer . removeRange ( [ cutStart , cutEnd ] )
239
+ ]
240
+ }
241
+
175
242
/**
176
243
* Move all lines of "node" with its comments to before the "target"
177
244
* @param {RuleFixer } fixer
@@ -255,6 +322,7 @@ module.exports = {
255
322
url : 'https://eslint.vuejs.org/rules/define-macros-order.html'
256
323
} ,
257
324
fixable : 'code' ,
325
+ hasSuggestions : true ,
258
326
schema : [
259
327
{
260
328
type : 'object' ,
@@ -266,14 +334,21 @@ module.exports = {
266
334
} ,
267
335
uniqueItems : true ,
268
336
additionalItems : false
337
+ } ,
338
+ defineExposeLast : {
339
+ type : 'boolean'
269
340
}
270
341
} ,
271
342
additionalProperties : false
272
343
}
273
344
] ,
274
345
messages : {
275
346
macrosNotOnTop :
276
- '{{macro}} should be the first statement in `<script setup>` (after any potential import statements or type definitions).'
347
+ '{{macro}} should be the first statement in `<script setup>` (after any potential import statements or type definitions).' ,
348
+ defineExposeNotTheLast :
349
+ '`defineExpose` should be the last statement in `<script setup>`.' ,
350
+ putExposeAtTheLast :
351
+ 'Put `defineExpose` as the last statement in `<script setup>`.'
277
352
}
278
353
} ,
279
354
create
0 commit comments