@@ -11,16 +11,17 @@ namespace Microsoft.AspNetCore.StaticWebAssets.Tasks;
1111internal sealed class StaticWebAssetPathPattern : IEquatable < StaticWebAssetPathPattern >
1212#else
1313[ DebuggerDisplay ( $ "{{{nameof(GetDebuggerDisplay)}(),nq}}") ]
14+ [ System . Diagnostics . CodeAnalysis . SuppressMessage ( "Style" , "IDE0057:Use range operator" , Justification = "Can't use range syntax in full framework" ) ]
1415public sealed class StaticWebAssetPathPattern : IEquatable < StaticWebAssetPathPattern >
1516#endif
1617{
17- private const string FingerprintStart = "#[" ;
18- private const string FingerprintEnd = "]" ;
19- private const char FingerprintOptional = '?' ;
20- private const char FingerprintPreferred = '!' ;
21- private const char FingerprintValueSeparator = '=' ;
22- private const char FingerprintParameterStart = '{' ;
23- private const char FingerprintParameterEnd = '}' ;
18+ private const string PatternStart = "#[" ;
19+ private const char PatternEnd = ']' ;
20+ private const char PatternOptional = '?' ;
21+ private const char PatternPreferred = '!' ;
22+ private const char PatternValueSeparator = '=' ;
23+ private const char PatternParameterStart = '{' ;
24+ private const char PatternParameterEnd = '}' ;
2425
2526 public StaticWebAssetPathPattern ( string path ) : this ( path . AsMemory ( ) ) { }
2627
@@ -71,7 +72,7 @@ public static StaticWebAssetPathPattern Parse(ReadOnlyMemory<char> rawPathMemory
7172 {
7273 var pattern = new StaticWebAssetPathPattern ( rawPathMemory ) ;
7374 var current = rawPathMemory ;
74- var nextToken = MemoryExtensions . IndexOf ( current . Span , FingerprintStart . AsSpan ( ) , StringComparison . OrdinalIgnoreCase ) ;
75+ var nextToken = MemoryExtensions . IndexOf ( current . Span , PatternStart . AsSpan ( ) , StringComparison . OrdinalIgnoreCase ) ;
7576 if ( nextToken == - 1 )
7677 {
7778 var literalSegment = new StaticWebAssetPathSegment ( ) ;
@@ -90,7 +91,7 @@ public static StaticWebAssetPathPattern Parse(ReadOnlyMemory<char> rawPathMemory
9091 while ( nextToken != - 1 )
9192 {
9293 current = current . Slice ( nextToken ) ;
93- var tokenEnd = MemoryExtensions . IndexOf ( current . Span , FingerprintEnd . AsSpan ( ) , StringComparison . Ordinal ) ;
94+ var tokenEnd = MemoryExtensions . IndexOf ( current . Span , PatternEnd ) ;
9495 if ( tokenEnd == - 1 )
9596 {
9697 if ( assetIdentity != null )
@@ -112,17 +113,18 @@ public static StaticWebAssetPathPattern Parse(ReadOnlyMemory<char> rawPathMemory
112113
113114 // Check if the segment is optional (ends with ? or !)
114115 if ( tokenEnd < current . Length - 1 &&
115- ( current . Span [ tokenEnd + 1 ] == FingerprintOptional || current . Span [ tokenEnd + 1 ] == FingerprintPreferred ) )
116+ ( current . Span [ tokenEnd + 1 ] == PatternOptional || current . Span [ tokenEnd + 1 ] == PatternPreferred ) )
116117 {
117118 token . IsOptional = true ;
118- if ( current . Span [ tokenEnd + 1 ] == FingerprintPreferred )
119+ if ( current . Span [ tokenEnd + 1 ] == PatternPreferred )
119120 {
120121 token . IsPreferred = true ;
121122 }
122123 tokenEnd ++ ;
123124 }
125+
124126 current = current . Slice ( tokenEnd + 1 ) ;
125- nextToken = MemoryExtensions . IndexOf ( current . Span , FingerprintStart . AsSpan ( ) , StringComparison . OrdinalIgnoreCase ) ;
127+ nextToken = MemoryExtensions . IndexOf ( current . Span , PatternStart . AsSpan ( ) , StringComparison . OrdinalIgnoreCase ) ;
126128
127129 if ( nextToken == - 1 && current . Length > 0 )
128130 {
@@ -141,6 +143,61 @@ public static StaticWebAssetPathPattern Parse(ReadOnlyMemory<char> rawPathMemory
141143 return pattern ;
142144 }
143145
146+ // Iterate over the token expression and add the parts to the token segment
147+ // Some examples are '.{fingerprint}', '{fingerprint}.', '{fingerprint}{fingerprint}', {fingerprint}.{fingerprint}
148+ // The '.' represents sample literal content.
149+ // The value within the {} represents token variables.
150+ private static void AddTokenSegmentParts ( ReadOnlyMemory < char > tokenExpression , StaticWebAssetPathSegment token )
151+ {
152+ var current = tokenExpression ;
153+ var nextToken = MemoryExtensions . IndexOf ( current . Span , PatternParameterStart ) ;
154+ if ( nextToken is not ( - 1 ) and > 0 )
155+ {
156+ var literalPart = new StaticWebAssetSegmentPart { Name = current . Slice ( 0 , nextToken ) , IsLiteral = true } ;
157+ token . Parts . Add ( literalPart ) ;
158+ }
159+
160+ while ( nextToken != - 1 )
161+ {
162+ current = current . Slice ( nextToken ) ;
163+ var tokenEnd = MemoryExtensions . IndexOf ( current . Span , PatternParameterEnd ) ;
164+ if ( tokenEnd == - 1 )
165+ {
166+ throw new InvalidOperationException ( $ "Invalid token expression '{ tokenExpression } '. Missing '}}' token.") ;
167+ }
168+
169+ var embeddedValue = MemoryExtensions . IndexOf ( current . Span , PatternValueSeparator ) ;
170+ if ( embeddedValue != - 1 )
171+ {
172+ var tokenPart = new StaticWebAssetSegmentPart
173+ {
174+ Name = current . Slice ( 1 , embeddedValue - 1 ) ,
175+ IsLiteral = false ,
176+ Value = current . Slice ( embeddedValue + 1 , tokenEnd - embeddedValue - 1 )
177+ } ;
178+ token . Parts . Add ( tokenPart ) ;
179+ }
180+ else
181+ {
182+ var tokenPart = new StaticWebAssetSegmentPart { Name = current . Slice ( 1 , tokenEnd - 1 ) , IsLiteral = false } ;
183+ token . Parts . Add ( tokenPart ) ;
184+ }
185+
186+ current = current . Slice ( tokenEnd + 1 ) ;
187+ nextToken = MemoryExtensions . IndexOf ( current . Span , PatternParameterStart ) ;
188+ if ( nextToken == - 1 && current . Length > 0 )
189+ {
190+ var literalPart = new StaticWebAssetSegmentPart { Name = current , IsLiteral = true } ;
191+ token . Parts . Add ( literalPart ) ;
192+ }
193+ else if ( nextToken > 0 )
194+ {
195+ var literalPart = new StaticWebAssetSegmentPart { Name = current . Slice ( 0 , nextToken ) , IsLiteral = true } ;
196+ token . Parts . Add ( literalPart ) ;
197+ }
198+ }
199+ }
200+
144201 public static StaticWebAssetPathPattern Parse ( string rawPath , string assetIdentity = null )
145202 {
146203 return Parse ( rawPath . AsMemory ( ) , assetIdentity ) ;
@@ -246,7 +303,6 @@ public IEnumerable<StaticWebAssetPathPattern> ExpandPatternExpression()
246303 // - asset.css produces a single pattern (asset.css).
247304 // - other#[.{fingerprint}].js produces a single pattern asset#[.{fingerprint}].js
248305 // - last#[.{fingerprint}]?.txt produces two patterns last#[.{fingerprint}]?.txt and last.txt
249-
250306 var hasOptionalSegments = false ;
251307 foreach ( var segment in Segments )
252308 {
@@ -376,61 +432,6 @@ internal void EmbedTokens(StaticWebAsset staticWebAsset, StaticWebAssetTokenReso
376432 RawPattern = GetRawPattern ( Segments ) ;
377433 }
378434
379- // Iterate over the token expression and add the parts to the token segment
380- // Some examples are '.{fingerprint}', '{fingerprint}.', '{fingerprint}{fingerprint}', {fingerprint}.{fingerprint}
381- // The '.' represents sample literal content.
382- // The value within the {} represents token variables.
383- private static void AddTokenSegmentParts ( ReadOnlyMemory < char > tokenExpression , StaticWebAssetPathSegment token )
384- {
385- var current = tokenExpression ;
386- var nextToken = MemoryExtensions . IndexOf ( current . Span , FingerprintParameterStart ) ;
387- if ( nextToken is not ( - 1 ) and > 0 )
388- {
389- var literalPart = new StaticWebAssetSegmentPart { Name = current . Slice ( 0 , nextToken ) , IsLiteral = true } ;
390- token . Parts . Add ( literalPart ) ;
391- }
392-
393- while ( nextToken != - 1 )
394- {
395- current = current . Slice ( nextToken ) ;
396- var tokenEnd = MemoryExtensions . IndexOf ( current . Span , FingerprintParameterEnd ) ;
397- if ( tokenEnd == - 1 )
398- {
399- throw new InvalidOperationException ( $ "Invalid token expression '{ tokenExpression } '. Missing '}}' token.") ;
400- }
401-
402- var embeddedValue = MemoryExtensions . IndexOf ( current . Span , FingerprintValueSeparator ) ;
403- if ( embeddedValue != - 1 )
404- {
405- var tokenPart = new StaticWebAssetSegmentPart
406- {
407- Name = current . Slice ( 1 , embeddedValue - 1 ) ,
408- IsLiteral = false ,
409- Value = current . Slice ( embeddedValue + 1 , tokenEnd - embeddedValue - 1 )
410- } ;
411- token . Parts . Add ( tokenPart ) ;
412- }
413- else
414- {
415- var tokenPart = new StaticWebAssetSegmentPart { Name = current . Slice ( 1 , tokenEnd - 1 ) , IsLiteral = false } ;
416- token . Parts . Add ( tokenPart ) ;
417- }
418-
419- current = current . Slice ( tokenEnd + 1 ) ;
420- nextToken = MemoryExtensions . IndexOf ( current . Span , FingerprintParameterStart ) ;
421- if ( nextToken == - 1 && current . Length > 0 )
422- {
423- var literalPart = new StaticWebAssetSegmentPart { Name = current , IsLiteral = true } ;
424- token . Parts . Add ( literalPart ) ;
425- }
426- else if ( nextToken > 0 )
427- {
428- var literalPart = new StaticWebAssetSegmentPart { Name = current . Slice ( 0 , nextToken ) , IsLiteral = true } ;
429- token . Parts . Add ( literalPart ) ;
430- }
431- }
432- }
433-
434435 private static ReadOnlyMemory < char > GetRawPattern ( IList < StaticWebAssetPathSegment > segments )
435436 {
436437 var stringBuilder = new StringBuilder ( ) ;
@@ -440,25 +441,25 @@ private static ReadOnlyMemory<char> GetRawPattern(IList<StaticWebAssetPathSegmen
440441 var isLiteral = IsLiteralSegment ( segment ) ;
441442 if ( ! isLiteral )
442443 {
443- stringBuilder . Append ( "#[" ) ;
444+ stringBuilder . Append ( PatternStart ) ;
444445 }
445446 for ( var j = 0 ; j < segment . Parts . Count ; j ++ )
446447 {
447448 var part = segment . Parts [ j ] ;
448- stringBuilder . Append ( part . IsLiteral ? part . Name : $$ """ {{{(!part.Value.IsEmpty ? $""" { part . Name } = { part . Value } """ : part.Name)}}}""" ) ;
449+ stringBuilder . Append ( part . IsLiteral ? part . Name : $$ """ {{{(!part.Value.IsEmpty ? $""" { part . Name } { PatternValueSeparator } { part . Value } """ : part.Name)}}}""" ) ;
449450 }
450451 if ( ! isLiteral )
451452 {
452- stringBuilder . Append ( ']' ) ;
453+ stringBuilder . Append ( PatternEnd ) ;
453454 if ( segment . IsOptional )
454455 {
455456 if ( segment . IsPreferred )
456457 {
457- stringBuilder . Append ( '!' ) ;
458+ stringBuilder . Append ( PatternPreferred ) ;
458459 }
459460 else
460461 {
461- stringBuilder . Append ( '?' ) ;
462+ stringBuilder . Append ( PatternOptional ) ;
462463 }
463464 }
464465 }
@@ -496,10 +497,12 @@ public override int GetHashCode()
496497#endif
497498
498499 public static bool operator == ( StaticWebAssetPathPattern left , StaticWebAssetPathPattern right ) => EqualityComparer < StaticWebAssetPathPattern > . Default . Equals ( left , right ) ;
500+
499501 public static bool operator != ( StaticWebAssetPathPattern left , StaticWebAssetPathPattern right ) => ! ( left == right ) ;
500502
501503 private string GetDebuggerDisplay ( ) => string . Concat ( Segments . Select ( s => s . GetDebuggerDisplay ( ) ) ) ;
502504
503505 private static bool IsLiteralSegment ( StaticWebAssetPathSegment segment ) => segment . Parts . Count == 1 && segment . Parts [ 0 ] . IsLiteral ;
506+
504507 internal static string PathWithoutTokens ( string path ) => Parse ( path ) . ComputePatternLabel ( ) ;
505508}
0 commit comments