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,34 +1053,57 @@ module.exports = {
1120
1053
return null
1121
1054
}
1122
1055
1123
- if ( visitor . onDefinePropsEnter || visitor . onDefinePropsExit ) {
1056
+ const hasPropsEvent =
1057
+ visitor . onDefinePropsEnter || visitor . onDefinePropsExit
1058
+ const hasEmitsEvent =
1059
+ visitor . onDefineEmitsEnter || visitor . onDefineEmitsExit
1060
+ if ( hasPropsEvent || hasEmitsEvent ) {
1124
1061
const definePropsMap = new Map ( )
1062
+ const defineEmitsMap = new Map ( )
1125
1063
/**
1126
1064
* @param {CallExpression } node
1127
1065
*/
1128
1066
scriptSetupVisitor . CallExpression = ( node ) => {
1129
- if (
1130
- inScriptSetup ( node ) &&
1131
- node . callee . type === 'Identifier' &&
1132
- node . callee . name === 'defineProps'
1133
- ) {
1134
- /** @type {(ComponentArrayProp | ComponentObjectProp | ComponentTypeProp)[] } */
1135
- let props = [ ]
1136
- if ( node . arguments . length >= 1 ) {
1137
- const defNode = getObjectOrArray ( node . arguments [ 0 ] )
1138
- if ( defNode ) {
1139
- props = getComponentPropsFromDefine ( defNode )
1067
+ if ( inScriptSetup ( node ) && node . callee . type === 'Identifier' ) {
1068
+ if ( hasPropsEvent && node . callee . name === 'defineProps' ) {
1069
+ /** @type {(ComponentArrayProp | ComponentObjectProp | ComponentTypeProp)[] } */
1070
+ let props = [ ]
1071
+ if ( node . arguments . length >= 1 ) {
1072
+ const defNode = getObjectOrArray ( node . arguments [ 0 ] )
1073
+ if ( defNode ) {
1074
+ props = getComponentPropsFromDefine ( defNode )
1075
+ }
1076
+ } else if (
1077
+ node . typeParameters &&
1078
+ node . typeParameters . params . length >= 1
1079
+ ) {
1080
+ props = getComponentPropsFromTypeDefine (
1081
+ context ,
1082
+ node . typeParameters . params [ 0 ]
1083
+ )
1140
1084
}
1141
- } else if (
1142
- node . typeParameters &&
1143
- node . typeParameters . params . length >= 1
1144
- ) {
1145
- props = getComponentPropsFromTypeDefine (
1146
- context ,
1147
- node . typeParameters . params [ 0 ]
1148
- )
1085
+ callVisitor ( 'onDefinePropsEnter' , node , props )
1086
+ definePropsMap . set ( node , props )
1087
+ } else if ( hasEmitsEvent ) {
1088
+ /** @type {(ComponentArrayEmit | ComponentObjectEmit | ComponentTypeEmit)[] } */
1089
+ let emits = [ ]
1090
+ if ( node . arguments . length >= 1 ) {
1091
+ const defNode = getObjectOrArray ( node . arguments [ 0 ] )
1092
+ if ( defNode ) {
1093
+ emits = getComponentEmitsFromDefine ( defNode )
1094
+ }
1095
+ } else if (
1096
+ node . typeParameters &&
1097
+ node . typeParameters . params . length >= 1
1098
+ ) {
1099
+ emits = getComponentEmitsFromTypeDefine (
1100
+ context ,
1101
+ node . typeParameters . params [ 0 ]
1102
+ )
1103
+ }
1104
+ callVisitor ( 'onDefineEmitsEnter' , node , emits )
1105
+ defineEmitsMap . set ( node , emits )
1149
1106
}
1150
- callVisitor ( 'onDefinePropsEnter' , node , props )
1151
1107
}
1152
1108
callVisitor ( 'CallExpression' , node )
1153
1109
}
@@ -1157,6 +1113,10 @@ module.exports = {
1157
1113
callVisitor ( 'onDefinePropsExit' , node , definePropsMap . get ( node ) )
1158
1114
definePropsMap . delete ( node )
1159
1115
}
1116
+ if ( defineEmitsMap . has ( node ) ) {
1117
+ callVisitor ( 'onDefineEmitsExit' , node , defineEmitsMap . get ( node ) )
1118
+ defineEmitsMap . delete ( node )
1119
+ }
1160
1120
}
1161
1121
}
1162
1122
@@ -2422,3 +2382,54 @@ function getComponentPropsFromDefine(propsNode) {
2422
2382
} )
2423
2383
}
2424
2384
}
2385
+
2386
+ /**
2387
+ * Get all emits by looking at all component's properties
2388
+ * @param {ObjectExpression|ArrayExpression } emitsNode Object with emits definition
2389
+ * @return {(ComponentArrayEmit | ComponentObjectEmit)[] } Array of component emits
2390
+ */
2391
+ function getComponentEmitsFromDefine ( emitsNode ) {
2392
+ if ( emitsNode . type === 'ObjectExpression' ) {
2393
+ return emitsNode . properties . filter ( isProperty ) . map ( ( prop ) => {
2394
+ const emitName = getStaticPropertyName ( prop )
2395
+ if ( emitName != null ) {
2396
+ return {
2397
+ type : 'object' ,
2398
+ key : prop . key ,
2399
+ emitName,
2400
+ value : skipTSAsExpression ( prop . value ) ,
2401
+ node : prop
2402
+ }
2403
+ }
2404
+ return {
2405
+ type : 'object' ,
2406
+ key : null ,
2407
+ emitName : null ,
2408
+ value : skipTSAsExpression ( prop . value ) ,
2409
+ node : prop
2410
+ }
2411
+ } )
2412
+ } else {
2413
+ return emitsNode . elements . filter ( isDef ) . map ( ( emit ) => {
2414
+ if ( emit . type === 'Literal' || emit . type === 'TemplateLiteral' ) {
2415
+ const emitName = getStringLiteralValue ( emit )
2416
+ if ( emitName != null ) {
2417
+ return {
2418
+ type : 'array' ,
2419
+ key : emit ,
2420
+ emitName,
2421
+ value : null ,
2422
+ node : emit
2423
+ }
2424
+ }
2425
+ }
2426
+ return {
2427
+ type : 'array' ,
2428
+ key : null ,
2429
+ emitName : null ,
2430
+ value : null ,
2431
+ node : emit
2432
+ }
2433
+ } )
2434
+ }
2435
+ }
0 commit comments