RouteTemplate.parse constructor
RouteTemplate.parse(
- String source, {
- bool allowQuery = true,
})
Implementation
factory RouteTemplate.parse(String source, {bool allowQuery = true}) {
final tokens = <RouteTemplateToken>[];
var literalStart = 0;
var cursor = 0;
void addLiteral(int end) {
if (end > literalStart) {
tokens.add(RouteTemplateToken.literal(
source.substring(literalStart, end),
));
}
}
while (cursor < source.length) {
final character = source[cursor];
if (allowQuery && (character == '?' || character == '#')) {
addLiteral(cursor);
return RouteTemplate._(tokens, source.substring(cursor));
}
if (character != ':' ||
cursor + 1 == source.length ||
!_isNameCharacter(source.codeUnitAt(cursor + 1))) {
cursor++;
continue;
}
final start = cursor > literalStart &&
(source[cursor - 1] == '/' || source[cursor - 1] == '.')
? cursor - 1
: cursor;
addLiteral(start);
final prefix = source.substring(start, cursor);
final nameStart = ++cursor;
while (cursor < source.length &&
_isNameCharacter(source.codeUnitAt(cursor))) {
cursor++;
}
final name = source.substring(nameStart, cursor);
String? pattern;
if (cursor < source.length && source[cursor] == '(') {
final patternStart = ++cursor;
var depth = 1;
var inCharacterClass = false;
while (cursor < source.length && depth > 0) {
final character = source[cursor];
if (character == r'\') {
cursor += 2;
continue;
}
if (character == '[') inCharacterClass = true;
if (character == ']') inCharacterClass = false;
if (!inCharacterClass) {
if (character == '(') depth++;
if (character == ')') depth--;
}
cursor++;
}
if (depth != 0) {
throw FormatException('Unclosed route parameter pattern', source);
}
pattern = source.substring(patternStart, cursor - 1);
}
// A terminal '?' or one before another path separator modifies the
// parameter. '?tab=posts' is an existing query string instead.
var optional = false;
if (cursor < source.length && source[cursor] == '?') {
final next = cursor + 1 == source.length ? '' : source[cursor + 1];
if (!allowQuery || ['', '/', '.', '?', '#', '*'].contains(next)) {
optional = true;
cursor++;
}
}
final wildcard = cursor < source.length && source[cursor] == '*';
if (wildcard) cursor++;
tokens.add(RouteTemplateToken.parameter(
source: source.substring(start, cursor),
name: name,
prefix: prefix,
pattern: pattern,
optional: optional,
wildcard: wildcard,
));
literalStart = cursor;
}
addLiteral(source.length);
return RouteTemplate._(tokens, '');
}