import { readFileSync, readdirSync, unlinkSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import process from "node:process"; const root = join(import.meta.dirname, ".."); const uiRoot = join(root, "packages", "ui"); const componentsDir = join(uiRoot, "components"); const preservedButton = readFileSync(join(componentsDir, "Button.wrn"), "utf8"); const preservedAdvancedSelect = readFileSync(join(componentsDir, "AdvancedSelect.wrn"), "utf8"); const groups = { layout: [ "Container", "Columns", "Grid", "LayoutSplitter", "Typography", "Image", "Link", "Divider", "Kbd", "CustomScrollbar", ], base: [ "Accordion", "Alert", "Avatar", "AvatarGroup", "Badge", "Blockquote", "Button", "ButtonGroup", "Card", "ChatBubble", "Carousel", "Collapse", "DatePicker", "DeviceFrame", "List", "ListGroup", "LegendIndicator", "Progress", "FileUploadProgress", "Rating", "Skeleton", "Spinner", "StyledIcon", "Toast", "Timeline", "TreeView", "Marquee", ], navigation: [ "Navbar", "MegaMenu", "Nav", "Tabs", "Sidebar", "Scrollspy", "Breadcrumb", "Pagination", "Stepper", ], forms: [ "Input", "InputGroup", "Textarea", "FileInput", "Checkbox", "Radio", "Switch", "Select", "RangeSlider", "ColorPicker", "TimePicker", ], "advanced-forms": [ "AdvancedSelect", "Combobox", "SearchBox", "InputNumber", "StrongPassword", "TogglePassword", "ToggleCount", "CopyMarkup", "PinInput", ], overlays: ["Dropdown", "ContextMenu", "Modal", "Drawer", "Popover", "Tooltip"], tables: ["Table"], integrations: [ "AdvancedRangeSlider", "AdvancedDatePicker", "Chart", "Clipboard", "Confetti", "DataMap", "DataTable", "DragAndDrop", "FileUpload", "Map", "ToastNotifications", "WysiwygEditor", ], }; const displayName = (name) => name.replace(/([a-z0-9])([A-Z])/g, "$1 $2"); const kebab = (name) => displayName(name).replace(/\s+/g, "-").toLowerCase(); function layoutComponent(name) { if (name === "Image") return `component Image { props { src = "" alt = "" width = "" height = "" loading = "lazy" rounded = false class = "" } view {
{alt}
} } `; if (name === "Link") return `component Link { props { label = "Link" href = "#" target = "" rel = "" external = false class = "" } view { {label}{#if external}{/if} } } `; if (name === "Divider") return `component Divider { props { label = "" orientation = "horizontal" class = "" } view { } } `; if (name === "Kbd") return `component Kbd { props { label = "⌘ K" class = "" } view { {label} } } `; const tag = name === "Typography" ? "article" : "div"; return `component ${name} { props { columns = 2 gap = "md" maxWidth = "xl" class = "" } view { <${tag} class="wire-next wire-next--${kebab(name)} wire-next--gap-{gap} wire-next--columns-{columns} wire-next--max-{maxWidth} {class}"> } } `; } function collectionComponent(name) { if (name === "Accordion" || name === "Collapse") return `component ${name} { props { items = [] multiple = false class = "" } view {
{#each items as item}
{item.label}
{item.content}
{/each}
} } `; if (name === "Progress" || name === "FileUploadProgress") return `component ${name} { props { label = "Progress" value = 50 max = 100 showValue = true class = "" } view {
{label}{#if showValue}{value}%{/if}
} } `; if (name === "Spinner" || name === "Skeleton") return `component ${name} { props { label = "Loading" size = "md" lines = 3 class = "" } view {
{#if "${name}" === "Skeleton"}{#each Array(lines).fill(0) as line}{/each}{:else}{/if}
} } `; return `component ${name} { props { title = "${displayName(name)}" description = "" items = [] variant = "default" class = "" } view {
{#if title}{title}{/if} {#if description}

{description}

{/if} {#if items}
{#each items as item}{item.label}{/each}
{/if}
} } `; } function navigationComponent(name) { return `component ${name} { props { label = "${displayName(name)}" items = [] active = "" orientation = "horizontal" class = "" } view { } } `; } function formComponent(name) { const typeByName = { Input: "text", SearchBox: "search", InputNumber: "number", StrongPassword: "password", TogglePassword: "password", PinInput: "text", DatePicker: "date", AdvancedDatePicker: "date", TimePicker: "time", ColorPicker: "color", RangeSlider: "range", AdvancedRangeSlider: "range", FileInput: "file", }; if (name === "Textarea" || name === "WysiwygEditor") return `component ${name} { props { label = "${displayName(name)}" name = "" value = "" placeholder = "" rows = 5 disabled = false required = false class = "" } view { } } `; if (name === "Checkbox" || name === "Radio" || name === "Switch") return `component ${name} { props { label = "${displayName(name)}" name = "" value = "on" checked = false disabled = false class = "" } view { } } `; if (name.includes("Select") || name === "Combobox") return `component ${name} { props { label = "${displayName(name)}" name = "" value = "" options = [] placeholder = "Select an option" multiple = false disabled = false class = "" } view { } } `; const inputType = typeByName[name] ?? "text"; return `component ${name} { props { label = "${displayName(name)}" name = "" value = "" placeholder = "" type = "${inputType}" min = "" max = "" step = "" disabled = false required = false class = "" } view { } } `; } function overlayComponent(name) { const modal = name === "Modal" || name === "Drawer"; return `component ${name} { props { title = "${displayName(name)}" description = "" open = false placement = "bottom" closeLabel = "Close" class = "" } view {
{title}
{#if description}

{description}

{/if}
} } `; } function dataComponent(name) { if (name === "Table" || name === "DataTable") return `component ${name} { props { caption = "${displayName(name)}" columns = [] rows = [] striped = true class = "" } view {
{#each columns as column}{/each}{#each rows as row}{#each columns as column}{/each}{/each}
{caption}
{column.label}
{row[column.key]}
} } `; return collectionComponent(name); } function sourceFor(name, category) { if (name === "Button") return preservedButton; if (name === "AdvancedSelect") return preservedAdvancedSelect; if (category === "layout") return layoutComponent(name); if (category === "navigation") return navigationComponent(name); if (category === "forms" || category === "advanced-forms") return formComponent(name); if (category === "overlays") return overlayComponent(name); if (category === "tables" || category === "integrations") return dataComponent(name); if (name === "DatePicker") return formComponent(name); return collectionComponent(name); } function withUniversalDesignProps(source) { let next = source; if (!/^\s+color\s*=/m.test(next)) { next = next.replace(/(\s+props\s*\{\r?\n)/, '$1 color = "primary"\n'); } if (!/^\s+size\s*=/m.test(next)) { next = next.replace(/(\s+props\s*\{\r?\n)/, '$1 size = "default"\n'); } return next.replace( /class="wire-next(?![^"]*wire-next--color-)/, 'class="wire-next wire-next--color-{color} wire-next--size-{size}', ); } const entries = Object.entries(groups).flatMap(([category, names]) => names.map((name) => ({ name, category, purpose: `Theme-aware, responsive ${displayName(name).toLowerCase()} component.`, })), ); for (const file of readdirSync(componentsDir)) { if (file.endsWith(".wrn")) unlinkSync(join(componentsDir, file)); } for (const entry of entries) { writeFileSync( join(componentsDir, `${entry.name}.wrn`), withUniversalDesignProps(sourceFor(entry.name, entry.category)), "utf8", ); } writeFileSync( join(uiRoot, "component-catalog.json"), `${JSON.stringify({ sourceDocuments: ["Screenshot-directed WRNexus UI catalog reset"], components: entries }, null, 2)}\n`, ); writeFileSync( join(uiRoot, "component-migrations.json"), `${JSON.stringify({ generatedFrom: "full component catalog reset", removedCount: 0, replacements: {} }, null, 2)}\n`, ); process.stdout.write(`Reset @wrnexus/ui to ${entries.length} canonical components.\n`);