fix(forms): preserve regex quantifiers and use inline constraint errors

This commit is contained in:
Clintchiz committed 2026-08-26 17:13:07 +05:30
1 parent 1dd60ded0d
commit fe40cc56df
13 files changed
+132 -26

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/compiler",
"version": "0.8.26",
"version": "0.8.27",
"type": "module",
"main": "src/index.ts",
"exports": {
+6 -4
View File
@@ -912,7 +912,7 @@ function renderNestedComponentInvocation(
const compiledValue = wholeExpression
? `\${__wrnProp(${ctx.resolveExpr(wholeExpression)})}`
: compileAttrValue(attr.value, ctx);
: compileAttrValue(attr.value, ctx, attr.name === "pattern");
const rendered = ` ${attr.name}="${compiledValue}"`;
@@ -2254,7 +2254,7 @@ function compileText(raw: string, ctx: CompCtx): string {
}
/** Compile an attribute value; `{expr}` is baked server-side (loop vars stay literal). */
function compileAttrValue(raw: string, ctx: CompCtx): string {
function compileAttrValue(raw: string, ctx: CompCtx, regexPattern = false): string {
if (!raw.includes("{")) return escLit(attrEscape(raw));
let out = "";
let last = 0;
@@ -2263,7 +2263,9 @@ function compileAttrValue(raw: string, ctx: CompCtx): string {
while ((m = INTERP_RE.exec(raw))) {
out += escLit(attrEscape(raw.slice(last, m.index)));
const expr = m[1]!.trim();
if (ctx.loopVars && exprRefsState(expr, ctx.loopVars)) {
if (regexPattern && /^\d+(?:,\d*)?$/.test(expr)) {
out += escLit(attrEscape(m[0])); // Regex quantifiers are not template expressions.
} else if (ctx.loopVars && exprRefsState(expr, ctx.loopVars)) {
out += escLit(`{${expr}}`); // hydrated per-item by the list renderer
} else {
out += `\${__wrnAttr(${ctx.resolveExpr(expr)})}`;
@@ -2628,7 +2630,7 @@ function renderComponentNode(node: ViewNode, ctx: CompCtx): string {
const compiledValue =
isExplicitComponentMount && wholeExpression
? `\${__wrnProp(${elementContext.resolveExpr(wholeExpression)})}`
: compileAttrValue(a.value, elementContext);
: compileAttrValue(a.value, elementContext, a.name === "pattern");
/*
* A constraint attribute whose value is only known at render time (a
@@ -0,0 +1,22 @@
import { test, expect } from "bun:test";
import { parse, generate } from "../src/index.ts";
test("HTML and component pattern attributes preserve regex quantifiers", () => {
for (const tag of ["input", "Input"]) {
for (const pattern of ["[0-9]{6}", "[a-z]{2,8}", "[A-Z]{1,}"]) {
const code = generate(parse(`page Example { view { <${tag} pattern="${pattern}" /> } }`));
expect(code).toContain(pattern);
expect(code).not.toContain("__wrnAttr(6)");
expect(code).not.toContain("__wrnAttr(2,8)");
}
}
});
test("dynamic pattern props still compile as expressions", () => {
const code = generate(
parse(
'component Example { props { pattern: string = "" } view { <input pattern="{pattern}" /> } }',
),
);
expect(code).toContain("__wrnAttr(pattern)");
});