@@ -332,124 +332,87 @@ public String getCanonicalResourceName(Set<String> knownResources) {
332332 if (knownResources == null ) {
333333 return "" ;
334334 }
335- StringBuilder canonical = new StringBuilder ();
336- StringBuilder currentSequence = new StringBuilder ();
335+
336+ int firstBindingIndex = -1 ;
337+ for (int i = 0 ; i < segments .size (); i ++) {
338+ if (segments .get (i ).kind () == SegmentKind .BINDING ) {
339+ firstBindingIndex = i ;
340+ break ;
341+ }
342+ }
343+
344+ if (firstBindingIndex == -1 ) {
345+ return "" ;
346+ }
347+
348+ int startIndex = 0 ;
349+ for (int i = firstBindingIndex - 1 ; i >= 0 ; i --) {
350+ Segment seg = segments .get (i );
351+ if (seg .kind () == SegmentKind .LITERAL ) {
352+ String value = seg .value ();
353+ if (value .matches ("^v\\ d+.*" ) || value .matches ("^u\\ d+.*" )) {
354+ startIndex = i + 1 ;
355+ break ;
356+ }
357+ }
358+ }
359+
360+ int lastValidEndBindingIndex = -1 ;
337361 boolean inBinding = false ;
338- String currentBindingName = "" ;
339- boolean keepBinding = true ;
340- List <Segment > bindingSegments = new ArrayList <>();
341- boolean afterKeptNamedBinding = false ;
362+ int literalCountInBinding = 0 ;
363+ int currentBindingStartIndex = -1 ;
342364
343365 for (int i = 0 ; i < segments .size (); i ++) {
344366 Segment seg = segments .get (i );
345367 if (seg .kind () == SegmentKind .BINDING ) {
346368 inBinding = true ;
347- currentBindingName = seg .value ();
348- bindingSegments .clear ();
349- keepBinding = true ;
369+ literalCountInBinding = 0 ;
370+ currentBindingStartIndex = i ;
350371 } else if (seg .kind () == SegmentKind .END_BINDING ) {
351372 inBinding = false ;
352- StringBuilder innerPattern = new StringBuilder ();
353- int literalCount = 0 ;
354- for (Segment innerSeg : bindingSegments ) {
355- if (innerSeg .kind () == SegmentKind .LITERAL ) {
356- String value = innerSeg .value ();
357- if (value .matches ("^v\\ d+.*" ) || value .matches ("^u\\ d+.*" )) {
358- continue ;
359- }
360- literalCount ++;
361- if (innerPattern .length () > 0 ) {
362- innerPattern .append ("/" );
363- }
364- innerPattern .append (value );
365- } else if (innerSeg .kind () == SegmentKind .WILDCARD ) {
366- if (innerPattern .length () > 0 ) {
367- innerPattern .append ("/" );
368- }
369- innerPattern .append ("*" );
370- }
371- }
373+ boolean isValidPair = false ;
372374
373- boolean extractInner = false ;
374- if (canonical .length () == 0 && currentSequence .length () == 0 ) {
375- if (i + 1 < segments .size ()) {
376- Segment nextSeg = segments .get (i + 1 );
377- if (nextSeg .kind () == SegmentKind .LITERAL ) {
378- String nextValue = nextSeg .value ();
379- if (knownResources .contains (nextValue )) {
380- extractInner = true ;
375+ if (literalCountInBinding > 1 ) {
376+ // Named bindings are unconditionally considered pairs
377+ isValidPair = true ;
378+ } else {
379+ // Check inner literals
380+ for (int j = currentBindingStartIndex + 1 ; j < i ; j ++) {
381+ if (segments .get (j ).kind () == SegmentKind .LITERAL ) {
382+ if (knownResources .contains (segments .get (j ).value ())) {
383+ isValidPair = true ;
384+ break ;
381385 }
382386 }
383387 }
384- }
385-
386- if (extractInner ) {
387- if (innerPattern .length () > 0 ) {
388- if (canonical .length () > 0 ) {
389- canonical .append ("/" );
388+ // If not valid yet, check preceding literal
389+ if (!isValidPair && currentBindingStartIndex > 0 ) {
390+ Segment prevSeg = segments .get (currentBindingStartIndex - 1 );
391+ if (prevSeg .kind () == SegmentKind .LITERAL && knownResources .contains (prevSeg .value ())) {
392+ isValidPair = true ;
390393 }
391- canonical .append (innerPattern );
392- }
393- } else {
394- if (currentSequence .length () > 0 ) {
395- if (canonical .length () > 0 ) {
396- canonical .append ("/" );
397- }
398- canonical .append (currentSequence );
399- currentSequence .setLength (0 );
400- }
401- if (canonical .length () > 0 ) {
402- canonical .append ("/" );
403394 }
395+ }
404396
405- if (literalCount <= 1 || innerPattern .toString ().equals ("*" )) {
406- canonical .append ("{" ).append (currentBindingName ).append ("}" );
407- } else {
408- canonical
409- .append ("{" )
410- .append (currentBindingName )
411- .append ("=" )
412- .append (innerPattern )
413- .append ("}" );
414- afterKeptNamedBinding = true ;
415- }
397+ if (isValidPair ) {
398+ lastValidEndBindingIndex = i ;
416399 }
417400 } else if (seg .kind () == SegmentKind .LITERAL ) {
418- String value = seg .value ();
419- if (value .matches ("^v\\ d+.*" ) || value .matches ("^u\\ d+.*" )) {
420- continue ;
421- }
422401 if (inBinding ) {
423- bindingSegments .add (seg );
424- if (!knownResources .contains (value )) {
425- keepBinding = false ;
426- }
427- } else {
428- if (knownResources .contains (value )) {
429- if (currentSequence .length () > 0 ) {
430- currentSequence .append ("/" );
431- }
432- currentSequence .append (value );
433- } else {
434- if (afterKeptNamedBinding ) {
435- if (currentSequence .length () > 0 ) {
436- currentSequence .append ("/" );
437- }
438- currentSequence .append (value );
439- } else {
440- if (canonical .length () > 0 || currentSequence .length () > 0 ) {
441- break ;
442- }
443- }
402+ String value = seg .value ();
403+ if (!value .matches ("^v\\ d+.*" ) && !value .matches ("^u\\ d+.*" )) {
404+ literalCountInBinding ++;
444405 }
445406 }
446- } else if (seg .kind () == SegmentKind .WILDCARD ) {
447- if (inBinding ) {
448- bindingSegments .add (seg );
449- }
450407 }
451408 }
452- return canonical .toString ();
409+
410+ if (lastValidEndBindingIndex == -1 || lastValidEndBindingIndex < startIndex ) {
411+ return "" ;
412+ }
413+
414+ List <Segment > canonicalSegments = segments .subList (startIndex , lastValidEndBindingIndex + 1 );
415+ return toSyntax (canonicalSegments , true );
453416 }
454417
455418 /**
@@ -1278,7 +1241,7 @@ private String decodeUrl(String url) {
12781241 // the list iterator in its state.
12791242 private static boolean peek (ListIterator <Segment > segments , SegmentKind ... kinds ) {
12801243 int start = segments .nextIndex ();
1281- boolean success = false ;
1244+ boolean success = true ;
12821245 for (SegmentKind kind : kinds ) {
12831246 if (!segments .hasNext () || segments .next ().kind () != kind ) {
12841247 success = false ;
0 commit comments