@@ -241,5 +241,114 @@ module.exports = {
241241 assert ( typeof name === 'string' )
242242
243243 return VOID_ELEMENT_NAMES . has ( name . toLowerCase ( ) )
244+ } ,
245+
246+ /**
247+ * Check whether the given node is a Vue component based
248+ * on the filename and default export type
249+ * export default {} in .vue || .jsx
250+ * @param {ASTNode } node Node to check
251+ * @param {string } path File name with extension
252+ * @returns {boolean }
253+ */
254+ isVueComponentFile ( node , path ) {
255+ const isVueFile = path . endsWith ( '.vue' ) || path . endsWith ( '.jsx' )
256+ return isVueFile &&
257+ node . type === 'ExportDefaultDeclaration' &&
258+ node . declaration . type === 'ObjectExpression'
259+ } ,
260+
261+ /**
262+ * Check whether given node is Vue component
263+ * Vue.component('xxx', {}) || component('xxx', {})
264+ * @param {ASTNode } node Node to check
265+ * @returns {boolean }
266+ */
267+ isVueComponent ( node ) {
268+ const callee = node . callee
269+
270+ const isFullVueComponent = node . type === 'CallExpression' &&
271+ callee . type === 'MemberExpression' &&
272+ callee . object . type === 'Identifier' &&
273+ callee . object . name === 'Vue' &&
274+ callee . property . type === 'Identifier' &&
275+ callee . property . name === 'component' &&
276+ node . arguments . length &&
277+ node . arguments . slice ( - 1 ) [ 0 ] . type === 'ObjectExpression'
278+
279+ const isDestructedVueComponent = callee . type === 'Identifier' &&
280+ callee . name === 'component'
281+
282+ return isFullVueComponent || isDestructedVueComponent
283+ } ,
284+
285+ /**
286+ * Check whether given node is new Vue instance
287+ * new Vue({})
288+ * @param {ASTNode } node Node to check
289+ * @returns {boolean }
290+ */
291+ isVueInstance ( node ) {
292+ const callee = node . callee
293+ return node . type === 'NewExpression' &&
294+ callee . type === 'Identifier' &&
295+ callee . name === 'Vue' &&
296+ node . arguments . length &&
297+ node . arguments [ 0 ] . type === 'ObjectExpression'
298+ } ,
299+
300+ executeOnVueComponent ( context , cb ) {
301+ const filePath = context . getFilename ( )
302+ const _this = this
303+
304+ return {
305+ 'ExportDefaultDeclaration:exit' ( node ) {
306+ // export default {} in .vue || .jsx
307+ if ( ! _this . isVueComponentFile ( node , filePath ) ) return
308+ cb ( node . declaration . properties )
309+ } ,
310+ 'CallExpression:exit' ( node ) {
311+ // Vue.component('xxx', {}) || component('xxx', {})
312+ if ( ! _this . isVueComponent ( node ) ) return
313+ cb ( node . arguments . slice ( - 1 ) [ 0 ] . properties )
314+ } ,
315+ 'NewExpression:exit' ( node ) {
316+ // new Vue({})
317+ if ( ! _this . isVueInstance ( node ) ) return
318+ cb ( node . arguments [ 0 ] . properties )
319+ }
320+ }
321+ } ,
322+
323+ getComputedProperties ( componentProperties ) {
324+ const computedPropertiesNode = componentProperties
325+ . filter ( p =>
326+ p . key . type === 'Identifier' &&
327+ p . key . name === 'computed' &&
328+ p . value . type === 'ObjectExpression'
329+ ) [ 0 ]
330+
331+ if ( ! computedPropertiesNode ) { return [ ] }
332+
333+ const computedProperties = computedPropertiesNode . value . properties
334+
335+ return computedProperties . map ( cp => {
336+ const key = cp . key . name
337+ let value
338+
339+ if ( cp . value . type === 'FunctionExpression' ) {
340+ value = cp . value . body
341+ } else if ( cp . value . type === 'ObjectExpression' ) {
342+ value = cp . value . properties
343+ . filter ( p =>
344+ p . key . type === 'Identifier' &&
345+ p . key . name === 'get' &&
346+ p . value . type === 'FunctionExpression'
347+ )
348+ . map ( p => p . value . body ) [ 0 ]
349+ }
350+
351+ return { key, value }
352+ } )
244353 }
245354}
0 commit comments