@@ -7,12 +7,21 @@ namespace Microsoft.AspNetCore.StaticWebAssets.Tasks;
77
88#if WASM_TASKS
99[ DebuggerDisplay ( $ "{{{nameof(GetDebuggerDisplay)}(),nq}}") ]
10+ [ System . Diagnostics . CodeAnalysis . SuppressMessage ( "Style" , "IDE0057:Use range operator" , Justification = "Can't use range syntax in full framework" ) ]
1011internal sealed class StaticWebAssetPathPattern : IEquatable < StaticWebAssetPathPattern >
1112#else
1213[ DebuggerDisplay ( $ "{{{nameof(GetDebuggerDisplay)}(),nq}}") ]
1314public sealed class StaticWebAssetPathPattern : IEquatable < StaticWebAssetPathPattern >
1415#endif
1516{
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 = '}' ;
24+
1625 public StaticWebAssetPathPattern ( string path ) : this ( path . AsMemory ( ) ) { }
1726
1827 public StaticWebAssetPathPattern ( ReadOnlyMemory < char > rawPathMemory ) => RawPattern = rawPathMemory ;
@@ -61,28 +70,27 @@ public StaticWebAssetPathPattern(List<StaticWebAssetPathSegment> segments)
6170 public static StaticWebAssetPathPattern Parse ( ReadOnlyMemory < char > rawPathMemory , string assetIdentity = null )
6271 {
6372 var pattern = new StaticWebAssetPathPattern ( rawPathMemory ) ;
64- var nextToken = MemoryExtensions . IndexOf ( rawPathMemory . Span , "#[" . AsSpan ( ) , StringComparison . OrdinalIgnoreCase ) ;
73+ var current = rawPathMemory ;
74+ var nextToken = MemoryExtensions . IndexOf ( current . Span , FingerprintStart . AsSpan ( ) , StringComparison . OrdinalIgnoreCase ) ;
6575 if ( nextToken == - 1 )
6676 {
6777 var literalSegment = new StaticWebAssetPathSegment ( ) ;
68- literalSegment . Parts . Add ( new StaticWebAssetSegmentPart { Name = rawPathMemory , IsLiteral = true } ) ;
78+ literalSegment . Parts . Add ( new StaticWebAssetSegmentPart { Name = current , IsLiteral = true } ) ;
6979 pattern . Segments . Add ( literalSegment ) ;
7080 return pattern ;
7181 }
7282
7383 if ( nextToken > 0 )
7484 {
7585 var literalSegment = new StaticWebAssetPathSegment ( ) ;
76- #if NET9_0_OR_GREATER
77- literalSegment . Parts . Add ( new StaticWebAssetSegmentPart { Name = rawPathMemory [ ..nextToken ] , IsLiteral = true } ) ;
78- #else
79- literalSegment . Parts . Add ( new StaticWebAssetSegmentPart { Name = rawPathMemory . Slice ( 0 , nextToken ) , IsLiteral = true } ) ;
80- #endif
86+ literalSegment . Parts . Add ( new StaticWebAssetSegmentPart { Name = current . Slice ( 0 , nextToken ) , IsLiteral = true } ) ;
8187 pattern . Segments . Add ( literalSegment ) ;
8288 }
89+
8390 while ( nextToken != - 1 )
8491 {
85- var tokenEnd = MemoryExtensions . IndexOf ( rawPathMemory . Slice ( nextToken ) . Span , "]" . AsSpan ( ) , StringComparison . Ordinal ) ;
92+ current = current . Slice ( nextToken ) ;
93+ var tokenEnd = MemoryExtensions . IndexOf ( current . Span , FingerprintEnd . AsSpan ( ) , StringComparison . Ordinal ) ;
8694 if ( tokenEnd == - 1 )
8795 {
8896 if ( assetIdentity != null )
@@ -96,31 +104,36 @@ public static StaticWebAssetPathPattern Parse(ReadOnlyMemory<char> rawPathMemory
96104 }
97105 }
98106
99- var tokenExpression = rawPathMemory . Slice ( nextToken + 2 , tokenEnd - nextToken - 2 ) ;
107+ var tokenExpression = current . Slice ( 2 , tokenEnd - 2 ) ;
100108
101109 var token = new StaticWebAssetPathSegment ( ) ;
102110 AddTokenSegmentParts ( tokenExpression , token ) ;
103111 pattern . Segments . Add ( token ) ;
104112
105113 // Check if the segment is optional (ends with ? or !)
106- if ( tokenEnd < rawPathMemory . Length - 1 && ( rawPathMemory . Span [ tokenEnd + 1 ] == '?' || rawPathMemory . Span [ tokenEnd + 1 ] == '!' ) )
114+ if ( tokenEnd < current . Length - 1 &&
115+ ( current . Span [ tokenEnd + 1 ] == FingerprintOptional || current . Span [ tokenEnd + 1 ] == FingerprintPreferred ) )
107116 {
108117 token . IsOptional = true ;
109- if ( rawPathMemory . Span [ tokenEnd + 1 ] == '!' )
118+ if ( current . Span [ tokenEnd + 1 ] == FingerprintPreferred )
110119 {
111120 token . IsPreferred = true ;
112121 }
113122 tokenEnd ++ ;
114123 }
124+ current = current . Slice ( tokenEnd + 1 ) ;
125+ nextToken = MemoryExtensions . IndexOf ( current . Span , FingerprintStart . AsSpan ( ) , StringComparison . OrdinalIgnoreCase ) ;
115126
116- nextToken = MemoryExtensions . IndexOf ( rawPathMemory . Slice ( tokenEnd ) . Span , "#[" . AsSpan ( ) , StringComparison . OrdinalIgnoreCase ) ;
117-
118- // Add a literal segment if there is more content after the token and before the next one
119- if ( ( nextToken != - 1 && nextToken > tokenEnd + 1 ) || ( nextToken == - 1 && tokenEnd < rawPathMemory . Length - 1 ) )
127+ if ( nextToken == - 1 && current . Length > 0 )
120128 {
121- var literalEnd = nextToken == - 1 ? rawPathMemory . Length : nextToken ;
122129 var literalSegment = new StaticWebAssetPathSegment ( ) ;
123- literalSegment . Parts . Add ( new StaticWebAssetSegmentPart { Name = rawPathMemory . Slice ( tokenEnd + 1 , literalEnd - tokenEnd - 1 ) , IsLiteral = true } ) ;
130+ literalSegment . Parts . Add ( new StaticWebAssetSegmentPart { Name = current , IsLiteral = true } ) ;
131+ pattern . Segments . Add ( literalSegment ) ;
132+ }
133+ else if ( nextToken > 0 )
134+ {
135+ var literalSegment = new StaticWebAssetPathSegment ( ) ;
136+ literalSegment . Parts . Add ( new StaticWebAssetSegmentPart { Name = current . Slice ( 0 , nextToken ) , IsLiteral = true } ) ;
124137 pattern . Segments . Add ( literalSegment ) ;
125138 }
126139 }
@@ -170,14 +183,15 @@ public static StaticWebAssetPathPattern Parse(string rawPath, string assetIdenti
170183 var missingValue = "" ;
171184 foreach ( var tokenName in tokenNames )
172185 {
173- if ( ! tokens . TryGetValue ( staticWebAsset , tokenName . ToString ( ) , out var tokenValue ) || string . IsNullOrEmpty ( tokenValue ) )
186+ var tokenNameString = tokenName . ToString ( ) ;
187+ if ( ! tokens . TryGetValue ( staticWebAsset , tokenNameString , out var tokenValue ) || string . IsNullOrEmpty ( tokenValue ) )
174188 {
175189 foundAllValues = false ;
176- missingValue = tokenName . ToString ( ) ;
190+ missingValue = tokenNameString ;
177191 break ;
178192 }
179193
180- dictionary [ tokenName . ToString ( ) ] = tokenValue ;
194+ dictionary [ tokenNameString ] = tokenValue ;
181195 }
182196
183197 if ( ! foundAllValues && ! segment . IsOptional )
@@ -368,46 +382,50 @@ internal void EmbedTokens(StaticWebAsset staticWebAsset, StaticWebAssetTokenReso
368382 // The value within the {} represents token variables.
369383 private static void AddTokenSegmentParts ( ReadOnlyMemory < char > tokenExpression , StaticWebAssetPathSegment token )
370384 {
371- var nextToken = MemoryExtensions . IndexOf ( tokenExpression . Span , "{" . AsSpan ( ) , StringComparison . Ordinal ) ;
385+ var current = tokenExpression ;
386+ var nextToken = MemoryExtensions . IndexOf ( current . Span , FingerprintParameterStart ) ;
372387 if ( nextToken is not ( - 1 ) and > 0 )
373388 {
374- #if NET9_0_OR_GREATER
375- var literalPart = new StaticWebAssetSegmentPart { Name = tokenExpression [ ..nextToken ] , IsLiteral = true } ;
376- #else
377- var literalPart = new StaticWebAssetSegmentPart { Name = tokenExpression . Slice ( 0 , nextToken ) , IsLiteral = true } ;
378- #endif
389+ var literalPart = new StaticWebAssetSegmentPart { Name = current . Slice ( 0 , nextToken ) , IsLiteral = true } ;
379390 token . Parts . Add ( literalPart ) ;
380391 }
392+
381393 while ( nextToken != - 1 )
382394 {
383- var tokenEnd = MemoryExtensions . IndexOf ( tokenExpression . Slice ( nextToken ) . Span , "}" . AsSpan ( ) , StringComparison . Ordinal ) ;
395+ current = current . Slice ( nextToken ) ;
396+ var tokenEnd = MemoryExtensions . IndexOf ( current . Span , FingerprintParameterEnd ) ;
384397 if ( tokenEnd == - 1 )
385398 {
386399 throw new InvalidOperationException ( $ "Invalid token expression '{ tokenExpression } '. Missing '}}' token.") ;
387400 }
388401
389- var embeddedValue = MemoryExtensions . IndexOf ( tokenExpression . Slice ( nextToken ) . Span , "=" . AsSpan ( ) , StringComparison . Ordinal ) ;
402+ var embeddedValue = MemoryExtensions . IndexOf ( current . Span , FingerprintValueSeparator ) ;
390403 if ( embeddedValue != - 1 )
391404 {
392405 var tokenPart = new StaticWebAssetSegmentPart
393406 {
394- Name = tokenExpression . Slice ( nextToken + 1 , embeddedValue - nextToken - 1 ) ,
407+ Name = current . Slice ( 1 , embeddedValue - 1 ) ,
395408 IsLiteral = false ,
396- Value = tokenExpression . Slice ( embeddedValue + 1 , tokenEnd - embeddedValue - 1 )
409+ Value = current . Slice ( embeddedValue + 1 , tokenEnd - embeddedValue - 1 )
397410 } ;
398411 token . Parts . Add ( tokenPart ) ;
399412 }
400413 else
401414 {
402- var tokenPart = new StaticWebAssetSegmentPart { Name = tokenExpression . Slice ( nextToken + 1 , tokenEnd - nextToken - 1 ) , IsLiteral = false } ;
415+ var tokenPart = new StaticWebAssetSegmentPart { Name = current . Slice ( 1 , tokenEnd - 1 ) , IsLiteral = false } ;
403416 token . Parts . Add ( tokenPart ) ;
404417 }
405418
406- nextToken = MemoryExtensions . IndexOf ( tokenExpression . Slice ( tokenEnd ) . Span , "}" . AsSpan ( ) , StringComparison . Ordinal ) ;
407- if ( ( nextToken != - 1 && nextToken > tokenEnd + 1 ) || ( nextToken == - 1 && tokenEnd < tokenExpression . Length - 1 ) )
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 )
408427 {
409- var literalEnd = nextToken == - 1 ? tokenExpression . Length : nextToken ;
410- var literalPart = new StaticWebAssetSegmentPart { Name = tokenExpression . Slice ( tokenEnd + 1 , literalEnd - tokenEnd - 1 ) , IsLiteral = true } ;
428+ var literalPart = new StaticWebAssetSegmentPart { Name = current . Slice ( 0 , nextToken ) , IsLiteral = true } ;
411429 token . Parts . Add ( literalPart ) ;
412430 }
413431 }
0 commit comments