@@ -46,7 +46,7 @@ module.exports = {
4646 fixable : null ,
4747 schema : [ ] ,
4848 messages : {
49- forbidden : 'The `expose` after `await` expression are forbidden .'
49+ forbidden : '`{{name}}` is forbidden after an `await` expression.'
5050 }
5151 } ,
5252 /** @param {RuleContext } context */
@@ -55,147 +55,192 @@ module.exports = {
5555 * @typedef {object } SetupScopeData
5656 * @property {boolean } afterAwait
5757 * @property {[number,number] } range
58- * @property {Set< Identifier> } exposeReferenceIds
59- * @property {Set< Identifier> } contextReferenceIds
58+ * @property {(node: Identifier, callNode: CallExpression) => boolean } isExposeReferenceId
59+ * @property {(node: Identifier) => boolean } isContextReferenceId
6060 */
6161 /**
6262 * @typedef {object } ScopeStack
6363 * @property {ScopeStack | null } upper
64- * @property {FunctionDeclaration | FunctionExpression | ArrowFunctionExpression } scopeNode
64+ * @property {FunctionDeclaration | FunctionExpression | ArrowFunctionExpression | Program } scopeNode
6565 */
66- /** @type {Map<FunctionDeclaration | FunctionExpression | ArrowFunctionExpression, SetupScopeData> } */
66+ /** @type {Map<FunctionDeclaration | FunctionExpression | ArrowFunctionExpression | Program , SetupScopeData> } */
6767 const setupScopes = new Map ( )
6868
6969 /** @type {ScopeStack | null } */
7070 let scopeStack = null
7171
72- return utils . defineVueVisitor ( context , {
73- onSetupFunctionEnter ( node ) {
74- const contextParam = node . params [ 1 ]
75- if ( ! contextParam ) {
76- // no arguments
77- return
78- }
79- if ( contextParam . type === 'RestElement' ) {
80- // cannot check
81- return
82- }
83- if ( contextParam . type === 'ArrayPattern' ) {
84- // cannot check
85- return
72+ return utils . compositingVisitors (
73+ {
74+ /**
75+ * @param {Program } node
76+ */
77+ Program ( node ) {
78+ scopeStack = {
79+ upper : scopeStack ,
80+ scopeNode : node
81+ }
8682 }
87- /** @type {Set<Identifier> } */
88- const contextReferenceIds = new Set ( )
89- /** @type {Set<Identifier> } */
90- const exposeReferenceIds = new Set ( )
91- if ( contextParam . type === 'ObjectPattern' ) {
92- const exposeProperty = utils . findAssignmentProperty (
93- contextParam ,
94- 'expose'
95- )
96- if ( ! exposeProperty ) {
97- return
83+ } ,
84+ {
85+ /**
86+ * @param {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression } node
87+ */
88+ ':function' ( node ) {
89+ scopeStack = {
90+ upper : scopeStack ,
91+ scopeNode : node
9892 }
99- const exposeParam = exposeProperty . value
100- // `setup(props, {emit})`
101- const variable =
102- exposeParam . type === 'Identifier'
103- ? findVariable ( context . getScope ( ) , exposeParam )
104- : null
105- if ( ! variable ) {
93+ } ,
94+ ':function:exit' ( ) {
95+ scopeStack = scopeStack && scopeStack . upper
96+ } ,
97+ /** @param { AwaitExpression } node */
98+ AwaitExpression ( node ) {
99+ if ( ! scopeStack ) {
106100 return
107101 }
108- for ( const reference of variable . references ) {
109- if ( ! reference . isRead ( ) ) {
110- continue
111- }
112- exposeReferenceIds . add ( reference . identifier )
102+ const setupScope = setupScopes . get ( scopeStack . scopeNode )
103+ if ( ! setupScope || ! utils . inRange ( setupScope . range , node ) ) {
104+ return
113105 }
114- } else if ( contextParam . type === 'Identifier' ) {
115- // `setup(props, context)`
116- const variable = findVariable ( context . getScope ( ) , contextParam )
117- if ( ! variable ) {
106+ setupScope . afterAwait = true
107+ } ,
108+ /** @param {CallExpression } node */
109+ CallExpression ( node ) {
110+ if ( ! scopeStack ) {
118111 return
119112 }
120- for ( const reference of variable . references ) {
121- if ( ! reference . isRead ( ) ) {
122- continue
123- }
124- contextReferenceIds . add ( reference . identifier )
113+ const setupScope = setupScopes . get ( scopeStack . scopeNode )
114+ if (
115+ ! setupScope ||
116+ ! setupScope . afterAwait ||
117+ ! utils . inRange ( setupScope . range , node )
118+ ) {
119+ return
125120 }
126- }
127- setupScopes . set ( node , {
128- afterAwait : false ,
129- range : node . range ,
130- exposeReferenceIds,
131- contextReferenceIds
132- } )
133- } ,
134- /**
135- * @param {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression } node
136- */
137- ':function' ( node ) {
138- scopeStack = {
139- upper : scopeStack ,
140- scopeNode : node
141- }
142- } ,
143- ':function:exit' ( ) {
144- scopeStack = scopeStack && scopeStack . upper
145- } ,
146- /** @param {AwaitExpression } node */
147- AwaitExpression ( node ) {
148- if ( ! scopeStack ) {
149- return
150- }
151- const setupScope = setupScopes . get ( scopeStack . scopeNode )
152- if ( ! setupScope || ! utils . inRange ( setupScope . range , node ) ) {
153- return
154- }
155- setupScope . afterAwait = true
156- } ,
157- /** @param {CallExpression } node */
158- CallExpression ( node ) {
159- if ( ! scopeStack ) {
160- return
161- }
162- const setupScope = setupScopes . get ( scopeStack . scopeNode )
163- if (
164- ! setupScope ||
165- ! setupScope . afterAwait ||
166- ! utils . inRange ( setupScope . range , node )
167- ) {
168- return
169- }
170- const { contextReferenceIds, exposeReferenceIds } = setupScope
171- if (
172- node . callee . type === 'Identifier' &&
173- exposeReferenceIds . has ( node . callee )
174- ) {
175- // setup(props,{expose}) {expose()}
176- context . report ( {
177- node,
178- messageId : 'forbidden'
179- } )
180- } else {
181- const expose = getCalleeMemberNode ( node )
121+ const { isContextReferenceId, isExposeReferenceId } = setupScope
182122 if (
183- expose &&
184- expose . name === 'expose' &&
185- expose . member . object . type === 'Identifier' &&
186- contextReferenceIds . has ( expose . member . object )
123+ node . callee . type === 'Identifier' &&
124+ isExposeReferenceId ( node . callee , node )
187125 ) {
188- // setup(props,context ) {context.emit ()}
126+ // setup(props,{expose} ) {expose ()}
189127 context . report ( {
190128 node,
191- messageId : 'forbidden'
129+ messageId : 'forbidden' ,
130+ data : {
131+ name : node . callee . name
132+ }
192133 } )
134+ } else {
135+ const expose = getCalleeMemberNode ( node )
136+ if (
137+ expose &&
138+ expose . name === 'expose' &&
139+ expose . member . object . type === 'Identifier' &&
140+ isContextReferenceId ( expose . member . object )
141+ ) {
142+ // setup(props,context) {context.emit()}
143+ context . report ( {
144+ node,
145+ messageId : 'forbidden' ,
146+ data : {
147+ name : expose . name
148+ }
149+ } )
150+ }
193151 }
194152 }
195153 } ,
196- onSetupFunctionExit ( node ) {
197- setupScopes . delete ( node )
198- }
199- } )
154+ ( ( ) => {
155+ const scriptSetup = utils . getScriptSetupElement ( context )
156+ if ( ! scriptSetup ) {
157+ return { }
158+ }
159+ return {
160+ /**
161+ * @param {Program } node
162+ */
163+ Program ( node ) {
164+ context
165+ . getScope ( )
166+ . references . find ( ( ref ) => ref . identifier . name === 'defineExpose' )
167+ setupScopes . set ( node , {
168+ afterAwait : false ,
169+ range : scriptSetup . range ,
170+ isExposeReferenceId : ( _id , callNode ) =>
171+ callNode . parent . type === 'ExpressionStatement' &&
172+ callNode . parent . parent === node ,
173+ isContextReferenceId : ( ) => false
174+ } )
175+ }
176+ }
177+ } ) ( ) ,
178+ utils . defineVueVisitor ( context , {
179+ onSetupFunctionEnter ( node ) {
180+ const contextParam = node . params [ 1 ]
181+ if ( ! contextParam ) {
182+ // no arguments
183+ return
184+ }
185+ if ( contextParam . type === 'RestElement' ) {
186+ // cannot check
187+ return
188+ }
189+ if ( contextParam . type === 'ArrayPattern' ) {
190+ // cannot check
191+ return
192+ }
193+ /** @type {Set<Identifier> } */
194+ const contextReferenceIds = new Set ( )
195+ /** @type {Set<Identifier> } */
196+ const exposeReferenceIds = new Set ( )
197+ if ( contextParam . type === 'ObjectPattern' ) {
198+ const exposeProperty = utils . findAssignmentProperty (
199+ contextParam ,
200+ 'expose'
201+ )
202+ if ( ! exposeProperty ) {
203+ return
204+ }
205+ const exposeParam = exposeProperty . value
206+ // `setup(props, {emit})`
207+ const variable =
208+ exposeParam . type === 'Identifier'
209+ ? findVariable ( context . getScope ( ) , exposeParam )
210+ : null
211+ if ( ! variable ) {
212+ return
213+ }
214+ for ( const reference of variable . references ) {
215+ if ( ! reference . isRead ( ) ) {
216+ continue
217+ }
218+ exposeReferenceIds . add ( reference . identifier )
219+ }
220+ } else if ( contextParam . type === 'Identifier' ) {
221+ // `setup(props, context)`
222+ const variable = findVariable ( context . getScope ( ) , contextParam )
223+ if ( ! variable ) {
224+ return
225+ }
226+ for ( const reference of variable . references ) {
227+ if ( ! reference . isRead ( ) ) {
228+ continue
229+ }
230+ contextReferenceIds . add ( reference . identifier )
231+ }
232+ }
233+ setupScopes . set ( node , {
234+ afterAwait : false ,
235+ range : node . range ,
236+ isExposeReferenceId : ( id ) => exposeReferenceIds . has ( id ) ,
237+ isContextReferenceId : ( id ) => contextReferenceIds . has ( id )
238+ } )
239+ } ,
240+ onSetupFunctionExit ( node ) {
241+ setupScopes . delete ( node )
242+ }
243+ } )
244+ )
200245 }
201246}
0 commit comments