From e7887f054f264944cc0d7318e95e3d501e28948a Mon Sep 17 00:00:00 2001 From: Marc Mintel Date: Wed, 14 Jan 2026 13:10:45 +0100 Subject: [PATCH] website refactor --- .../page-query-must-use-builders.js | 59 ++++++++++++++++--- .../eslint-rules/rsc-boundary-rules.js | 1 + 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/apps/website/eslint-rules/page-query-must-use-builders.js b/apps/website/eslint-rules/page-query-must-use-builders.js index aff9c71ed..37626f1a7 100644 --- a/apps/website/eslint-rules/page-query-must-use-builders.js +++ b/apps/website/eslint-rules/page-query-must-use-builders.js @@ -31,6 +31,7 @@ module.exports = { let hasBuilderImport = false; const builderUsages = []; const returnStatements = []; + const builtVariables = new Set(); return { // Check for builder imports @@ -51,6 +52,42 @@ module.exports = { } }, + // Track variable assignments from builders + VariableDeclarator(node) { + if (node.init && node.init.type === 'CallExpression') { + const callee = node.init.callee; + if (callee.type === 'MemberExpression' && + callee.property.type === 'Identifier' && + callee.property.name === 'build') { + builtVariables.add(node.id.name); + } + } + }, + + // Track variable assignments from builders + VariableDeclarator(node) { + if (node.init && node.init.type === 'CallExpression') { + const callee = node.init.callee; + if (callee.type === 'MemberExpression' && + callee.property.type === 'Identifier' && + callee.property.name === 'build') { + builtVariables.add(node.id.name); + } + } + }, + + // Track variable assignments from builders + VariableDeclarator(node) { + if (node.init && node.init.type === 'CallExpression') { + const callee = node.init.callee; + if (callee.type === 'MemberExpression' && + callee.property.type === 'Identifier' && + callee.property.name === 'build') { + builtVariables.add(node.id.name); + } + } + }, + // Track return statements ReturnStatement(node) { if (node.argument) { @@ -70,33 +107,37 @@ module.exports = { // Check if return statements use builders returnStatements.forEach(returnNode => { const returnExpr = returnNode.argument; - + // Check if it's a builder call if (returnExpr && returnExpr.type === 'CallExpression') { const callee = returnExpr.callee; - + // Check if it's a builder method call (e.g., ViewDataBuilder.build()) - if (callee.type === 'MemberExpression' && - callee.property.type === 'Identifier' && + if (callee.type === 'MemberExpression' && + callee.property.type === 'Identifier' && callee.property.name === 'build') { // This is good - using a builder return; } - + // Check if it's a direct Result.ok() with DTO - if (callee.type === 'MemberExpression' && - callee.object.type === 'Identifier' && + if (callee.type === 'MemberExpression' && + callee.object.type === 'Identifier' && callee.object.name === 'Result' && callee.property.type === 'Identifier' && callee.property.name === 'ok') { - + // Check if the argument is a variable that might be a DTO if (returnExpr.arguments && returnExpr.arguments[0]) { const arg = returnExpr.arguments[0]; - + // If it's an identifier, check if it's likely a DTO if (arg.type === 'Identifier') { const varName = arg.name; + // Skip if it's a variable built from a builder + if (builtVariables.has(varName)) { + return; + } // Common DTO patterns: result, data, dto, apiResult, etc. if (varName.match(/(result|data|dto|apiResult|response)/i)) { context.report({ diff --git a/apps/website/eslint-rules/rsc-boundary-rules.js b/apps/website/eslint-rules/rsc-boundary-rules.js index 32df410de..a276ad27e 100644 --- a/apps/website/eslint-rules/rsc-boundary-rules.js +++ b/apps/website/eslint-rules/rsc-boundary-rules.js @@ -333,6 +333,7 @@ module.exports = { NewExpression(node) { if (node.callee.type === 'Identifier' && /^[A-Z]/.test(node.callee.name) && + !node.callee.name.endsWith('PageQuery') && !isInComment(node)) { context.report({ node,