Skip to content

Return the regexp used for matching #329

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed

Conversation

ex1st
Copy link

@ex1st ex1st commented Sep 21, 2024

This is an attempt to return the functionality to build a routers tree for express app.
Developers can replace layer.regexp by layer.matchers[0].regexp in original code from @dougwilson expressjs/express#5858 (comment)

expressjs/express#5961

@blakeembrey
Copy link
Member

While this can be added I’d rather not add it for this reason. I think you’d be better off describing what you actually want as a feature and working on getting that added officially, since that code feels like it could break any time the regex changes and I don’t understand how it would work properly for all the different features of path-to-regexp.

What is it you actually want from Express?

@ex1st
Copy link
Author

ex1st commented Sep 25, 2024

Hi @blakeembrey, if pillarjs/router#123 will be merged, i will close it.

What is it you actually want from Express?

List of routes.

@ex1st
Copy link
Author

ex1st commented Apr 29, 2025

Hi @blakeembrey do you plan to fix it in another way, or have you just closed it?

@blakeembrey
Copy link
Member

As I said above:

I think you’d be better off describing what you actually want as a feature and working on getting that added officially, since that code feels like it could break any time the regex changes and I don’t understand how it would work properly for all the different features of path-to-regexp.

Since you replied that you want a "list of routes", this isn't the right library for that. The regex isn't helpful toward that goal and you would want to try and land this in the router instead.

@blakeembrey
Copy link
Member

blakeembrey commented Apr 29, 2025

I think it'd also help to be a bit more granular about what a "list of routes" is, or open a PR, or provide some examples in the router library. For example, how should the list handle an array or nested routers? Or a nested router in an array? What's the preferred output format? A flat array, or a nested tree? Do you care about the structure of the application itself in those routes? Should the output format be a string or TokenData? Is regex really the best output format for what people want to do with the list?

Most of this isn't something that would be exposed at this level, but features could be added when the above questions get clarification if we need additional features in the library.

@ex1st
Copy link
Author

ex1st commented Apr 29, 2025

Now I'm creating a list of routes using the modified code by @dougwilson, but path-to-regex no longer returns a regex. Next code works but I want to drop the crazy monkey-patching of RegExp.prototype.

function availableRoutes(router) {
	const routes = router.stack
		.filter(r => r.route)
		.map(r => {
			return {
				method: Object.keys(r.route.methods)[0].toUpperCase(),
				path: r.route.path
			};
		});
	const subRouters = router.stack
		.filter(r => r.name === "router");
	for (const subRouter of subRouters) {
		const orig = RegExp.prototype.exec;
		let source;
		RegExp.prototype.exec = function(...args) {
			Object.defineProperty(RegExp.prototype, "exec", {
				value: orig,
				writable: true,
				enumerable: false,
				configurable: true
			});
			source = this.source;
			return this.exec(...args);
		};
		subRouter.matchers[0]();
		source = source.replaceAll(/[$?=(){}\\|^]+/g, "").replaceAll(/:[/]+/g, "/");
		const subroutes = availableRoutes(subRouter.handle);
		for (const sr of subroutes) {
			sr.path = `${source}${sr.path}`.replaceAll(/\/+/g, "/");
			routes.push(sr);
		}
	}
	return routes;
}

to

function availableRoutes(router) {
	const routes = router.stack
		.filter(r => r.route)
		.map(r => {
			return {
				method: Object.keys(r.route.methods)[0].toUpperCase(),
				path: r.route.path
			};
		});
	const subRouters = router.stack
		.filter(r => r.name === "router");
	for (const subRouter of subRouters) {
		const source = subRouter.matchers[0].regexp.replaceAll(/[$?=(){}\\|^]+/g, "").replaceAll(/:[/]+/g, "/");
		const subroutes = availableRoutes(subRouter.handle);
		for (const sr of subroutes) {
			sr.path = `${source}${sr.path}`.replaceAll(/\/+/g, "/");
			routes.push(sr);
		}
	}
	return routes;
}

@blakeembrey
Copy link
Member

I think I understand what you're doing, I still don't really understand the goals though. I think we might be stuck on the XY problem, where you have a specific solution already but it won't really work in a bunch of different cases or for other users.

I'm trying to make assumptions about what you actually want, but I just don't know since I don't have the use-case. .replaceAll(/[$?=(){}\\|^]+/g, "").replaceAll(/:[/]+/g, "/") doesn't seem particularly helpful to me. It just spits out garbage and could break any time I change the regex output.

For example, pathToRegexp('/file/:path{.:ext}').regexp.source.replaceAll(/[$?=(){}\\|^]+/g, "").replaceAll(/:[/]+/g, "/") outputs:

'/file/[/]+.[/.]+/file/[/]+/'

That doesn't seem like what you'd want right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants