diff --git a/app.js b/app.js index 8175689..878fa43 100644 --- a/app.js +++ b/app.js @@ -1,6 +1,7 @@ const express = require('express'); const fsPromises = require('fs').promises; const glob = require('glob'); +const { match: createPathMatch } = require('path-to-regexp'); (async () => { const app = express(); @@ -8,20 +9,40 @@ const glob = require('glob'); cwd: './routes', dot: true, }); + const pathMatches = []; app.use(async (req, res, next) => { - let stats = await Promise.all([ - fsPromises.stat(`./routes/${req.url}.js`).catch(() => "nofile"), - fsPromises.stat(`./routes/${req.url}/index.js`).catch(() => "nofile"), - ]); - if ( req.url.endsWith('/') && stats[1] !== "nofile" ) { - req.url = `${req.url}index`; - } else if ( stats[0] === "nofile" && stats[1] !== "nofile" ) { - req.url = `${req.url}/index` + const requestUrl = new URL(req.url, "https://example.com/"); + var candidateUrl = ""; + var secondCandidateUrl = ""; + for ( let pathMatch in pathMatches ) { + if ( patchMatches[pathMatch](requestUrl.pathname) ) { + // If we get an exact match, we don't need to process further. + return next(); + } else if ( requestUrl.pathname.endsWith('/') && patchMatches[pathMatch](`${requestUrl.pathname}index`) ) { + // If we end with a /, and the index path matches, lets do the index path, but prioritize the non-index path. + let secondRequestUrl = new URL(requestUrl); + secondRequestUrl.pathname = `${requestUrl.pathname}index`; + candidateUrl = secondRequestUrl.toString().substring(19); + } else if ( pathName[pathMatch](`${requestUrl.pathname}/index`) ) { + // If we don't end with a /, and the /index path matches, lets do the /index path, but prioritize paths checked previously. + let secondRequestUrl = new URL(requestUrl); + secondRequestUrl.pathname = `${requestUrl.pathname}/index`; + secondCandidateUrl = secondRequestUrl.toString().substring(19); + } } - next(); + if ( candidateUrl !== "" ) { + req.url = candidateUrl; + return next(); + } + if ( secondCandidateUrl !== "" ) { + req.url = secondCandidateUrl; + return next(); + } + return next(); }); for ( let routeScript in routes ) { - let route = routes[routeScript].replace(".js", ""); + let route = routes[routeScript].replace(/\.js$/, ""); + pathMatches.push(createPathMatch(route)); let routeObj = require(`./routes/${route}`); if ( routeObj.get ) { app.get(`/${route}`, routeObj.get); diff --git a/package-lock.json b/package-lock.json index ae2d4fb..db44817 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,8 @@ "license": "WTFPL", "dependencies": { "express": "^4.18.2", - "glob": "^9.3.0" + "glob": "^9.3.0", + "path-to-regexp": "^6.2.1" } }, "node_modules/accepts": { @@ -210,6 +211,11 @@ "node": ">= 0.10.0" } }, + "node_modules/express/node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, "node_modules/finalhandler": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", @@ -481,9 +487,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", + "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==" }, "node_modules/proxy-addr": { "version": "2.0.7", diff --git a/package.json b/package.json index e8607ff..e8c52a2 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "license": "WTFPL", "dependencies": { "express": "^4.18.2", - "glob": "^9.3.0" + "glob": "^9.3.0", + "path-to-regexp": "^6.2.1" } }