Skip to content

Commit f5c31e6

Browse files
committed
chore(router): lint++
1 parent e94dc52 commit f5c31e6

File tree

6 files changed

+83
-80
lines changed

6 files changed

+83
-80
lines changed

packages/qwik-router/src/buildtime/build.ts

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { addError, addWarning } from '../utils/format';
22
import { resolveSourceFiles } from './routing/resolve-source-file';
3+
import { routeSortCompare } from './routing/sort-routes';
34
import { walkRoutes } from './routing/walk-routes-dir';
45
import { walkServerPlugins } from './routing/walk-server-plugins';
56
import type { RoutingContext, BuiltRoute, RewriteRouteOption } from './types';
@@ -21,35 +22,29 @@ export async function parseRoutesDir(ctx: RoutingContext) {
2122
}
2223
}
2324

24-
export async function updateRoutingContext(ctx: RoutingContext) {
25-
if (!ctx.activeBuild) {
26-
ctx.activeBuild = new Promise<void>((resolve, reject) => {
27-
walkServerPlugins(ctx.opts)
28-
.then((serverPlugins) => {
29-
ctx.serverPlugins = serverPlugins;
30-
return walkRoutes(ctx.opts.routesDir);
31-
})
32-
.then((sourceFiles) => {
33-
const resolved = resolveSourceFiles(ctx.opts, sourceFiles);
34-
rewriteRoutes(ctx, resolved);
35-
ctx.layouts = resolved.layouts;
36-
ctx.routes = resolved.routes;
37-
ctx.entries = resolved.entries;
38-
ctx.serviceWorkers = resolved.serviceWorkers;
39-
ctx.menus = resolved.menus;
40-
resolve();
41-
}, reject)
42-
.finally(() => {
43-
ctx.activeBuild = null;
44-
});
45-
});
46-
}
25+
export function updateRoutingContext(ctx: RoutingContext) {
26+
ctx.activeBuild ||= _updateRoutingContext(ctx).finally(() => {
27+
ctx.activeBuild = null;
28+
});
4729
return ctx.activeBuild;
4830
}
4931

50-
function rewriteRoutes(ctx: RoutingContext, resolvedFiles: ReturnType<typeof resolveSourceFiles>) {
51-
if (!ctx.opts.rewriteRoutes || !resolvedFiles.routes) {
52-
return;
32+
async function _updateRoutingContext(ctx: RoutingContext) {
33+
const serverPlugins = await walkServerPlugins(ctx.opts);
34+
const sourceFiles = await walkRoutes(ctx.opts.routesDir);
35+
const resolved = resolveSourceFiles(ctx.opts, sourceFiles);
36+
resolved.routes = rewriteRoutes(ctx, resolved.routes);
37+
ctx.serverPlugins = serverPlugins;
38+
ctx.layouts = resolved.layouts;
39+
ctx.routes = resolved.routes;
40+
ctx.entries = resolved.entries;
41+
ctx.serviceWorkers = resolved.serviceWorkers;
42+
ctx.menus = resolved.menus;
43+
}
44+
45+
function rewriteRoutes(ctx: RoutingContext, routes: BuiltRoute[]) {
46+
if (!ctx.opts.rewriteRoutes) {
47+
return routes;
5348
}
5449

5550
const translatedRoutes: BuiltRoute[] = [];
@@ -60,7 +55,7 @@ function rewriteRoutes(ctx: RoutingContext, resolvedFiles: ReturnType<typeof res
6055

6156
segmentsToTranslate = Array.from(new Set(segmentsToTranslate));
6257

63-
resolvedFiles.routes.forEach((route) => {
58+
routes.forEach((route) => {
6459
// always push the original route
6560
translatedRoutes.push(route);
6661

@@ -91,7 +86,7 @@ function rewriteRoutes(ctx: RoutingContext, resolvedFiles: ReturnType<typeof res
9186
}
9287
});
9388

94-
resolvedFiles.routes = translatedRoutes;
89+
return translatedRoutes.sort(routeSortCompare);
9590
}
9691

9792
function translateRoute(

packages/qwik-router/src/buildtime/routing/sort-routes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { BuiltRoute } from '../types';
22

3+
/** Sort routes by pathname, then by extension. Longer routes are sorted first. */
34
export function routeSortCompare(a: BuiltRoute, b: BuiltRoute) {
45
const maxSegments = Math.max(a.segments.length, b.segments.length);
56

packages/qwik-router/src/middleware/request-handler/request-event.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,11 @@ export function createRequestEvent(
144144
return exit();
145145
};
146146

147-
const exit = () => {
147+
const exit = <T extends AbortMessage | RedirectMessage | RewriteMessage>(
148+
message: T = new AbortMessage() as T
149+
) => {
148150
routeModuleIndex = ABORT_INDEX;
149-
return new AbortMessage();
151+
return message;
150152
};
151153

152154
const loaders: Record<string, ValueOrPromise<unknown> | undefined> = {};
@@ -252,8 +254,7 @@ export function createRequestEvent(
252254
if (statusCode > 301) {
253255
headers.set('Cache-Control', 'no-store');
254256
}
255-
exit();
256-
return new RedirectMessage();
257+
return exit(new RedirectMessage());
257258
},
258259

259260
rewrite: (pathname: string) => {
@@ -262,7 +263,7 @@ export function createRequestEvent(
262263
throw new Error('Rewrite does not support absolute urls');
263264
}
264265
sharedMap.set(RequestEvIsRewrite, true);
265-
return new RewriteMessage(pathname.replace(/\/+/g, '/'));
266+
return exit(new RewriteMessage(pathname.replace(/\/+/g, '/')));
266267
},
267268

268269
defer: (returnData) => {

packages/qwik-router/src/middleware/request-handler/request-handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { getRouteMatchPathname, runQwikRouter, type QwikRouterRun } from './user
1111
*/
1212
let qwikRouterConfigActual: QwikRouterConfig;
1313
/**
14-
* The request handler for QwikRouter. Called by every integration.
14+
* The request handler for QwikRouter. Called by every adapter.
1515
*
1616
* @public
1717
*/

packages/qwik-router/src/middleware/request-handler/user-response.ts

Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,31 @@ import type {
88
import { getErrorHtml } from './error-handler';
99
import { createRequestEvent, getRequestMode, type RequestEventInternal } from './request-event';
1010
import { encoder } from './resolve-request-handlers';
11-
import type { ServerRequestEvent, StatusCodes } from './types';
1211
// Import separately to avoid duplicate imports in the vite dev server
1312
import {
1413
AbortMessage,
1514
RedirectMessage,
1615
RewriteMessage,
1716
ServerError,
1817
} from '@qwik.dev/router/middleware/request-handler';
18+
import type { QwikSerializer, ServerRequestEvent, StatusCodes } from './types';
1919

2020
export interface QwikRouterRun<T> {
21+
/**
22+
* The response to the request, if any. If there is no response, there might have been an error,
23+
* or the request was aborted.
24+
*/
2125
response: Promise<T | null>;
2226
requestEv: RequestEvent;
23-
completion: Promise<unknown>;
27+
/**
28+
* Promise for the completion of the request.
29+
*
30+
* If it returns a RedirectMessage, it means the request must be redirected.
31+
*
32+
* If it returns an Error, it means there was an error, and if possible, the response already
33+
* includes the error. The error is informational only.
34+
*/
35+
completion: Promise<RedirectMessage | Error | undefined>;
2436
}
2537

2638
let asyncStore: AsyncStore | undefined;
@@ -67,7 +79,7 @@ async function runNext(
6779
requestEv: RequestEventInternal,
6880
rebuildRouteInfo: RebuildRouteInfoInternal,
6981
resolve: (value: any) => void
70-
) {
82+
): Promise<Error | RedirectMessage | undefined> {
7183
try {
7284
const isValidURL = (url: URL) => new URL(url.pathname + url.search, url);
7385
isValidURL(requestEv.originalUrl);
@@ -90,9 +102,10 @@ async function runNext(
90102
if (e instanceof RedirectMessage) {
91103
const stream = requestEv.getWritableStream();
92104
await stream.close();
105+
return e;
93106
} else if (e instanceof RewriteMessage) {
94107
if (rewriteAttempt > 50) {
95-
throw new Error(`Infinite rewrite loop`);
108+
return new Error(`Infinite rewrite loop`);
96109
}
97110

98111
rewriteAttempt += 1;
@@ -101,48 +114,47 @@ async function runNext(
101114
const { loadedRoute, requestHandlers } = await rebuildRouteInfo(url);
102115
requestEv.resetRoute(loadedRoute, requestHandlers, url);
103116
return await _runNext();
104-
} else if (e instanceof ServerError) {
105-
if (!requestEv.headersSent) {
106-
const status = e.status as StatusCodes;
107-
const accept = requestEv.request.headers.get('Accept');
108-
if (accept && !accept.includes('text/html')) {
109-
requestEv.headers.set('Content-Type', 'application/qwik-json');
110-
requestEv.send(status, await _serialize([e.data]));
111-
} else {
112-
const html = getErrorHtml(e.status, e.data);
113-
requestEv.html(status, html);
114-
}
117+
} else if (e instanceof AbortMessage) {
118+
return;
119+
} else if (e instanceof ServerError && !requestEv.headersSent) {
120+
const status = e.status as StatusCodes;
121+
const accept = requestEv.request.headers.get('Accept');
122+
if (accept && !accept.includes('text/html')) {
123+
requestEv.headers.set('Content-Type', 'application/qwik-json');
124+
requestEv.send(status, await _serialize([e.data]));
125+
} else {
126+
// TODO render the custom error route
127+
requestEv.html(status, getErrorHtml(status, e.data));
115128
}
116-
} else if (!(e instanceof AbortMessage)) {
117-
if (getRequestMode(requestEv) !== 'dev') {
118-
try {
119-
if (!requestEv.headersSent) {
120-
requestEv.headers.set('content-type', 'text/html; charset=utf-8');
121-
requestEv.cacheControl({ noCache: true });
122-
requestEv.status(500);
123-
}
124-
const stream = requestEv.getWritableStream();
125-
if (!stream.locked) {
126-
const writer = stream.getWriter();
127-
await writer.write(encoder.encode(getErrorHtml(500, 'Internal Server Error')));
128-
await writer.close();
129-
}
130-
} catch {
131-
console.error('Unable to render error page');
129+
return e;
130+
}
131+
if (getRequestMode(requestEv) !== 'dev') {
132+
try {
133+
if (!requestEv.headersSent) {
134+
requestEv.headers.set('content-type', 'text/html; charset=utf-8');
135+
requestEv.cacheControl({ noCache: true });
136+
requestEv.status(500);
137+
}
138+
const stream = requestEv.getWritableStream();
139+
if (!stream.locked) {
140+
const writer = stream.getWriter();
141+
await writer.write(encoder.encode(getErrorHtml(500, 'Internal Server Error')));
142+
await writer.close();
132143
}
144+
} catch {
145+
console.error('Unable to render error page');
133146
}
134-
135-
return e;
136147
}
137-
}
138148

139-
return undefined;
149+
return e as Error;
150+
}
140151
}
141152

142153
try {
143154
return await _runNext();
144155
} finally {
145156
if (!requestEv.isDirty()) {
157+
// The request didn't get handled, so we need to resolve with null.
146158
resolve(null);
147159
}
148160
}

packages/qwik-router/src/utils/fs.ts

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export function normalizePath(path: string) {
7979
export function normalizePathSlash(path: string) {
8080
// MIT https://github.com/sindresorhus/slash/blob/main/license
8181
// Convert Windows backslash paths to slash paths: foo\\bar ➔ foo/bar
82-
const isExtendedLengthPath = /^\\\\\?\\/.test(path);
82+
const isExtendedLengthPath = path.startsWith('\\\\?\\');
8383
const hasNonAscii = /[^\u0000-\u0080]+/.test(path); // eslint-disable-line no-control-regex
8484

8585
if (isExtendedLengthPath || hasNonAscii) {
@@ -139,17 +139,17 @@ export function createFileId(
139139
const PAGE_MODULE_EXTS: { [type: string]: boolean } = {
140140
'.tsx': true,
141141
'.jsx': true,
142-
};
142+
} as const;
143143

144144
const MODULE_EXTS: { [type: string]: boolean } = {
145145
'.ts': true,
146146
'.js': true,
147-
};
147+
} as const;
148148

149149
const MARKDOWN_EXTS: { [type: string]: boolean } = {
150150
'.md': true,
151151
'.mdx': true,
152-
};
152+
} as const;
153153

154154
export function isIndexModule(extlessName: string) {
155155
return /^index(|!|@.+)$/.test(extlessName);
@@ -192,13 +192,7 @@ export function isEntryName(extlessName: string) {
192192
}
193193

194194
export function isErrorName(extlessName: string) {
195-
try {
196-
const statusCode = parseInt(extlessName, 10);
197-
return statusCode >= 400 && statusCode <= 599;
198-
} catch (e) {
199-
//
200-
}
201-
return false;
195+
return /^[45][0-9]{2}$/.test(extlessName);
202196
}
203197

204198
export function isGroupedLayoutName(dirName: string, warn = true) {

0 commit comments

Comments
 (0)