15
15
* @typedef {import('../../typings/eslint-plugin-vue/util-types/utils').ComponentArrayProp } ComponentArrayProp
16
16
* @typedef {import('../../typings/eslint-plugin-vue/util-types/utils').ComponentObjectProp } ComponentObjectProp
17
17
* @typedef {import('../../typings/eslint-plugin-vue/util-types/utils').ComponentTypeProp } ComponentTypeProp
18
- */
19
- /**
20
- * @typedef {object } ComponentArrayEmitDetectName
21
- * @property {'array' } type
22
- * @property {Literal | TemplateLiteral } key
23
- * @property {string } emitName
24
- * @property {null } value
25
- * @property {Expression | SpreadElement } node
26
- *
27
- * @typedef {object } ComponentArrayEmitUnknownName
28
- * @property {'array' } type
29
- * @property {null } key
30
- * @property {null } emitName
31
- * @property {null } value
32
- * @property {Expression | SpreadElement } node
33
- *
34
- * @typedef {ComponentArrayEmitDetectName | ComponentArrayEmitUnknownName } ComponentArrayEmit
35
- *
36
- * @typedef {object } ComponentObjectEmitDetectName
37
- * @property {'object' } type
38
- * @property {Expression } key
39
- * @property {string } emitName
40
- * @property {Expression } value
41
- * @property {Property } node
42
- *
43
- * @typedef {object } ComponentObjectEmitUnknownName
44
- * @property {'object' } type
45
- * @property {null } key
46
- * @property {null } emitName
47
- * @property {Expression } value
48
- * @property {Property } node
49
- *
50
- * @typedef {ComponentObjectEmitDetectName | ComponentObjectEmitUnknownName } ComponentObjectEmit
18
+ * @typedef {import('../../typings/eslint-plugin-vue/util-types/utils').ComponentArrayEmit } ComponentArrayEmit
19
+ * @typedef {import('../../typings/eslint-plugin-vue/util-types/utils').ComponentObjectEmit } ComponentObjectEmit
20
+ * @typedef {import('../../typings/eslint-plugin-vue/util-types/utils').ComponentTypeEmit } ComponentTypeEmit
51
21
*/
52
22
/**
53
23
* @typedef { {key: string | null, value: BlockStatement | null} } ComponentComputedProperty
@@ -82,7 +52,10 @@ const path = require('path')
82
52
const vueEslintParser = require ( 'vue-eslint-parser' )
83
53
const traverseNodes = vueEslintParser . AST . traverseNodes
84
54
const { findVariable } = require ( 'eslint-utils' )
85
- const { getComponentPropsFromTypeDefine } = require ( './ts-ast-utils' )
55
+ const {
56
+ getComponentPropsFromTypeDefine,
57
+ getComponentEmitsFromTypeDefine
58
+ } = require ( './ts-ast-utils' )
86
59
87
60
/**
88
61
* @type { WeakMap<RuleContext, Token[]> }
@@ -769,49 +742,7 @@ module.exports = {
769
742
return [ ]
770
743
}
771
744
772
- if ( emitsNode . value . type === 'ObjectExpression' ) {
773
- return emitsNode . value . properties . filter ( isProperty ) . map ( ( prop ) => {
774
- const emitName = getStaticPropertyName ( prop )
775
- if ( emitName != null ) {
776
- return {
777
- type : 'object' ,
778
- key : prop . key ,
779
- emitName,
780
- value : skipTSAsExpression ( prop . value ) ,
781
- node : prop
782
- }
783
- }
784
- return {
785
- type : 'object' ,
786
- key : null ,
787
- emitName : null ,
788
- value : skipTSAsExpression ( prop . value ) ,
789
- node : prop
790
- }
791
- } )
792
- } else {
793
- return emitsNode . value . elements . filter ( isDef ) . map ( ( prop ) => {
794
- if ( prop . type === 'Literal' || prop . type === 'TemplateLiteral' ) {
795
- const emitName = getStringLiteralValue ( prop )
796
- if ( emitName != null ) {
797
- return {
798
- type : 'array' ,
799
- key : prop ,
800
- emitName,
801
- value : null ,
802
- node : prop
803
- }
804
- }
805
- }
806
- return {
807
- type : 'array' ,
808
- key : null ,
809
- emitName : null ,
810
- value : null ,
811
- node : prop
812
- }
813
- } )
814
- }
745
+ return getComponentEmitsFromDefine ( emitsNode . value )
815
746
} ,
816
747
817
748
/**
@@ -1051,6 +982,8 @@ module.exports = {
1051
982
*
1052
983
* - `onDefinePropsEnter` ... Event when defineProps is found.
1053
984
* - `onDefinePropsExit` ... Event when defineProps visit ends.
985
+ * - `onDefineEmitsEnter` ... Event when defineEmits is found.
986
+ * - `onDefineEmitsExit` ... Event when defineEmits visit ends.
1054
987
*
1055
988
* @param {RuleContext } context The ESLint rule context object.
1056
989
* @param {ScriptSetupVisitor } visitor The visitor to traverse the AST nodes.
@@ -1120,9 +1053,11 @@ module.exports = {
1120
1053
return null
1121
1054
}
1122
1055
1123
- if ( visitor . onDefinePropsEnter || visitor . onDefinePropsExit ) {
1124
- const definePropsMap = new Map ( )
1125
-
1056
+ const hasPropsEvent =
1057
+ visitor . onDefinePropsEnter || visitor . onDefinePropsExit
1058
+ const hasEmitsEvent =
1059
+ visitor . onDefineEmitsEnter || visitor . onDefineEmitsExit
1060
+ if ( hasPropsEvent || hasEmitsEvent ) {
1126
1061
/** @type {ESNode | null } */
1127
1062
let nested = null
1128
1063
scriptSetupVisitor [ ':function, BlockStatement' ] = ( node ) => {
@@ -1135,33 +1070,56 @@ module.exports = {
1135
1070
nested = null
1136
1071
}
1137
1072
}
1073
+ const definePropsMap = new Map ( )
1074
+ const defineEmitsMap = new Map ( )
1138
1075
/**
1139
1076
* @param {CallExpression } node
1140
1077
*/
1141
1078
scriptSetupVisitor . CallExpression = ( node ) => {
1142
1079
if (
1143
1080
! nested &&
1144
1081
inScriptSetup ( node ) &&
1145
- node . callee . type === 'Identifier' &&
1146
- node . callee . name === 'defineProps'
1082
+ node . callee . type === 'Identifier'
1147
1083
) {
1148
- /** @type {(ComponentArrayProp | ComponentObjectProp | ComponentTypeProp)[] } */
1149
- let props = [ ]
1150
- if ( node . arguments . length >= 1 ) {
1151
- const defNode = getObjectOrArray ( node . arguments [ 0 ] )
1152
- if ( defNode ) {
1153
- props = getComponentPropsFromDefine ( defNode )
1084
+ if ( hasPropsEvent && node . callee . name === 'defineProps' ) {
1085
+ /** @type {(ComponentArrayProp | ComponentObjectProp | ComponentTypeProp)[] } */
1086
+ let props = [ ]
1087
+ if ( node . arguments . length >= 1 ) {
1088
+ const defNode = getObjectOrArray ( node . arguments [ 0 ] )
1089
+ if ( defNode ) {
1090
+ props = getComponentPropsFromDefine ( defNode )
1091
+ }
1092
+ } else if (
1093
+ node . typeParameters &&
1094
+ node . typeParameters . params . length >= 1
1095
+ ) {
1096
+ props = getComponentPropsFromTypeDefine (
1097
+ context ,
1098
+ node . typeParameters . params [ 0 ]
1099
+ )
1154
1100
}
1155
- } else if (
1156
- node . typeParameters &&
1157
- node . typeParameters . params . length >= 1
1158
- ) {
1159
- props = getComponentPropsFromTypeDefine (
1160
- context ,
1161
- node . typeParameters . params [ 0 ]
1162
- )
1101
+ callVisitor ( 'onDefinePropsEnter' , node , props )
1102
+ definePropsMap . set ( node , props )
1103
+ } else if ( hasEmitsEvent && node . callee . name === 'defineEmits' ) {
1104
+ /** @type {(ComponentArrayEmit | ComponentObjectEmit | ComponentTypeEmit)[] } */
1105
+ let emits = [ ]
1106
+ if ( node . arguments . length >= 1 ) {
1107
+ const defNode = getObjectOrArray ( node . arguments [ 0 ] )
1108
+ if ( defNode ) {
1109
+ emits = getComponentEmitsFromDefine ( defNode )
1110
+ }
1111
+ } else if (
1112
+ node . typeParameters &&
1113
+ node . typeParameters . params . length >= 1
1114
+ ) {
1115
+ emits = getComponentEmitsFromTypeDefine (
1116
+ context ,
1117
+ node . typeParameters . params [ 0 ]
1118
+ )
1119
+ }
1120
+ callVisitor ( 'onDefineEmitsEnter' , node , emits )
1121
+ defineEmitsMap . set ( node , emits )
1163
1122
}
1164
- callVisitor ( 'onDefinePropsEnter' , node , props )
1165
1123
}
1166
1124
callVisitor ( 'CallExpression' , node )
1167
1125
}
@@ -1171,6 +1129,10 @@ module.exports = {
1171
1129
callVisitor ( 'onDefinePropsExit' , node , definePropsMap . get ( node ) )
1172
1130
definePropsMap . delete ( node )
1173
1131
}
1132
+ if ( defineEmitsMap . has ( node ) ) {
1133
+ callVisitor ( 'onDefineEmitsExit' , node , defineEmitsMap . get ( node ) )
1134
+ defineEmitsMap . delete ( node )
1135
+ }
1174
1136
}
1175
1137
}
1176
1138
@@ -2472,3 +2434,54 @@ function getComponentPropsFromDefine(propsNode) {
2472
2434
} )
2473
2435
}
2474
2436
}
2437
+
2438
+ /**
2439
+ * Get all emits by looking at all component's properties
2440
+ * @param {ObjectExpression|ArrayExpression } emitsNode Object with emits definition
2441
+ * @return {(ComponentArrayEmit | ComponentObjectEmit)[] } Array of component emits
2442
+ */
2443
+ function getComponentEmitsFromDefine ( emitsNode ) {
2444
+ if ( emitsNode . type === 'ObjectExpression' ) {
2445
+ return emitsNode . properties . filter ( isProperty ) . map ( ( prop ) => {
2446
+ const emitName = getStaticPropertyName ( prop )
2447
+ if ( emitName != null ) {
2448
+ return {
2449
+ type : 'object' ,
2450
+ key : prop . key ,
2451
+ emitName,
2452
+ value : skipTSAsExpression ( prop . value ) ,
2453
+ node : prop
2454
+ }
2455
+ }
2456
+ return {
2457
+ type : 'object' ,
2458
+ key : null ,
2459
+ emitName : null ,
2460
+ value : skipTSAsExpression ( prop . value ) ,
2461
+ node : prop
2462
+ }
2463
+ } )
2464
+ } else {
2465
+ return emitsNode . elements . filter ( isDef ) . map ( ( emit ) => {
2466
+ if ( emit . type === 'Literal' || emit . type === 'TemplateLiteral' ) {
2467
+ const emitName = getStringLiteralValue ( emit )
2468
+ if ( emitName != null ) {
2469
+ return {
2470
+ type : 'array' ,
2471
+ key : emit ,
2472
+ emitName,
2473
+ value : null ,
2474
+ node : emit
2475
+ }
2476
+ }
2477
+ }
2478
+ return {
2479
+ type : 'array' ,
2480
+ key : null ,
2481
+ emitName : null ,
2482
+ value : null ,
2483
+ node : emit
2484
+ }
2485
+ } )
2486
+ }
2487
+ }
0 commit comments