release: WRNexusJS 0.6.0
This commit is contained in:
@@ -81,6 +81,11 @@
|
||||
"category": "base",
|
||||
"purpose": "Theme-aware, responsive button group component."
|
||||
},
|
||||
{
|
||||
"name": "CTASection",
|
||||
"category": "marketing",
|
||||
"purpose": "Close a page or major section with conversion-focused copy, actions, and optional supporting visual content."
|
||||
},
|
||||
{
|
||||
"name": "Card",
|
||||
"category": "base",
|
||||
@@ -151,11 +156,6 @@
|
||||
"category": "advanced-forms",
|
||||
"purpose": "Theme-aware, responsive copy markup component."
|
||||
},
|
||||
{
|
||||
"name": "CTASection",
|
||||
"category": "marketing",
|
||||
"purpose": "Close a page or major section with conversion-focused copy, actions, and optional supporting visual content."
|
||||
},
|
||||
{
|
||||
"name": "CustomScrollbar",
|
||||
"category": "layout",
|
||||
@@ -481,26 +481,26 @@
|
||||
"category": "navigation",
|
||||
"purpose": "Switch between related responsive content panels with horizontal or vertical orientation and selection events."
|
||||
},
|
||||
{
|
||||
"name": "Textarea",
|
||||
"category": "forms",
|
||||
"purpose": "Theme-aware, responsive textarea component."
|
||||
},
|
||||
{
|
||||
"name": "TextLink",
|
||||
"category": "marketing",
|
||||
"purpose": "Render an accessible text action with optional icon, arrow, underline, external state, and semantic styling."
|
||||
},
|
||||
{
|
||||
"name": "Timeline",
|
||||
"category": "base",
|
||||
"purpose": "Present responsive chronological activity, milestones, or workflow status with rich item metadata."
|
||||
"name": "Textarea",
|
||||
"category": "forms",
|
||||
"purpose": "Theme-aware, responsive textarea component."
|
||||
},
|
||||
{
|
||||
"name": "TimePicker",
|
||||
"category": "forms",
|
||||
"purpose": "Theme-aware, responsive time picker component."
|
||||
},
|
||||
{
|
||||
"name": "Timeline",
|
||||
"category": "base",
|
||||
"purpose": "Present responsive chronological activity, milestones, or workflow status with rich item metadata."
|
||||
},
|
||||
{
|
||||
"name": "Toast",
|
||||
"category": "base",
|
||||
|
||||
@@ -2278,6 +2278,193 @@
|
||||
"events": ["click", "select", "change"],
|
||||
"source": "components/ButtonGroup.wrn"
|
||||
},
|
||||
{
|
||||
"name": "CTASection",
|
||||
"mount": "CTASection",
|
||||
"category": "marketing",
|
||||
"purpose": "Close a page or major section with conversion-focused copy, actions, and optional supporting visual content.",
|
||||
"props": [
|
||||
{
|
||||
"name": "eyebrow",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "title",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Ready to get started?\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "icon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "align",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"center\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "size",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "color",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"primary\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "variant",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"solid\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "primaryLabel",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Get started\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "primaryHref",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"#\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "primaryIcon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "secondaryLabel",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "secondaryHref",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "secondaryIcon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "backgroundImage",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualImage",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualAlt",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualIcon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualTitle",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualDescription",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualItems",
|
||||
"type": "unknown[]",
|
||||
"required": false,
|
||||
"default": "[]",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualPosition",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"right\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "maxWidth",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"xl\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "fullBleed",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "false",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "class",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"slots": ["default", "actions", "visual", "footer"],
|
||||
"outputs": [],
|
||||
"events": [],
|
||||
"source": "components/CTASection.wrn"
|
||||
},
|
||||
{
|
||||
"name": "Card",
|
||||
"mount": "Card",
|
||||
@@ -4250,193 +4437,6 @@
|
||||
"events": ["copy", "success", "error"],
|
||||
"source": "components/CopyMarkup.wrn"
|
||||
},
|
||||
{
|
||||
"name": "CTASection",
|
||||
"mount": "CTASection",
|
||||
"category": "marketing",
|
||||
"purpose": "Close a page or major section with conversion-focused copy, actions, and optional supporting visual content.",
|
||||
"props": [
|
||||
{
|
||||
"name": "eyebrow",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "title",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Ready to get started?\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "icon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "align",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"center\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "size",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "color",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"primary\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "variant",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"solid\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "primaryLabel",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Get started\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "primaryHref",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"#\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "primaryIcon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "secondaryLabel",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "secondaryHref",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "secondaryIcon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "backgroundImage",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualImage",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualAlt",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualIcon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualTitle",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualDescription",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualItems",
|
||||
"type": "unknown[]",
|
||||
"required": false,
|
||||
"default": "[]",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualPosition",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"right\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "maxWidth",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"xl\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "fullBleed",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "false",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "class",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"slots": ["default", "actions", "visual", "footer"],
|
||||
"outputs": [],
|
||||
"events": [],
|
||||
"source": "components/CTASection.wrn"
|
||||
},
|
||||
{
|
||||
"name": "CustomScrollbar",
|
||||
"mount": "CustomScrollbar",
|
||||
@@ -12144,6 +12144,129 @@
|
||||
"events": [],
|
||||
"source": "components/Tabs.wrn"
|
||||
},
|
||||
{
|
||||
"name": "TextLink",
|
||||
"mount": "TextLink",
|
||||
"category": "marketing",
|
||||
"purpose": "Render an accessible text action with optional icon, arrow, underline, external state, and semantic styling.",
|
||||
"props": [
|
||||
{
|
||||
"name": "label",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Learn more\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "href",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"#\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "target",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "rel",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "external",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "false",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "icon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "iconPosition",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"start\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "showArrow",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "true",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "underline",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "false",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "size",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "color",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"primary\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "variant",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "disabled",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "false",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "class",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"slots": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "click",
|
||||
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
|
||||
},
|
||||
{
|
||||
"name": "focus",
|
||||
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
|
||||
},
|
||||
{
|
||||
"name": "blur",
|
||||
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
|
||||
}
|
||||
],
|
||||
"events": ["click", "focus", "blur"],
|
||||
"source": "components/TextLink.wrn"
|
||||
},
|
||||
{
|
||||
"name": "Textarea",
|
||||
"mount": "Textarea",
|
||||
@@ -12338,190 +12461,6 @@
|
||||
"events": ["input", "change", "focus", "blur", "invalid"],
|
||||
"source": "components/Textarea.wrn"
|
||||
},
|
||||
{
|
||||
"name": "TextLink",
|
||||
"mount": "TextLink",
|
||||
"category": "marketing",
|
||||
"purpose": "Render an accessible text action with optional icon, arrow, underline, external state, and semantic styling.",
|
||||
"props": [
|
||||
{
|
||||
"name": "label",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Learn more\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "href",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"#\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "target",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "rel",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "external",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "false",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "icon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "iconPosition",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"start\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "showArrow",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "true",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "underline",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "false",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "size",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "color",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"primary\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "variant",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "disabled",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "false",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "class",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"slots": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "click",
|
||||
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
|
||||
},
|
||||
{
|
||||
"name": "focus",
|
||||
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
|
||||
},
|
||||
{
|
||||
"name": "blur",
|
||||
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
|
||||
}
|
||||
],
|
||||
"events": ["click", "focus", "blur"],
|
||||
"source": "components/TextLink.wrn"
|
||||
},
|
||||
{
|
||||
"name": "Timeline",
|
||||
"mount": "Timeline",
|
||||
"category": "base",
|
||||
"purpose": "Present responsive chronological activity, milestones, or workflow status with rich item metadata.",
|
||||
"props": [
|
||||
{
|
||||
"name": "size",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "color",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"primary\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "title",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Timeline\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "items",
|
||||
"type": "unknown[]",
|
||||
"required": false,
|
||||
"default": "[]",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "variant",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "class",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"slots": ["default"],
|
||||
"outputs": [],
|
||||
"events": [],
|
||||
"source": "components/Timeline.wrn"
|
||||
},
|
||||
{
|
||||
"name": "TimePicker",
|
||||
"mount": "TimePicker",
|
||||
@@ -12745,6 +12684,67 @@
|
||||
"events": ["input", "change", "focus", "blur", "open", "close", "invalid"],
|
||||
"source": "components/TimePicker.wrn"
|
||||
},
|
||||
{
|
||||
"name": "Timeline",
|
||||
"mount": "Timeline",
|
||||
"category": "base",
|
||||
"purpose": "Present responsive chronological activity, milestones, or workflow status with rich item metadata.",
|
||||
"props": [
|
||||
{
|
||||
"name": "size",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "color",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"primary\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "title",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Timeline\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "items",
|
||||
"type": "unknown[]",
|
||||
"required": false,
|
||||
"default": "[]",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "variant",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "class",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"slots": ["default"],
|
||||
"outputs": [],
|
||||
"events": [],
|
||||
"source": "components/Timeline.wrn"
|
||||
},
|
||||
{
|
||||
"name": "Toast",
|
||||
"mount": "Toast",
|
||||
|
||||
@@ -399,3 +399,9 @@ Comparison base: `WRNexusJS(4).zip`. Dependency directories, `.git`, and `.wrnex
|
||||
- Corrected the compiler regression test export-stripping regex from an over-escaped literal `\\s` match to the intended whitespace `\s` match.
|
||||
- Confirmed the generated peer-function browser module executes and updates shared state from `0` to `1`.
|
||||
- Added a release validator guard for the exact test source regression.
|
||||
|
||||
## R12 release reference gate
|
||||
|
||||
- Fixed false stale component-reference failures on Windows/autocrlf checkouts.
|
||||
- The release gate now uses canonical Git diffs and validates all three generated UI reference files.
|
||||
- Component-reference ordering is deterministic across operating systems and locales.
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# R12 release reference gate fix
|
||||
|
||||
## Failure
|
||||
|
||||
`bun run scripts/release.ts publish` could stop with:
|
||||
|
||||
```text
|
||||
UI component reference is stale.
|
||||
M packages/ui/component-reference.json
|
||||
```
|
||||
|
||||
even when the generated content was current.
|
||||
|
||||
## Root cause
|
||||
|
||||
The release gate used `git status --short` immediately after the generator ran. On Windows, generated files are written with LF while an `autocrlf` checkout may use CRLF. Git status can report the worktree file as modified even when its canonical Git content is unchanged.
|
||||
|
||||
The generator also writes `component-catalog.json`, but that file was not part of the release gate. Component ordering used `localeCompare`, which can vary by operating-system locale.
|
||||
|
||||
## Fix
|
||||
|
||||
- Compare generated files with `git diff --quiet`, which applies Git text normalization.
|
||||
- Show real differences with `git diff --name-status`.
|
||||
- Include all generated UI reference files:
|
||||
- `packages/ui/component-catalog.json`
|
||||
- `packages/ui/component-reference.json`
|
||||
- `packages/ui/COMPONENTS.md`
|
||||
- Replace locale-dependent sorting with a deterministic ASCII comparator.
|
||||
- Add validation guards for the complete release gate.
|
||||
|
||||
## Expected result
|
||||
|
||||
A line-ending-only rewrite does not block publication. A real component-reference, catalog, or documentation difference still blocks publication and prints the exact changed files.
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"releaseReferenceGate": {
|
||||
"deterministicGeneration": true,
|
||||
"lineEndingOnlyDiffIgnored": true,
|
||||
"regeneratedReferenceClean": true,
|
||||
"realContentDifferenceDetected": true,
|
||||
"generatedFiles": [
|
||||
"packages/ui/component-catalog.json",
|
||||
"packages/ui/component-reference.json",
|
||||
"packages/ui/COMPONENTS.md"
|
||||
]
|
||||
},
|
||||
"validation": {
|
||||
"passes": 20,
|
||||
"warnings": 1,
|
||||
"failures": 0,
|
||||
"warning": "Bun is unavailable in the packaging environment; run the full Bun check locally."
|
||||
}
|
||||
}
|
||||
@@ -36,3 +36,7 @@ This archive also includes the focused fixes for generated browser identifier sa
|
||||
- Nested peer calls no longer have their state changes overwritten by stale outer aliases.
|
||||
- Synchronous, asynchronous, and throwing peer calls refresh shared state correctly.
|
||||
- Added an executable `validate:0.6` regression probe for the exact compiler failure.
|
||||
|
||||
### R12 release workflow correction
|
||||
|
||||
The private publish workflow now compares generated UI reference files using canonical Git diffs, includes the component catalog, and uses platform-independent generator ordering. This prevents line-ending-only rewrites from being reported as stale references on Windows.
|
||||
|
||||
@@ -100,3 +100,9 @@ The complete `bun run check` command remains the authoritative local release gat
|
||||
- Nested peer calls no longer have their state changes overwritten by stale outer aliases.
|
||||
- Synchronous, asynchronous, and throwing peer calls refresh shared state correctly.
|
||||
- Added an executable `validate:0.6` regression probe for the exact compiler failure.
|
||||
|
||||
## R12 release-reference validation
|
||||
|
||||
- Release verification uses `git diff --quiet` instead of `git status --short` for generated UI references.
|
||||
- `component-catalog.json`, `component-reference.json`, and `COMPONENTS.md` are all covered.
|
||||
- Generator ordering no longer depends on `localeCompare`.
|
||||
|
||||
+69
-324
@@ -145,51 +145,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.generateBrowserModule = generateBrowserModule;
|
||||
const syntax_1 = require("@wrnexus/syntax");
|
||||
const RESERVED_BINDINGS = new Set([
|
||||
"await",
|
||||
"break",
|
||||
"case",
|
||||
"catch",
|
||||
"class",
|
||||
"const",
|
||||
"continue",
|
||||
"debugger",
|
||||
"default",
|
||||
"delete",
|
||||
"do",
|
||||
"else",
|
||||
"enum",
|
||||
"export",
|
||||
"extends",
|
||||
"false",
|
||||
"finally",
|
||||
"for",
|
||||
"function",
|
||||
"if",
|
||||
"implements",
|
||||
"import",
|
||||
"in",
|
||||
"instanceof",
|
||||
"interface",
|
||||
"let",
|
||||
"new",
|
||||
"null",
|
||||
"package",
|
||||
"private",
|
||||
"protected",
|
||||
"public",
|
||||
"return",
|
||||
"static",
|
||||
"super",
|
||||
"switch",
|
||||
"this",
|
||||
"throw",
|
||||
"true",
|
||||
"try",
|
||||
"typeof",
|
||||
"var",
|
||||
"void",
|
||||
"while",
|
||||
"with",
|
||||
"await", "break", "case", "catch", "class", "const", "continue", "debugger",
|
||||
"default", "delete", "do", "else", "enum", "export", "extends", "false",
|
||||
"finally", "for", "function", "if", "implements", "import", "in",
|
||||
"instanceof", "interface", "let", "new", "null", "package", "private",
|
||||
"protected", "public", "return", "static", "super", "switch", "this",
|
||||
"throw", "true", "try", "typeof", "var", "void", "while", "with",
|
||||
"yield",
|
||||
]);
|
||||
const RUNTIME_BINDINGS = new Set([
|
||||
@@ -231,7 +192,9 @@ function functionEntry(ast, fn, availableFunctions) {
|
||||
: "";
|
||||
const stateAliases = stateNames.length ? `let { ${stateNames.join(", ")} } = context.state;` : "";
|
||||
const propAliases = propNames.length ? `const { ${propNames.join(", ")} } = context.props;` : "";
|
||||
const syncStateToContext = stateNames.map((name) => `context.state.${name} = ${name};`).join(" ");
|
||||
const syncStateToContext = stateNames
|
||||
.map((name) => `context.state.${name} = ${name};`)
|
||||
.join(" ");
|
||||
const syncStateFromContext = stateNames
|
||||
.map((name) => `${name} = context.state.${name};`)
|
||||
.join(" ");
|
||||
@@ -267,9 +230,7 @@ function functionEntry(ast, fn, availableFunctions) {
|
||||
!parameterNames.has("server") ? "const server = context.server;" : "",
|
||||
!parameterNames.has("props") ? "const props = context.props;" : "",
|
||||
!parameterNames.has("refs") ? "const refs = context.refs;" : "",
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join("\n ");
|
||||
].filter(Boolean).join("\n ");
|
||||
return `${JSON.stringify(fn.name)}: ${fn.async ? "async " : ""}function(context${parameters ? `, ${parameters}` : ""}) {
|
||||
${initialStateSnapshot}
|
||||
${stateAliases}
|
||||
@@ -287,19 +248,18 @@ function generateBrowserModule(ast) {
|
||||
const functions = ast.runtimeFunctions.filter((fn) => ["legacy", "client", "shared"].includes(fn.runtime));
|
||||
const functionNames = functions.map((fn) => fn.name);
|
||||
const state = ast.states.filter((entry) => entry.runtime !== "server").map((entry) => entry.name);
|
||||
const storeImports = ast.structuredImports.filter((entry) => !entry.typeOnly && entry.source.endsWith(".wrn") && /(?:^|\/)stores?\//.test(entry.source));
|
||||
const storeImports = ast.structuredImports
|
||||
.filter((entry) => !entry.typeOnly && entry.source.endsWith(".wrn") && /(?:^|\/)stores?\//.test(entry.source));
|
||||
const imports = ast.structuredImports
|
||||
.filter((entry) => !entry.typeOnly)
|
||||
.filter((entry) => !entry.source.endsWith(".wrn") || /(?:^|\/)stores?\//.test(entry.source))
|
||||
.map((entry) => entry.raw)
|
||||
.join("\n");
|
||||
const importedBindings = storeImports
|
||||
.flatMap((entry) => [
|
||||
const importedBindings = storeImports.flatMap((entry) => [
|
||||
...(entry.defaultImport ? [entry.defaultImport] : []),
|
||||
...(entry.namespaceImport ? [entry.namespaceImport] : []),
|
||||
...entry.namedImports.map((item) => item.local),
|
||||
])
|
||||
.filter(safeIdentifier);
|
||||
]).filter(safeIdentifier);
|
||||
return `// generated WRNexusJS browser module for ${ast.name}
|
||||
${imports}
|
||||
export const __wrnexusClientFunctions = {
|
||||
@@ -994,12 +954,7 @@ function targetFunctions(ast, target) {
|
||||
.join("\n\n");
|
||||
}
|
||||
function publicOutputNames(ast) {
|
||||
return [
|
||||
...new Set([
|
||||
...ast.outputs.map((output) => output.name),
|
||||
...ast.events.map((event) => event.name),
|
||||
]),
|
||||
];
|
||||
return [...new Set([...ast.outputs.map((output) => output.name), ...ast.events.map((event) => event.name)])];
|
||||
}
|
||||
function generate(ast) {
|
||||
if (ast.kind === "global-store" || ast.kind === "page-store")
|
||||
@@ -1700,7 +1655,9 @@ function generateComponent(ast) {
|
||||
};
|
||||
const ctx = {
|
||||
stateNames,
|
||||
functionNames: new Set(ast.runtimeFunctions.filter((fn) => fn.runtime !== "server").map((fn) => fn.name)),
|
||||
functionNames: new Set(ast.runtimeFunctions
|
||||
.filter((fn) => fn.runtime !== "server")
|
||||
.map((fn) => fn.name)),
|
||||
resolveExpr,
|
||||
eventNames: publicOutputNames(ast),
|
||||
};
|
||||
@@ -2067,11 +2024,7 @@ exports.createComponentContract = createComponentContract;
|
||||
function unionOptions(type) {
|
||||
if (!type || !type.includes("|"))
|
||||
return undefined;
|
||||
const values = type
|
||||
.split("|")
|
||||
.map((part) => part.trim())
|
||||
.filter((part) => /^(?:"[^"]*"|'[^']*')$/.test(part))
|
||||
.map((part) => part.slice(1, -1));
|
||||
const values = type.split("|").map((part) => part.trim()).filter((part) => /^(?:"[^"]*"|'[^']*')$/.test(part)).map((part) => part.slice(1, -1));
|
||||
return values.length ? values : undefined;
|
||||
}
|
||||
function createComponentContract(ast) {
|
||||
@@ -2087,32 +2040,17 @@ function createComponentContract(ast) {
|
||||
})),
|
||||
outputs: ast.outputs.map((output) => ({
|
||||
name: output.name,
|
||||
...(output.payload
|
||||
? { payloadName: output.payload.name, payloadType: output.payload.valueType }
|
||||
: {}),
|
||||
...(output.payload ? { payloadName: output.payload.name, payloadType: output.payload.valueType } : {}),
|
||||
})),
|
||||
functions: ast.runtimeFunctions.map((fn) => ({
|
||||
name: fn.name,
|
||||
runtime: fn.runtime,
|
||||
async: fn.async,
|
||||
parameters: fn.parameters.map((param) => ({
|
||||
name: param.name,
|
||||
type: param.valueType ?? "unknown",
|
||||
optional: param.optional,
|
||||
})),
|
||||
parameters: fn.parameters.map((param) => ({ name: param.name, type: param.valueType ?? "unknown", optional: param.optional })),
|
||||
returnType: fn.returnType ?? (fn.async ? "Promise<unknown>" : "unknown"),
|
||||
})),
|
||||
states: ast.states.map((state) => ({
|
||||
name: state.name,
|
||||
runtime: state.runtime,
|
||||
type: state.valueType ?? "unknown",
|
||||
initializer: state.expr,
|
||||
})),
|
||||
computed: ast.computed.map((entry) => ({
|
||||
name: entry.name,
|
||||
type: entry.valueType ?? "unknown",
|
||||
expression: entry.expr,
|
||||
})),
|
||||
states: ast.states.map((state) => ({ name: state.name, runtime: state.runtime, type: state.valueType ?? "unknown", initializer: state.expr })),
|
||||
computed: ast.computed.map((entry) => ({ name: entry.name, type: entry.valueType ?? "unknown", expression: entry.expr })),
|
||||
imports: ast.structuredImports.map((entry) => ({
|
||||
source: entry.source,
|
||||
typeOnly: entry.typeOnly,
|
||||
@@ -2131,37 +2069,19 @@ exports.resolveWrnImports = resolveWrnImports;
|
||||
const node_fs_1 = require("node:fs");
|
||||
const node_path_1 = require("node:path");
|
||||
function candidates(path) {
|
||||
return (0, node_path_1.extname)(path)
|
||||
? [path]
|
||||
: [
|
||||
path,
|
||||
`${path}.wrn`,
|
||||
`${path}.ts`,
|
||||
`${path}.d.ts`,
|
||||
(0, node_path_1.join)(path, "index.wrn"),
|
||||
(0, node_path_1.join)(path, "index.ts"),
|
||||
];
|
||||
return (0, node_path_1.extname)(path) ? [path] : [path, `${path}.wrn`, `${path}.ts`, `${path}.d.ts`, (0, node_path_1.join)(path, "index.wrn"), (0, node_path_1.join)(path, "index.ts")];
|
||||
}
|
||||
function resolveWrnImport(declaration, importer, options) {
|
||||
const source = declaration.source;
|
||||
if (!source.startsWith(".") && !source.startsWith("@/"))
|
||||
return { declaration, resolved: source };
|
||||
const aliasRoot = options.aliases?.["@"] ?? "./app";
|
||||
const base = source.startsWith("@/")
|
||||
? (0, node_path_1.resolve)(options.appRoot, aliasRoot, source.slice(2))
|
||||
: (0, node_path_1.resolve)((0, node_path_1.dirname)(importer), source);
|
||||
const base = source.startsWith("@/") ? (0, node_path_1.resolve)(options.appRoot, aliasRoot, source.slice(2)) : (0, node_path_1.resolve)((0, node_path_1.dirname)(importer), source);
|
||||
const found = candidates(base).find(node_fs_1.existsSync);
|
||||
if (found)
|
||||
return { declaration, resolved: (0, node_fs_1.realpathSync)(found) };
|
||||
const severity = (options.mode ?? "compatible") === "explicit" ? "error" : "warning";
|
||||
return {
|
||||
declaration,
|
||||
diagnostic: {
|
||||
code: "WRN-IMPORT-NOT-FOUND",
|
||||
message: `Cannot resolve import '${source}' from ${importer}`,
|
||||
severity,
|
||||
},
|
||||
};
|
||||
return { declaration, diagnostic: { code: "WRN-IMPORT-NOT-FOUND", message: `Cannot resolve import '${source}' from ${importer}`, severity } };
|
||||
}
|
||||
function resolveWrnImports(declarations, importer, options) {
|
||||
return declarations.map((declaration) => resolveWrnImport(declaration, importer, options));
|
||||
@@ -2585,12 +2505,7 @@ exports.createWrnSourceMap = createWrnSourceMap;
|
||||
function createWrnSourceMap(source, generated) {
|
||||
const sourceLines = source.split(/\r?\n/).length;
|
||||
const generatedLines = generated.split(/\r?\n/).length;
|
||||
const mappings = Array.from({ length: Math.min(sourceLines, generatedLines) }, (_, index) => ({
|
||||
generatedLine: index + 1,
|
||||
sourceLine: index + 1,
|
||||
sourceColumn: 1,
|
||||
kind: "line",
|
||||
}));
|
||||
const mappings = Array.from({ length: Math.min(sourceLines, generatedLines) }, (_, index) => ({ generatedLine: index + 1, sourceLine: index + 1, sourceColumn: 1, kind: "line" }));
|
||||
return { version: 1, source, generated, mappings };
|
||||
}
|
||||
|
||||
@@ -2604,52 +2519,12 @@ const syntax_1 = require("@wrnexus/syntax");
|
||||
const type_codegen_ts_1 = require("./type-codegen.js");
|
||||
const server_codegen_ts_1 = require("./server-codegen.js");
|
||||
const RESERVED_BINDINGS = new Set([
|
||||
"await",
|
||||
"break",
|
||||
"case",
|
||||
"catch",
|
||||
"class",
|
||||
"const",
|
||||
"continue",
|
||||
"debugger",
|
||||
"default",
|
||||
"delete",
|
||||
"do",
|
||||
"else",
|
||||
"enum",
|
||||
"export",
|
||||
"extends",
|
||||
"false",
|
||||
"finally",
|
||||
"for",
|
||||
"function",
|
||||
"if",
|
||||
"implements",
|
||||
"import",
|
||||
"in",
|
||||
"instanceof",
|
||||
"interface",
|
||||
"let",
|
||||
"new",
|
||||
"null",
|
||||
"package",
|
||||
"private",
|
||||
"protected",
|
||||
"public",
|
||||
"return",
|
||||
"static",
|
||||
"super",
|
||||
"switch",
|
||||
"this",
|
||||
"throw",
|
||||
"true",
|
||||
"try",
|
||||
"typeof",
|
||||
"var",
|
||||
"void",
|
||||
"while",
|
||||
"with",
|
||||
"yield",
|
||||
"await", "break", "case", "catch", "class", "const", "continue", "debugger",
|
||||
"default", "delete", "do", "else", "enum", "export", "extends", "false",
|
||||
"finally", "for", "function", "if", "implements", "import", "in",
|
||||
"instanceof", "interface", "let", "new", "null", "package", "private",
|
||||
"protected", "public", "return", "static", "super", "switch", "this",
|
||||
"throw", "true", "try", "typeof", "var", "void", "while", "with", "yield",
|
||||
]);
|
||||
function safeBinding(name) {
|
||||
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) && !RESERVED_BINDINGS.has(name);
|
||||
@@ -2722,8 +2597,7 @@ function generateStoreModule(ast) {
|
||||
const lifecycle = lifecycleSource(ast, stateNames, false);
|
||||
const manifest = (0, server_codegen_ts_1.rpcManifest)(ast);
|
||||
const remoteFunctions = manifest.map((entry) => entry.function);
|
||||
const rpcWrappers = remoteFunctions
|
||||
.map((name) => `${JSON.stringify(name)}: async (...received) => {
|
||||
const rpcWrappers = remoteFunctions.map((name) => `${JSON.stringify(name)}: async (...received) => {
|
||||
const rpcContext = received.pop();
|
||||
if (!rpcContext || !rpcContext.request) throw new Error("WRN-RPC-CONTEXT: request context is required");
|
||||
let container = __wrnexusRpcContainers.get(rpcContext.request);
|
||||
@@ -2736,8 +2610,7 @@ function generateStoreModule(ast) {
|
||||
const action = store.actions[${JSON.stringify(name)}];
|
||||
if (typeof action !== "function") throw new Error(${JSON.stringify(`WRN-RPC-FUNCTION: store action '${name}' is unavailable on the server`)});
|
||||
return action(...received);
|
||||
}`)
|
||||
.join(",\n");
|
||||
}`).join(",\n");
|
||||
return `${ast.imports.join("\n")}\nimport { defineStore } from "@wrnexus/store";\nimport { createRequestStoreContainer } from "@wrnexus/store/server";\n\n${ast.types.join("\n\n")}\n\nexport const ${ast.name} = defineStore({\n name: ${JSON.stringify(ast.name)},\n kind: ${JSON.stringify(ast.storeKind)},\n createSharedState: () => (${stateObject(ast, "shared")}),\n createClientState: () => (${stateObject(ast, "client")}),\n createServerState: () => (${stateObject(ast, "server")}),\n computed: { ${computed} },\n actions: { ${actions} },\n persist: ${persistence},\n lifecycle: { ${lifecycle} },\n});\n\nexport default ${ast.name};\n\nconst __wrnexusRpcContainers = new WeakMap();\nexport const __wrnexusServerFunctions = {\n${rpcWrappers}\n};\nexport const __wrnexusRpcManifest = ${JSON.stringify(manifest, null, 2)};\n\n${(0, type_codegen_ts_1.generateDeclarations)(ast)}\n`;
|
||||
}
|
||||
/** Standalone browser artifact for an imported `.wrn` store. */
|
||||
@@ -2989,12 +2862,8 @@ const type_codegen_ts_1 = require("./type-codegen.js");
|
||||
const store_codegen_ts_1 = require("./store-codegen.js");
|
||||
function generateTargets(ast) {
|
||||
return {
|
||||
server: ast.kind === "global-store" || ast.kind === "page-store"
|
||||
? (0, store_codegen_ts_1.generateStoreModule)(ast)
|
||||
: (0, server_codegen_ts_1.generateServerFunctionsModule)(ast),
|
||||
browser: ast.kind === "global-store" || ast.kind === "page-store"
|
||||
? (0, store_codegen_ts_1.generateStoreBrowserModule)(ast)
|
||||
: (0, client_codegen_ts_1.generateBrowserModule)(ast),
|
||||
server: ast.kind === "global-store" || ast.kind === "page-store" ? (0, store_codegen_ts_1.generateStoreModule)(ast) : (0, server_codegen_ts_1.generateServerFunctionsModule)(ast),
|
||||
browser: ast.kind === "global-store" || ast.kind === "page-store" ? (0, store_codegen_ts_1.generateStoreBrowserModule)(ast) : (0, client_codegen_ts_1.generateBrowserModule)(ast),
|
||||
declarations: (0, type_codegen_ts_1.generateDeclarations)(ast),
|
||||
contract: (0, component_contract_ts_1.createComponentContract)(ast),
|
||||
rpc: (0, server_codegen_ts_1.rpcManifest)(ast),
|
||||
@@ -3027,47 +2896,22 @@ __exportStar(require("@wrnexus/syntax/tokenizer"), exports);
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.generateDeclarations = generateDeclarations;
|
||||
function member(name) {
|
||||
return /^[A-Za-z_$][\w$]*$/.test(name) ? name : JSON.stringify(name);
|
||||
}
|
||||
function member(name) { return /^[A-Za-z_$][\w$]*$/.test(name) ? name : JSON.stringify(name); }
|
||||
function params(astParams) {
|
||||
return astParams
|
||||
.map((param) => `${member(param.name)}${param.optional ? "?" : ""}: ${param.valueType ?? "unknown"}`)
|
||||
.join(", ");
|
||||
return astParams.map((param) => `${member(param.name)}${param.optional ? "?" : ""}: ${param.valueType ?? "unknown"}`).join(", ");
|
||||
}
|
||||
function generateDeclarations(ast) {
|
||||
const inline = ast.types
|
||||
.map((body) => body.trim())
|
||||
.filter(Boolean)
|
||||
.join("\n\n");
|
||||
const inline = ast.types.map((body) => body.trim()).filter(Boolean).join("\n\n");
|
||||
if (ast.kind === "global-store" || ast.kind === "page-store") {
|
||||
const state = ast.states
|
||||
.filter((entry) => entry.runtime !== "server")
|
||||
.map((entry) => ` readonly ${member(entry.name)}: ${entry.valueType ?? "unknown"};`)
|
||||
.join("\n");
|
||||
const computed = ast.computed
|
||||
.map((entry) => ` readonly ${member(entry.name)}: ${entry.valueType ?? "unknown"};`)
|
||||
.join("\n");
|
||||
const actions = ast.runtimeFunctions
|
||||
.filter((fn) => fn.runtime !== "server")
|
||||
.map((fn) => ` ${member(fn.name)}(${params(fn.parameters)}): ${fn.returnType ?? (fn.async ? "Promise<unknown>" : "unknown")};`)
|
||||
.join("\n");
|
||||
const state = ast.states.filter((entry) => entry.runtime !== "server").map((entry) => ` readonly ${member(entry.name)}: ${entry.valueType ?? "unknown"};`).join("\n");
|
||||
const computed = ast.computed.map((entry) => ` readonly ${member(entry.name)}: ${entry.valueType ?? "unknown"};`).join("\n");
|
||||
const actions = ast.runtimeFunctions.filter((fn) => fn.runtime !== "server").map((fn) => ` ${member(fn.name)}(${params(fn.parameters)}): ${fn.returnType ?? (fn.async ? "Promise<unknown>" : "unknown")};`).join("\n");
|
||||
return `${inline ? `${inline}\n\n` : ""}export interface ${ast.name}State {\n${state}\n}\n\nexport interface ${ast.name}Computed {\n${computed}\n}\n\nexport interface ${ast.name}Actions {\n${actions}\n}\n\nexport interface ${ast.name}Instance extends ${ast.name}State, ${ast.name}Computed, ${ast.name}Actions {\n reset(): void;\n snapshot(): Readonly<${ast.name}State>;\n}\n\ndeclare const store: ${ast.name}Instance;\nexport default store;\n`;
|
||||
}
|
||||
const props = ast.props
|
||||
.map((prop) => ` readonly ${member(prop.name)}${prop.required ? "" : "?"}: ${prop.valueType ?? "unknown"};`)
|
||||
.join("\n");
|
||||
const outputs = ast.outputs
|
||||
.map((output) => ` ${member(output.name)}(${output.payload ? `${member(output.payload.name)}${output.payload.optional ? "?" : ""}: ${output.payload.valueType}` : ""}): void;`)
|
||||
.join("\n");
|
||||
const clientFunctions = ast.runtimeFunctions
|
||||
.filter((fn) => fn.runtime === "client" || fn.runtime === "shared" || fn.runtime === "legacy")
|
||||
.map((fn) => ` ${member(fn.name)}(${params(fn.parameters)}): ${fn.returnType ?? (fn.async ? "Promise<unknown>" : "unknown")};`)
|
||||
.join("\n");
|
||||
const serverFunctions = ast.runtimeFunctions
|
||||
.filter((fn) => fn.runtime === "server")
|
||||
.map((fn) => ` ${member(fn.name)}(${params(fn.parameters)}): Promise<Awaited<${fn.returnType ?? "unknown"}>>;`)
|
||||
.join("\n");
|
||||
const props = ast.props.map((prop) => ` readonly ${member(prop.name)}${prop.required ? "" : "?"}: ${prop.valueType ?? "unknown"};`).join("\n");
|
||||
const outputs = ast.outputs.map((output) => ` ${member(output.name)}(${output.payload ? `${member(output.payload.name)}${output.payload.optional ? "?" : ""}: ${output.payload.valueType}` : ""}): void;`).join("\n");
|
||||
const clientFunctions = ast.runtimeFunctions.filter((fn) => fn.runtime === "client" || fn.runtime === "shared" || fn.runtime === "legacy").map((fn) => ` ${member(fn.name)}(${params(fn.parameters)}): ${fn.returnType ?? (fn.async ? "Promise<unknown>" : "unknown")};`).join("\n");
|
||||
const serverFunctions = ast.runtimeFunctions.filter((fn) => fn.runtime === "server").map((fn) => ` ${member(fn.name)}(${params(fn.parameters)}): Promise<Awaited<${fn.returnType ?? "unknown"}>>;`).join("\n");
|
||||
return `${inline ? `${inline}\n\n` : ""}export interface ${ast.name}Props {\n${props}\n}\n\nexport interface ${ast.name}Outputs {\n${outputs}\n}\n\nexport interface ${ast.name}ClientFunctions {\n${clientFunctions}\n}\n\nexport interface ${ast.name}ServerCalls {\n${serverFunctions}\n}\n`;
|
||||
}
|
||||
|
||||
@@ -3315,88 +3159,38 @@ function astDiagnostics(ast, options) {
|
||||
for (const call of fn.body.matchAll(/\boutput\.([A-Za-z_$][\w$]*)\s*\(/g)) {
|
||||
const outputName = call[1];
|
||||
if (fn.runtime === "server") {
|
||||
diagnostics.push({
|
||||
code: "WRN-OUTPUT-SERVER-CALL",
|
||||
severity: "error",
|
||||
message: `Server function '${fn.name}' cannot call output.${outputName}().`,
|
||||
hint: "Return a typed value to the browser and call the output from a client function.",
|
||||
file: options.file,
|
||||
});
|
||||
diagnostics.push({ code: "WRN-OUTPUT-SERVER-CALL", severity: "error", message: `Server function '${fn.name}' cannot call output.${outputName}().`, hint: "Return a typed value to the browser and call the output from a client function.", file: options.file });
|
||||
}
|
||||
else if (!outputs.has(outputName)) {
|
||||
diagnostics.push({
|
||||
code: "WRN-OUTPUT-UNKNOWN",
|
||||
severity: "error",
|
||||
message: `Unknown output '${outputName}' called from '${fn.name}'.`,
|
||||
hint: `Declare ${outputName}(payload) inside outputs { ... }.`,
|
||||
file: options.file,
|
||||
});
|
||||
diagnostics.push({ code: "WRN-OUTPUT-UNKNOWN", severity: "error", message: `Unknown output '${outputName}' called from '${fn.name}'.`, hint: `Declare ${outputName}(payload) inside outputs { ... }.`, file: options.file });
|
||||
}
|
||||
}
|
||||
if (fn.runtime === "client" && /\b(?:process|Bun|Deno|__dirname|require)\b/.test(fn.body)) {
|
||||
diagnostics.push({
|
||||
code: "WRN-CLIENT-SERVER-API",
|
||||
severity: "error",
|
||||
message: `Client function '${fn.name}' references a server-only API.`,
|
||||
hint: "Move that operation into a server function and call it through server.name(...).",
|
||||
file: options.file,
|
||||
});
|
||||
diagnostics.push({ code: "WRN-CLIENT-SERVER-API", severity: "error", message: `Client function '${fn.name}' references a server-only API.`, hint: "Move that operation into a server function and call it through server.name(...).", file: options.file });
|
||||
}
|
||||
if (fn.runtime === "server" &&
|
||||
/\b(?:window|document|localStorage|sessionStorage|navigator)\b/.test(fn.body)) {
|
||||
diagnostics.push({
|
||||
code: "WRN-SERVER-BROWSER-API",
|
||||
severity: "error",
|
||||
message: `Server function '${fn.name}' references a browser-only API.`,
|
||||
hint: "Move that code into a client function.",
|
||||
file: options.file,
|
||||
});
|
||||
if (fn.runtime === "server" && /\b(?:window|document|localStorage|sessionStorage|navigator)\b/.test(fn.body)) {
|
||||
diagnostics.push({ code: "WRN-SERVER-BROWSER-API", severity: "error", message: `Server function '${fn.name}' references a browser-only API.`, hint: "Move that code into a client function.", file: options.file });
|
||||
}
|
||||
const parameterNames = new Set(fn.parameters.map((parameter) => parameter.name));
|
||||
for (const prop of ast.props) {
|
||||
if (containsReadonlyPropMutation(fn.body, prop.name, parameterNames)) {
|
||||
diagnostics.push({
|
||||
code: "WRN-PROP-READONLY",
|
||||
severity: "error",
|
||||
message: `Function '${fn.name}' attempts to mutate readonly prop '${prop.name}'.`,
|
||||
hint: "Copy the prop into state before mutating it.",
|
||||
file: options.file,
|
||||
});
|
||||
diagnostics.push({ code: "WRN-PROP-READONLY", severity: "error", message: `Function '${fn.name}' attempts to mutate readonly prop '${prop.name}'.`, hint: "Copy the prop into state before mutating it.", file: options.file });
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const state of ast.states) {
|
||||
if (state.runtime === "shared" &&
|
||||
/^(?:new\s+(?:Map|Set|WeakMap|WeakSet)|(?:async\s+)?function\b|.*=>)/.test(state.expr.trim())) {
|
||||
diagnostics.push({
|
||||
code: "WRN-STATE-NON-SERIALIZABLE",
|
||||
severity: "error",
|
||||
message: `Shared state '${state.name}' is not safely serializable.`,
|
||||
hint: "Use JSON-compatible data or move the value into client/server state.",
|
||||
file: options.file,
|
||||
});
|
||||
if (state.runtime === "shared" && /^(?:new\s+(?:Map|Set|WeakMap|WeakSet)|(?:async\s+)?function\b|.*=>)/.test(state.expr.trim())) {
|
||||
diagnostics.push({ code: "WRN-STATE-NON-SERIALIZABLE", severity: "error", message: `Shared state '${state.name}' is not safely serializable.`, hint: "Use JSON-compatible data or move the value into client/server state.", file: options.file });
|
||||
}
|
||||
}
|
||||
if (ast.persist) {
|
||||
const stateNames = new Set(ast.states.filter((state) => state.runtime !== "server").map((state) => state.name));
|
||||
for (const name of ast.persist.include)
|
||||
if (!stateNames.has(name))
|
||||
diagnostics.push({
|
||||
code: "WRN-PERSIST-UNKNOWN-FIELD",
|
||||
severity: "error",
|
||||
message: `Persist include references unknown or server-only state '${name}'.`,
|
||||
hint: "Persist only declared shared/client state fields.",
|
||||
file: options.file,
|
||||
});
|
||||
diagnostics.push({ code: "WRN-PERSIST-UNKNOWN-FIELD", severity: "error", message: `Persist include references unknown or server-only state '${name}'.`, hint: "Persist only declared shared/client state fields.", file: options.file });
|
||||
for (const name of ast.persist.include)
|
||||
if (/token|password|secret|otp|api.?key/i.test(name))
|
||||
diagnostics.push({
|
||||
code: "WRN-PERSIST-SENSITIVE",
|
||||
severity: "error",
|
||||
message: `Sensitive field '${name}' cannot be persisted.`,
|
||||
hint: "Remove secrets, tokens, passwords, OTPs, and API keys from persistence.",
|
||||
file: options.file,
|
||||
});
|
||||
diagnostics.push({ code: "WRN-PERSIST-SENSITIVE", severity: "error", message: `Sensitive field '${name}' cannot be persisted.`, hint: "Remove secrets, tokens, passwords, OTPs, and API keys from persistence.", file: options.file });
|
||||
}
|
||||
return diagnostics;
|
||||
}
|
||||
@@ -3623,8 +3417,7 @@ function parse(source) {
|
||||
try {
|
||||
// A file may contain a page, component, layout, global store, or page store.
|
||||
const opener = lx.next();
|
||||
if (opener.type !== "ident" ||
|
||||
!["page", "component", "layout", "global"].includes(opener.value)) {
|
||||
if (opener.type !== "ident" || !["page", "component", "layout", "global"].includes(opener.value)) {
|
||||
throw new ParseError(`Expected 'page', 'component', 'layout', 'global store', or 'page store' but got '${opener.value || opener.type}' at offset ${opener.pos}`);
|
||||
}
|
||||
let kind;
|
||||
@@ -3636,9 +3429,7 @@ function parse(source) {
|
||||
storeKind = "global";
|
||||
name = expect("ident").value;
|
||||
}
|
||||
else if (opener.value === "page" &&
|
||||
lx.peek().type === "ident" &&
|
||||
lx.peek().value === "store") {
|
||||
else if (opener.value === "page" && lx.peek().type === "ident" && lx.peek().value === "store") {
|
||||
lx.next();
|
||||
kind = "page-store";
|
||||
storeKind = "page";
|
||||
@@ -3753,12 +3544,7 @@ function parse(source) {
|
||||
hasDefault = true;
|
||||
}
|
||||
const defaultValue = hasDefault ? lx.readPropInitializer() : "undefined";
|
||||
props.push({
|
||||
name: pName,
|
||||
valueType,
|
||||
required: !hasDefault && !optional,
|
||||
default: defaultValue,
|
||||
});
|
||||
props.push({ name: pName, valueType, required: !hasDefault && !optional, default: defaultValue });
|
||||
}
|
||||
expect("rbrace");
|
||||
break;
|
||||
@@ -3782,12 +3568,7 @@ function parse(source) {
|
||||
else {
|
||||
expect("eq");
|
||||
}
|
||||
states.push({
|
||||
name: sName,
|
||||
valueType,
|
||||
expr: lx.readPropInitializer(),
|
||||
runtime: "shared",
|
||||
});
|
||||
states.push({ name: sName, valueType, expr: lx.readPropInitializer(), runtime: "shared" });
|
||||
break;
|
||||
}
|
||||
case "computed": {
|
||||
@@ -3892,9 +3673,7 @@ function parse(source) {
|
||||
const rawMode = kw.value;
|
||||
const mode = rawMode === "client" ? "client" : "ssr";
|
||||
lx.next();
|
||||
if ((rawMode === "client" || rawMode === "server") &&
|
||||
lx.peek().type === "ident" &&
|
||||
lx.peek().value === "state") {
|
||||
if ((rawMode === "client" || rawMode === "server") && lx.peek().type === "ident" && lx.peek().value === "state") {
|
||||
lx.next();
|
||||
if (lx.peek().type !== "lbrace")
|
||||
throw new ParseError(`Expected a grouped ${rawMode} state block`);
|
||||
@@ -4440,13 +4219,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.WRN_DIAGNOSTIC_CODES = exports.WRN_RUNTIME_TARGETS = exports.WRN_HYDRATION_STRATEGIES = exports.WRN_ROOT_MEMBERS = exports.WRN_ROOT_KINDS = exports.WRN_LANGUAGE_VERSION = void 0;
|
||||
/** Canonical, machine-readable WRN language capabilities. */
|
||||
exports.WRN_LANGUAGE_VERSION = "0.6";
|
||||
exports.WRN_ROOT_KINDS = [
|
||||
"page",
|
||||
"component",
|
||||
"layout",
|
||||
"global-store",
|
||||
"page-store",
|
||||
];
|
||||
exports.WRN_ROOT_KINDS = ["page", "component", "layout", "global-store", "page-store"];
|
||||
exports.WRN_ROOT_MEMBERS = [
|
||||
"layout",
|
||||
"runtime",
|
||||
@@ -5009,9 +4782,7 @@ function findTopLevelChar(input, wanted) {
|
||||
return -1;
|
||||
}
|
||||
function parseParameters(source) {
|
||||
return splitTopLevel(source)
|
||||
.filter(Boolean)
|
||||
.map((entry) => {
|
||||
return splitTopLevel(source).filter(Boolean).map((entry) => {
|
||||
const eq = findTopLevelChar(entry, "=");
|
||||
const declaration = (eq >= 0 ? entry.slice(0, eq) : entry).trim();
|
||||
const defaultValue = eq >= 0 ? entry.slice(eq + 1).trim() : undefined;
|
||||
@@ -5020,12 +4791,7 @@ function parseParameters(source) {
|
||||
const optional = rawName.endsWith("?");
|
||||
const name = optional ? rawName.slice(0, -1).trim() : rawName;
|
||||
const valueType = colon >= 0 ? declaration.slice(colon + 1).trim() : undefined;
|
||||
return {
|
||||
name,
|
||||
optional,
|
||||
...(valueType ? { valueType } : {}),
|
||||
...(defaultValue ? { default: defaultValue } : {}),
|
||||
};
|
||||
return { name, optional, ...(valueType ? { valueType } : {}), ...(defaultValue ? { default: defaultValue } : {}) };
|
||||
});
|
||||
}
|
||||
function skipTrivia(source, start) {
|
||||
@@ -5203,15 +4969,7 @@ function parseOutputs(source) {
|
||||
throw new Error(`Output '${nameToken.word}' payload requires a type`);
|
||||
out.push({
|
||||
name: nameToken.word,
|
||||
...(payload
|
||||
? {
|
||||
payload: {
|
||||
name: payload.name,
|
||||
valueType: payload.valueType,
|
||||
optional: payload.optional,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
...(payload ? { payload: { name: payload.name, valueType: payload.valueType, optional: payload.optional } } : {}),
|
||||
});
|
||||
}
|
||||
return out;
|
||||
@@ -5244,11 +5002,7 @@ function parseStructuredImports(imports) {
|
||||
const localTypeOnly = /^type\s+/.test(item);
|
||||
const cleaned = item.replace(/^type\s+/, "").trim();
|
||||
const [imported, local] = cleaned.split(/\s+as\s+/);
|
||||
return {
|
||||
imported: imported.trim(),
|
||||
local: (local ?? imported).trim(),
|
||||
typeOnly: typeOnly || localTypeOnly,
|
||||
};
|
||||
return { imported: imported.trim(), local: (local ?? imported).trim(), typeOnly: typeOnly || localTypeOnly };
|
||||
});
|
||||
}
|
||||
return declaration;
|
||||
@@ -5274,12 +5028,7 @@ function parseStateDeclarations(source, runtime) {
|
||||
if (eq.type !== "eq")
|
||||
throw new tokenizer_ts_1.LexError(`Expected '=' after state '${nameToken.value}' at offset ${eq.pos}`);
|
||||
}
|
||||
out.push({
|
||||
name: nameToken.value,
|
||||
...(valueType ? { valueType } : {}),
|
||||
expr: lx.readPropInitializer(),
|
||||
runtime,
|
||||
});
|
||||
out.push({ name: nameToken.value, ...(valueType ? { valueType } : {}), expr: lx.readPropInitializer(), runtime });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -5303,11 +5052,7 @@ function parseComputedDeclarations(source) {
|
||||
if (eq.type !== "eq")
|
||||
throw new tokenizer_ts_1.LexError(`Expected '=' after computed '${nameToken.value}' at offset ${eq.pos}`);
|
||||
}
|
||||
out.push({
|
||||
name: nameToken.value,
|
||||
...(valueType ? { valueType } : {}),
|
||||
expr: lx.readPropInitializer(),
|
||||
});
|
||||
out.push({ name: nameToken.value, ...(valueType ? { valueType } : {}), expr: lx.readPropInitializer() });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -134,14 +134,6 @@ export interface Routes {
|
||||
"/tables": Record<string, never>;
|
||||
"/templates": Record<string, never>;
|
||||
"/themes": Record<string, never>;
|
||||
"/v06-functions": Record<string, never>;
|
||||
"/v06-imports": Record<string, never>;
|
||||
"/v06-migration": Record<string, never>;
|
||||
"/v06-outputs": Record<string, never>;
|
||||
"/v06-runtime": Record<string, never>;
|
||||
"/v06-state": Record<string, never>;
|
||||
"/v06-stores": Record<string, never>;
|
||||
"/v06-types": Record<string, never>;
|
||||
}
|
||||
|
||||
export type RoutePath = keyof Routes;
|
||||
|
||||
@@ -81,6 +81,11 @@
|
||||
"category": "base",
|
||||
"purpose": "Theme-aware, responsive button group component."
|
||||
},
|
||||
{
|
||||
"name": "CTASection",
|
||||
"category": "marketing",
|
||||
"purpose": "Close a page or major section with conversion-focused copy, actions, and optional supporting visual content."
|
||||
},
|
||||
{
|
||||
"name": "Card",
|
||||
"category": "base",
|
||||
@@ -151,11 +156,6 @@
|
||||
"category": "advanced-forms",
|
||||
"purpose": "Theme-aware, responsive copy markup component."
|
||||
},
|
||||
{
|
||||
"name": "CTASection",
|
||||
"category": "marketing",
|
||||
"purpose": "Close a page or major section with conversion-focused copy, actions, and optional supporting visual content."
|
||||
},
|
||||
{
|
||||
"name": "CustomScrollbar",
|
||||
"category": "layout",
|
||||
@@ -481,26 +481,26 @@
|
||||
"category": "navigation",
|
||||
"purpose": "Switch between related responsive content panels with horizontal or vertical orientation and selection events."
|
||||
},
|
||||
{
|
||||
"name": "Textarea",
|
||||
"category": "forms",
|
||||
"purpose": "Theme-aware, responsive textarea component."
|
||||
},
|
||||
{
|
||||
"name": "TextLink",
|
||||
"category": "marketing",
|
||||
"purpose": "Render an accessible text action with optional icon, arrow, underline, external state, and semantic styling."
|
||||
},
|
||||
{
|
||||
"name": "Timeline",
|
||||
"category": "base",
|
||||
"purpose": "Present responsive chronological activity, milestones, or workflow status with rich item metadata."
|
||||
"name": "Textarea",
|
||||
"category": "forms",
|
||||
"purpose": "Theme-aware, responsive textarea component."
|
||||
},
|
||||
{
|
||||
"name": "TimePicker",
|
||||
"category": "forms",
|
||||
"purpose": "Theme-aware, responsive time picker component."
|
||||
},
|
||||
{
|
||||
"name": "Timeline",
|
||||
"category": "base",
|
||||
"purpose": "Present responsive chronological activity, milestones, or workflow status with rich item metadata."
|
||||
},
|
||||
{
|
||||
"name": "Toast",
|
||||
"category": "base",
|
||||
|
||||
@@ -2278,6 +2278,193 @@
|
||||
"events": ["click", "select", "change"],
|
||||
"source": "components/ButtonGroup.wrn"
|
||||
},
|
||||
{
|
||||
"name": "CTASection",
|
||||
"mount": "CTASection",
|
||||
"category": "marketing",
|
||||
"purpose": "Close a page or major section with conversion-focused copy, actions, and optional supporting visual content.",
|
||||
"props": [
|
||||
{
|
||||
"name": "eyebrow",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "title",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Ready to get started?\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "icon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "align",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"center\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "size",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "color",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"primary\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "variant",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"solid\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "primaryLabel",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Get started\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "primaryHref",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"#\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "primaryIcon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "secondaryLabel",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "secondaryHref",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "secondaryIcon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "backgroundImage",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualImage",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualAlt",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualIcon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualTitle",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualDescription",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualItems",
|
||||
"type": "unknown[]",
|
||||
"required": false,
|
||||
"default": "[]",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualPosition",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"right\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "maxWidth",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"xl\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "fullBleed",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "false",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "class",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"slots": ["default", "actions", "visual", "footer"],
|
||||
"outputs": [],
|
||||
"events": [],
|
||||
"source": "components/CTASection.wrn"
|
||||
},
|
||||
{
|
||||
"name": "Card",
|
||||
"mount": "Card",
|
||||
@@ -4250,193 +4437,6 @@
|
||||
"events": ["copy", "success", "error"],
|
||||
"source": "components/CopyMarkup.wrn"
|
||||
},
|
||||
{
|
||||
"name": "CTASection",
|
||||
"mount": "CTASection",
|
||||
"category": "marketing",
|
||||
"purpose": "Close a page or major section with conversion-focused copy, actions, and optional supporting visual content.",
|
||||
"props": [
|
||||
{
|
||||
"name": "eyebrow",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "title",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Ready to get started?\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "icon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "align",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"center\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "size",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "color",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"primary\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "variant",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"solid\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "primaryLabel",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Get started\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "primaryHref",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"#\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "primaryIcon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "secondaryLabel",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "secondaryHref",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "secondaryIcon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "backgroundImage",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualImage",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualAlt",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualIcon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualTitle",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualDescription",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualItems",
|
||||
"type": "unknown[]",
|
||||
"required": false,
|
||||
"default": "[]",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "visualPosition",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"right\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "maxWidth",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"xl\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "fullBleed",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "false",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "class",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"slots": ["default", "actions", "visual", "footer"],
|
||||
"outputs": [],
|
||||
"events": [],
|
||||
"source": "components/CTASection.wrn"
|
||||
},
|
||||
{
|
||||
"name": "CustomScrollbar",
|
||||
"mount": "CustomScrollbar",
|
||||
@@ -12144,6 +12144,129 @@
|
||||
"events": [],
|
||||
"source": "components/Tabs.wrn"
|
||||
},
|
||||
{
|
||||
"name": "TextLink",
|
||||
"mount": "TextLink",
|
||||
"category": "marketing",
|
||||
"purpose": "Render an accessible text action with optional icon, arrow, underline, external state, and semantic styling.",
|
||||
"props": [
|
||||
{
|
||||
"name": "label",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Learn more\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "href",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"#\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "target",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "rel",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "external",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "false",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "icon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "iconPosition",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"start\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "showArrow",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "true",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "underline",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "false",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "size",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "color",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"primary\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "variant",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "disabled",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "false",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "class",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"slots": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "click",
|
||||
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
|
||||
},
|
||||
{
|
||||
"name": "focus",
|
||||
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
|
||||
},
|
||||
{
|
||||
"name": "blur",
|
||||
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
|
||||
}
|
||||
],
|
||||
"events": ["click", "focus", "blur"],
|
||||
"source": "components/TextLink.wrn"
|
||||
},
|
||||
{
|
||||
"name": "Textarea",
|
||||
"mount": "Textarea",
|
||||
@@ -12338,190 +12461,6 @@
|
||||
"events": ["input", "change", "focus", "blur", "invalid"],
|
||||
"source": "components/Textarea.wrn"
|
||||
},
|
||||
{
|
||||
"name": "TextLink",
|
||||
"mount": "TextLink",
|
||||
"category": "marketing",
|
||||
"purpose": "Render an accessible text action with optional icon, arrow, underline, external state, and semantic styling.",
|
||||
"props": [
|
||||
{
|
||||
"name": "label",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Learn more\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "href",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"#\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "target",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "rel",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "external",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "false",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "icon",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "iconPosition",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"start\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "showArrow",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "true",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "underline",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "false",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "size",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "color",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"primary\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "variant",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "disabled",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": "false",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "class",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"slots": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "click",
|
||||
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
|
||||
},
|
||||
{
|
||||
"name": "focus",
|
||||
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
|
||||
},
|
||||
{
|
||||
"name": "blur",
|
||||
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
|
||||
}
|
||||
],
|
||||
"events": ["click", "focus", "blur"],
|
||||
"source": "components/TextLink.wrn"
|
||||
},
|
||||
{
|
||||
"name": "Timeline",
|
||||
"mount": "Timeline",
|
||||
"category": "base",
|
||||
"purpose": "Present responsive chronological activity, milestones, or workflow status with rich item metadata.",
|
||||
"props": [
|
||||
{
|
||||
"name": "size",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "color",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"primary\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "title",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Timeline\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "items",
|
||||
"type": "unknown[]",
|
||||
"required": false,
|
||||
"default": "[]",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "variant",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "class",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"slots": ["default"],
|
||||
"outputs": [],
|
||||
"events": [],
|
||||
"source": "components/Timeline.wrn"
|
||||
},
|
||||
{
|
||||
"name": "TimePicker",
|
||||
"mount": "TimePicker",
|
||||
@@ -12745,6 +12684,67 @@
|
||||
"events": ["input", "change", "focus", "blur", "open", "close", "invalid"],
|
||||
"source": "components/TimePicker.wrn"
|
||||
},
|
||||
{
|
||||
"name": "Timeline",
|
||||
"mount": "Timeline",
|
||||
"category": "base",
|
||||
"purpose": "Present responsive chronological activity, milestones, or workflow status with rich item metadata.",
|
||||
"props": [
|
||||
{
|
||||
"name": "size",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "color",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"primary\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "title",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"Timeline\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "items",
|
||||
"type": "unknown[]",
|
||||
"required": false,
|
||||
"default": "[]",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "variant",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"default\"",
|
||||
"options": []
|
||||
},
|
||||
{
|
||||
"name": "class",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "\"\"",
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
"slots": ["default"],
|
||||
"outputs": [],
|
||||
"events": [],
|
||||
"source": "components/Timeline.wrn"
|
||||
},
|
||||
{
|
||||
"name": "Toast",
|
||||
"mount": "Toast",
|
||||
|
||||
@@ -95,6 +95,10 @@ function words(name) {
|
||||
return name.replace(/([a-z0-9])([A-Z])/g, "$1 $2").toLowerCase();
|
||||
}
|
||||
|
||||
function compareText(left, right) {
|
||||
return left < right ? -1 : left > right ? 1 : 0;
|
||||
}
|
||||
|
||||
const sourceEntries = readdirSync(componentsDir)
|
||||
.filter((file) => file.endsWith(".wrn"))
|
||||
.map((file) => {
|
||||
@@ -150,7 +154,7 @@ const components = [...sourceByName.values()]
|
||||
source: `components/${file}`,
|
||||
};
|
||||
})
|
||||
.sort((left, right) => left.name.localeCompare(right.name));
|
||||
.sort((left, right) => compareText(left.name, right.name));
|
||||
|
||||
const catalogComponents = components.map((component) => ({
|
||||
name: component.name,
|
||||
@@ -180,7 +184,9 @@ const lines = [
|
||||
`This reference is generated from the ${components.length} packaged \`.wrn\` component sources. Props marked required have no default; all others show their runtime default.`,
|
||||
"",
|
||||
];
|
||||
for (const category of [...new Set(components.map((component) => component.category))].sort()) {
|
||||
for (const category of [...new Set(components.map((component) => component.category))].sort(
|
||||
compareText,
|
||||
)) {
|
||||
lines.push(`## ${category[0].toUpperCase()}${category.slice(1)}`, "");
|
||||
for (const component of components.filter((item) => item.category === category)) {
|
||||
const props = component.props.length
|
||||
|
||||
+19
-5
@@ -208,7 +208,11 @@ function prepare(all: PackageInfo[], version: string) {
|
||||
}
|
||||
|
||||
function verifyUiComponentReference(): void {
|
||||
const generatedFiles = ["packages/ui/component-reference.json", "packages/ui/COMPONENTS.md"];
|
||||
const generatedFiles = [
|
||||
"packages/ui/component-catalog.json",
|
||||
"packages/ui/component-reference.json",
|
||||
"packages/ui/COMPONENTS.md",
|
||||
];
|
||||
|
||||
const result = run(
|
||||
process.execPath,
|
||||
@@ -226,22 +230,32 @@ function verifyUiComponentReference(): void {
|
||||
throw new Error(`Failed to generate the UI component reference.${detail ? `\n${detail}` : ""}`);
|
||||
}
|
||||
|
||||
const changed = output("git", ["status", "--short", "--", ...generatedFiles], root).trim();
|
||||
// Do not use `git status --short` here. On Windows, the generator writes LF
|
||||
// while an autocrlf checkout may contain CRLF. `git status` can report those
|
||||
// files as modified even when their canonical Git content is identical.
|
||||
// `git diff --quiet` applies Git's normal text conversion and only fails for
|
||||
// a real generated-content difference.
|
||||
const changedStatus = run("git", ["diff", "--quiet", "--", ...generatedFiles], root, {
|
||||
capture: true,
|
||||
allowFailure: true,
|
||||
}).status;
|
||||
|
||||
if (!changed) {
|
||||
if (changedStatus === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const changed = output("git", ["diff", "--name-status", "--", ...generatedFiles], root);
|
||||
|
||||
throw new Error(
|
||||
[
|
||||
"UI component reference is stale.",
|
||||
"",
|
||||
changed,
|
||||
changed || generatedFiles.join("\n"),
|
||||
"",
|
||||
"Run:",
|
||||
" bun run scripts/generate-ui-component-reference.mjs",
|
||||
" bun run format",
|
||||
" git add packages/ui/component-reference.json packages/ui/COMPONENTS.md",
|
||||
" git add packages/ui/component-catalog.json packages/ui/component-reference.json packages/ui/COMPONENTS.md",
|
||||
' git commit -m "docs(ui): refresh component reference"',
|
||||
" git push origin main",
|
||||
].join("\n"),
|
||||
|
||||
@@ -395,6 +395,34 @@ if (!compilerTargetTestSource.includes('targets.browser.replace(/^export\\s+/gm,
|
||||
pass("R11 peer-function executable regression test uses the correct export-stripping regex");
|
||||
}
|
||||
|
||||
const releaseSource = readFileSync(join(root, "scripts/release.ts"), "utf8");
|
||||
const referenceGeneratorSource = readFileSync(
|
||||
join(root, "scripts/generate-ui-component-reference.mjs"),
|
||||
"utf8",
|
||||
);
|
||||
for (const [label, condition] of [
|
||||
[
|
||||
"canonical generated-reference Git comparison",
|
||||
releaseSource.includes('["diff", "--quiet", "--", ...generatedFiles]') &&
|
||||
releaseSource.includes('["diff", "--name-status", "--", ...generatedFiles]'),
|
||||
],
|
||||
[
|
||||
"component catalog included in the release reference gate",
|
||||
releaseSource.includes('"packages/ui/component-catalog.json"'),
|
||||
],
|
||||
[
|
||||
"platform-independent component reference ordering",
|
||||
referenceGeneratorSource.includes("function compareText(left, right)") &&
|
||||
referenceGeneratorSource.includes("compareText(left.name, right.name)") &&
|
||||
!referenceGeneratorSource.includes("localeCompare"),
|
||||
],
|
||||
]) {
|
||||
if (!condition) fail(`R12 regression: missing ${label}`);
|
||||
}
|
||||
if (!failures.some((item) => item.startsWith("R12 regression:"))) {
|
||||
pass("R12 release reference gate is canonical, complete, and platform independent");
|
||||
}
|
||||
|
||||
const showcaseFiles = walk(join(root, "examples/component-showcase/app"), (path) =>
|
||||
path.endsWith(".wrn"),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user