@@ -95,8 +95,12 @@ function create(context) {
9595 const options = context . options
9696 /** @type {[string, string] } */
9797 const order = ( options [ 0 ] && options [ 0 ] . order ) || DEFAULT_ORDER
98+ /** @type {boolean } */
99+ const defineExposeLast = ( options [ 0 ] && options [ 0 ] . defineExposeLast ) || false
98100 /** @type {Map<string, ASTNode> } */
99101 const macrosNodes = new Map ( )
102+ /** @type {ASTNode } */
103+ let defineExposeNode
100104
101105 return utils . compositingVisitors (
102106 utils . defineScriptSetupVisitor ( context , {
@@ -111,6 +115,9 @@ function create(context) {
111115 } ,
112116 onDefineSlotsExit ( node ) {
113117 macrosNodes . set ( MACROS_SLOTS , getDefineMacrosStatement ( node ) )
118+ } ,
119+ onDefineExposeExit ( node ) {
120+ defineExposeNode = getDefineMacrosStatement ( node )
114121 }
115122 } ) ,
116123 {
@@ -131,6 +138,14 @@ function create(context) {
131138 ( data ) => utils . isDef ( data . node )
132139 )
133140
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+
134149 for ( const [ index , should ] of orderedList . entries ( ) ) {
135150 const targetStatement = program . body [ firstStatementIndex + index ]
136151
@@ -172,6 +187,58 @@ function create(context) {
172187 } )
173188 }
174189
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+
175242 /**
176243 * Move all lines of "node" with its comments to before the "target"
177244 * @param {RuleFixer } fixer
@@ -255,6 +322,7 @@ module.exports = {
255322 url : 'https://eslint.vuejs.org/rules/define-macros-order.html'
256323 } ,
257324 fixable : 'code' ,
325+ hasSuggestions : true ,
258326 schema : [
259327 {
260328 type : 'object' ,
@@ -266,14 +334,21 @@ module.exports = {
266334 } ,
267335 uniqueItems : true ,
268336 additionalItems : false
337+ } ,
338+ defineExposeLast : {
339+ type : 'boolean'
269340 }
270341 } ,
271342 additionalProperties : false
272343 }
273344 ] ,
274345 messages : {
275346 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>`.'
277352 }
278353 } ,
279354 create
0 commit comments