website refactor

This commit is contained in:
2026-01-14 02:02:24 +01:00
parent 8d7c709e0c
commit 4522d41aef
291 changed files with 12763 additions and 9309 deletions

View File

@@ -17,10 +17,61 @@ module.exports = {
manualSearchParams: 'Manual URLSearchParams construction. Use SearchParamBuilder instead: import { SearchParamBuilder } from "@/lib/routing/search-params"',
manualGetParam: 'Manual search param access with get(). Use SearchParamParser instead: import { SearchParamParser } from "@/lib/routing/search-params"',
manualSetParam: 'Manual search param setting with set(). Use SearchParamBuilder instead',
manualQueryString:
'Manual query-string construction detected (e.g. "?returnTo=..."). Use SearchParamBuilder instead: import { SearchParamBuilder } from "@/lib/routing/search-params/SearchParamBuilder"',
},
},
create(context) {
const SEARCH_PARAM_KEYS = new Set([
// Auth
'returnTo',
'token',
'email',
'error',
'message',
// Sponsor
'type',
'campaignId',
// Pagination
'page',
'limit',
'offset',
// Sorting
'sortBy',
'order',
// Filters
'status',
'role',
'tier',
]);
/**
* Detect patterns like:
* - "?returnTo="
* - "&returnTo="
* - "?page="
* - "returnTo=" (within a URL string)
*/
function containsManualQueryParamFragment(raw) {
if (typeof raw !== 'string' || raw.length === 0) return false;
// Fast pre-check
if (!raw.includes('?') && !raw.includes('&') && !raw.includes('=')) return false;
for (const key of SEARCH_PARAM_KEYS) {
if (
raw.includes(`?${key}=`) ||
raw.includes(`&${key}=`) ||
// catches "...returnTo=..." in some string-building scenarios
raw.includes(`${key}=`)
) {
return true;
}
}
return false;
}
return {
// Detect: new URLSearchParams()
NewExpression(node) {
@@ -49,6 +100,42 @@ module.exports = {
}
},
// Detect manual query strings, e.g.
// `${routes.auth.login}?returnTo=${routes.protected.onboarding}`
// routes.auth.login + '?returnTo=' + routes.protected.onboarding
TemplateLiteral(node) {
// If any static chunk contains a query-param fragment, treat it as manual.
for (const quasi of node.quasis) {
const raw = quasi.value && (quasi.value.raw ?? quasi.value.cooked);
if (containsManualQueryParamFragment(raw)) {
context.report({
node,
messageId: 'manualQueryString',
});
return;
}
}
},
BinaryExpression(node) {
// String concatenation patterns, e.g. a + '?returnTo=' + b
if (node.operator !== '+') return;
// If either side is a literal string containing query params, report.
const left = node.left;
const right = node.right;
if (left && left.type === 'Literal' && typeof left.value === 'string' && containsManualQueryParamFragment(left.value)) {
context.report({ node, messageId: 'manualQueryString' });
return;
}
if (right && right.type === 'Literal' && typeof right.value === 'string' && containsManualQueryParamFragment(right.value)) {
context.report({ node, messageId: 'manualQueryString' });
return;
}
},
// Detect: params.get() or params.set()
CallExpression(node) {
if (node.callee.type === 'MemberExpression') {