/**
* scaffold-login-page/generate.ts — PURE spec -> GeneratedFile[] (zero I/O).
*
* Emits, into web/{appCode}-web/src/:
* - auth/{ComponentName}.tsx the editable login override (dev-owned)
* - extensions/login.generated.ts wiring: loginExtensions = { pages: { [PAGE_KEYS.LOGIN]: ... } }
*
* and (via index.ts) wires main.tsx to import + spread `loginExtensions` into the
* provider's `extensions: {}` — coexisting with any `...vitrineExtensions` spread
* already there (the two register different PAGE_KEYS).
*
* The component consumes the package's public seam: `useLoginForm()` drives the
* real /api/auth/login flow (tokens land in httpOnly cookies, redirects + onboarding
* handled inside the hook — the component only owns presentation), OAuth buttons
* hit /api/auth/{microsoft,google}, and the Entra SSO button goes to /sso. Only the
* providers + registration link the spec asks for are emitted — that is the UI-side
* masking the backend cannot do.
*/
import type { GeneratedFile, ProjectLayout, ScaffoldLoginPageInput } from './types.js';
const BANNER =
'/* Scaffolded by /login-config (scaffold-login-page) — editable. Re-running keeps your edits (use force to overwrite). */\n';
/** JSON string literal for embedding in generated source. */
const s = (v: string): string => JSON.stringify(v);
function providerButton(label: string, target: string): string {
return ` `;
}
// ============================================================================
// Login page component (dev-owned, editable; emitted once unless --force)
// ============================================================================
export function buildLoginComponent(spec: ScaffoldLoginPageInput): string {
const { providers, branding } = spec;
const comp = spec.componentName;
const title = branding?.title ?? branding?.appName ?? 'Connexion';
const imports = [
`import type { ReactElement } from 'react';`,
`import type { PageProps } from '@atlashub/smartstack';`,
];
if (providers.local) imports.push(`import { useLoginForm } from '@atlashub/smartstack';`);
// Branding header (text passed as JSX expressions so any character is safe).
const brandingParts: string[] = [];
if (branding?.logoUrl) {
brandingParts.push(` `);
}
brandingParts.push(`
{${s(title)}}
`);
if (branding?.subtitle) {
brandingParts.push(`
{${s(branding.subtitle)}}
`);
}
// Email/password form (only when the local provider is shown).
let formBlock = '';
if (providers.local) {
const forgot = spec.showForgotPassword
? `