@@ -43,19 +43,6 @@ export class UriTemplate {
4343 UriTemplate . validateLength ( template , MAX_TEMPLATE_LENGTH , 'Template' ) ;
4444 this . template = template ;
4545 this . parts = this . parse ( template ) ;
46-
47- // Templates with a literal '?' in a string segment are incompatible
48- // with match()'s split-at-'?' query parsing — the path regex would
49- // include the escaped '?' but the URI is split before matching.
50- // Supporting this requires a fragile two-code-path implementation
51- // that has proven bug-prone, so reject at construction time.
52- const literalQueryPart = this . parts . find ( part => typeof part === 'string' && part . includes ( '?' ) ) ;
53- if ( literalQueryPart !== undefined ) {
54- throw new Error (
55- `UriTemplate: literal '?' in template string is not supported. ` +
56- `Use {?param} to introduce query parameters instead. Template: "${ template } "`
57- ) ;
58- }
5946 }
6047
6148 toString ( ) : string {
@@ -297,14 +284,27 @@ export class UriTemplate {
297284 }
298285 }
299286
300- // Strip any URI fragment before splitting path/query.
301- const hashIndex = uri . indexOf ( '#' ) ;
302- const uriNoFrag = hashIndex === - 1 ? uri : uri . slice ( 0 , hashIndex ) ;
287+ // Only strip the URI fragment when the template has no {#var} operator;
288+ // otherwise the fragment is part of what the path regex must capture.
289+ const hasHashOperator = this . parts . some ( p => typeof p !== 'string' && p . operator === '#' ) ;
290+ let working = uri ;
291+ if ( ! hasHashOperator ) {
292+ const hashIndex = working . indexOf ( '#' ) ;
293+ if ( hashIndex !== - 1 ) working = working . slice ( 0 , hashIndex ) ;
294+ }
303295
304- // Split URI into path and query parts at the first '?'
305- const queryIndex = uriNoFrag . indexOf ( '?' ) ;
306- const pathPart = queryIndex === - 1 ? uriNoFrag : uriNoFrag . slice ( 0 , queryIndex ) ;
307- const queryPart = queryIndex === - 1 ? '' : uriNoFrag . slice ( queryIndex + 1 ) ;
296+ // Only split path/query when the template actually has {?..}/{&..}
297+ // operators. Otherwise match the path regex against the full URI so
298+ // {+var} can capture across '?' as it did before query-param support.
299+ let pathPart = working ;
300+ let queryPart = '' ;
301+ if ( queryParts . length > 0 ) {
302+ const queryIndex = working . indexOf ( '?' ) ;
303+ if ( queryIndex !== - 1 ) {
304+ pathPart = working . slice ( 0 , queryIndex ) ;
305+ queryPart = working . slice ( queryIndex + 1 ) ;
306+ }
307+ }
308308
309309 pattern += '$' ;
310310 UriTemplate . validateLength ( pattern , MAX_REGEX_LENGTH , 'Generated regex pattern' ) ;
0 commit comments