@@ -116,7 +116,7 @@ export function parsePredictedClassifications(
116116 // Order the sinks by the input alphabetically. This will ensure that the first argument is always
117117 // first in the list of sinks, the second argument is always second, etc.
118118 // If we get back "Argument[1]" and "Argument[3]", "Argument[1]" should always be first
119- sinks . sort ( ( a , b ) => ( a . input ?? "" ) . localeCompare ( b . input ?? "" ) ) ;
119+ sinks . sort ( ( a , b ) => compareInputOutput ( a . input ?? "" , b . input ?? "" ) ) ;
120120
121121 const sink = sinks [ 0 ] ;
122122
@@ -159,3 +159,60 @@ function toMethodClassification(modeledMethod: ModeledMethod): Classification {
159159function toFullMethodSignature ( method : Method ) : string {
160160 return `${ method . package } .${ method . type } #${ method . name } ${ method . signature } ` ;
161161}
162+
163+ const argumentRegex = / ^ A r g u m e n t \[ ( \d + ) ] $ / ;
164+
165+ // Argument[this] is before ReturnValue
166+ const nonNumericArgumentOrder = [ "Argument[this]" , "ReturnValue" ] ;
167+
168+ /**
169+ * Compare two inputs or outputs matching `Argument[<number>]`, `Argument[this]`, or `ReturnValue`.
170+ * If they are the same, return 0. If a is less than b, returns a negative number.
171+ * If a is greater than b, returns a positive number.
172+ */
173+ export function compareInputOutput ( a : string , b : string ) : number {
174+ if ( a === b ) {
175+ return 0 ;
176+ }
177+
178+ const aMatch = a . match ( argumentRegex ) ;
179+ const bMatch = b . match ( argumentRegex ) ;
180+
181+ // Numeric arguments are always first
182+ if ( aMatch && ! bMatch ) {
183+ return - 1 ;
184+ }
185+ if ( ! aMatch && bMatch ) {
186+ return 1 ;
187+ }
188+
189+ // Neither is an argument
190+ if ( ! aMatch && ! bMatch ) {
191+ const aIndex = nonNumericArgumentOrder . indexOf ( a ) ;
192+ const bIndex = nonNumericArgumentOrder . indexOf ( b ) ;
193+
194+ // If either one is unknown, it is sorted last
195+ if ( aIndex === - 1 && bIndex === - 1 ) {
196+ return a . localeCompare ( b ) ;
197+ }
198+ if ( aIndex === - 1 ) {
199+ return 1 ;
200+ }
201+ if ( bIndex === - 1 ) {
202+ return - 1 ;
203+ }
204+
205+ return aIndex - bIndex ;
206+ }
207+
208+ // This case shouldn't happen, but makes TypeScript happy
209+ if ( ! aMatch || ! bMatch ) {
210+ return 0 ;
211+ }
212+
213+ // Both are arguments
214+ const aIndex = parseInt ( aMatch [ 1 ] ) ;
215+ const bIndex = parseInt ( bMatch [ 1 ] ) ;
216+
217+ return aIndex - bIndex ;
218+ }
0 commit comments