Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 41 additions & 29 deletions src/js/Route.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,37 +75,49 @@ export default class Route {
* @return {Object|false} - If this route matches, returns the matched parameters.
*/
matchesUrl(url) {
if (!this.definition.methods.includes('GET')) return false;

// Transform the route's template into a regex that will match a hydrated URL,
// by replacing its parameter segments with matchers for parameter values
const pattern = this.template
.replace(/[.*+$()[\]]/g, '\\$&')
.replace(/(\/?){([^}?]*)(\??)}/g, (_, slash, segment, optional) => {
const regex = `(?<${segment}>${
this.wheres[segment]?.replace(/(^\^)|(\$$)/g, '') || '[^/?]+'
})`;
return optional ? `(${slash}${regex})?` : `${slash}${regex}`;
})
.replace(/^\w+:\/\//, '');

const [location, query] = url.replace(/^\w+:\/\//, '').split('?');

const matches =
new RegExp(`^${pattern}/?$`).exec(location) ??
new RegExp(`^${pattern}/?$`).exec(decodeURI(location));

if (matches) {
for (const k in matches.groups) {
matches.groups[k] =
typeof matches.groups[k] === 'string'
? decodeURIComponent(matches.groups[k])
: matches.groups[k];
try {
if (!this.definition.methods.includes('GET')) return false;

// Store parameter names in order of appearance
const paramNames = [];

// Transform the route's template into a regex that will match a hydrated URL,
// by replacing its parameter segments with matchers for parameter values
const pattern = this.template
.replace(/[.*+$()[\]]/g, '\\$&')
.replace(/(\/?){([^}?]*)(\??)}/g, (_, slash, segment, optional) => {
paramNames.push(segment); // Store the parameter name
const regex = `(${
this.wheres[segment]?.replace(/(^\^)|(\$$)/g, '') || '[^/?]+'
})`;
return optional ? `(?:${slash}${regex})?` : `${slash}${regex}`;
})
.replace(/^\w+:\/\//, '');

const [location, query] = url.replace(/^\w+:\/\//, '').split('?');

const matches =
new RegExp(`^${pattern}/?$`).exec(location) ??
new RegExp(`^${pattern}/?$`).exec(decodeURI(location));

if (matches) {
// Build params object manually using the stored parameter names
const params = {};
// Start from index 1 to skip the full match at index 0
for (let i = 0; i < paramNames.length; i++) {
const value = matches[i + 1];
params[paramNames[i]] = typeof value === 'string'
? decodeURIComponent(value)
: value;
}
return { params, query: parse(query) };
}
return { params: matches.groups, query: parse(query) };
}

return false;
return false;
} catch (error) {
console.error('Ziggy matchesUrl error:', error);
return false;
}
}

/**
Expand Down