Spaces:
Sleeping
Sleeping
File size: 9,369 Bytes
cc11e77 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | // acceptancePatternsCore.ts — S-P3-1: split da acceptancePatterns.ts
// Sezioni: Auth / Login, CRUD, Dashboard, API / Backend, Database,
// Pagamenti, SaaS / Multi-tenant, Test suite, Package.json / deps
import type { AcceptanceTest } from './acceptanceTypes'; // anti-ciclo: tipo estratto da goalTestDeriver
export interface GoalPattern {
re: RegExp;
tests: Array<Omit<AcceptanceTest, "id">>;
}
export const CORE_PATTERNS: GoalPattern[] = [
// ── Auth / Login / Registration ─────────────────────────────────────────────
{
re: /login|signin|sign.?in|sign.?up|signup|registr(?:az|ation|ati)?|autenticaz|authentication|auth(?:orization|entication)?|logout|sessione?|password|jwt|bearer|token.?auth|oauth|2fa|mfa|otp/i,
tests: [
{
requirement: "File di autenticazione presente",
critical: true,
checkFn: `
const authFiles = files.filter(f =>
/auth|login|signin|session/i.test(f.path) && f.content
);
return { pass: authFiles.length > 0,
detail: authFiles.length > 0
? "Trovato: " + authFiles.map(f=>f.path).join(", ")
: "Mancano file auth/login nel VFS" };
`,
},
{
requirement: "Form di login con input email/password",
critical: false,
checkFn: `
const loginFile = files.find(f =>
/login|signin/i.test(f.path) && /email|password|input/i.test(f.content||"")
);
return { pass: !!loginFile,
detail: loginFile ? loginFile.path : "Nessun form login con email+password trovato" };
`,
},
],
},
// ── CRUD (crud|crm|list|crea|create|gestione) ───────────────────────────────
{
re: /\bcrud\b|(?:crea|aggiungi|add).{0,50}(?:modifica|edit|update).{0,50}(?:elimina|delete|rimuovi)|(?:insert|update|delete).{0,30}(?:insert|update|delete)|gestione.{0,40}(?:utenti|prodotti|ordini|clienti|record|entit)|lista.*(?:crea|aggiungi|modifica|elimina)|tabella.*modificabil/i,
tests: [
{
requirement: "Operazioni CRUD presenti nel codice",
critical: true,
checkFn: `
const crudOps = { create: false, read: false, update: false, delete: false };
for (const f of files) {
const c = (f.content||"").toLowerCase();
if (/insert|create|post.*body|supabase.*insert|\.add\(/i.test(c)) crudOps.create = true;
if (/select|find|get.*list|fetch.*all|supabase.*select/i.test(c)) crudOps.read = true;
if (/update|patch|put.*body|supabase.*update|\.set\(/i.test(c)) crudOps.update = true;
if (/delete|remove|supabase.*delete|\.destroy\(/i.test(c)) crudOps.delete = true;
}
const missing = Object.entries(crudOps).filter(([,v])=>!v).map(([k])=>k);
return { pass: missing.length === 0,
detail: missing.length === 0
? "C/R/U/D tutte presenti"
: "Mancano operazioni: " + missing.join(", ") };
`,
},
],
},
// ── Dashboard ───────────────────────────────────────────────────────────────
{
re: /dashboard|pannello|statistiche|analytics|chart|grafico|kpi/i,
tests: [
{
requirement: "Componente dashboard / statistiche presente",
critical: true,
checkFn: `
const dash = files.find(f =>
/dashboard|stats|analytics/i.test(f.path) && f.content
);
return { pass: !!dash,
detail: dash ? dash.path : "Manca file dashboard/stats nel VFS" };
`,
},
{
requirement: "Dati / metriche visualizzati (chart o tabella)",
critical: false,
checkFn: `
const hasChart = files.some(f =>
/recharts|chart\.js|apex|d3|nivo|canvas|<table|<tr/i.test(f.content||"")
);
return { pass: hasChart,
detail: hasChart ? "Libreria chart o tabella trovata" : "Nessuna visualizzazione dati trovata" };
`,
},
],
},
// ── API / Backend ───────────────────────────────────────────────────────────
{
re: /api|endpoint|rest|fastapi|express|backend|server/i,
tests: [
{
requirement: "File route/endpoint presente",
critical: true,
checkFn: `
const route = files.find(f =>
/route|endpoint|controller|api\//i.test(f.path) &&
/(app\.(get|post|put|delete|patch)|router\.|@app\.|@router\.)/i.test(f.content||"")
);
return { pass: !!route,
detail: route ? route.path : "Nessun route/endpoint trovato" };
`,
},
{
requirement: "Almeno 1 endpoint GET e 1 POST",
critical: false,
checkFn: `
const allCode = files.map(f=>f.content||"").join("\\n");
const hasGet = /(app|router)\.(get|route)\(|@app\.get|@router\.get/i.test(allCode);
const hasPost = /(app|router)\.(post|route)\(|@app\.post|@router\.post/i.test(allCode);
return { pass: hasGet && hasPost,
detail: (!hasGet ? "Manca GET " : "") + (!hasPost ? "Manca POST" : "GET e POST presenti") };
`,
},
],
},
// ── Database ────────────────────────────────────────────────────────────────
{
re: /database|supabase|postgresql|postgres|mysql|mongodb|sqlite|prisma|drizzle/i,
tests: [
{
requirement: "Schema / modello dati presente",
critical: true,
checkFn: `
const schema = files.find(f =>
/schema|model|migration|\.sql$|prisma/i.test(f.path) && f.content
);
const hasTableDef = files.some(f =>
/create table|defineTable|pgTable|model.*{|Schema\(/i.test(f.content||"")
);
return { pass: !!(schema || hasTableDef),
detail: schema ? schema.path : (hasTableDef ? "Schema trovato in codice" : "Manca schema/modello dati") };
`,
},
],
},
// ── Pagamenti ───────────────────────────────────────────────────────────────
{
re: /pagamento|stripe|payment|checkout|abbonamento|subscription/i,
tests: [
{
requirement: "Integrazione pagamenti (Stripe / checkout)",
critical: true,
checkFn: `
const payment = files.find(f =>
/stripe|payment|checkout/i.test(f.content||"")
);
return { pass: !!payment,
detail: payment ? payment.path : "Nessuna integrazione pagamenti trovata" };
`,
},
],
},
// ── SaaS / Multi-tenant ─────────────────────────────────────────────────────
{
re: /saas|multi.?tenant|organization|workspace|team/i,
tests: [
{
requirement: "Isolamento tenant (organization_id / workspace_id)",
critical: true,
checkFn: `
const allCode = files.map(f=>f.content||"").join("\\n");
const hasTenant = /organization_id|tenant_id|workspace_id|org_id|team_id/i.test(allCode);
return { pass: hasTenant,
detail: hasTenant ? "Tenant isolation trovata" : "Manca organization_id/tenant_id nei modelli" };
`,
},
],
},
// ── Test suite ──────────────────────────────────────────────────────────────
{
re: /test.*suite|unit test|integration test|vitest|jest|pytest/i,
tests: [
{
requirement: "File di test presenti",
critical: true,
checkFn: `
const tests = files.filter(f => /\\.test\\.|spec\\.|__tests__/i.test(f.path));
return { pass: tests.length > 0,
detail: tests.length > 0
? tests.length + " file di test: " + tests.slice(0,3).map(f=>f.path).join(", ")
: "Nessun file .test.ts / spec.ts trovato" };
`,
},
],
},
// ── Package.json / deps ─────────────────────────────────────────────────────
{
re: /\bapp\b|\bsito\b|progetto|project|applicazione/i,
tests: [
{
requirement: "package.json o requirements.txt presente",
critical: false,
checkFn: `
const pkg = files.find(f => f.path === "package.json" || f.path === "/package.json"
|| f.path === "requirements.txt");
return { pass: !!pkg, detail: pkg ? pkg.path + " trovato" : "Manca package.json / requirements.txt" };
`,
},
],
},
];
|