@@ -29,6 +29,7 @@ export interface ICheckerArguments {
29
29
flags : string
30
30
error : string
31
31
messages : string [ ]
32
+ debugRegex : null | ( string | string [ ] ) [ ] ,
32
33
}
33
34
34
35
/**
@@ -73,7 +74,10 @@ export async function checkCommitMessages(
73
74
core . info ( `- OK: "${ message } "` )
74
75
} else {
75
76
core . info ( `- failed: "${ message } "` )
76
- result = false
77
+ if ( args . debugRegex !== null ) {
78
+ core . info ( debugRegexMatching ( args . debugRegex , message ) ) ;
79
+ }
80
+ result = false ;
77
81
}
78
82
}
79
83
@@ -98,3 +102,80 @@ function checkMessage(
98
102
const regex = new RegExp ( pattern , flags )
99
103
return regex . test ( message )
100
104
}
105
+
106
+ /*
107
+ * Debugs until which characters does a regex matches.
108
+ */
109
+ const debugRegexMatching = ( regexes : ( string | string [ ] ) [ ] , str : string ) : string => {
110
+ str = str . replaceAll ( '\r' , '' ) ;
111
+ let matchesUntil = 0 ;
112
+ const copyStr = str ;
113
+ let rgx ;
114
+
115
+ do {
116
+ if ( Array . isArray ( regexes [ 0 ] ) ) {
117
+ const previousLength = str . length ;
118
+ const [ newString , failedAt ] = optionalRemoval ( regexes [ 0 ] , str ) ;
119
+ str = newString ;
120
+ matchesUntil += previousLength - str . length ;
121
+
122
+ if ( failedAt !== null ) {
123
+ break ;
124
+ }
125
+ } else {
126
+ rgx = new RegExp ( "^" + regexes [ 0 ] ) ;
127
+
128
+ if ( rgx . test ( str ) ) {
129
+ const previousLength = str . length ;
130
+ str = str . replace ( rgx , '' ) ;
131
+ matchesUntil += previousLength - str . length ;
132
+ } else {
133
+ break ;
134
+ }
135
+ }
136
+
137
+ regexes = regexes . splice ( 1 ) ;
138
+ } while ( regexes . length > 0 ) ;
139
+
140
+ if ( str . length === 0 && regexes . length === 0 ) {
141
+ return "The regex should work." ;
142
+ } else {
143
+ const paddingLeft = Math . max ( matchesUntil - 10 , 0 ) ;
144
+ const paddingRight = Math . min ( matchesUntil + 10 , copyStr . length ) ;
145
+ const rightDots = paddingRight !== copyStr . length ? '…' : '' ;
146
+ const leftDots = paddingLeft !== 0 ? '…' : '' ;
147
+
148
+ if ( str . length > 0 && regexes . length === 0 ) {
149
+ return `Trailing characters: "${ str } "
150
+ --------------------------------
151
+ Context: "${ leftDots } ${ copyStr . slice ( paddingLeft , Math . min ( copyStr . length , matchesUntil + 10 ) ) . replaceAll ( '\n' , '' ) } ${ rightDots } "
152
+ ${ " " . repeat ( matchesUntil - paddingLeft ) } ^` ;
153
+ } else {
154
+ return `The regex stopped matching at index: ${ matchesUntil } .
155
+ Expected: "${ rgx } "
156
+ Context: "${ leftDots } ${ copyStr . slice ( paddingLeft , paddingRight ) . replaceAll ( '\n' , '' ) } ${ rightDots } "
157
+ ${ " " . repeat ( matchesUntil - paddingLeft ) } ^${ "~" . repeat ( paddingRight - matchesUntil ) } ` ;
158
+ }
159
+ }
160
+ }
161
+
162
+ /// If the first member of the optionalRegexes is matching then all the other should match. Else we don't test the others.
163
+ const optionalRemoval = ( optionalRegexes : string [ ] , str : string ) : [ string , number | null ] => {
164
+ let rgx = new RegExp ( "^" + optionalRegexes [ 0 ] ) ;
165
+
166
+ if ( rgx . test ( str ) ) {
167
+ do {
168
+ rgx = new RegExp ( "^" + optionalRegexes [ 0 ] ) ;
169
+
170
+ if ( rgx . test ( str ) ) {
171
+ str = str . replace ( rgx , '' ) ;
172
+ } else {
173
+ return [ str , 0 ] ;
174
+ }
175
+ optionalRegexes = optionalRegexes . splice ( 1 ) ;
176
+ } while ( optionalRegexes . length > 0 ) ;
177
+ }
178
+
179
+ return [ str , null ] ;
180
+ }
181
+
0 commit comments