1- import 'package:collection/collection.dart' ;
2- import 'package:equatable/equatable.dart' ;
3-
41import '../tree/node.dart' ;
2+ import '../tree/tree.dart' ;
53import 'descriptor.dart' ;
64import 'utils.dart' ;
75
86final _knownDescriptors = {'number' : numDescriptor};
97
10- /// build a parametric definition from a route part
11- ParameterDefinition ? _buildParamDefinition (String part, bool terminal) {
12- if (closeDoorParametricRegex.hasMatch (part)) {
13- throw ArgumentError .value (
14- part, null , 'Parameter definition is invalid. Close door neighbors' );
15- }
8+ SingleParameterDefn _singleParamDefn (RegExpMatch m) {
9+ final group = m.group (2 )! ;
10+ var param = group;
1611
17- ParameterDefinition makeDefinition (RegExpMatch m, {bool end = false }) {
12+ Iterable <ParameterDescriptor >? descriptors;
13+
14+ if (group.contains ('|' )) {
1815 final parts = m.group (2 )! .split ('|' );
16+ param = parts.first;
1917
20- Iterable <ParameterDescriptor >? descriptors;
2118 if (parts.length > 1 ) {
2219 descriptors = parts.sublist (1 ).map ((e) {
2320 final value = e.isRegex ? regexDescriptor : _knownDescriptors[e];
@@ -28,14 +25,20 @@ ParameterDefinition? _buildParamDefinition(String part, bool terminal) {
2825 return value;
2926 });
3027 }
28+ }
3129
32- return ParameterDefinition ._(
33- parts.first,
34- prefix: m.group (1 )? .nullIfEmpty,
35- suffix: m.group (3 )? .nullIfEmpty,
36- terminal: end,
37- descriptors: descriptors ?? const [],
38- );
30+ return SingleParameterDefn ._(
31+ param,
32+ prefix: m.group (1 )? .nullIfEmpty,
33+ suffix: m.group (3 )? .nullIfEmpty,
34+ descriptors: descriptors ?? const [],
35+ );
36+ }
37+
38+ ParameterDefinition buildParamDefinition (String part) {
39+ if (closeDoorParametricRegex.hasMatch (part)) {
40+ throw ArgumentError .value (
41+ part, null , 'Parameter definition is invalid. Close door neighbors' );
3942 }
4043
4144 final matches = parametricDefnsRegex.allMatches (part);
@@ -44,122 +47,145 @@ ParameterDefinition? _buildParamDefinition(String part, bool terminal) {
4447 }
4548
4649 if (matches.length == 1 ) {
47- return makeDefinition (matches.first, end : terminal );
50+ return _singleParamDefn (matches.first);
4851 }
4952
50- final parent = makeDefinition (matches.first, end: false );
51- final subdefns = matches.skip (1 );
52- final subparts = subdefns.mapIndexed (
53- (i, e) => makeDefinition (e, end: i == (subdefns.length - 1 ) && terminal),
54- );
53+ final defns = matches.map (_singleParamDefn);
54+ final partsMap = {for (final defn in defns) defn.name: defn};
5555
56- return CompositeParameterDefinition ._(parent, subparts : subparts );
56+ return CompositeParameterDefinition ._(partsMap, defns.last.name );
5757}
5858
59- class ParameterDefinition with EquatableMixin , HandlerStore {
59+ abstract class ParameterDefinition implements HandlerStore {
60+ String get name;
61+
62+ String get templateStr;
63+
64+ RegExp get template;
65+
66+ String get key;
67+
68+ bool get terminal;
69+
70+ Map <String , dynamic >? resolveParams (String pattern);
71+ }
72+
73+ class SingleParameterDefn extends ParameterDefinition with HandlerStoreMixin {
74+ @override
6075 final String name;
76+
6177 final String ? prefix;
6278 final String ? suffix;
63- final bool terminal;
6479
6580 final Iterable <ParameterDescriptor > descriptors;
6681
67- ParameterDefinition ._(
82+ @override
83+ final String templateStr;
84+
85+ @override
86+ late final RegExp template;
87+
88+ @override
89+ String get key => 'prefix=$prefix &suffix=$suffix &terminal=$terminal ' ;
90+
91+ bool _terminal;
92+
93+ @override
94+ bool get terminal => _terminal;
95+
96+ SingleParameterDefn ._(
6897 this .name, {
6998 this .descriptors = const [],
7099 this .prefix,
71100 this .suffix,
72- this .terminal = false ,
73- });
74-
75- String get templateStr {
76- String result = '<$name >' ;
77- if (prefix != null ) result = "$prefix $result " ;
78- if (suffix != null ) result = '$result $suffix ' ;
79- return result;
80- }
81-
82- RegExp ? _paramRegexCache;
83- RegExp get template {
84- if (_paramRegexCache != null ) return _paramRegexCache! ;
85- return _paramRegexCache = buildRegexFromTemplate (templateStr);
86- }
87-
88- factory ParameterDefinition .from (String part, {bool terminal = false }) {
89- return _buildParamDefinition (part, terminal)! ;
101+ }) : templateStr = buildTemplateString (
102+ name: name,
103+ prefix: prefix,
104+ suffix: suffix,
105+ ),
106+ _terminal = false {
107+ template = buildRegexFromTemplate (templateStr);
90108 }
91109
92110 bool matches (String pattern) => template.hasMatch (pattern);
93111
94- bool isExactExceptName (ParameterDefinition defn) {
95- if (methods.isNotEmpty) {
96- final hasMethod = defn.methods.any ((e) => methods.contains (e));
97- if (! hasMethod) return false ;
98- }
99-
100- return prefix == defn.prefix &&
101- suffix == defn.suffix &&
102- terminal == defn.terminal;
103- }
104-
105- Map <String , dynamic > resolveParams (final String pattern) {
112+ @override
113+ Map <String , dynamic >? resolveParams (final String pattern) {
106114 final params = resolveParamsFromPath (template, pattern);
115+ if (params == null ) return null ;
116+
107117 return params
108- ..[name] = descriptors.fold < dynamic > (
118+ ..[name] = descriptors.fold (
109119 params[name],
110120 (value, descriptor) => descriptor (value),
111121 );
112122 }
113123
114124 @override
115- List <Object ?> get props => [prefix, name, suffix, terminal];
125+ void addRoute <T >(HTTPMethod method, IndexedValue <T > handler) {
126+ super .addRoute (method, handler);
127+ _terminal = true ;
128+ }
116129}
117130
118- class CompositeParameterDefinition extends ParameterDefinition {
119- final Iterable <ParameterDefinition > subparts;
131+ class CompositeParameterDefinition extends ParameterDefinition
132+ implements HandlerStore {
133+ final Map <String , SingleParameterDefn > parts;
134+ final String _lastPartKey;
120135
121- CompositeParameterDefinition ._(
122- ParameterDefinition parent, {
123- required this .subparts,
124- }) : super ._(
125- parent.name,
126- prefix: parent.prefix,
127- suffix: parent.suffix,
128- terminal: false ,
129- descriptors: parent.descriptors,
130- );
136+ SingleParameterDefn get _maybeTerminalPart => parts[_lastPartKey]! ;
137+
138+ CompositeParameterDefinition ._(this .parts, this ._lastPartKey);
131139
132140 @override
133- List < Object ?> get props => [ super .props, ...subparts] ;
141+ String get templateStr => parts.values. map ((e) => e.templateStr). join () ;
134142
135143 @override
136- bool get terminal => subparts. any ((e) => e.terminal );
144+ String get name => parts.values. map ((e) => e.name). join ( '|' );
137145
138146 @override
139- String get templateStr {
140- return '${super .templateStr }${subparts .map ((e ) => e .templateStr ).join ()}' ;
141- }
147+ String get key => parts.values.map ((e) => e.key).join ('|' );
142148
143149 @override
144- RegExp get template {
145- if (_paramRegexCache != null ) return _paramRegexCache! ;
146- return _paramRegexCache = buildRegexFromTemplate (templateStr);
147- }
150+ RegExp get template => buildRegexFromTemplate (templateStr);
148151
149152 @override
150- Map <String , dynamic > resolveParams (String pattern) {
151- final params = resolveParamsFromPath (template, pattern);
152- final definitions =
153- [this , ...subparts].where ((e) => e.descriptors.isNotEmpty);
154- if (definitions.isEmpty) return params;
153+ bool get terminal => _maybeTerminalPart.terminal;
155154
156- for (final defn in definitions) {
157- params[defn.name] = defn.descriptors.fold <dynamic >(
158- params[defn.name],
159- (value, descriptor) => descriptor (value),
155+ @override
156+ Map <String , dynamic >? resolveParams (String pattern) {
157+ final result = resolveParamsFromPath (template, pattern);
158+ if (result == null ) return null ;
159+
160+ for (final param in result.keys) {
161+ final defn = parts[param]! ;
162+ final value = result[param];
163+
164+ result[param] = defn.descriptors.fold <dynamic >(
165+ value,
166+ (value, fn) => fn (value),
160167 );
161168 }
162169
163- return params;
170+ return result;
171+ }
172+
173+ @override
174+ void addMiddleware <T >(IndexedValue <T > handler) {
175+ _maybeTerminalPart.addMiddleware (handler);
164176 }
177+
178+ @override
179+ void addRoute <T >(HTTPMethod method, IndexedValue <T > handler) =>
180+ _maybeTerminalPart.addRoute (method, handler);
181+
182+ @override
183+ IndexedValue ? getHandler (HTTPMethod method) =>
184+ _maybeTerminalPart.getHandler (method);
185+
186+ @override
187+ bool hasMethod (HTTPMethod method) => _maybeTerminalPart.hasMethod (method);
188+
189+ @override
190+ Iterable <HTTPMethod > get methods => _maybeTerminalPart.methods;
165191}
0 commit comments